From a107edc216f94c5ec059fdf74541908bc7e979bb Mon Sep 17 00:00:00 2001 From: Eugene Tarassov Date: Thu, 10 Nov 2011 17:19:02 -0800 Subject: Agent code is moved into separate "agent" directory, all C code moved into "tcf" directory. --- agent/tcf/services/linenumbers_proxy.c | 316 +++++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 agent/tcf/services/linenumbers_proxy.c (limited to 'agent/tcf/services/linenumbers_proxy.c') diff --git a/agent/tcf/services/linenumbers_proxy.c b/agent/tcf/services/linenumbers_proxy.c new file mode 100644 index 00000000..3f920727 --- /dev/null +++ b/agent/tcf/services/linenumbers_proxy.c @@ -0,0 +1,316 @@ +/******************************************************************************* + * Copyright (c) 2010 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ + +/* + * TCF service line Numbers - proxy version. + * + * The service associates locations in the source files with the corresponding + * machine instruction addresses in the executable object. + */ + +#include + +#if ENABLE_LineNumbersProxy + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HASH_SIZE (16 * MEM_USAGE_FACTOR - 1) + +/* Line numbers cahce, one per channel */ +typedef struct LineNumbersCache { + unsigned magic; + Channel * channel; + LINK link_root; + LINK link_addr[HASH_SIZE]; +} LineNumbersCache; + +/* Line number to address translation cache */ +typedef struct LineAddressCache { + unsigned magic; + LINK link_cache; + AbstractCache cache; + Context * ctx; + char * file; + int line; + int column; + ReplyHandlerInfo * pending; + ErrorReport * error; + int areas_cnt; + CodeArea * areas; + int disposed; +} LineAddressCache; + +#define LINE_NUMBERS_CACHE_MAGIC 0x19873654 + +#define root2cache(A) ((LineNumbersCache *)((char *)(A) - offsetof(LineNumbersCache, link_root))) +#define cache2addr(A) ((LineAddressCache *)((char *)(A) - offsetof(LineAddressCache, link_cache))) + +static LINK root; + +static int code_area_cnt = 0; +static int code_area_max = 0; +static CodeArea * code_area_buf = NULL; + +static void free_line_address_cache(LineAddressCache * cache) { + assert(cache->magic == LINE_NUMBERS_CACHE_MAGIC); + list_remove(&cache->link_cache); + cache->disposed = 1; + if (cache->pending == NULL) { + int i; + cache->magic = 0; + cache_dispose(&cache->cache); + release_error_report(cache->error); + context_unlock(cache->ctx); + for (i = 0; i < cache->areas_cnt; i++) { + CodeArea * area = cache->areas + i; + loc_free(area->file); + loc_free(area->directory); + } + loc_free(cache->areas); + loc_free(cache->file); + loc_free(cache); + } +} + +static void free_line_numbers_cache(LineNumbersCache * cache) { + int i; + assert(cache->magic == LINE_NUMBERS_CACHE_MAGIC); + cache->magic = 0; + for (i = 0; i < HASH_SIZE; i++) { + while (!list_is_empty(cache->link_addr + i)) { + free_line_address_cache(cache2addr(cache->link_addr[i].next)); + } + } + channel_unlock(cache->channel); + list_remove(&cache->link_root); + loc_free(cache); +} + +static LineNumbersCache * get_line_numbers_cache(void) { + LINK * l = NULL; + LineNumbersCache * cache = NULL; + Channel * c = cache_channel(); + if (c == NULL) exception(ERR_SYM_NOT_FOUND); + for (l = root.next; l != &root; l = l->next) { + LineNumbersCache * x = root2cache(l); + if (x->channel == c) { + cache = x; + break; + } + } + if (cache == NULL) { + int i = 0; + cache = (LineNumbersCache *)loc_alloc_zero(sizeof(LineNumbersCache)); + cache->magic = LINE_NUMBERS_CACHE_MAGIC; + cache->channel = c; + list_add_first(&cache->link_root, &root); + for (i = 0; i < HASH_SIZE; i++) { + list_init(cache->link_addr + i); + } + channel_lock(c); + } + return cache; +} + +static unsigned hash_addr(Context * ctx, const char * file, int line, int column) { + int i; + unsigned h = 0; + for (i = 0; file[i]; i++) h += file[i]; + return (h + ((uintptr_t)ctx >> 4) + (unsigned)line + (unsigned)column) % HASH_SIZE; +} + +static void read_code_area_props(InputStream * inp, const char * name, void * args) { + CodeArea * area = (CodeArea *)args; + if (strcmp(name, "SLine") == 0) area->start_line = json_read_long(inp); + else if (strcmp(name, "SCol") == 0) area->start_column = json_read_long(inp); + else if (strcmp(name, "SAddr") == 0) area->start_address = (ContextAddress)json_read_uint64(inp); + else if (strcmp(name, "ELine") == 0) area->end_line = json_read_long(inp); + else if (strcmp(name, "ECol") == 0) area->end_column = json_read_long(inp); + else if (strcmp(name, "EAddr") == 0) area->end_address = (ContextAddress)json_read_uint64(inp); + else if (strcmp(name, "File") == 0) area->file = json_read_alloc_string(inp); + else if (strcmp(name, "Dir") == 0) area->directory = json_read_alloc_string(inp); + else if (strcmp(name, "ISA") == 0) area->isa = json_read_long(inp); + else if (strcmp(name, "IsStmt") == 0) area->is_statement = json_read_boolean(inp); + else if (strcmp(name, "BasicBlock") == 0) area->basic_block = json_read_boolean(inp); + else if (strcmp(name, "PrologueEnd") == 0) area->prologue_end = json_read_boolean(inp); + else if (strcmp(name, "EpilogueBegin") == 0) area->epilogue_begin = json_read_boolean(inp); +} + +static void read_code_area_array(InputStream * inp, void * args) { + CodeArea * area = NULL; + if (code_area_cnt >= code_area_max) { + code_area_max += 8; + code_area_buf = (CodeArea *)loc_realloc(code_area_buf, sizeof(CodeArea) * code_area_max); + } + area = code_area_buf + code_area_cnt++; + memset(area, 0, sizeof(CodeArea)); + json_read_struct(inp, read_code_area_props, area); +} + +static void validate_map_to_memory(Channel * c, void * args, int error) { + Trap trap; + LineAddressCache * f = (LineAddressCache *)args; + assert(f->magic == LINE_NUMBERS_CACHE_MAGIC); + assert(f->pending != NULL); + assert(f->error == NULL); + if (set_trap(&trap)) { + f->pending = NULL; + if (!error) { + error = read_errno(&c->inp); + code_area_cnt = 0; + json_read_array(&c->inp, read_code_area_array, NULL); + if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); + if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); + if (code_area_cnt > 0) { + f->areas_cnt = code_area_cnt; + f->areas = (CodeArea *)loc_alloc(sizeof(CodeArea) * code_area_cnt); + memcpy(f->areas, code_area_buf, sizeof(CodeArea) * code_area_cnt); + } + } + clear_trap(&trap); + } + else { + error = trap.error; + } + f->error = get_error_report(error); + cache_notify(&f->cache); + if (f->disposed) free_line_address_cache(f); + if (trap.error) exception(trap.error); +} + +int line_to_address(Context * ctx, char * file, int line, int column, + LineNumbersCallBack * client, void * args) { + LINK * l = NULL; + LineNumbersCache * cache = NULL; + LineAddressCache * f = NULL; + unsigned h; + Trap trap; + + if (!set_trap(&trap)) return -1; + + ctx = context_get_group(ctx, CONTEXT_GROUP_PROCESS); + h = hash_addr(ctx, file, line, column); + cache = get_line_numbers_cache(); + assert(cache->magic == LINE_NUMBERS_CACHE_MAGIC); + for (l = cache->link_addr[h].next; l != cache->link_addr + h; l = l->next) { + LineAddressCache * c = cache2addr(l); + if (c->ctx == ctx && c->line == line && c->column == column && strcmp(c->file, file) == 0) { + assert(c->magic == LINE_NUMBERS_CACHE_MAGIC); + f = c; + break; + } + } + + if (f == NULL) { + Channel * c = cache_channel(); + if (c == NULL) exception(ERR_UNSUPPORTED); + f = (LineAddressCache *)loc_alloc_zero(sizeof(LineAddressCache)); + list_add_first(&f->link_cache, cache->link_addr + h); + f->magic = LINE_NUMBERS_CACHE_MAGIC; + context_lock(f->ctx = ctx); + f->file = loc_strdup(file); + f->line = line; + f->column = column; + f->pending = protocol_send_command(c, "LineNumbers", "mapToMemory", validate_map_to_memory, f); + json_write_string(&c->out, ctx->id); + write_stream(&c->out, 0); + json_write_string(&c->out, file); + write_stream(&c->out, 0); + json_write_long(&c->out, line); + write_stream(&c->out, 0); + json_write_long(&c->out, column); + write_stream(&c->out, 0); + write_stream(&c->out, MARKER_EOM); + cache_wait(&f->cache); + } + else if (f->pending != NULL) { + cache_wait(&f->cache); + } + else if (f->error != NULL) { + char msg[FILE_PATH_SIZE + 64]; + snprintf(msg, sizeof(msg), "Text position '%s:%d' not found", file, line); + exception(set_errno(set_error_report_errno(f->error), msg)); + } + else { + int i; + for (i = 0; i < f->areas_cnt; i++) { + client(f->areas + i, args); + } + } + clear_trap(&trap); + return 0; +} + +static void flush_cache(Context * ctx) { + LINK * l; + LINK * m; + int i; + + for (m = root.next; m != &root; m = m->next) { + LineNumbersCache * cache = root2cache(m); + for (i = 0; i < HASH_SIZE; i++) { + l = cache->link_addr[i].next; + while (l != cache->link_addr + i) { + LineAddressCache * c = cache2addr(l); + l = l->next; + if (c->ctx == ctx) free_line_address_cache(c); + } + } + } +} + +static void event_context_created(Context * ctx, void * x) { + if (ctx == context_get_group(ctx, CONTEXT_GROUP_PROCESS)) flush_cache(ctx); +} + +static void event_context_exited(Context * ctx, void * x) { + if (ctx == context_get_group(ctx, CONTEXT_GROUP_PROCESS)) flush_cache(ctx); +} + +static void event_context_changed(Context * ctx, void * x) { + flush_cache(context_get_group(ctx, CONTEXT_GROUP_PROCESS)); +} + +static void channel_close_listener(Channel * c) { + LINK * l = root.next; + while (l != &root) { + LineNumbersCache * cache = root2cache(l); + l = l->next; + if (cache->channel == c) free_line_numbers_cache(cache); + } +} + +void ini_line_numbers_lib(void) { + static ContextEventListener listener = { + event_context_created, + event_context_exited, + NULL, + NULL, + event_context_changed + }; + list_init(&root); + add_context_event_listener(&listener, NULL); + add_channel_close_listener(channel_close_listener); +} + +#endif /* ENABLE_LineNumbersProxy */ -- cgit v1.2.3