Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'agent/tcf/services/symbols_proxy.c')
-rw-r--r--agent/tcf/services/symbols_proxy.c1356
1 files changed, 1356 insertions, 0 deletions
diff --git a/agent/tcf/services/symbols_proxy.c b/agent/tcf/services/symbols_proxy.c
new file mode 100644
index 00000000..d145de92
--- /dev/null
+++ b/agent/tcf/services/symbols_proxy.c
@@ -0,0 +1,1356 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 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
+ *******************************************************************************/
+
+/*
+ * Symbols service - proxy implementation, gets symbols information from host.
+ */
+
+/* TODO: need to cleanup symbols cache from data that not used for long time */
+
+#include <config.h>
+
+#if ENABLE_SymbolsProxy
+
+#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/stacktrace.h>
+#include <services/symbols.h>
+#if ENABLE_RCBP_TEST
+# include <main/test.h>
+#endif
+
+#define HASH_SIZE (4 * MEM_USAGE_FACTOR - 1)
+
+/* Symbols cahce, one per channel */
+typedef struct SymbolsCache {
+ Channel * channel;
+ LINK link_root;
+ LINK link_sym[HASH_SIZE];
+ LINK link_find_by_name[HASH_SIZE];
+ LINK link_find_in_scope[HASH_SIZE];
+ LINK link_list[HASH_SIZE];
+ LINK link_frame[HASH_SIZE];
+ int service_available;
+} SymbolsCache;
+
+/* Symbol properties cache */
+typedef struct SymInfoCache {
+ unsigned magic;
+ LINK link_syms;
+ AbstractCache cache;
+ char * id;
+ char * type_id;
+ char * base_type_id;
+ char * index_type_id;
+ char * register_id;
+ char * name;
+ Context * update_owner;
+ int update_policy;
+ int sym_class;
+ int type_class;
+ int has_size;
+ int has_address;
+ int has_offset;
+ int has_length;
+ int has_lower_bound;
+ int has_upper_bound;
+ SYM_FLAGS flags;
+ ContextAddress address;
+ ContextAddress size;
+ ContextAddress offset;
+ ContextAddress length;
+ int64_t lower_bound;
+ int64_t upper_bound;
+ char * value;
+ size_t value_size;
+ int big_endian;
+ char ** children_ids;
+ int children_count;
+ ReplyHandlerInfo * pending_get_context;
+ ReplyHandlerInfo * pending_get_children;
+ ErrorReport * error_get_context;
+ ErrorReport * error_get_children;
+ int done_context;
+ int done_children;
+ LINK array_syms;
+ int disposed;
+} SymInfoCache;
+
+/* Cached result of get_array_symbol() */
+typedef struct ArraySymCache {
+ LINK link_sym;
+ AbstractCache cache;
+ ContextAddress length;
+ ReplyHandlerInfo * pending;
+ ErrorReport * error;
+ char * id;
+ int disposed;
+} ArraySymCache;
+
+/* Cached result of find_symbol() */
+typedef struct FindSymCache {
+ LINK link_syms;
+ AbstractCache cache;
+ ReplyHandlerInfo * pending;
+ ErrorReport * error;
+ int update_policy;
+ Context * ctx;
+ uint64_t ip;
+ char * scope;
+ char * name;
+ char * id;
+ int disposed;
+} FindSymCache;
+
+/* Cached result of enumerate_symbols() */
+typedef struct ListSymCache {
+ LINK link_syms;
+ AbstractCache cache;
+ ReplyHandlerInfo * pending;
+ ErrorReport * error;
+ int update_policy;
+ Context * ctx;
+ uint64_t ip;
+ char ** list;
+ unsigned list_size;
+ unsigned list_max;
+ int disposed;
+} ListSymCache;
+
+typedef struct StackFrameCache {
+ LINK link_syms;
+ AbstractCache cache;
+ ReplyHandlerInfo * pending;
+ ErrorReport * error;
+ Context * ctx;
+ uint64_t ip;
+ uint64_t address;
+ uint64_t size;
+
+ StackTracingCommandSequence * fp;
+ StackTracingCommandSequence ** regs;
+ int regs_cnt;
+
+ int disposed;
+} StackFrameCache;
+
+#define SYM_CACHE_MAGIC 0x38254865
+
+#define root2syms(A) ((SymbolsCache *)((char *)(A) - offsetof(SymbolsCache, link_root)))
+#define syms2sym(A) ((SymInfoCache *)((char *)(A) - offsetof(SymInfoCache, link_syms)))
+#define syms2find(A) ((FindSymCache *)((char *)(A) - offsetof(FindSymCache, link_syms)))
+#define syms2list(A) ((ListSymCache *)((char *)(A) - offsetof(ListSymCache, link_syms)))
+#define sym2arr(A) ((ArraySymCache *)((char *)(A) - offsetof(ArraySymCache, link_sym)))
+#define syms2frame(A)((StackFrameCache *)((char *)(A) - offsetof(StackFrameCache, link_syms)))
+
+struct Symbol {
+ unsigned magic;
+ SymInfoCache * cache;
+};
+
+#include <services/symbols_alloc.h>
+
+static LINK root;
+
+static const char * SYMBOLS = "Symbols";
+
+static unsigned hash_sym_id(const char * id) {
+ int i;
+ unsigned h = 0;
+ for (i = 0; id[i]; i++) h += id[i];
+ return h % HASH_SIZE;
+}
+
+static unsigned hash_find(Context * ctx, const char * name, uint64_t ip) {
+ int i;
+ unsigned h = 0;
+ for (i = 0; name[i]; i++) h += name[i];
+ return (h + ((uintptr_t)ctx >> 4) + (unsigned)ip) % HASH_SIZE;
+}
+
+static unsigned hash_list(Context * ctx, uint64_t ip) {
+ return (((uintptr_t)ctx >> 4) + (unsigned)ip) % HASH_SIZE;
+}
+
+static unsigned hash_frame(Context * ctx) {
+ return ((uintptr_t)ctx >> 4) % HASH_SIZE;
+}
+
+static SymbolsCache * get_symbols_cache(void) {
+ LINK * l = NULL;
+ SymbolsCache * syms = NULL;
+ Channel * c = cache_channel();
+ if (c == NULL) {
+ str_exception(ERR_OTHER, "get_symbols_cache(): illegal cache access");
+ }
+ for (l = root.next; l != &root; l = l->next) {
+ SymbolsCache * x = root2syms(l);
+ if (x->channel == c) {
+ syms = x;
+ break;
+ }
+ }
+ if (syms == NULL) {
+ int i = 0;
+ syms = (SymbolsCache *)loc_alloc_zero(sizeof(SymbolsCache));
+ syms->channel = c;
+ list_add_first(&syms->link_root, &root);
+ for (i = 0; i < HASH_SIZE; i++) {
+ list_init(syms->link_sym + i);
+ list_init(syms->link_find_by_name + i);
+ list_init(syms->link_find_in_scope + i);
+ list_init(syms->link_list + i);
+ list_init(syms->link_frame + i);
+ }
+ channel_lock(c);
+ for (i = 0; i < c->peer_service_cnt; i++) {
+ if (strcmp(c->peer_service_list[i], SYMBOLS) == 0) syms->service_available = 1;
+ }
+ }
+ return syms;
+}
+
+static void free_arr_sym_cache(ArraySymCache * a) {
+ list_remove(&a->link_sym);
+ a->disposed = 1;
+ if (a->pending == NULL) {
+ cache_dispose(&a->cache);
+ release_error_report(a->error);
+ loc_free(a->id);
+ loc_free(a);
+ }
+}
+
+static void free_sym_info_cache(SymInfoCache * c) {
+ assert(c->magic == SYM_CACHE_MAGIC);
+ list_remove(&c->link_syms);
+ c->disposed = 1;
+ if (c->pending_get_context == NULL && c->pending_get_children == NULL) {
+ c->magic = 0;
+ cache_dispose(&c->cache);
+ loc_free(c->id);
+ loc_free(c->type_id);
+ loc_free(c->base_type_id);
+ loc_free(c->index_type_id);
+ loc_free(c->register_id);
+ loc_free(c->name);
+ loc_free(c->value);
+ loc_free(c->children_ids);
+ if (c->update_owner != NULL) context_unlock(c->update_owner);
+ release_error_report(c->error_get_context);
+ release_error_report(c->error_get_children);
+ while (!list_is_empty(&c->array_syms)) {
+ free_arr_sym_cache(sym2arr(c->array_syms.next));
+ }
+ loc_free(c);
+ }
+}
+
+static void free_find_sym_cache(FindSymCache * c) {
+ list_remove(&c->link_syms);
+ c->disposed = 1;
+ if (c->pending == NULL) {
+ cache_dispose(&c->cache);
+ release_error_report(c->error);
+ context_unlock(c->ctx);
+ loc_free(c->name);
+ loc_free(c->id);
+ loc_free(c);
+ }
+}
+
+static void free_list_sym_cache(ListSymCache * c) {
+ list_remove(&c->link_syms);
+ c->disposed = 1;
+ if (c->pending == NULL) {
+ unsigned j;
+ cache_dispose(&c->cache);
+ release_error_report(c->error);
+ context_unlock(c->ctx);
+ for (j = 0; j < c->list_size; j++) loc_free(c->list[j]);
+ loc_free(c->list);
+ loc_free(c);
+ }
+}
+
+static void free_stack_frame_cache(StackFrameCache * c) {
+ list_remove(&c->link_syms);
+ c->disposed = 1;
+ if (c->pending == NULL) {
+ int i;
+ cache_dispose(&c->cache);
+ release_error_report(c->error);
+ context_unlock(c->ctx);
+ for (i = 0; i < c->regs_cnt; i++) loc_free(c->regs[i]);
+ loc_free(c->regs);
+ loc_free(c->fp);
+ loc_free(c);
+ }
+}
+
+static void free_symbols_cache(SymbolsCache * syms) {
+ int i;
+ for (i = 0; i < HASH_SIZE; i++) {
+ while (!list_is_empty(syms->link_sym + i)) {
+ free_sym_info_cache(syms2sym(syms->link_sym[i].next));
+ }
+ while (!list_is_empty(syms->link_find_by_name + i)) {
+ free_find_sym_cache(syms2find(syms->link_find_by_name[i].next));
+ }
+ while (!list_is_empty(syms->link_find_in_scope + i)) {
+ free_find_sym_cache(syms2find(syms->link_find_in_scope[i].next));
+ }
+ while (!list_is_empty(syms->link_list + i)) {
+ free_list_sym_cache(syms2list(syms->link_list[i].next));
+ }
+ while (!list_is_empty(syms->link_frame + i)) {
+ free_stack_frame_cache(syms2frame(syms->link_frame[i].next));
+ }
+ }
+ channel_unlock(syms->channel);
+ list_remove(&syms->link_root);
+ loc_free(syms);
+}
+
+static Channel * get_channel(SymbolsCache * syms) {
+ if (!syms->service_available) str_exception(ERR_SYM_NOT_FOUND, "Symbols service not available");
+ return syms->channel;
+}
+
+static void read_context_data(InputStream * inp, const char * name, void * args) {
+ char id[256];
+ SymInfoCache * s = (SymInfoCache *)args;
+ if (strcmp(name, "ID") == 0) { json_read_string(inp, id, sizeof(id)); assert(strcmp(id, s->id) == 0); }
+ else if (strcmp(name, "OwnerID") == 0) { json_read_string(inp, id, sizeof(id)); s->update_owner = id2ctx(id); }
+ else if (strcmp(name, "Name") == 0) s->name = json_read_alloc_string(inp);
+ else if (strcmp(name, "UpdatePolicy") == 0) s->update_policy = json_read_long(inp);
+ else if (strcmp(name, "Class") == 0) s->sym_class = json_read_long(inp);
+ else if (strcmp(name, "TypeClass") == 0) s->type_class = json_read_long(inp);
+ else if (strcmp(name, "TypeID") == 0) s->type_id = json_read_alloc_string(inp);
+ else if (strcmp(name, "BaseTypeID") == 0) s->base_type_id = json_read_alloc_string(inp);
+ else if (strcmp(name, "IndexTypeID") == 0) s->index_type_id = json_read_alloc_string(inp);
+ else if (strcmp(name, "Size") == 0) { s->size = json_read_long(inp); s->has_size = 1; }
+ else if (strcmp(name, "Length") == 0) { s->length = json_read_long(inp); s->has_length = 1; }
+ else if (strcmp(name, "LowerBound") == 0) { s->lower_bound = json_read_int64(inp); s->has_lower_bound = 1; }
+ else if (strcmp(name, "UpperBound") == 0) { s->upper_bound = json_read_int64(inp); s->has_upper_bound = 1; }
+ else if (strcmp(name, "Offset") == 0) { s->offset = json_read_long(inp); s->has_offset = 1; }
+ else if (strcmp(name, "Address") == 0) { s->address = (ContextAddress)json_read_uint64(inp); s->has_address = 1; }
+ else if (strcmp(name, "Register") == 0) s->register_id = json_read_alloc_string(inp);
+ else if (strcmp(name, "Flags") == 0) s->flags = json_read_ulong(inp);
+ else if (strcmp(name, "Value") == 0) s->value = json_read_alloc_binary(inp, &s->value_size);
+ else if (strcmp(name, "BigEndian") == 0) s->big_endian = json_read_boolean(inp);
+ else json_skip_object(inp);
+}
+
+static void validate_context(Channel * c, void * args, int error) {
+ Trap trap;
+ SymInfoCache * s = (SymInfoCache *)args;
+ assert(s->pending_get_context != NULL);
+ assert(s->error_get_context == NULL);
+ assert(s->update_owner == NULL);
+ assert(!s->done_context);
+ if (set_trap(&trap)) {
+ s->pending_get_context = NULL;
+ s->done_context = 1;
+ if (!error) {
+ error = read_errno(&c->inp);
+ json_read_struct(&c->inp, read_context_data, s);
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+ if (!error && s->update_owner == NULL) error = ERR_INV_CONTEXT;
+ if (!error && s->update_owner->exited) error = ERR_ALREADY_EXITED;
+ }
+ clear_trap(&trap);
+ if (s->update_owner != NULL) context_lock(s->update_owner);
+ }
+ else {
+ error = trap.error;
+ s->update_owner = NULL;
+ }
+ s->error_get_context = get_error_report(error);
+ cache_notify(&s->cache);
+ if (s->disposed) free_sym_info_cache(s);
+ if (trap.error) exception(trap.error);
+}
+
+static SymInfoCache * get_sym_info_cache(const Symbol * sym) {
+ Trap trap;
+ SymInfoCache * s = sym->cache;
+ assert(sym->magic == SYMBOL_MAGIC);
+ assert(s->magic == SYM_CACHE_MAGIC);
+ assert(s->id != NULL);
+ if (!set_trap(&trap)) return NULL;
+ if (s->pending_get_context != NULL) {
+ cache_wait(&s->cache);
+ }
+ else if (s->error_get_context != NULL) {
+ exception(set_error_report_errno(s->error_get_context));
+ }
+ else if (!s->done_context) {
+ Channel * c = cache_channel();
+ if (c == NULL) exception(ERR_SYM_NOT_FOUND);
+ s->pending_get_context = protocol_send_command(c, SYMBOLS, "getContext", validate_context, s);
+ json_write_string(&c->out, s->id);
+ write_stream(&c->out, 0);
+ write_stream(&c->out, MARKER_EOM);
+ cache_wait(&s->cache);
+ }
+ clear_trap(&trap);
+ return s;
+}
+
+static void validate_find(Channel * c, void * args, int error) {
+ Trap trap;
+ FindSymCache * f = (FindSymCache *)args;
+ assert(f->pending != NULL);
+ assert(f->error == NULL);
+ if (set_trap(&trap)) {
+ f->pending = NULL;
+ if (!error) {
+ error = read_errno(&c->inp);
+ f->id = json_read_alloc_string(&c->inp);
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+ }
+ clear_trap(&trap);
+ }
+ else {
+ error = trap.error;
+ }
+ f->error = get_error_report(error);
+ assert(f->error != NULL || f->id != NULL);
+ cache_notify(&f->cache);
+ if (f->disposed) free_find_sym_cache(f);
+ if (trap.error) exception(trap.error);
+}
+
+int find_symbol_by_name(Context * ctx, int frame, ContextAddress addr, char * name, Symbol ** sym) {
+ uint64_t ip = 0;
+ LINK * l = NULL;
+ SymbolsCache * syms = NULL;
+ FindSymCache * f = NULL;
+ unsigned h;
+ Trap trap;
+
+ if (!set_trap(&trap)) return -1;
+
+ if (frame == STACK_NO_FRAME) {
+ ctx = context_get_group(ctx, CONTEXT_GROUP_PROCESS);
+ ip = addr;
+ }
+ else {
+ StackFrame * info = NULL;
+ if (frame == STACK_TOP_FRAME && (frame = get_top_frame(ctx)) < 0) exception(errno);;
+ if (get_frame_info(ctx, frame, &info) < 0) exception(errno);
+ if (read_reg_value(info, get_PC_definition(ctx), &ip) < 0) exception(errno);
+ }
+
+ h = hash_find(ctx, name, ip);
+ syms = get_symbols_cache();
+ for (l = syms->link_find_by_name[h].next; l != syms->link_find_by_name + h; l = l->next) {
+ FindSymCache * c = syms2find(l);
+ if (c->ctx == ctx && c->ip == ip && strcmp(c->name, name) == 0) {
+ f = c;
+ break;
+ }
+ }
+
+#if ENABLE_RCBP_TEST
+ if ((f == NULL && !syms->service_available) || (f != NULL && f->pending == NULL && f->error != NULL)) {
+ void * address = NULL;
+ int sym_class = 0;
+ if (find_test_symbol(ctx, name, &address, &sym_class) >= 0) {
+ char bf[256];
+ if (f == NULL) {
+ f = (FindSymCache *)loc_alloc_zero(sizeof(FindSymCache));
+ list_add_first(&f->link_syms, syms->link_find_by_name + h);
+ context_lock(f->ctx = ctx);
+ f->name = loc_strdup(name);
+ f->ip = ip;
+ }
+ else {
+ release_error_report(f->error);
+ loc_free(f->id);
+ f->error = NULL;
+ f->id = NULL;
+ }
+ f->update_policy = UPDATE_ON_MEMORY_MAP_CHANGES;
+ snprintf(bf, sizeof(bf), "@T.%X.%"PRIX64".%s", sym_class,
+ (uint64_t)(uintptr_t)address, context_get_group(ctx, CONTEXT_GROUP_PROCESS)->id);
+ f->id = loc_strdup(bf);
+ }
+ }
+#endif
+
+ if (f == NULL) {
+ Channel * c = get_channel(syms);
+ f = (FindSymCache *)loc_alloc_zero(sizeof(FindSymCache));
+ list_add_first(&f->link_syms, syms->link_find_by_name + h);
+ context_lock(f->ctx = ctx);
+ f->ip = ip;
+ f->name = loc_strdup(name);
+ f->update_policy = ip ? UPDATE_ON_EXE_STATE_CHANGES : UPDATE_ON_MEMORY_MAP_CHANGES;
+ f->pending = protocol_send_command(c, SYMBOLS, "find", validate_find, f);
+ if (frame != STACK_NO_FRAME) {
+ json_write_string(&c->out, frame2id(ctx, frame));
+ }
+ else {
+ json_write_string(&c->out, ctx->id);
+ }
+ write_stream(&c->out, 0);
+ json_write_uint64(&c->out, ip);
+ write_stream(&c->out, 0);
+ json_write_string(&c->out, name);
+ 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[256];
+ snprintf(msg, sizeof(msg), "Symbol '%s' not found", name);
+ exception(set_errno(set_error_report_errno(f->error), msg));
+ }
+ else if (id2symbol(f->id, sym) < 0) {
+ exception(errno);
+ }
+ clear_trap(&trap);
+ return 0;
+}
+
+int find_symbol_in_scope(Context * ctx, int frame, ContextAddress addr, Symbol * scope, char * name, Symbol ** sym) {
+ uint64_t ip = 0;
+ LINK * l = NULL;
+ SymbolsCache * syms = NULL;
+ FindSymCache * f = NULL;
+ unsigned h;
+ Trap trap;
+
+ if (!set_trap(&trap)) return -1;
+
+ if (frame == STACK_NO_FRAME) {
+ ctx = context_get_group(ctx, CONTEXT_GROUP_PROCESS);
+ ip = addr;
+ }
+ else {
+ StackFrame * info = NULL;
+ if (frame == STACK_TOP_FRAME && (frame = get_top_frame(ctx)) < 0) exception(errno);;
+ if (get_frame_info(ctx, frame, &info) < 0) exception(errno);
+ if (read_reg_value(info, get_PC_definition(ctx), &ip) < 0) exception(errno);
+ }
+
+ h = hash_find(ctx, name, ip);
+ syms = get_symbols_cache();
+ for (l = syms->link_find_in_scope[h].next; l != syms->link_find_in_scope + h; l = l->next) {
+ FindSymCache * c = syms2find(l);
+ if (c->ctx == ctx && c->ip == ip && strcmp(c->name, name) == 0) {
+ if (scope == NULL && c->scope == NULL) {
+ f = c;
+ break;
+ }
+ if (scope == NULL || c->scope == NULL) continue;
+ if (strcmp(scope->cache->id, c->scope) == 0) {
+ f = c;
+ break;
+ }
+ }
+ }
+
+ if (f == NULL) {
+ Channel * c = get_channel(syms);
+ f = (FindSymCache *)loc_alloc_zero(sizeof(FindSymCache));
+ list_add_first(&f->link_syms, syms->link_find_in_scope + h);
+ context_lock(f->ctx = ctx);
+ f->ip = ip;
+ if (scope != NULL) f->scope = loc_strdup(scope->cache->id);
+ f->name = loc_strdup(name);
+ f->update_policy = ip ? UPDATE_ON_EXE_STATE_CHANGES : UPDATE_ON_MEMORY_MAP_CHANGES;
+ f->pending = protocol_send_command(c, SYMBOLS, "findInScope", validate_find, f);
+ if (frame != STACK_NO_FRAME) {
+ json_write_string(&c->out, frame2id(ctx, frame));
+ }
+ else {
+ json_write_string(&c->out, ctx->id);
+ }
+ write_stream(&c->out, 0);
+ json_write_uint64(&c->out, ip);
+ write_stream(&c->out, 0);
+ json_write_string(&c->out, scope ? scope->cache->id : NULL);
+ write_stream(&c->out, 0);
+ json_write_string(&c->out, name);
+ 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[256];
+ snprintf(msg, sizeof(msg), "Symbol '%s' not found", name);
+ exception(set_errno(set_error_report_errno(f->error), msg));
+ }
+ else if (id2symbol(f->id, sym) < 0) {
+ exception(errno);
+ }
+ clear_trap(&trap);
+ return 0;
+}
+
+int find_symbol_by_addr(Context * ctx, int frame, ContextAddress addr, Symbol ** sym) {
+ errno = ERR_UNSUPPORTED;
+ return -1;
+}
+
+static void read_sym_list_item(InputStream * inp, void * args) {
+ ListSymCache * f = (ListSymCache *)args;
+ char * id = json_read_alloc_string(inp);
+ if (f->list_size >= f->list_max) {
+ f->list_max += 16;
+ f->list = (char **)loc_realloc(f->list, f->list_max * sizeof(char *));
+ }
+ f->list[f->list_size++] = id;
+}
+
+static void validate_list(Channel * c, void * args, int error) {
+ Trap trap;
+ ListSymCache * f = (ListSymCache *)args;
+ assert(f->pending != NULL);
+ assert(f->error == NULL);
+ if (set_trap(&trap)) {
+ f->pending = NULL;
+ if (!error) {
+ error = read_errno(&c->inp);
+ json_read_array(&c->inp, read_sym_list_item, f);
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+ }
+ clear_trap(&trap);
+ }
+ else {
+ error = trap.error;
+ }
+ f->error = get_error_report(error);
+ cache_notify(&f->cache);
+ if (f->disposed) free_list_sym_cache(f);
+ if (trap.error) exception(trap.error);
+}
+
+int enumerate_symbols(Context * ctx, int frame, EnumerateSymbolsCallBack * func, void * args) {
+ uint64_t ip = 0;
+ unsigned h;
+ LINK * l;
+ Trap trap;
+ SymbolsCache * syms = NULL;
+ ListSymCache * f = NULL;
+
+ if (!set_trap(&trap)) return -1;
+
+ if (frame == STACK_NO_FRAME) {
+ ctx = context_get_group(ctx, CONTEXT_GROUP_PROCESS);
+ }
+ else {
+ StackFrame * info = NULL;
+ if (frame == STACK_TOP_FRAME && (frame = get_top_frame(ctx)) < 0) exception(errno);;
+ if (get_frame_info(ctx, frame, &info) < 0) exception(errno);
+ if (read_reg_value(info, get_PC_definition(ctx), &ip) < 0) exception(errno);
+ }
+
+ h = hash_list(ctx, ip);
+ syms = get_symbols_cache();
+ for (l = syms->link_list[h].next; l != syms->link_list + h; l = l->next) {
+ ListSymCache * c = syms2list(l);
+ if (c->ctx == ctx && c->ip == ip) {
+ f = c;
+ break;
+ }
+ }
+
+ if (f == NULL) {
+ Channel * c = get_channel(syms);
+ f = (ListSymCache *)loc_alloc_zero(sizeof(ListSymCache));
+ list_add_first(&f->link_syms, syms->link_list + h);
+ context_lock(f->ctx = ctx);
+ f->ip = ip;
+ f->update_policy = ip ? UPDATE_ON_EXE_STATE_CHANGES : UPDATE_ON_MEMORY_MAP_CHANGES;
+ f->pending = protocol_send_command(c, SYMBOLS, "list", validate_list, f);
+ if (frame != STACK_NO_FRAME) {
+ json_write_string(&c->out, frame2id(ctx, frame));
+ }
+ else {
+ json_write_string(&c->out, ctx->id);
+ }
+ 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) {
+ exception(set_error_report_errno(f->error));
+ }
+ else {
+ unsigned i;
+ for (i = 0; i < f->list_size; i++) {
+ Symbol * sym = NULL;
+ if (id2symbol(f->list[i], &sym) < 0) exception(errno);
+ func(args, sym);
+ }
+ }
+ clear_trap(&trap);
+ return 0;
+}
+
+const char * symbol2id(const Symbol * sym) {
+ SymInfoCache * s = sym->cache;
+ assert(s->magic == SYM_CACHE_MAGIC);
+ assert(s->id != NULL);
+ return s->id;
+}
+
+int id2symbol(const char * id, Symbol ** sym) {
+ LINK * l;
+ SymInfoCache * s = NULL;
+ unsigned h = hash_sym_id(id);
+ SymbolsCache * syms = get_symbols_cache();
+
+ for (l = syms->link_sym[h].next; l != syms->link_sym + h; l = l->next) {
+ SymInfoCache * x = syms2sym(l);
+ if (strcmp(x->id, id) == 0) {
+ s = x;
+ break;
+ }
+ }
+ if (s == NULL) {
+ s = (SymInfoCache *)loc_alloc_zero(sizeof(SymInfoCache));
+ s->magic = SYM_CACHE_MAGIC;
+ s->id = loc_strdup(id);
+ list_add_first(&s->link_syms, syms->link_sym + h);
+ list_init(&s->array_syms);
+#if ENABLE_RCBP_TEST
+ if (strncmp(id, "@T.", 3) == 0) {
+ int sym_class = 0;
+ uint64_t address = 0;
+ char ctx_id[256];
+ if (sscanf(id, "@T.%X.%"SCNx64".%255s", &sym_class, &address, ctx_id) == 3) {
+ s->done_context = 1;
+ s->has_address = 1;
+ s->address = (ContextAddress)address;
+ s->sym_class = sym_class;
+ s->update_policy = UPDATE_ON_MEMORY_MAP_CHANGES;
+ s->update_owner = id2ctx(ctx_id);
+ if (s->update_owner != NULL) context_lock(s->update_owner);
+ }
+ }
+#endif
+ }
+ *sym = alloc_symbol();
+ (*sym)->cache = s;
+ return 0;
+}
+
+/*************** Functions for retrieving symbol properties ***************************************/
+
+int get_symbol_class(const Symbol * sym, int * symbol_class) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ *symbol_class = c->sym_class;
+ return 0;
+}
+
+int get_symbol_type(const Symbol * sym, Symbol ** type) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ if (c->type_id) return id2symbol(c->type_id, type);
+ return 0;
+}
+
+int get_symbol_type_class(const Symbol * sym, int * type_class) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ *type_class = c->type_class;
+ return 0;
+}
+
+int get_symbol_update_policy(const Symbol * sym, char ** id, int * policy) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ if (c->update_owner == NULL) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ *id = c->update_owner->id;
+ *policy = c->update_policy;
+ return 0;
+}
+
+int get_symbol_name(const Symbol * sym, char ** name) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ *name = c->name;
+ return 0;
+}
+
+int get_symbol_base_type(const Symbol * sym, Symbol ** type) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ if (c->base_type_id) return id2symbol(c->base_type_id, type);
+ return 0;
+}
+
+int get_symbol_index_type(const Symbol * sym, Symbol ** type) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ if (c->index_type_id) return id2symbol(c->index_type_id, type);
+ return 0;
+}
+
+int get_symbol_size(const Symbol * sym, ContextAddress * size) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ if (!c->has_size) {
+ errno = set_errno(ERR_OTHER, "Debug info not available");
+ return -1;
+ }
+ *size = c->size;
+ return 0;
+}
+
+int get_symbol_length(const Symbol * sym, ContextAddress * length) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ if (c->has_length) {
+ *length = c->length;
+ return 0;
+ }
+ if (c->has_lower_bound && c->has_upper_bound) {
+ *length = (ContextAddress)(c->has_upper_bound - c->has_lower_bound + 1);
+ return 0;
+ }
+ errno = ERR_INV_CONTEXT;
+ return -1;
+}
+
+int get_symbol_lower_bound(const Symbol * sym, int64_t * lower_bound) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ if (!c->has_lower_bound) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ *lower_bound = c->lower_bound;
+ return 0;
+}
+
+int get_symbol_offset(const Symbol * sym, ContextAddress * offset) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ if (!c->has_offset) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ *offset = c->offset;
+ return 0;
+}
+
+int get_symbol_value(const Symbol * sym, void ** value, size_t * size, int * big_endian) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ if (c->sym_class != SYM_CLASS_VALUE) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ *value = c->value;
+ *size = c->value_size;
+ *big_endian = c->big_endian;
+ return 0;
+}
+
+int get_symbol_address(const Symbol * sym, ContextAddress * address) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ if (!c->has_address) {
+ errno = ERR_INV_ADDRESS;
+ return -1;
+ }
+ *address = c->address;
+ return 0;
+}
+
+int get_symbol_register(const Symbol * sym, Context ** ctx, int * frame, RegisterDefinition ** reg) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ if (c->register_id == NULL) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ return id2register(c->register_id, ctx, frame, reg);
+}
+
+int get_symbol_flags(const Symbol * sym, SYM_FLAGS * flags) {
+ SymInfoCache * c = get_sym_info_cache(sym);
+ if (c == NULL) return -1;
+ *flags = c->flags;
+ return 0;
+}
+
+static void validate_children(Channel * c, void * args, int error) {
+ Trap trap;
+ SymInfoCache * s = (SymInfoCache *)args;
+ assert(s->pending_get_children != NULL);
+ assert(s->error_get_children == NULL);
+ assert(!s->done_children);
+ if (set_trap(&trap)) {
+ s->pending_get_children = NULL;
+ s->done_children = 1;
+ if (!error) {
+ error = read_errno(&c->inp);
+ s->children_ids = json_read_alloc_string_array(&c->inp, &s->children_count);
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+ }
+ clear_trap(&trap);
+ }
+ else {
+ error = trap.error;
+ }
+ s->error_get_children = get_error_report(error);
+ cache_notify(&s->cache);
+ if (s->disposed) free_sym_info_cache(s);
+ if (trap.error) exception(trap.error);
+}
+
+int get_symbol_children(const Symbol * sym, Symbol *** children, int * count) {
+ Trap trap;
+ SymInfoCache * s = get_sym_info_cache(sym);
+ *children = NULL;
+ *count = 0;
+ if (s == NULL) return -1;
+ if (!set_trap(&trap)) return -1;
+ if (s->pending_get_children) {
+ cache_wait(&s->cache);
+ }
+ else if (s->error_get_children) {
+ exception(set_error_report_errno(s->error_get_children));
+ }
+ else if (!s->done_children) {
+ Channel * c = cache_channel();
+ if (c == NULL) exception(ERR_SYM_NOT_FOUND);
+ s->pending_get_children = protocol_send_command(c, SYMBOLS, "getChildren", validate_children, s);
+ json_write_string(&c->out, s->id);
+ write_stream(&c->out, 0);
+ write_stream(&c->out, MARKER_EOM);
+ cache_wait(&s->cache);
+ }
+ else if (s->children_count > 0) {
+ int i, cnt = s->children_count;
+ static Symbol ** buf = NULL;
+ static int buf_len = 0;
+ if (buf_len < cnt) {
+ buf_len = cnt;
+ buf = (Symbol **)loc_realloc(buf, cnt * sizeof(Symbol *));
+ }
+ for (i = 0; i < cnt; i++) {
+ if (id2symbol(s->children_ids[i], buf + i) < 0) exception(errno);
+ }
+ *children = buf;
+ *count = cnt;
+ }
+ clear_trap(&trap);
+ return 0;
+}
+
+static void validate_type_id(Channel * c, void * args, int error) {
+ Trap trap;
+ ArraySymCache * s = (ArraySymCache *)args;
+ assert(s->pending != NULL);
+ assert(s->error == NULL);
+ assert(s->id == NULL);
+ if (set_trap(&trap)) {
+ s->pending = NULL;
+ if (!error) {
+ error = read_errno(&c->inp);
+ s->id = json_read_alloc_string(&c->inp);
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+ }
+ clear_trap(&trap);
+ }
+ else {
+ error = trap.error;
+ }
+ s->error = get_error_report(error);
+ cache_notify(&s->cache);
+ if (s->disposed) free_arr_sym_cache(s);
+ if (trap.error) exception(trap.error);
+}
+
+int get_array_symbol(const Symbol * sym, ContextAddress length, Symbol ** ptr) {
+ LINK * l;
+ Trap trap;
+ ArraySymCache * a = NULL;
+ SymInfoCache * s = get_sym_info_cache(sym);
+ if (s == NULL) return -1;
+ if (!set_trap(&trap)) return -1;
+ for (l = s->array_syms.next; l != &s->array_syms; l = l->next) {
+ ArraySymCache * x = sym2arr(l);
+ if (x->length == length) {
+ a = x;
+ break;
+ }
+ }
+ if (a == NULL) {
+ Channel * c = cache_channel();
+ if (c == NULL) exception(ERR_SYM_NOT_FOUND);
+ a = (ArraySymCache *)loc_alloc_zero(sizeof(*a));
+ list_add_first(&a->link_sym, &s->array_syms);
+ a->length = length;
+ a->pending = protocol_send_command(c, SYMBOLS, "getArrayType", validate_type_id, a);
+ json_write_string(&c->out, s->id);
+ write_stream(&c->out, 0);
+ json_write_uint64(&c->out, length);
+ write_stream(&c->out, 0);
+ write_stream(&c->out, MARKER_EOM);
+ cache_wait(&a->cache);
+ }
+ else if (a->pending != NULL) {
+ cache_wait(&a->cache);
+ }
+ else if (a->error != NULL) {
+ exception(set_error_report_errno(a->error));
+ }
+ else if (id2symbol(a->id, ptr) < 0) {
+ exception(errno);
+ }
+ clear_trap(&trap);
+ return 0;
+}
+
+/*************************************************************************************************/
+
+static int trace_cmds_cnt = 0;
+static int trace_cmds_max = 0;
+static StackTracingCommand * trace_cmds = NULL;
+
+static int trace_regs_cnt = 0;
+static int trace_regs_max = 0;
+static StackTracingCommandSequence ** trace_regs = NULL;
+
+static int trace_error = 0;
+
+ContextAddress is_plt_section(Context * ctx, ContextAddress addr) {
+ /* TODO: is_plt_section() in symbols proxy */
+ return 0;
+}
+
+static void read_stack_trace_command(InputStream * inp, void * args) {
+ char id[256];
+ Context * ctx = NULL;
+ int frame = STACK_NO_FRAME;
+ StackTracingCommand * cmd = NULL;
+ if (trace_cmds_cnt >= trace_cmds_max) {
+ trace_cmds_max += 16;
+ trace_cmds = (StackTracingCommand *)loc_realloc(trace_cmds, trace_cmds_max * sizeof(StackTracingCommand));
+ }
+ cmd = trace_cmds + trace_cmds_cnt++;
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->cmd = json_read_long(inp);
+ switch (cmd->cmd) {
+ case SFT_CMD_NUMBER:
+ if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX);
+ cmd->num = json_read_int64(inp);
+ break;
+ case SFT_CMD_REGISTER:
+ if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX);
+ json_read_string(inp, id, sizeof(id));
+ if (id2register(id, &ctx, &frame, &cmd->reg) < 0) trace_error = errno;
+ break;
+ case SFT_CMD_DEREF:
+ if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX);
+ cmd->size = json_read_ulong(inp);
+ if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX);
+ cmd->big_endian = json_read_boolean(inp);
+ break;
+ }
+}
+
+static void read_stack_trace_register(InputStream * inp, const char * id, void * args) {
+ if (trace_regs_cnt >= trace_regs_max) {
+ trace_regs_max += 16;
+ trace_regs = (StackTracingCommandSequence **)loc_realloc(trace_regs, trace_regs_max * sizeof(StackTracingCommandSequence *));
+ }
+ trace_cmds_cnt = 0;
+ if (json_read_array(inp, read_stack_trace_command, NULL)) {
+ Context * ctx = NULL;
+ int frame = STACK_NO_FRAME;
+ StackTracingCommandSequence * reg = (StackTracingCommandSequence *)loc_alloc(
+ sizeof(StackTracingCommandSequence) + (trace_cmds_cnt - 1) * sizeof(StackTracingCommand));
+ if (id2register(id, &ctx, &frame, &reg->reg) < 0) {
+ trace_error = errno;
+ loc_free(reg);
+ }
+ else {
+ reg->cmds_cnt = trace_cmds_cnt;
+ reg->cmds_max = trace_cmds_cnt;
+ memcpy(reg->cmds, trace_cmds, trace_cmds_cnt * sizeof(StackTracingCommand));
+ trace_regs[trace_regs_cnt++] = reg;
+ }
+ }
+}
+
+static void validate_frame(Channel * c, void * args, int error) {
+ Trap trap;
+ StackFrameCache * f = (StackFrameCache *)args;
+ assert(f->pending != NULL);
+ assert(f->error == NULL);
+ if (set_trap(&trap)) {
+ f->pending = NULL;
+ if (!error) {
+ uint64_t addr, size;
+ trace_error = 0;
+ error = read_errno(&c->inp);
+ addr = json_read_uint64(&c->inp);
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ size = json_read_uint64(&c->inp);
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (error || size == 0) {
+ f->address = f->ip & ~(uint64_t)3;
+ f->size = 4;
+ }
+ else {
+ assert(addr <= f->ip);
+ assert(addr + size > f->ip);
+ f->address = addr;
+ f->size = size;
+ }
+ trace_cmds_cnt = 0;
+ if (json_read_array(&c->inp, read_stack_trace_command, NULL)) {
+ f->fp = (StackTracingCommandSequence *)loc_alloc(sizeof(StackTracingCommandSequence) + (trace_cmds_cnt - 1) * sizeof(StackTracingCommand));
+ f->fp->reg = NULL;
+ f->fp->cmds_cnt = trace_cmds_cnt;
+ f->fp->cmds_max = trace_cmds_cnt;
+ memcpy(f->fp->cmds, trace_cmds, trace_cmds_cnt * sizeof(StackTracingCommand));
+ }
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ trace_regs_cnt = 0;
+ if (json_read_struct(&c->inp, read_stack_trace_register, NULL)) {
+ f->regs_cnt = trace_regs_cnt;
+ f->regs = (StackTracingCommandSequence **)loc_alloc(trace_regs_cnt * sizeof(StackTracingCommandSequence *));
+ memcpy(f->regs, trace_regs, trace_regs_cnt * sizeof(StackTracingCommandSequence *));
+ }
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
+ if (!error && trace_error) error = trace_error;
+ }
+ clear_trap(&trap);
+ }
+ else {
+ error = trap.error;
+ }
+ if (get_error_code(error) != ERR_INV_COMMAND) f->error = get_error_report(error);
+ cache_notify(&f->cache);
+ if (f->disposed) free_stack_frame_cache(f);
+ if (trap.error) exception(trap.error);
+}
+
+int get_next_stack_frame(StackFrame * frame, StackFrame * down) {
+ Trap trap;
+ unsigned h;
+ LINK * l;
+ uint64_t ip = 0;
+ Context * ctx = frame->ctx;
+ /* Here we assume that stack tracing info is valid for all threads in same memory space */
+ Context * prs = context_get_group(ctx, CONTEXT_GROUP_PROCESS);
+ SymbolsCache * syms = NULL;
+ StackFrameCache * f = NULL;
+
+ if (!set_trap(&trap)) return -1;
+
+ if (read_reg_value(frame, get_PC_definition(ctx), &ip) < 0) {
+ if (frame->is_top_frame) exception(errno);
+ clear_trap(&trap);
+ return 0;
+ }
+
+ h = hash_frame(prs);
+ syms = get_symbols_cache();
+ for (l = syms->link_frame[h].next; l != syms->link_frame + h; l = l->next) {
+ StackFrameCache * c = syms2frame(l);
+ if (c->ctx == prs) {
+ if (c->pending != NULL) {
+ cache_wait(&c->cache);
+ }
+ else if (c->address <= ip && c->address + c->size > ip) {
+ f = c;
+ break;
+ }
+ }
+ }
+
+ assert(f == NULL || f->pending == NULL);
+
+ if (f == NULL && !syms->service_available) {
+ /* nothing */
+ }
+ else if (f == NULL) {
+ Channel * c = get_channel(syms);
+ f = (StackFrameCache *)loc_alloc_zero(sizeof(StackFrameCache));
+ list_add_first(&f->link_syms, syms->link_frame + h);
+ context_lock(f->ctx = prs);
+ f->ip = ip;
+ f->pending = protocol_send_command(c, SYMBOLS, "findFrameInfo", validate_frame, f);
+ json_write_string(&c->out, f->ctx->id);
+ write_stream(&c->out, 0);
+ json_write_uint64(&c->out, ip);
+ write_stream(&c->out, 0);
+ write_stream(&c->out, MARKER_EOM);
+ cache_wait(&f->cache);
+ }
+ else if (f->error != NULL) {
+ exception(set_error_report_errno(f->error));
+ }
+ else if (f->fp != NULL) {
+ Trap trap;
+ if (set_trap(&trap)) {
+ int i;
+ frame->fp = (ContextAddress)evaluate_stack_trace_commands(ctx, frame, f->fp);
+ for (i = 0; i < f->regs_cnt; i++) {
+ uint64_t v = evaluate_stack_trace_commands(ctx, frame, f->regs[i]);
+ if (write_reg_value(down, f->regs[i]->reg, v) < 0) exception(errno);
+ }
+ clear_trap(&trap);
+ }
+ else {
+ frame->fp = 0;
+ }
+ }
+
+ clear_trap(&trap);
+ return 0;
+}
+
+/*************************************************************************************************/
+
+static void flush_syms(Context * ctx, int mode) {
+ LINK * l;
+ LINK * m;
+ int i;
+
+ for (m = root.next; m != &root; m = m->next) {
+ SymbolsCache * syms = root2syms(m);
+ for (i = 0; i < HASH_SIZE; i++) {
+ l = syms->link_sym[i].next;
+ while (l != syms->link_sym + i) {
+ SymInfoCache * c = syms2sym(l);
+ l = l->next;
+ if (!c->done_context || c->error_get_context != NULL) {
+ free_sym_info_cache(c);
+ }
+ else if (c->update_policy == 0 || c->update_owner == NULL || c->update_owner->exited) {
+ free_sym_info_cache(c);
+ }
+ else if ((mode & (1 << c->update_policy)) && ctx == c->update_owner) {
+ free_sym_info_cache(c);
+ }
+ }
+ l = syms->link_find_by_name[i].next;
+ while (l != syms->link_find_by_name + i) {
+ FindSymCache * c = syms2find(l);
+ l = l->next;
+ if ((mode & (1 << c->update_policy)) && c->ctx == ctx) {
+ free_find_sym_cache(c);
+ }
+ }
+ l = syms->link_find_in_scope[i].next;
+ while (l != syms->link_find_in_scope + i) {
+ FindSymCache * c = syms2find(l);
+ l = l->next;
+ if ((mode & (1 << c->update_policy)) && c->ctx == ctx) {
+ free_find_sym_cache(c);
+ }
+ }
+ l = syms->link_list[i].next;
+ while (l != syms->link_list + i) {
+ ListSymCache * c = syms2list(l);
+ l = l->next;
+ if ((mode & (1 << c->update_policy)) && c->ctx == ctx) {
+ free_list_sym_cache(c);
+ }
+ }
+ if (mode & (1 << UPDATE_ON_MEMORY_MAP_CHANGES)) {
+ Context * prs = context_get_group(ctx, CONTEXT_GROUP_PROCESS);
+ l = syms->link_frame[i].next;
+ while (l != syms->link_frame + i) {
+ StackFrameCache * c = syms2frame(l);
+ l = l->next;
+ if (c->ctx == prs) free_stack_frame_cache(c);
+ }
+ }
+ }
+ }
+}
+
+static void event_context_created(Context * ctx, void * x) {
+ flush_syms(ctx, ~0);
+}
+
+static void event_context_exited(Context * ctx, void * x) {
+ flush_syms(ctx, ~0);
+}
+
+static void event_context_stopped(Context * ctx, void * x) {
+ flush_syms(ctx, (1 << UPDATE_ON_EXE_STATE_CHANGES));
+}
+
+static void event_context_started(Context * ctx, void * x) {
+ flush_syms(ctx, (1 << UPDATE_ON_EXE_STATE_CHANGES));
+}
+
+static void event_context_changed(Context * ctx, void * x) {
+ flush_syms(ctx, (1 << UPDATE_ON_MEMORY_MAP_CHANGES) | (1 << UPDATE_ON_EXE_STATE_CHANGES));
+}
+
+static void channel_close_listener(Channel * c) {
+ LINK * l = root.next;
+ while (l != &root) {
+ SymbolsCache * s = root2syms(l);
+ l = l->next;
+ if (s->channel == c) free_symbols_cache(s);
+ }
+}
+
+void ini_symbols_lib(void) {
+ static ContextEventListener listener = {
+ event_context_created,
+ event_context_exited,
+ event_context_stopped,
+ event_context_started,
+ event_context_changed
+ };
+ list_init(&root);
+ add_context_event_listener(&listener, NULL);
+ add_channel_close_listener(channel_close_listener);
+}
+
+#endif

Back to the top