Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'agent/tcf/services/symbols_elf.c')
-rw-r--r--agent/tcf/services/symbols_elf.c2159
1 files changed, 2159 insertions, 0 deletions
diff --git a/agent/tcf/services/symbols_elf.c b/agent/tcf/services/symbols_elf.c
new file mode 100644
index 00000000..1e28d419
--- /dev/null
+++ b/agent/tcf/services/symbols_elf.c
@@ -0,0 +1,2159 @@
+/*******************************************************************************
+ * 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 - ELF version.
+ */
+
+#include <config.h>
+
+#if SERVICE_Symbols && !ENABLE_SymbolsProxy && ENABLE_ELF
+
+#if defined(_WRS_KERNEL)
+# include <symLib.h>
+# include <sysSymTbl.h>
+#endif
+
+#include <errno.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <framework/errors.h>
+#include <framework/myalloc.h>
+#include <framework/events.h>
+#include <framework/exceptions.h>
+#include <services/tcf_elf.h>
+#include <services/dwarf.h>
+#include <services/dwarfcache.h>
+#include <services/dwarfexpr.h>
+#include <services/dwarfframe.h>
+#include <services/stacktrace.h>
+#include <services/symbols.h>
+#if ENABLE_RCBP_TEST
+# include <main/test.h>
+#endif
+
+struct Symbol {
+ unsigned magic;
+ ObjectInfo * obj;
+ ObjectInfo * var; /* 'this' object if the symbol represents implicit 'this' reference */
+ ELF_Section * tbl;
+ int has_size;
+ int has_address;
+ ContextAddress size;
+ ContextAddress address;
+ int sym_class;
+ Context * ctx;
+ int frame;
+ unsigned index;
+ unsigned dimension;
+ unsigned cardinal;
+ ContextAddress length;
+ Symbol * base;
+};
+
+#define is_cardinal_type_pseudo_symbol(s) (s->sym_class == SYM_CLASS_TYPE && s->obj == NULL && s->base == NULL)
+
+#include <services/symbols_alloc.h>
+
+static Context * sym_ctx;
+static int sym_frame;
+static ContextAddress sym_ip;
+
+static int get_sym_context(Context * ctx, int frame, ContextAddress addr) {
+ if (frame == STACK_NO_FRAME) {
+ ctx = context_get_group(ctx, CONTEXT_GROUP_PROCESS);
+ sym_ip = addr;
+ }
+ else if (frame == STACK_TOP_FRAME) {
+ if (!ctx->stopped) {
+ errno = ERR_IS_RUNNING;
+ return -1;
+ }
+ if (ctx->exited) {
+ errno = ERR_ALREADY_EXITED;
+ return -1;
+ }
+ sym_ip = get_regs_PC(ctx);
+ }
+ else {
+ U8_T ip = 0;
+ StackFrame * info = NULL;
+ if (get_frame_info(ctx, frame, &info) < 0) return -1;
+ if (read_reg_value(info, get_PC_definition(ctx), &ip) < 0) return -1;
+ sym_ip = (ContextAddress)ip;
+ }
+ sym_ctx = ctx;
+ sym_frame = frame;
+ return 0;
+}
+
+/* Map ELF symbol table entry value to run-time address in given context address space */
+static int syminfo2address(Context * ctx, ELF_SymbolInfo * info, ContextAddress * address) {
+ switch (info->type) {
+ case STT_OBJECT:
+ case STT_FUNC:
+ {
+ U8_T value = info->value;
+ ELF_File * file = info->sym_section->file;
+ ELF_Section * sec = NULL;
+ if (info->section_index == SHN_UNDEF) {
+ errno = ERR_INV_ADDRESS;
+ return -1;
+ }
+ if (info->section_index == SHN_ABS) {
+ *address = (ContextAddress)value;
+ return 0;
+ }
+ if (info->section_index == SHN_COMMON) {
+ errno = ERR_INV_ADDRESS;
+ return -1;
+ }
+ if (file->type == ET_REL && info->section != NULL) {
+ sec = info->section;
+ value += sec->addr;
+ }
+ *address = elf_map_to_run_time_address(ctx, file, sec, (ContextAddress)value);
+ if (*address == 0 && file->type == ET_EXEC) *address = (ContextAddress)value;
+ return 0;
+ }
+ }
+ errno = ERR_INV_ADDRESS;
+ return -1;
+}
+
+static int is_frame_based_object(Symbol * sym) {
+ int res = 0;
+ ContextAddress addr = 0;
+ ContextAddress size = 0;
+ Context * org_ctx = sym_ctx;
+ int org_frame = sym_frame;
+ ContextAddress org_ip = sym_ip;
+
+ if (sym->sym_class == SYM_CLASS_REFERENCE) {
+ if (get_symbol_address(sym, &addr) < 0) {
+ res = 1;
+ }
+ else {
+ sym->has_address = 1;
+ sym->address = addr;
+ }
+ }
+
+ if (!res) {
+ if (get_symbol_size(sym, &size) < 0) {
+ res = 1;
+ }
+ else {
+ sym->has_size = 1;
+ sym->size = size;
+ }
+ }
+
+ sym_ctx = org_ctx;
+ sym_frame = org_frame;
+ sym_ip = org_ip;
+ return res;
+}
+
+static void object2symbol(ObjectInfo * obj, Symbol ** res) {
+ Symbol * sym = alloc_symbol();
+ sym->obj = obj;
+ switch (obj->mTag) {
+ case TAG_global_subroutine:
+ case TAG_subroutine:
+ case TAG_subprogram:
+ case TAG_entry_point:
+ sym->sym_class = SYM_CLASS_FUNCTION;
+ break;
+ case TAG_array_type:
+ case TAG_class_type:
+ case TAG_enumeration_type:
+ case TAG_pointer_type:
+ case TAG_reference_type:
+ case TAG_mod_pointer:
+ case TAG_mod_reference:
+ case TAG_string_type:
+ case TAG_structure_type:
+ case TAG_subroutine_type:
+ case TAG_union_type:
+ case TAG_ptr_to_member_type:
+ case TAG_set_type:
+ case TAG_subrange_type:
+ case TAG_base_type:
+ case TAG_fund_type:
+ case TAG_file_type:
+ case TAG_packed_type:
+ case TAG_thrown_type:
+ case TAG_const_type:
+ case TAG_volatile_type:
+ case TAG_restrict_type:
+ case TAG_interface_type:
+ case TAG_unspecified_type:
+ case TAG_mutable_type:
+ case TAG_shared_type:
+ case TAG_typedef:
+ sym->sym_class = SYM_CLASS_TYPE;
+ break;
+ case TAG_global_variable:
+ case TAG_inheritance:
+ case TAG_member:
+ case TAG_formal_parameter:
+ case TAG_unspecified_parameters:
+ case TAG_local_variable:
+ case TAG_variable:
+ sym->sym_class = SYM_CLASS_REFERENCE;
+ break;
+ case TAG_constant:
+ case TAG_enumerator:
+ sym->sym_class = SYM_CLASS_VALUE;
+ break;
+ }
+ sym->frame = STACK_NO_FRAME;
+ sym->ctx = context_get_group(sym_ctx, CONTEXT_GROUP_PROCESS);
+ if (sym_frame != STACK_NO_FRAME && is_frame_based_object(sym)) {
+ sym->frame = sym_frame;
+ sym->ctx = sym_ctx;
+ }
+ *res = sym;
+}
+
+static ObjectInfo * get_object_type(ObjectInfo * obj) {
+ if (obj != NULL) {
+ switch (obj->mTag) {
+ case TAG_global_subroutine:
+ case TAG_subroutine:
+ case TAG_subprogram:
+ case TAG_entry_point:
+ case TAG_enumerator:
+ case TAG_formal_parameter:
+ case TAG_unspecified_parameters:
+ case TAG_global_variable:
+ case TAG_local_variable:
+ case TAG_variable:
+ case TAG_inheritance:
+ case TAG_member:
+ case TAG_constant:
+ obj = obj->mType;
+ break;
+ }
+ }
+ return obj;
+}
+
+static int is_modified_type(ObjectInfo * obj) {
+ if (obj != NULL && obj->mType != NULL) {
+ switch (obj->mTag) {
+ case TAG_subrange_type:
+ case TAG_packed_type:
+ case TAG_const_type:
+ case TAG_volatile_type:
+ case TAG_restrict_type:
+ case TAG_shared_type:
+ case TAG_typedef:
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static ObjectInfo * get_original_type(ObjectInfo * obj) {
+ obj = get_object_type(obj);
+ while (is_modified_type(obj)) {
+ obj = obj->mType;
+ }
+ return obj;
+}
+
+static int get_num_prop(ObjectInfo * obj, U2_T at, U8_T * res) {
+ Trap trap;
+ PropertyValue v;
+
+ if (!set_trap(&trap)) return 0;
+ read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, at, &v);
+ *res = get_numeric_property_value(&v);
+ clear_trap(&trap);
+ return 1;
+}
+
+/* Check run-time 'addr' belongs to an object address range(s) */
+static int check_in_range(ObjectInfo * obj, ContextAddress rt_offs, ContextAddress addr) {
+ Trap trap;
+
+ if (obj->u.mAddr.mHighPC > obj->u.mAddr.mLowPC) {
+ ContextAddress lt_addr = addr - rt_offs;
+ return lt_addr >= obj->u.mAddr.mLowPC && lt_addr < obj->u.mAddr.mHighPC;
+ }
+
+ if (set_trap(&trap)) {
+ CompUnit * unit = obj->mCompUnit;
+ DWARFCache * cache = get_dwarf_cache(unit->mFile);
+ ELF_Section * debug_ranges = cache->mDebugRanges;
+ if (debug_ranges != NULL) {
+ ContextAddress lt_addr = addr - rt_offs;
+ ContextAddress base = unit->mLowPC;
+ PropertyValue v;
+ U8_T offs = 0;
+ int res = 0;
+
+ read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_ranges, &v);
+ offs = get_numeric_property_value(&v);
+ dio_EnterSection(&unit->mDesc, debug_ranges, offs);
+ for (;;) {
+ ELF_Section * sec = NULL;
+ U8_T x = dio_ReadAddress(&sec);
+ U8_T y = dio_ReadAddress(&sec);
+ if (x == 0 && y == 0) break;
+ if (x == ((U8_T)1 << unit->mDesc.mAddressSize * 8) - 1) {
+ base = (ContextAddress)y;
+ }
+ else {
+ x = base + x;
+ y = base + y;
+ if (x <= lt_addr && lt_addr < y) {
+ res = 1;
+ break;
+ }
+ }
+ }
+ dio_ExitSection();
+ clear_trap(&trap);
+ return res;
+ }
+ clear_trap(&trap);
+ }
+ return 0;
+}
+
+static int find_in_object_tree(ObjectInfo * list, ContextAddress rt_offs, ContextAddress ip, const char * name, Symbol ** sym) {
+ Symbol * sym_imp = NULL; /* Imported from a namespace */
+ Symbol * sym_enu = NULL; /* Enumeration constant */
+ Symbol * sym_cur = NULL; /* Found in current scope */
+ Symbol * sym_base = NULL; /* Found in base class (inherited) */
+ Symbol * sym_this = NULL; /* Found in 'this' reference */
+ ObjectInfo * obj = list;
+ while (obj != NULL) {
+ if (obj->mName != NULL) {
+ U8_T v = 0;
+ if (strcmp(obj->mName, name) == 0) {
+ object2symbol(obj, &sym_cur);
+ }
+ if (sym_frame != STACK_NO_FRAME && strcmp(obj->mName, "this") == 0 && get_num_prop(obj, AT_artificial, &v) && v != 0) {
+ ObjectInfo * type = get_original_type(obj);
+ if ((type->mTag == TAG_pointer_type || type->mTag == TAG_mod_pointer) && type->mType != NULL) {
+ type = get_original_type(type->mType);
+ find_in_object_tree(type->mChildren, 0, 0, name, &sym_this);
+ if (sym_this != NULL) {
+ sym_this->ctx = sym_ctx;
+ sym_this->frame = sym_frame;
+ sym_this->var = obj;
+ }
+ }
+ }
+ }
+ switch (obj->mTag) {
+ case TAG_enumeration_type:
+ find_in_object_tree(obj->mChildren, 0, 0, name, &sym_enu);
+ break;
+ case TAG_global_subroutine:
+ case TAG_subroutine:
+ case TAG_subprogram:
+ case TAG_entry_point:
+ case TAG_lexical_block:
+ case TAG_inlined_subroutine:
+ if (ip != 0 && check_in_range(obj, rt_offs, ip)) {
+ if (find_in_object_tree(obj->mChildren, rt_offs, ip, name, sym)) return 1;
+ }
+ break;
+ case TAG_inheritance:
+ find_in_object_tree(obj->mType->mChildren, 0, 0, name, &sym_base);
+ break;
+ case TAG_imported_module:
+ {
+ PropertyValue p;
+ ObjectInfo * module;
+ read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_import, &p);
+ module = find_object(get_dwarf_cache(obj->mCompUnit->mFile), p.mValue);
+ if (module != NULL) find_in_object_tree(module->mChildren, 0, 0, name, &sym_imp);
+ }
+ break;
+ }
+ obj = obj->mSibling;
+ }
+ if (*sym == NULL) *sym = sym_cur;
+ if (*sym == NULL) *sym = sym_base;
+ if (*sym == NULL) *sym = sym_this;
+ if (*sym == NULL) *sym = sym_enu;
+ if (*sym == NULL) *sym = sym_imp;
+ return *sym != NULL;
+}
+
+static int find_in_dwarf(const char * name, Symbol ** sym) {
+ ContextAddress rt_addr = 0;
+ UnitAddressRange * range = elf_find_unit(sym_ctx, sym_ip, sym_ip, &rt_addr);
+ *sym = NULL;
+ if (range != NULL) {
+ CompUnit * unit = range->mUnit;
+ if (find_in_object_tree(unit->mObject->mChildren, rt_addr - range->mAddr, sym_ip, name, sym)) return 1;
+ if (unit->mBaseTypes != NULL) {
+ if (find_in_object_tree(unit->mBaseTypes->mObject->mChildren, 0, 0, name, sym)) return 1;
+ }
+ }
+ return 0;
+}
+
+static int find_by_name_in_pub_names(DWARFCache * cache, PubNamesTable * tbl, char * name, Symbol ** sym) {
+ unsigned n = tbl->mHash[calc_symbol_name_hash(name)];
+ while (n != 0) {
+ U8_T id = tbl->mNext[n].mID;
+ ObjectInfo * obj = find_object(cache, id);
+ if (obj == NULL || obj->mName == NULL) str_exception(ERR_INV_DWARF, "Invalid .debug_pubnames section");
+ if (strcmp(obj->mName, name) == 0) {
+ object2symbol(obj, sym);
+ return 1;
+ }
+ n = tbl->mNext[n].mNext;
+ }
+ return 0;
+}
+
+static void create_symbol_names_hash(ELF_Section * tbl) {
+ unsigned i;
+ unsigned sym_size = tbl->file->elf64 ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym);
+ unsigned sym_cnt = (unsigned)(tbl->size / sym_size);
+ tbl->sym_names_hash = (unsigned *)loc_alloc_zero(SYM_HASH_SIZE * sizeof(unsigned));
+ tbl->sym_names_next = (unsigned *)loc_alloc_zero(sym_cnt * sizeof(unsigned));
+ for (i = 0; i < sym_cnt; i++) {
+ ELF_SymbolInfo sym;
+ unpack_elf_symbol_info(tbl, i, &sym);
+ if (sym.bind == STB_GLOBAL && sym.name != NULL && sym.section_index != SHN_UNDEF) {
+ unsigned h = calc_symbol_name_hash(sym.name);
+ tbl->sym_names_next[i] = tbl->sym_names_hash[h];
+ tbl->sym_names_hash[h] = i;
+ }
+ }
+}
+
+static int find_by_name_in_sym_table(DWARFCache * cache, char * name, Symbol ** res) {
+ unsigned m = 0;
+ unsigned h = calc_symbol_name_hash(name);
+ unsigned cnt = 0;
+ Context * prs = context_get_group(sym_ctx, CONTEXT_GROUP_PROCESS);
+ for (m = 1; m < cache->mFile->section_cnt; m++) {
+ unsigned n;
+ ELF_Section * tbl = cache->mFile->sections + m;
+ if (tbl->sym_count == 0) continue;
+ if (tbl->sym_names_hash == NULL) create_symbol_names_hash(tbl);
+ n = tbl->sym_names_hash[h];
+ while (n) {
+ ELF_SymbolInfo sym_info;
+ unpack_elf_symbol_info(tbl, n, &sym_info);
+ if (cmp_symbol_names(name, sym_info.name) == 0) {
+ int found = 0;
+ ContextAddress addr = 0;
+ if (sym_info.section_index != SHN_ABS && syminfo2address(prs, &sym_info, &addr) == 0) {
+ UnitAddressRange * range = elf_find_unit(sym_ctx, addr, addr, NULL);
+ if (range != NULL) {
+ ObjectInfo * obj = range->mUnit->mObject->mChildren;
+ while (obj != NULL) {
+ switch (obj->mTag) {
+ case TAG_global_subroutine:
+ case TAG_global_variable:
+ case TAG_subroutine:
+ case TAG_subprogram:
+ case TAG_variable:
+ if (obj->mName != NULL && strcmp(obj->mName, name) == 0) {
+ object2symbol(obj, res);
+ found = 1;
+ cnt++;
+ }
+ break;
+ }
+ obj = obj->mSibling;
+ }
+ }
+ }
+ if (!found) {
+ Symbol * sym = alloc_symbol();
+ sym->frame = STACK_NO_FRAME;
+ sym->ctx = prs;
+ sym->tbl = tbl;
+ sym->index = n;
+ switch (sym_info.type) {
+ case STT_FUNC:
+ sym->sym_class = SYM_CLASS_FUNCTION;
+ break;
+ case STT_OBJECT:
+ sym->sym_class = SYM_CLASS_REFERENCE;
+ break;
+ default:
+ sym->sym_class = SYM_CLASS_VALUE;
+ break;
+ }
+ *res = sym;
+ cnt++;
+ }
+ }
+ n = tbl->sym_names_next[n];
+ }
+ }
+ return cnt == 1;
+}
+
+int find_symbol_by_name(Context * ctx, int frame, ContextAddress ip, char * name, Symbol ** res) {
+ int error = 0;
+ int found = 0;
+
+ assert(ctx != NULL);
+
+#if defined(_WRS_KERNEL)
+ {
+ char * ptr;
+ SYM_TYPE type;
+
+ if (symFindByName(sysSymTbl, name, &ptr, &type) != OK) {
+ error = errno;
+ assert(error != 0);
+ if (error == S_symLib_SYMBOL_NOT_FOUND) error = 0;
+ }
+ else {
+ Symbol * sym = alloc_symbol();
+ sym->ctx = context_get_group(ctx, CONTEXT_GROUP_PROCESS);
+ sym->frame = STACK_NO_FRAME;
+ sym->address = (ContextAddress)ptr;
+ sym->has_address = 1;
+
+ if (SYM_IS_TEXT(type)) {
+ sym->sym_class = SYM_CLASS_FUNCTION;
+ }
+ else {
+ sym->sym_class = SYM_CLASS_REFERENCE;
+ }
+ *res = sym;
+ found = 1;
+ }
+ }
+#endif
+
+ if (error == 0 && !found && get_sym_context(ctx, frame, ip) < 0) error = errno;
+
+ if (error == 0 && !found && sym_ip != 0) {
+ Trap trap;
+ if (set_trap(&trap)) {
+ found = find_in_dwarf(name, res);
+ clear_trap(&trap);
+ }
+ else {
+ error = trap.error;
+ }
+ }
+
+ if (error == 0 && !found) {
+ ELF_File * file = elf_list_first(sym_ctx, sym_ip, sym_ip ? sym_ip : ~(ContextAddress)0);
+ if (file == NULL) error = errno;
+ while (error == 0 && file != NULL) {
+ Trap trap;
+ if (set_trap(&trap)) {
+ DWARFCache * cache = get_dwarf_cache(file);
+ if (cache->mPubNames.mHash != NULL) {
+ found = find_by_name_in_pub_names(cache, &cache->mPubNames, name, res);
+ if (!found && cache->mPubTypes.mHash != NULL) {
+ found = find_by_name_in_pub_names(cache, &cache->mPubTypes, name, res);
+ }
+ }
+ if (!found) {
+ found = find_by_name_in_sym_table(cache, name, res);
+ }
+ clear_trap(&trap);
+ }
+ else {
+ error = trap.error;
+ break;
+ }
+ if (found) break;
+ file = elf_list_next(sym_ctx);
+ if (file == NULL) error = errno;
+ }
+ elf_list_done(sym_ctx);
+ }
+
+ if (error == 0 && !found && sym_ip != 0) {
+ Trap trap;
+ if (set_trap(&trap)) {
+ const char * s = NULL;
+ if (strcmp(name, "signed") == 0) s = "int";
+ else if (strcmp(name, "signed int") == 0) s = "int";
+ else if (strcmp(name, "unsigned") == 0) s = "unsigned int";
+ else if (strcmp(name, "short") == 0) s = "short int";
+ else if (strcmp(name, "signed short") == 0) s = "short int";
+ else if (strcmp(name, "signed short int") == 0) s = "short int";
+ else if (strcmp(name, "unsigned short") == 0) s = "unsigned short int";
+ else if (strcmp(name, "long") == 0) s = "long int";
+ else if (strcmp(name, "signed long") == 0) s = "long int";
+ else if (strcmp(name, "signed long int") == 0) s = "long int";
+ else if (strcmp(name, "unsigned long") == 0) s = "unsigned long int";
+ else if (strcmp(name, "long long") == 0) s = "long long int";
+ else if (strcmp(name, "signed long long") == 0) s = "long long int";
+ else if (strcmp(name, "signed long long int") == 0) s = "long long int";
+ else if (strcmp(name, "unsigned long long") == 0) s = "unsigned long long int";
+ else if (strcmp(name, "char") == 0) s = "signed char";
+ if (s != NULL) {
+ found = find_in_dwarf(s, res);
+ if (!found) {
+ s = NULL;
+ if (strcmp(name, "char") == 0) s = "unsigned char";
+ if (s != NULL) found = find_in_dwarf(s, res);
+ }
+ }
+ clear_trap(&trap);
+ }
+ else {
+ error = trap.error;
+ }
+ }
+
+#if ENABLE_RCBP_TEST
+ if (!found) {
+ int sym_class = 0;
+ void * address = NULL;
+ found = find_test_symbol(ctx, name, &address, &sym_class) >= 0;
+ if (found) {
+ Symbol * sym = alloc_symbol();
+ sym->ctx = context_get_group(ctx, CONTEXT_GROUP_PROCESS);
+ sym->frame = STACK_NO_FRAME;
+ sym->address = (ContextAddress)address;
+ sym->has_address = 1;
+ sym->sym_class = sym_class;
+ *res = sym;
+ }
+ }
+#endif
+
+ if (error == 0 && !found && sym_ip == 0) {
+ /* Search all compilation units */
+ ELF_File * file = elf_list_first(sym_ctx, 0, ~(ContextAddress)0);
+ if (file == NULL) error = errno;
+ while (error == 0 && file != NULL) {
+ Trap trap;
+ if (set_trap(&trap)) {
+ unsigned i;
+ DWARFCache * cache = get_dwarf_cache(file);
+ for (i = 0; i < cache->mAddrRangesCnt; i++) {
+ UnitAddressRange * range = cache->mAddrRanges + i;
+ CompUnit * unit = range->mUnit;
+ ContextAddress rt_addr = elf_map_to_run_time_address(sym_ctx, file, unit->mTextSection, range->mAddr);
+ if (rt_addr != 0) {
+ *res = NULL;
+ sym_ip = rt_addr;
+ if (find_in_object_tree(unit->mObject->mChildren, rt_addr - range->mAddr, sym_ip, name, res)) found = 1;
+ if (!found && unit->mBaseTypes != NULL) {
+ if (find_in_object_tree(unit->mBaseTypes->mObject->mChildren, 0, 0, name, res)) found = 1;
+ }
+ if (found) break;
+ }
+ }
+ clear_trap(&trap);
+ }
+ else {
+ error = trap.error;
+ break;
+ }
+ if (found) break;
+ file = elf_list_next(sym_ctx);
+ if (file == NULL) error = errno;
+ }
+ elf_list_done(sym_ctx);
+ sym_ip = 0;
+ }
+
+ if (error == 0 && !found) error = ERR_SYM_NOT_FOUND;
+
+ assert(error || (*res != NULL && (*res)->ctx != NULL));
+
+ if (error) {
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+int find_symbol_in_scope(Context * ctx, int frame, ContextAddress ip, Symbol * scope, char * name, Symbol ** res) {
+ int error = 0;
+ int found = 0;
+
+ *res = NULL;
+ if (get_sym_context(ctx, frame, ip) < 0) error = errno;
+
+ if (!error && scope == NULL && sym_ip != 0) {
+ ELF_File * file = elf_list_first(sym_ctx, sym_ip, sym_ip);
+ if (file == NULL) error = errno;
+ while (error == 0 && file != NULL) {
+ Trap trap;
+ if (set_trap(&trap)) {
+ DWARFCache * cache = get_dwarf_cache(file);
+ UnitAddressRange * range = find_comp_unit_addr_range(cache, sym_ip, sym_ip);
+ if (range != NULL) {
+ found = find_in_object_tree(range->mUnit->mObject->mChildren, 0, 0, name, res);
+ }
+ if (!found) {
+ found = find_by_name_in_sym_table(cache, name, res);
+ }
+ clear_trap(&trap);
+ }
+ else {
+ error = trap.error;
+ break;
+ }
+ if (found) break;
+ file = elf_list_next(sym_ctx);
+ if (file == NULL) error = errno;
+ }
+ elf_list_done(sym_ctx);
+ }
+
+ if (!found && !error && scope != NULL && scope->obj != NULL) {
+ Trap trap;
+ if (set_trap(&trap)) {
+ found = find_in_object_tree(scope->obj->mChildren, 0, 0, name, res);
+ clear_trap(&trap);
+ }
+ else {
+ error = trap.error;
+ }
+ }
+
+ if (error == 0 && !found) error = ERR_SYM_NOT_FOUND;
+
+ assert(error || (*res != NULL && (*res)->ctx != NULL));
+
+ if (error) {
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+static int find_by_addr_in_unit(ObjectInfo * obj, int level, ContextAddress rt_offs, ContextAddress addr, Symbol ** res) {
+ while (obj != NULL) {
+ switch (obj->mTag) {
+ case TAG_global_subroutine:
+ case TAG_subroutine:
+ case TAG_subprogram:
+ case TAG_entry_point:
+ case TAG_lexical_block:
+ case TAG_inlined_subroutine:
+ if (check_in_range(obj, rt_offs, addr)) {
+ object2symbol(obj, res);
+ return 1;
+ }
+ if (check_in_range(obj, rt_offs, sym_ip)) {
+ return find_by_addr_in_unit(obj->mChildren, level + 1, rt_offs, addr, res);
+ }
+ break;
+ case TAG_formal_parameter:
+ case TAG_unspecified_parameters:
+ case TAG_local_variable:
+ if (sym_frame == STACK_NO_FRAME) break;
+ case TAG_variable:
+ {
+ U8_T lc = 0;
+ /* Ignore location evaluation errors. For example, the error can be caused by
+ * the object not being mapped into the context memory */
+ if (get_num_prop(obj, AT_location, &lc) && lc <= addr) {
+ U8_T sz = 0;
+ if (!get_num_prop(obj, AT_byte_size, &sz)) {
+ /* If object size unknown, continue search */
+ if (get_error_code(errno) == ERR_SYM_NOT_FOUND) break;
+ exception(errno);
+ }
+ if (lc + sz > addr) {
+ object2symbol(obj, res);
+ return 1;
+ }
+ }
+ }
+ break;
+ }
+ obj = obj->mSibling;
+ }
+ return 0;
+}
+
+static int find_by_addr_in_sym_tables(ContextAddress addr, Symbol ** res) {
+ ELF_File * file = NULL;
+ ELF_Section * section = NULL;
+ ELF_SymbolInfo sym_info;
+ ContextAddress lt_addr = elf_map_to_link_time_address(sym_ctx, addr, &file, &section);
+ elf_find_symbol_by_address(section, lt_addr, &sym_info);
+ while (sym_info.sym_section != NULL) {
+ int sym_class = SYM_CLASS_UNKNOWN;
+ assert(sym_info.section == section);
+ switch (sym_info.type) {
+ case STT_FUNC:
+ sym_class = SYM_CLASS_FUNCTION;
+ break;
+ case STT_OBJECT:
+ sym_class = SYM_CLASS_REFERENCE;
+ break;
+ }
+ if (sym_class != SYM_CLASS_UNKNOWN) {
+ ContextAddress sym_addr = sym_info.value;
+ if (file->type == ET_REL) sym_addr += section->addr;
+ assert(sym_addr <= lt_addr);
+ if (sym_addr + sym_info.size > lt_addr) {
+ Symbol * sym = alloc_symbol();
+ sym->frame = STACK_NO_FRAME;
+ sym->ctx = context_get_group(sym_ctx, CONTEXT_GROUP_PROCESS);
+ sym->tbl = sym_info.sym_section;
+ sym->index = sym_info.sym_index;
+ sym->sym_class = sym_class;
+ *res = sym;
+ return 1;
+ }
+ return 0;
+ }
+ elf_prev_symbol_by_address(&sym_info);
+ }
+ return 0;
+}
+
+int find_symbol_by_addr(Context * ctx, int frame, ContextAddress addr, Symbol ** res) {
+ Trap trap;
+ int found = 0;
+ ContextAddress rt_addr = 0;
+ UnitAddressRange * range = NULL;
+ if (!set_trap(&trap)) return -1;
+ if (frame == STACK_TOP_FRAME && (frame = get_top_frame(ctx)) < 0) exception(errno);
+ if (get_sym_context(ctx, frame, addr) < 0) exception(errno);
+ range = elf_find_unit(sym_ctx, addr, addr, &rt_addr);
+ if (range != NULL) found = find_by_addr_in_unit(range->mUnit->mObject->mChildren,
+ 0, rt_addr - range->mAddr, addr, res);
+ if (!found) found = find_by_addr_in_sym_tables(addr, res);
+ if (!found && sym_ip != 0) {
+ /* Search in compilation unit that contains stack frame PC */
+ range = elf_find_unit(sym_ctx, sym_ip, sym_ip, &rt_addr);
+ if (range != NULL) found = find_by_addr_in_unit(range->mUnit->mObject->mChildren,
+ 0, rt_addr - range->mAddr, addr, res);
+ }
+ if (!found) exception(ERR_SYM_NOT_FOUND);
+ clear_trap(&trap);
+ return 0;
+}
+
+static void enumerate_local_vars(ObjectInfo * obj, int level, ContextAddress rt_offs,
+ EnumerateSymbolsCallBack * call_back, void * args) {
+ while (obj != NULL) {
+ switch (obj->mTag) {
+ case TAG_global_subroutine:
+ case TAG_subroutine:
+ case TAG_subprogram:
+ case TAG_entry_point:
+ case TAG_lexical_block:
+ case TAG_inlined_subroutine:
+ if (check_in_range(obj, rt_offs, sym_ip)) {
+ enumerate_local_vars(obj->mChildren, level + 1, rt_offs, call_back, args);
+ }
+ break;
+ case TAG_formal_parameter:
+ case TAG_unspecified_parameters:
+ case TAG_local_variable:
+ case TAG_variable:
+ if (level > 0) {
+ Context * org_ctx = sym_ctx;
+ int org_frame = sym_frame;
+ ContextAddress org_ip = sym_ip;
+ Symbol * sym = NULL;
+ object2symbol(obj, &sym);
+ call_back(args, sym);
+ sym_ctx = org_ctx;
+ sym_frame = org_frame;
+ sym_ip = org_ip;
+ }
+ break;
+ }
+ obj = obj->mSibling;
+ }
+}
+
+int enumerate_symbols(Context * ctx, int frame, EnumerateSymbolsCallBack * call_back, void * args) {
+ Trap trap;
+ if (!set_trap(&trap)) return -1;
+ if (frame == STACK_TOP_FRAME && (frame = get_top_frame(ctx)) < 0) exception(errno);
+ if (get_sym_context(ctx, frame, 0) < 0) exception(errno);
+ if (sym_ip != 0) {
+ ContextAddress rt_addr = 0;
+ UnitAddressRange * range = elf_find_unit(sym_ctx, sym_ip, sym_ip, &rt_addr);
+ if (range != NULL) enumerate_local_vars(range->mUnit->mObject->mChildren,
+ 0, rt_addr - range->mAddr, call_back, args);
+ }
+ clear_trap(&trap);
+ return 0;
+}
+
+const char * symbol2id(const Symbol * sym) {
+ static char id[256];
+
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base) {
+ char base[256];
+ assert(sym->ctx == sym->base->ctx);
+ assert(sym->frame == STACK_NO_FRAME);
+ assert(sym->sym_class == SYM_CLASS_TYPE);
+ strcpy(base, symbol2id(sym->base));
+ snprintf(id, sizeof(id), "@P%"PRIX64".%s", (uint64_t)sym->length, base);
+ }
+ else {
+ ELF_File * file = NULL;
+ uint64_t obj_index = 0;
+ uint64_t var_index = 0;
+ unsigned tbl_index = 0;
+ int frame = sym->frame;
+ if (sym->obj != NULL) file = sym->obj->mCompUnit->mFile;
+ if (sym->tbl != NULL) file = sym->tbl->file;
+ if (sym->obj != NULL) obj_index = sym->obj->mID;
+ if (sym->var != NULL) var_index = sym->var->mID;
+ if (sym->tbl != NULL) tbl_index = sym->tbl->index;
+ if (frame == STACK_TOP_FRAME) frame = get_top_frame(sym->ctx);
+ assert(sym->var == NULL || sym->var->mCompUnit->mFile == file);
+ snprintf(id, sizeof(id), "@S%X.%lX.%lX.%"PRIX64".%"PRIX64".%"PRIX64".%X.%d.%X.%X.%X.%s",
+ sym->sym_class,
+ file ? (unsigned long)file->dev : 0ul,
+ file ? (unsigned long)file->ino : 0ul,
+ file ? file->mtime : (int64_t)0,
+ obj_index, var_index, tbl_index,
+ frame, sym->index,
+ sym->dimension, sym->cardinal,
+ sym->ctx->id);
+ }
+ return id;
+}
+
+static uint64_t read_hex(const char ** s) {
+ uint64_t res = 0;
+ const char * p = *s;
+ for (;;) {
+ if (*p >= '0' && *p <= '9') res = (res << 4) | (*p - '0');
+ else if (*p >= 'A' && *p <= 'F') res = (res << 4) | (*p - 'A' + 10);
+ else break;
+ p++;
+ }
+ *s = p;
+ return res;
+}
+
+static int read_int(const char ** s) {
+ int neg = 0;
+ int res = 0;
+ const char * p = *s;
+ if (*p == '-') {
+ neg = 1;
+ p++;
+ }
+ for (;;) {
+ if (*p >= '0' && *p <= '9') res = res * 10 + (*p - '0');
+ else break;
+ p++;
+ }
+ *s = p;
+ return neg ? -res : res;
+}
+
+int id2symbol(const char * id, Symbol ** res) {
+ Symbol * sym = alloc_symbol();
+ dev_t dev = 0;
+ ino_t ino = 0;
+ int64_t mtime;
+ uint64_t obj_index = 0;
+ uint64_t var_index = 0;
+ unsigned tbl_index = 0;
+ ELF_File * file = NULL;
+ const char * p;
+ Trap trap;
+
+ *res = sym;
+ if (id != NULL && id[0] == '@' && id[1] == 'P') {
+ p = id + 2;
+ sym->length = (ContextAddress)read_hex(&p);
+ if (*p == '.') p++;
+ if (id2symbol(p, &sym->base)) return -1;
+ sym->ctx = sym->base->ctx;
+ sym->frame = STACK_NO_FRAME;
+ sym->sym_class = SYM_CLASS_TYPE;
+ return 0;
+ }
+ else if (id != NULL && id[0] == '@' && id[1] == 'S') {
+ p = id + 2;
+ sym->sym_class = (int)read_hex(&p);
+ if (*p == '.') p++;
+ dev = (dev_t)read_hex(&p);
+ if (*p == '.') p++;
+ ino = (ino_t)read_hex(&p);
+ if (*p == '.') p++;
+ mtime = (int64_t)read_hex(&p);
+ if (*p == '.') p++;
+ obj_index = read_hex(&p);
+ if (*p == '.') p++;
+ var_index = read_hex(&p);
+ if (*p == '.') p++;
+ tbl_index = (unsigned)read_hex(&p);
+ if (*p == '.') p++;
+ sym->frame = read_int(&p);
+ if (*p == '.') p++;
+ sym->index = (unsigned)read_hex(&p);
+ if (*p == '.') p++;
+ sym->dimension = (unsigned)read_hex(&p);
+ if (*p == '.') p++;
+ sym->cardinal = (unsigned)read_hex(&p);
+ if (*p == '.') p++;
+ sym->ctx = id2ctx(p);
+ if (sym->ctx == NULL) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ if (dev == 0 && ino == 0 && mtime == 0) return 0;
+ file = elf_open_inode(sym->ctx, dev, ino, mtime);
+ if (file == NULL) return -1;
+ if (set_trap(&trap)) {
+ DWARFCache * cache = get_dwarf_cache(file);
+ if (obj_index) {
+ sym->obj = find_object(cache, obj_index);
+ if (sym->obj == NULL) exception(ERR_INV_CONTEXT);
+ }
+ if (var_index) {
+ sym->var = find_object(cache, var_index);
+ if (sym->var == NULL) exception(ERR_INV_CONTEXT);
+ }
+ if (tbl_index) {
+ if (tbl_index >= file->section_cnt) exception(ERR_INV_CONTEXT);
+ sym->tbl = file->sections + tbl_index;
+ }
+ clear_trap(&trap);
+ return 0;
+ }
+ }
+ else {
+ errno = ERR_INV_CONTEXT;
+ }
+ return -1;
+}
+
+ContextAddress is_plt_section(Context * ctx, ContextAddress addr) {
+ ELF_File * file = NULL;
+ ELF_Section * sec = NULL;
+ ContextAddress res = elf_map_to_link_time_address(ctx, addr, &file, &sec);
+ if (res == 0 || sec == NULL) return 0;
+ if (sec->name == NULL) return 0;
+ if (strcmp(sec->name, ".plt") != 0) return 0;
+ return sec->addr + (addr - res);
+}
+
+int get_stack_tracing_info(Context * ctx, ContextAddress rt_addr, StackTracingInfo ** info) {
+ /* TODO: no debug info exists for linux-gate.so, need to read stack tracing information from the kernel */
+ /* TODO: support for separate debug info files */
+ ELF_File * file = NULL;
+ ELF_Section * sec = NULL;
+ ContextAddress lt_addr = 0;
+ int error = 0;
+ Trap trap;
+
+ *info = NULL;
+
+ lt_addr = elf_map_to_link_time_address(ctx, rt_addr, &file, &sec);
+ if (file != NULL) {
+ /* This assert fails because of ambiguity in Linux memory maps:
+ * assert(rt_addr == elf_map_to_run_time_address(ctx, file, sec, lt_addr)); */
+ if (set_trap(&trap)) {
+ get_dwarf_stack_frame_info(ctx, file, sec, lt_addr);
+ if (dwarf_stack_trace_fp->cmds_cnt > 0) {
+ static StackTracingInfo buf;
+ buf.addr = (ContextAddress)dwarf_stack_trace_addr - lt_addr + rt_addr;
+ buf.size = (ContextAddress)dwarf_stack_trace_size;
+ buf.fp = dwarf_stack_trace_fp;
+ buf.regs = dwarf_stack_trace_regs;
+ buf.reg_cnt = dwarf_stack_trace_regs_cnt;
+ *info = &buf;
+ }
+ clear_trap(&trap);
+ }
+ else {
+ error = trap.error;
+ }
+ }
+
+ if (error) {
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+int get_next_stack_frame(StackFrame * frame, StackFrame * down) {
+ int error = 0;
+ uint64_t ip = 0;
+ Context * ctx = frame->ctx;
+ StackTracingInfo * info = NULL;
+
+ if (read_reg_value(frame, get_PC_definition(ctx), &ip) < 0) {
+ if (frame->is_top_frame) error = errno;
+ }
+ else if (get_stack_tracing_info(ctx, ip, &info) < 0) {
+ error = errno;
+ }
+ else if (info != NULL) {
+ Trap trap;
+ if (set_trap(&trap)) {
+ int i;
+ frame->fp = (ContextAddress)evaluate_stack_trace_commands(ctx, frame, info->fp);
+ for (i = 0; i < info->reg_cnt; i++) {
+ int ok = 0;
+ uint64_t v = 0;
+ Trap trap_reg;
+ if (set_trap(&trap_reg)) {
+ /* If a saved register value cannot be evaluated - ignore it */
+ v = evaluate_stack_trace_commands(ctx, frame, info->regs[i]);
+ clear_trap(&trap_reg);
+ ok = 1;
+ }
+ if (ok && write_reg_value(down, info->regs[i]->reg, v) < 0) exception(errno);
+ }
+ clear_trap(&trap);
+ }
+ else {
+ frame->fp = 0;
+ }
+ }
+ if (error) {
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+void ini_symbols_lib(void) {
+}
+
+/*************** Functions for retrieving symbol properties ***************************************/
+
+static int unpack(const Symbol * sym) {
+ ELF_File * file = NULL;
+ assert(sym->base == NULL);
+ assert(!is_cardinal_type_pseudo_symbol(sym));
+ if (get_sym_context(sym->ctx, sym->frame, 0) < 0) return -1;
+ if (sym->obj != NULL) file = sym->obj->mCompUnit->mFile;
+ if (sym->tbl != NULL) file = sym->tbl->file;
+ if (file != NULL) {
+ DWARFCache * cache = (DWARFCache *)file->dwarf_dt_cache;
+ if (cache == NULL || cache->magic != DWARF_CACHE_MAGIC) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static U8_T get_default_lower_bound(ObjectInfo * obj) {
+ switch (obj->mCompUnit->mLanguage) {
+ case LANG_FORTRAN77:
+ case LANG_FORTRAN90:
+ case LANG_FORTRAN95:
+ return 1;
+ }
+ return 0;
+}
+
+static U8_T get_object_length(ObjectInfo * obj) {
+ U8_T x, y;
+
+ if (get_num_prop(obj, AT_count, &x)) return x;
+ if (get_num_prop(obj, AT_upper_bound, &x)) {
+ if (!get_num_prop(obj, AT_lower_bound, &y)) {
+ y = get_default_lower_bound(obj);
+ }
+ return x + 1 - y;
+ }
+ if (obj->mTag == TAG_enumeration_type) {
+ ObjectInfo * c = obj->mChildren;
+ x = 0;
+ while (c != NULL) {
+ x++;
+ c = c->mSibling;
+ }
+ return x;
+ }
+ return 0;
+}
+
+static void alloc_cardinal_type_pseudo_symbol(Context * ctx, unsigned size, Symbol ** type) {
+ *type = alloc_symbol();
+ (*type)->ctx = context_get_group(ctx, CONTEXT_GROUP_PROCESS);
+ (*type)->frame = STACK_NO_FRAME;
+ (*type)->sym_class = SYM_CLASS_TYPE;
+ (*type)->cardinal = size;
+}
+
+static int map_to_sym_table(ObjectInfo * obj, Symbol ** sym) {
+ U8_T v = 0;
+ int found = 0;
+ if (get_num_prop(obj, AT_external, &v) && v != 0) {
+ Trap trap;
+ if (set_trap(&trap)) {
+ PropertyValue p;
+ DWARFCache * cache = get_dwarf_cache(obj->mCompUnit->mFile);
+ read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_MIPS_linkage_name, &p);
+ if (p.mAddr != NULL) found = find_by_name_in_sym_table(cache, (char *)p.mAddr, sym);
+ clear_trap(&trap);
+ }
+ }
+ return found;
+}
+
+int get_symbol_class(const Symbol * sym, int * sym_class) {
+ assert(sym->magic == SYMBOL_MAGIC);
+ *sym_class = sym->sym_class;
+ return 0;
+}
+
+int get_symbol_type(const Symbol * sym, Symbol ** type) {
+ ObjectInfo * obj = sym->obj;
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base || is_cardinal_type_pseudo_symbol(sym)) {
+ *type = (Symbol *)sym;
+ return 0;
+ }
+ if (sym->sym_class == SYM_CLASS_FUNCTION) {
+ *type = alloc_symbol();
+ (*type)->ctx = sym->ctx;
+ (*type)->frame = STACK_NO_FRAME;
+ (*type)->sym_class = SYM_CLASS_TYPE;
+ (*type)->base = (Symbol *)sym;
+ return 0;
+ }
+ if (unpack(sym) < 0) return -1;
+ obj = sym->sym_class == SYM_CLASS_TYPE ?
+ get_original_type(obj) : get_object_type(obj);
+ if (obj == NULL) {
+ *type = NULL;
+ }
+ else if (obj == sym->obj) {
+ *type = (Symbol *)sym;
+ }
+ else {
+ object2symbol(obj, type);
+ }
+ return 0;
+}
+
+int get_symbol_type_class(const Symbol * sym, int * type_class) {
+ U8_T x;
+ ObjectInfo * obj = sym->obj;
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base) {
+ if (sym->base->sym_class == SYM_CLASS_FUNCTION) *type_class = TYPE_CLASS_FUNCTION;
+ else if (sym->length > 0) *type_class = TYPE_CLASS_ARRAY;
+ else *type_class = TYPE_CLASS_POINTER;
+ return 0;
+ }
+ if (is_cardinal_type_pseudo_symbol(sym)) {
+ *type_class = TYPE_CLASS_CARDINAL;
+ return 0;
+ }
+ if (unpack(sym) < 0) return -1;
+ while (obj != NULL) {
+ switch (obj->mTag) {
+ case TAG_global_subroutine:
+ case TAG_subroutine:
+ case TAG_subprogram:
+ case TAG_entry_point:
+ case TAG_subroutine_type:
+ *type_class = TYPE_CLASS_FUNCTION;
+ return 0;
+ case TAG_array_type:
+ case TAG_string_type:
+ *type_class = TYPE_CLASS_ARRAY;
+ return 0;
+ case TAG_enumeration_type:
+ case TAG_enumerator:
+ *type_class = TYPE_CLASS_ENUMERATION;
+ return 0;
+ case TAG_pointer_type:
+ case TAG_reference_type:
+ case TAG_mod_pointer:
+ case TAG_mod_reference:
+ *type_class = TYPE_CLASS_POINTER;
+ return 0;
+ case TAG_class_type:
+ case TAG_structure_type:
+ case TAG_union_type:
+ case TAG_interface_type:
+ *type_class = TYPE_CLASS_COMPOSITE;
+ return 0;
+ case TAG_base_type:
+ if (get_num_prop(obj, AT_encoding, &x)) {
+ switch ((int)x) {
+ case ATE_address:
+ *type_class = TYPE_CLASS_POINTER;
+ return 0;
+ case ATE_boolean:
+ *type_class = TYPE_CLASS_INTEGER;
+ return 0;
+ case ATE_float:
+ *type_class = TYPE_CLASS_REAL;
+ return 0;
+ case ATE_signed:
+ case ATE_signed_char:
+ *type_class = TYPE_CLASS_INTEGER;
+ return 0;
+ case ATE_unsigned:
+ case ATE_unsigned_char:
+ *type_class = TYPE_CLASS_CARDINAL;
+ return 0;
+ }
+ }
+ *type_class = TYPE_CLASS_UNKNOWN;
+ return 0;
+ case TAG_fund_type:
+ switch (obj->u.mFundType) {
+ case FT_boolean:
+ *type_class = TYPE_CLASS_INTEGER;
+ return 0;
+ case FT_char:
+ *type_class = TYPE_CLASS_INTEGER;
+ return 0;
+ case FT_dbl_prec_float:
+ case FT_ext_prec_float:
+ case FT_float:
+ *type_class = TYPE_CLASS_REAL;
+ return 0;
+ case FT_signed_char:
+ case FT_signed_integer:
+ case FT_signed_long:
+ case FT_signed_short:
+ case FT_short:
+ case FT_integer:
+ case FT_long:
+ *type_class = TYPE_CLASS_INTEGER;
+ return 0;
+ case FT_unsigned_char:
+ case FT_unsigned_integer:
+ case FT_unsigned_long:
+ case FT_unsigned_short:
+ *type_class = TYPE_CLASS_CARDINAL;
+ return 0;
+ case FT_pointer:
+ *type_class = TYPE_CLASS_POINTER;
+ return 0;
+ case FT_void:
+ *type_class = TYPE_CLASS_CARDINAL;
+ return 0;
+ case FT_label:
+ case FT_complex:
+ case FT_dbl_prec_complex:
+ case FT_ext_prec_complex:
+ break;
+ }
+ *type_class = TYPE_CLASS_UNKNOWN;
+ return 0;
+ case TAG_subrange_type:
+ case TAG_packed_type:
+ case TAG_volatile_type:
+ case TAG_restrict_type:
+ case TAG_shared_type:
+ case TAG_const_type:
+ case TAG_typedef:
+ case TAG_formal_parameter:
+ case TAG_unspecified_parameters:
+ case TAG_global_variable:
+ case TAG_local_variable:
+ case TAG_variable:
+ case TAG_inheritance:
+ case TAG_member:
+ case TAG_constant:
+ obj = obj->mType;
+ break;
+ default:
+ obj = NULL;
+ break;
+ }
+ }
+ if (sym->tbl != NULL) {
+ ELF_SymbolInfo info;
+ unpack_elf_symbol_info(sym->tbl, sym->index, &info);
+ if (info.type == STT_FUNC) {
+ *type_class = TYPE_CLASS_FUNCTION;
+ return 0;
+ }
+ }
+ *type_class = TYPE_CLASS_UNKNOWN;
+ return 0;
+}
+
+int get_symbol_update_policy(const Symbol * sym, char ** id, int * policy) {
+ assert(sym->magic == SYMBOL_MAGIC);
+ *id = sym->ctx->id;
+ *policy = context_has_state(sym->ctx) ? UPDATE_ON_EXE_STATE_CHANGES : UPDATE_ON_MEMORY_MAP_CHANGES;
+ return 0;
+}
+
+int get_symbol_name(const Symbol * sym, char ** name) {
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base || is_cardinal_type_pseudo_symbol(sym)) {
+ *name = NULL;
+ }
+ else if (sym->obj != NULL) {
+ *name = sym->obj->mName;
+ }
+ else if (sym->tbl != NULL) {
+ ELF_SymbolInfo info;
+ unpack_elf_symbol_info(sym->tbl, sym->index, &info);
+ *name = info.name;
+ }
+ else {
+ *name = NULL;
+ }
+ return 0;
+}
+
+int get_symbol_size(const Symbol * sym, ContextAddress * size) {
+ ObjectInfo * obj = sym->obj;
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base) {
+ if (sym->length > 0) {
+ if (get_symbol_size(sym->base, size)) return -1;
+ *size *= sym->length;
+ }
+ else {
+ Symbol * base = sym->base;
+ while (base->obj == NULL && base->base != NULL) base = base->base;
+ if (base->obj != NULL) *size = base->obj->mCompUnit->mDesc.mAddressSize;
+ else *size = context_word_size(sym->ctx);
+ }
+ return 0;
+ }
+ if (is_cardinal_type_pseudo_symbol(sym)) {
+ *size = sym->cardinal;
+ return 0;
+ }
+ if (sym->has_size != 0) {
+ *size = sym->size;
+ return 0;
+ }
+ if (unpack(sym) < 0) return -1;
+ *size = 0;
+ if (obj != NULL) {
+ Trap trap;
+ int ok = 0;
+ U8_T sz = 0;
+
+ if (!set_trap(&trap)) return -1;
+ if (sym->dimension == 0) ok = get_num_prop(obj, AT_byte_size, &sz);
+ if (!ok && sym->sym_class == SYM_CLASS_FUNCTION) {
+ if (obj->u.mAddr.mHighPC > obj->u.mAddr.mLowPC) {
+ ok = 1;
+ sz = obj->u.mAddr.mHighPC - obj->u.mAddr.mLowPC;
+ }
+ }
+ else if (!ok) {
+ ObjectInfo * ref = NULL;
+ if (sym->sym_class == SYM_CLASS_REFERENCE) {
+ ref = obj;
+ if (obj->mType != NULL) {
+ obj = obj->mType;
+ if (sym->dimension == 0) ok = get_num_prop(obj, AT_byte_size, &sz);
+ }
+ }
+ while (!ok && obj->mType != NULL) {
+ if (!is_modified_type(obj) && obj->mTag != TAG_enumeration_type) break;
+ obj = obj->mType;
+ if (sym->dimension == 0) ok = get_num_prop(obj, AT_byte_size, &sz);
+ }
+ if (!ok && obj->mTag == TAG_array_type) {
+ unsigned i = 0;
+ U8_T length = 1;
+ ObjectInfo * elem_type = obj->mType;
+ ObjectInfo * idx = obj->mChildren;
+ while (idx != NULL) {
+ if (i++ >= sym->dimension) length *= get_object_length(idx);
+ idx = idx->mSibling;
+ }
+ ok = get_num_prop(obj, AT_stride_size, &sz);
+ if (ok) {
+ sz = (sz * length + 7) / 8;
+ }
+ else {
+ if (elem_type == NULL) str_exception(ERR_OTHER, "Unknown array element type");
+ ok = get_num_prop(elem_type, AT_byte_size, &sz);
+ while (!ok && elem_type->mType != NULL) {
+ if (!is_modified_type(elem_type) && elem_type->mTag != TAG_enumeration_type) break;
+ elem_type = elem_type->mType;
+ ok = get_num_prop(elem_type, AT_byte_size, &sz);
+ }
+ if (ok) sz *= length;
+ }
+ }
+ if (!ok && ref && ref->mTag != TAG_member && ref->mTag != TAG_inheritance) {
+ Trap trap;
+ if (set_trap(&trap)) {
+ PropertyValue v;
+ read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, ref, AT_location, &v);
+ if (v.mRegister) {
+ sz = v.mRegister->size;
+ ok = 1;
+ }
+ clear_trap(&trap);
+ }
+ }
+ if (!ok && ref != NULL) {
+ Symbol * elf_sym = NULL;
+ ContextAddress elf_sym_size = 0;
+ if (map_to_sym_table(ref, &elf_sym) && get_symbol_size(elf_sym, &elf_sym_size) == 0) {
+ sz = elf_sym_size;
+ ok = 1;
+ }
+ }
+ }
+ if (!ok) str_exception(ERR_INV_DWARF, "Object has no size attribute");
+ *size = (ContextAddress)sz;
+ clear_trap(&trap);
+ }
+ else if (sym->tbl != NULL) {
+ ELF_SymbolInfo info;
+ unpack_elf_symbol_info(sym->tbl, sym->index, &info);
+ switch (info.type) {
+ case STT_OBJECT:
+ case STT_FUNC:
+ *size = (ContextAddress)info.size;
+ break;
+ default:
+ *size = info.sym_section->file->elf64 ? 8 : 4;
+ break;
+ }
+ }
+ else {
+ errno = set_errno(ERR_OTHER, "Debug info not available");
+ return -1;
+ }
+ return 0;
+}
+
+int get_symbol_base_type(const Symbol * sym, Symbol ** base_type) {
+ ObjectInfo * obj = sym->obj;
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base) {
+ if (sym->base->sym_class == SYM_CLASS_FUNCTION) {
+ if (sym->base->obj != NULL && sym->base->obj->mType != NULL) {
+ if (unpack(sym->base) < 0) return -1;
+ object2symbol(sym->base->obj->mType, base_type);
+ }
+ else {
+ /* Function return type is 'void' */
+ alloc_cardinal_type_pseudo_symbol(sym->ctx, 0, base_type);
+ }
+ return 0;
+ }
+ *base_type = sym->base;
+ return 0;
+ }
+ if (is_cardinal_type_pseudo_symbol(sym)) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ if (unpack(sym) < 0) return -1;
+ obj = get_original_type(obj);
+ if (obj != NULL) {
+ if (obj->mTag == TAG_array_type) {
+ int i = sym->dimension;
+ ObjectInfo * idx = obj->mChildren;
+ while (i > 0 && idx != NULL) {
+ idx = idx->mSibling;
+ i--;
+ }
+ if (idx != NULL && idx->mSibling != NULL) {
+ *base_type = alloc_symbol();
+ **base_type = *sym;
+ (*base_type)->dimension++;
+ return 0;
+ }
+ }
+ if ((obj->mTag == TAG_pointer_type || obj->mTag == TAG_mod_pointer) && obj->mType == NULL) {
+ /* pointer to void */
+ alloc_cardinal_type_pseudo_symbol(sym->ctx, 0, base_type);
+ return 0;
+ }
+ obj = obj->mType;
+ if (obj != NULL) {
+ object2symbol(obj, base_type);
+ return 0;
+ }
+ }
+ errno = ERR_UNSUPPORTED;
+ return -1;
+}
+
+int get_symbol_index_type(const Symbol * sym, Symbol ** index_type) {
+ ObjectInfo * obj = sym->obj;
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base) {
+ if (sym->base->sym_class == SYM_CLASS_FUNCTION) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ alloc_cardinal_type_pseudo_symbol(sym->ctx, context_word_size(sym->ctx), index_type);
+ return 0;
+ }
+ if (is_cardinal_type_pseudo_symbol(sym)) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ if (unpack(sym) < 0) return -1;
+ obj = get_original_type(obj);
+ if (obj != NULL && obj->mTag == TAG_array_type) {
+ int i = sym->dimension;
+ ObjectInfo * idx = obj->mChildren;
+ while (i > 0 && idx != NULL) {
+ idx = idx->mSibling;
+ i--;
+ }
+ if (idx != NULL) {
+ object2symbol(idx, index_type);
+ return 0;
+ }
+ }
+ errno = ERR_UNSUPPORTED;
+ return -1;
+}
+
+int get_symbol_length(const Symbol * sym, ContextAddress * length) {
+ ObjectInfo * obj = sym->obj;
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base) {
+ if (sym->base->sym_class == SYM_CLASS_FUNCTION) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ *length = sym->length == 0 ? 1 : sym->length;
+ return 0;
+ }
+ if (is_cardinal_type_pseudo_symbol(sym)) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ if (unpack(sym) < 0) return -1;
+ obj = get_original_type(obj);
+ if (obj != NULL && obj->mTag == TAG_array_type) {
+ int i = sym->dimension;
+ ObjectInfo * idx = obj->mChildren;
+ while (i > 0 && idx != NULL) {
+ idx = idx->mSibling;
+ i--;
+ }
+ if (idx != NULL) {
+ Trap trap;
+ if (!set_trap(&trap)) return -1;
+ *length = (ContextAddress)get_object_length(idx);
+ clear_trap(&trap);
+ return 0;
+ }
+ }
+ errno = ERR_UNSUPPORTED;
+ return -1;
+}
+
+int get_symbol_lower_bound(const Symbol * sym, int64_t * value) {
+ ObjectInfo * obj = sym->obj;
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base) {
+ if (sym->base->sym_class == SYM_CLASS_FUNCTION) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ *value = 0;
+ return 0;
+ }
+ if (is_cardinal_type_pseudo_symbol(sym)) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ if (unpack(sym) < 0) return -1;
+ obj = get_original_type(obj);
+ if (obj != NULL && obj->mTag == TAG_array_type) {
+ int i = sym->dimension;
+ ObjectInfo * idx = obj->mChildren;
+ while (i > 0 && idx != NULL) {
+ idx = idx->mSibling;
+ i--;
+ }
+ if (idx != NULL) {
+ if (get_num_prop(obj, AT_lower_bound, (U8_T *)value)) return 0;
+ if (get_error_code(errno) != ERR_SYM_NOT_FOUND) return -1;
+ *value = get_default_lower_bound(obj);
+ return 0;
+ }
+ }
+ errno = ERR_UNSUPPORTED;
+ return -1;
+}
+
+int get_symbol_children(const Symbol * sym, Symbol *** children, int * count) {
+ static Symbol ** buf = NULL;
+ static int buf_len = 0;
+ ObjectInfo * obj = sym->obj;
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base) {
+ obj = sym->base->obj;
+ if (sym->base->sym_class == SYM_CLASS_FUNCTION) {
+ if (obj == NULL) {
+ *children = NULL;
+ *count = 0;
+ errno = ERR_SYM_NOT_FOUND;
+ return -1;
+ }
+ else {
+ int n = 0;
+ ObjectInfo * i = obj->mChildren;
+ if (unpack(sym->base) < 0) return -1;
+ while (i != NULL) {
+ if (i->mTag == TAG_formal_parameter || i->mTag == TAG_unspecified_parameters) {
+ Symbol * x = NULL;
+ Symbol * y = NULL;
+ object2symbol(i, &x);
+ if (get_symbol_type(x, &y) < 0) return -1;
+ if (buf_len <= n) {
+ buf_len += 16;
+ buf = (Symbol **)loc_realloc(buf, sizeof(Symbol *) * buf_len);
+ }
+ buf[n++] = y;
+ }
+ i = i->mSibling;
+ }
+ *children = buf;
+ *count = n;
+ return 0;
+ }
+ }
+ *children = NULL;
+ *count = 0;
+ return 0;
+ }
+ if (is_cardinal_type_pseudo_symbol(sym)) {
+ *children = NULL;
+ *count = 0;
+ return 0;
+ }
+ if (unpack(sym) < 0) return -1;
+ obj = get_original_type(obj);
+ if (obj != NULL) {
+ int n = 0;
+ ObjectInfo * i = obj->mChildren;
+ while (i != NULL) {
+ Symbol * x = NULL;
+ object2symbol(i, &x);
+ if (buf_len <= n) {
+ buf_len += 16;
+ buf = (Symbol **)loc_realloc(buf, sizeof(Symbol *) * buf_len);
+ }
+ buf[n++] = x;
+ i = i->mSibling;
+ }
+ *children = buf;
+ *count = n;
+ return 0;
+ }
+ *children = NULL;
+ *count = 0;
+ return 0;
+}
+
+int get_symbol_offset(const Symbol * sym, ContextAddress * offset) {
+ ObjectInfo * obj = sym->obj;
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base || is_cardinal_type_pseudo_symbol(sym)) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ if (unpack(sym) < 0) return -1;
+ if (obj != NULL && (obj->mTag == TAG_member || obj->mTag == TAG_inheritance)) {
+ U8_T v;
+ if (!get_num_prop(obj, AT_data_member_location, &v)) return -1;
+ *offset = (ContextAddress)v;
+ return 0;
+ }
+ errno = ERR_INV_CONTEXT;
+ return -1;
+}
+
+int get_symbol_value(const Symbol * sym, void ** value, size_t * size, int * big_endian) {
+ ObjectInfo * obj = sym->obj;
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base || is_cardinal_type_pseudo_symbol(sym) || sym->var) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ if (unpack(sym) < 0) return -1;
+ if (obj != NULL) {
+ Trap trap;
+ PropertyValue v;
+ static U1_T * bf = NULL;
+ static size_t bf_size = 0;
+ if (set_trap(&trap)) {
+ read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_const_value, &v);
+ if (v.mAddr != NULL) {
+ *size = v.mSize;
+ *value = v.mAddr;
+ }
+ else if (v.mRegister != NULL || v.mPieces != NULL) {
+ str_exception(ERR_INV_CONTEXT, "Constant DWARF attribute value expected");
+ }
+ else {
+ U8_T n = v.mValue;
+ size_t i = 0;
+ if (bf_size < sizeof(v.mValue)) {
+ bf_size = sizeof(v.mValue);
+ bf = (U1_T *)loc_realloc(bf, bf_size);
+ }
+ for (i = 0; i < sizeof(v.mValue); i++) {
+ bf[v.mBigEndian ? sizeof(v.mValue) - i - 1 : i] = n & 0xffu;
+ n = n >> 8;
+ }
+ *size = sizeof(v.mValue);
+ *value = bf;
+ }
+ *big_endian = v.mBigEndian;
+ clear_trap(&trap);
+ return 0;
+ }
+ else if (trap.error != ERR_SYM_NOT_FOUND) {
+ return -1;
+ }
+ if (set_trap(&trap)) {
+ read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_location, &v);
+ if (v.mPieces != NULL) {
+ U4_T n = 0;
+ U4_T bf_offs = 0;
+ while (n < v.mPieceCnt) {
+ U4_T i;
+ U1_T pbf[32];
+ PropertyValuePiece * piece = v.mPieces + n++;
+ U4_T piece_size = (piece->mBitSize + 7) / 8;
+ if (piece_size > sizeof(pbf)) exception(ERR_BUFFER_OVERFLOW);
+ if (bf_size < bf_offs / 8 + piece_size + 1) {
+ bf_size = bf_offs / 8 + piece_size + 1;
+ bf = (U1_T *)loc_realloc(bf, bf_size);
+ }
+ if (piece->mRegister) {
+ StackFrame * frame = NULL;
+ RegisterDefinition * def = piece->mRegister;
+ if (get_frame_info(v.mContext, v.mFrame, &frame) < 0) exception(errno);
+ if (read_reg_bytes(frame, def, 0, piece_size, pbf) < 0) exception(errno);
+ }
+ else {
+ if (context_read_mem(v.mContext, piece->mAddress, pbf, piece_size) < 0) exception(errno);
+ }
+ if (!piece->mBigEndian != !v.mBigEndian) swap_bytes(pbf, piece_size);
+ for (i = piece->mBitOffset; i < piece->mBitOffset + piece->mBitSize; i++) {
+ if (pbf[i / 8] & (1u << (i % 8))) {
+ bf[bf_offs / 8] |= (1u << (bf_offs % 8));
+ }
+ else {
+ bf[bf_offs / 8] &= ~(1u << (bf_offs % 8));
+ }
+ bf_offs++;
+ }
+ }
+ while (bf_offs % 8) {
+ bf[bf_offs / 8] &= ~(1u << (bf_offs % 8));
+ bf_offs++;
+ }
+ *value = bf;
+ *size = bf_offs / 8;
+ *big_endian = v.mBigEndian;
+ }
+ else if (v.mRegister != NULL) {
+ StackFrame * frame = NULL;
+ RegisterDefinition * def = v.mRegister;
+ ContextAddress sym_size = def->size;
+ unsigned val_offs = 0;
+ unsigned val_size = 0;
+
+ if (get_symbol_size(sym, &sym_size) < 0) exception(errno);
+ if (bf_size < sym_size) {
+ bf_size = (size_t)sym_size;
+ bf = (U1_T *)loc_realloc(bf, bf_size);
+ }
+ if (get_frame_info(v.mContext, v.mFrame, &frame) < 0) exception(errno);
+ val_size = def->size < sym_size ? (unsigned)def->size : (unsigned)sym_size;
+ if (def->big_endian) val_offs = (unsigned)def->size - val_size;
+ if (read_reg_bytes(frame, def, val_offs, val_size, bf) < 0) exception(errno);
+ *value = bf;
+ *size = val_size;
+ *big_endian = def->big_endian;
+ }
+ else {
+ exception(ERR_INV_CONTEXT);
+ }
+ clear_trap(&trap);
+ return 0;
+ }
+ else if (trap.error != ERR_SYM_NOT_FOUND) {
+ return -1;
+ }
+ set_errno(ERR_OTHER, "Object location or value info not available");
+ return -1;
+ }
+ if (sym->tbl != NULL) {
+ ELF_SymbolInfo info;
+ unpack_elf_symbol_info(sym->tbl, sym->index, &info);
+ switch (info.type) {
+ case STT_OBJECT:
+ case STT_FUNC:
+ set_errno(ERR_OTHER, "Symbol represents an address");
+ return -1;
+ }
+ if (info.sym_section->file->elf64) {
+ static U8_T buf = 0;
+ buf = info.value;
+ *value = &buf;
+ *size = 8;
+ }
+ else {
+ static U4_T buf = 0;
+ buf = (U4_T)info.value;
+ *value = &buf;
+ *size = 4;
+ }
+ *big_endian = big_endian_host();
+ return 0;
+ }
+ errno = ERR_INV_CONTEXT;
+ return -1;
+}
+
+static int calc_member_offset(ObjectInfo * type, ObjectInfo * member, ContextAddress * offs) {
+ PropertyValue v;
+ ObjectInfo * obj = NULL;
+ if (member->mParent == type) {
+ read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, member, AT_data_member_location, &v);
+ *offs = (ContextAddress)get_numeric_property_value(&v);
+ return 1;
+ }
+ obj = type->mChildren;
+ while (obj != NULL) {
+ if (obj->mTag == TAG_inheritance && calc_member_offset(obj->mType, member, offs)) {
+ read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_data_member_location, &v);
+ *offs += (ContextAddress)get_numeric_property_value(&v);
+ return 1;
+ }
+ obj = obj->mSibling;
+ }
+ return 0;
+}
+
+int get_symbol_address(const Symbol * sym, ContextAddress * address) {
+ ObjectInfo * obj = sym->obj;
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base || is_cardinal_type_pseudo_symbol(sym)) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ if (sym->has_address) {
+ *address = sym->address;
+ return 0;
+ }
+ if (unpack(sym) < 0) return -1;
+ if (sym->var != NULL) {
+ /* The symbol represents a member of a class instance */
+ Trap trap;
+ PropertyValue v;
+ ContextAddress base = 0;
+ ContextAddress offs = 0;
+ ObjectInfo * type = get_original_type(sym->var);
+ if (!set_trap(&trap)) return -1;
+ if ((type->mTag != TAG_pointer_type && type->mTag != TAG_mod_pointer) || type->mType == NULL) exception(ERR_INV_CONTEXT);
+ read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, sym->var, AT_location, &v);
+ if (v.mPieces != NULL) {
+ str_exception(ERR_UNSUPPORTED, "Unsupported location of 'this' pointer");
+ }
+ else if (v.mRegister != NULL) {
+ U8_T rv = 0;
+ StackFrame * frame = NULL;
+ if (get_frame_info(v.mContext, v.mFrame, &frame) < 0) exception(errno);
+ if (read_reg_value(frame, v.mRegister, &rv) < 0) exception(errno);
+ base = (ContextAddress)rv;
+ }
+ else {
+ if (elf_read_memory_word(sym_ctx, sym->var->mCompUnit->mFile,
+ (ContextAddress)get_numeric_property_value(&v), &base) < 0) exception(errno);
+ }
+ type = get_original_type(type->mType);
+ if (!calc_member_offset(type, obj, &offs)) exception(ERR_INV_CONTEXT);
+ clear_trap(&trap);
+ *address = base + offs;
+ return 0;
+ }
+ if (obj != NULL && obj->mTag != TAG_member && obj->mTag != TAG_inheritance) {
+ U8_T v;
+ Symbol * s = NULL;
+ if (get_num_prop(obj, AT_location, &v)) {
+ *address = (ContextAddress)v;
+ return 0;
+ }
+ if (get_error_code(errno) != ERR_SYM_NOT_FOUND) return -1;
+ if (get_num_prop(obj, AT_low_pc, &v)) {
+ *address = (ContextAddress)v;
+ return 0;
+ }
+ if (get_error_code(errno) != ERR_SYM_NOT_FOUND) return -1;
+ if (map_to_sym_table(obj, &s)) return get_symbol_address(s, address);
+ set_errno(ERR_OTHER, "No object location info found in DWARF data");
+ return -1;
+ }
+ if (sym->tbl != NULL) {
+ ELF_SymbolInfo info;
+ unpack_elf_symbol_info(sym->tbl, sym->index, &info);
+ return syminfo2address(sym_ctx, &info, address);
+ }
+
+ errno = ERR_INV_CONTEXT;
+ return -1;
+}
+
+int get_symbol_register(const Symbol * sym, Context ** ctx, int * frame, RegisterDefinition ** reg) {
+ ObjectInfo * obj = sym->obj;
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base || is_cardinal_type_pseudo_symbol(sym) || sym->has_address) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ if (unpack(sym) < 0) return -1;
+ if (obj != NULL && obj->mTag != TAG_member && obj->mTag != TAG_inheritance) {
+ Trap trap;
+ if (set_trap(&trap)) {
+ PropertyValue v;
+ read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_location, &v);
+ *ctx = sym_ctx;
+ *frame = sym_frame;
+ *reg = v.mRegister;
+ clear_trap(&trap);
+ return 0;
+ }
+ }
+
+ errno = ERR_INV_CONTEXT;
+ return -1;
+}
+
+int get_symbol_flags(const Symbol * sym, SYM_FLAGS * flags) {
+ U8_T v = 0;
+ ObjectInfo * i = NULL;
+ ObjectInfo * obj = sym->obj;
+ *flags = 0;
+ assert(sym->magic == SYMBOL_MAGIC);
+ if (sym->base || is_cardinal_type_pseudo_symbol(sym)) return 0;
+ if (unpack(sym) < 0) return -1;
+ i = obj;
+ while (i != NULL) {
+ switch (i->mTag) {
+ case TAG_subrange_type:
+ *flags |= SYM_FLAG_SUBRANGE_TYPE;
+ i = i->mType;
+ break;
+ case TAG_packed_type:
+ *flags |= SYM_FLAG_PACKET_TYPE;
+ i = i->mType;
+ break;
+ case TAG_const_type:
+ *flags |= SYM_FLAG_CONST_TYPE;
+ i = i->mType;
+ break;
+ case TAG_volatile_type:
+ *flags |= SYM_FLAG_VOLATILE_TYPE;
+ i = i->mType;
+ break;
+ case TAG_restrict_type:
+ *flags |= SYM_FLAG_RESTRICT_TYPE;
+ i = i->mType;
+ break;
+ case TAG_shared_type:
+ *flags |= SYM_FLAG_SHARED_TYPE;
+ i = i->mType;
+ break;
+ case TAG_typedef:
+ if (i == obj) *flags |= SYM_FLAG_TYPEDEF;
+ i = i->mType;
+ break;
+ case TAG_reference_type:
+ case TAG_mod_reference:
+ *flags |= SYM_FLAG_REFERENCE;
+ i = NULL;
+ break;
+ case TAG_union_type:
+ *flags |= SYM_FLAG_UNION_TYPE;
+ i = NULL;
+ break;
+ case TAG_class_type:
+ *flags |= SYM_FLAG_CLASS_TYPE;
+ i = NULL;
+ break;
+ case TAG_interface_type:
+ *flags |= SYM_FLAG_INTERFACE_TYPE;
+ i = NULL;
+ break;
+ case TAG_unspecified_parameters:
+ *flags |= SYM_FLAG_PARAMETER;
+ *flags |= SYM_FLAG_VARARG;
+ i = NULL;
+ break;
+ case TAG_formal_parameter:
+ case TAG_variable:
+ case TAG_constant:
+ case TAG_base_type:
+ if (i->mTag == TAG_formal_parameter) {
+ *flags |= SYM_FLAG_PARAMETER;
+ if (get_num_prop(i, AT_is_optional, &v) && v != 0) *flags |= SYM_FLAG_OPTIONAL;
+ }
+ if (i->mTag == TAG_variable && get_num_prop(obj, AT_external, &v) && v != 0) {
+ *flags |= SYM_FLAG_EXTERNAL;
+ }
+ if (get_num_prop(i, AT_endianity, &v)) {
+ if (v == DW_END_big) *flags |= SYM_FLAG_BIG_ENDIAN;
+ if (v == DW_END_little) *flags |= SYM_FLAG_LITTLE_ENDIAN;
+ }
+ i = NULL;
+ break;
+ default:
+ i = NULL;
+ break;
+ }
+ }
+ if (obj != NULL && sym->sym_class == SYM_CLASS_TYPE && !(*flags & (SYM_FLAG_BIG_ENDIAN|SYM_FLAG_LITTLE_ENDIAN))) {
+ *flags |= obj->mCompUnit->mFile->big_endian ? SYM_FLAG_BIG_ENDIAN : SYM_FLAG_LITTLE_ENDIAN;
+ }
+ return 0;
+}
+
+int get_array_symbol(const Symbol * sym, ContextAddress length, Symbol ** ptr) {
+ assert(sym->magic == SYMBOL_MAGIC);
+ assert(sym->sym_class == SYM_CLASS_TYPE);
+ assert(sym->frame == STACK_NO_FRAME);
+ assert(sym->ctx == context_get_group(sym->ctx, CONTEXT_GROUP_PROCESS));
+ *ptr = alloc_symbol();
+ (*ptr)->ctx = sym->ctx;
+ (*ptr)->frame = STACK_NO_FRAME;
+ (*ptr)->sym_class = SYM_CLASS_TYPE;
+ (*ptr)->base = (Symbol *)sym;
+ (*ptr)->length = length;
+ return 0;
+}
+
+#endif /* SERVICE_Symbols && ENABLE_ELF */

Back to the top