Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEugene Tarassov2011-11-10 20:19:02 -0500
committerEugene Tarassov2011-11-10 20:19:02 -0500
commita107edc216f94c5ec059fdf74541908bc7e979bb (patch)
treea0d9a448043cf5b969c2ede059b7d19a3aa64b71 /agent/tcf/services/linenumbers_proxy.c
parent07c7a005cded9e4b4ec842d756d0e4d79dade149 (diff)
downloadorg.eclipse.tcf.agent-a107edc216f94c5ec059fdf74541908bc7e979bb.tar.gz
org.eclipse.tcf.agent-a107edc216f94c5ec059fdf74541908bc7e979bb.tar.xz
org.eclipse.tcf.agent-a107edc216f94c5ec059fdf74541908bc7e979bb.zip
Agent code is moved into separate "agent" directory, all C code moved into "tcf" directory.
Diffstat (limited to 'agent/tcf/services/linenumbers_proxy.c')
-rw-r--r--agent/tcf/services/linenumbers_proxy.c316
1 files changed, 316 insertions, 0 deletions
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 <config.h>
+
+#if ENABLE_LineNumbersProxy
+
+#include <assert.h>
+#include <stdio.h>
+#include <framework/context.h>
+#include <framework/cache.h>
+#include <framework/json.h>
+#include <framework/events.h>
+#include <framework/myalloc.h>
+#include <framework/exceptions.h>
+#include <services/linenumbers.h>
+
+#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 */

Back to the top