blob: 9b66706320f3a92a4c6ddd19685578ecc2413525 [file] [log] [blame]
/*******************************************************************************
* 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.
*
* 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;
SymbolSection * tbl;
ContextAddress address;
int sym_class;
Context * ctx;
int frame;
unsigned index;
unsigned dimension;
ContextAddress size;
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, SymbolInfo * info, ContextAddress * address) {
switch (info->mType) {
case STT_OBJECT:
case STT_FUNC:
{
U8_T value = info->mValue;
ELF_File * file = info->mSymSection->mFile;
ELF_Section * sec = NULL;
if (info->mSectionIndex == SHN_UNDEF) {
errno = ERR_INV_ADDRESS;
return -1;
}
if (info->mSectionIndex == SHN_ABS) {
*address = (ContextAddress)value;
return 0;
}
if (info->mSectionIndex == SHN_COMMON) {
errno = ERR_INV_ADDRESS;
return -1;
}
if (file->type == ET_REL && info->mSection != NULL) {
sec = info->mSection;
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 void object2symbol(ObjectInfo * obj, Symbol ** res) {
Context * ctx = sym_ctx;
Symbol * sym = alloc_symbol();
sym->obj = obj;
sym->frame = STACK_NO_FRAME;
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_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:
sym->sym_class = SYM_CLASS_REFERENCE;
break;
case TAG_formal_parameter:
case TAG_local_variable:
case TAG_variable:
sym->sym_class = SYM_CLASS_REFERENCE;
sym->frame = sym_frame;
break;
case TAG_constant:
case TAG_enumerator:
sym->sym_class = SYM_CLASS_VALUE;
break;
}
if (sym->frame == STACK_NO_FRAME) ctx = context_get_group(ctx, CONTEXT_GROUP_PROCESS);
sym->ctx = ctx;
*res = sym;
}
static int get_num_prop(ObjectInfo * obj, int 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 'addr' belongs to an object address range(s) */
static int check_in_range(ObjectInfo * obj, ContextAddress addr) {
Trap trap;
if (set_trap(&trap)) {
U8_T pc0, pc1;
PropertyValue v0, v1;
read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_low_pc, &v0);
read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_high_pc, &v1);
pc0 = get_numeric_property_value(&v0);
pc1 = get_numeric_property_value(&v1);
clear_trap(&trap);
return pc0 <= addr && pc1 > addr;
}
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 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 <= addr && 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 ip, const char * name, Symbol ** sym) {
Symbol * sym_imp = NULL;
Symbol * sym_enu = NULL;
Symbol * sym_cur = NULL;
ObjectInfo * obj = list;
while (obj != NULL) {
if (obj->mName != NULL && strcmp(obj->mName, name) == 0) {
object2symbol(obj, &sym_cur);
}
switch (obj->mTag) {
case TAG_enumeration_type:
find_in_object_tree(obj->mChildren, 0, name, &sym_enu);
break;
case TAG_global_subroutine:
case TAG_subroutine:
case TAG_subprogram:
case TAG_entry_point:
case TAG_lexical_block:
if (ip != 0 && check_in_range(obj, ip)) {
if (find_in_object_tree(obj->mChildren, ip, name, sym)) return 1;
}
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, name, &sym_imp);
}
break;
}
obj = obj->mSibling;
}
if (*sym == NULL) *sym = sym_cur;
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) {
UnitAddressRange * range = elf_find_unit(sym_ctx, sym_ip, sym_ip, NULL);
*sym = NULL;
if (range != NULL) {
CompUnit * unit = range->mUnit;
if (find_in_object_tree(unit->mObject->mChildren, sym_ip, name, sym)) return 1;
if (unit->mBaseTypes != NULL) {
if (find_in_object_tree(unit->mBaseTypes->mObject->mChildren, 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(SymbolSection * tbl) {
unsigned i;
tbl->mSymNamesHash = (unsigned *)loc_alloc_zero(SYM_HASH_SIZE * sizeof(unsigned));
tbl->mSymNamesNext = (unsigned *)loc_alloc_zero(tbl->mSymCount * sizeof(unsigned));
for (i = 0; i < tbl->mSymCount; i++) {
SymbolInfo sym;
unpack_elf_symbol_info(tbl, i, &sym);
if (sym.mBind == STB_GLOBAL && sym.mName != NULL && sym.mSectionIndex != SHN_UNDEF) {
unsigned h = calc_symbol_name_hash(sym.mName);
tbl->mSymNamesNext[i] = tbl->mSymNamesHash[h];
tbl->mSymNamesHash[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);
while (m < cache->mSymSectionsCnt) {
unsigned n;
SymbolSection * tbl = cache->mSymSections[m];
if (tbl->mSymNamesHash == NULL) create_symbol_names_hash(tbl);
n = tbl->mSymNamesHash[h];
while (n) {
SymbolInfo sym_info;
unpack_elf_symbol_info(tbl, n, &sym_info);
if (cmp_symbol_names(name, sym_info.mName) == 0) {
ContextAddress addr = 0;
if (syminfo2address(prs, &sym_info, &addr) == 0) {
int found = 0;
if (sym_info.mSectionIndex != SHN_ABS) {
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.mType) {
case STT_FUNC:
sym->sym_class = SYM_CLASS_FUNCTION;
break;
case STT_OBJECT:
sym->sym_class = SYM_CLASS_REFERENCE;
break;
}
*res = sym;
cnt++;
}
}
}
n = tbl->mSymNamesNext[n];
}
m++;
}
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;
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, 0, ~(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);
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->sym_class = sym_class;
*res = sym;
}
}
#endif
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;
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, 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, 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 section_symbol_comparator(const void * x, const void * y) {
ELF_SecSymbol * rx = (ELF_SecSymbol *)x;
ELF_SecSymbol * ry = (ELF_SecSymbol *)y;
if (rx->address < ry->address) return -1;
if (rx->address > ry->address) return +1;
return 0;
}
static void create_symbol_addr_search_index(DWARFCache * cache, ELF_Section * sec) {
int elf64 = cache->mFile->elf64;
int swap = cache->mFile->byte_swap;
int rel = cache->mFile->type == ET_REL;
unsigned m = 0;
sec->symbols_max = (unsigned)(sec->size / 16) + 16;
sec->symbols = (ELF_SecSymbol *)loc_alloc(sec->symbols_max * sizeof(ELF_SecSymbol));
while (m < cache->mSymSectionsCnt) {
SymbolSection * tbl = cache->mSymSections[m];
unsigned n = 1;
while (n < tbl->mSymCount) {
U8_T addr = 0;
if (elf64) {
Elf64_Sym s = ((Elf64_Sym *)tbl->mSymPool)[n];
if (swap) SWAP(s.st_shndx);
if (s.st_shndx == sec->index) {
switch (ELF64_ST_TYPE(s.st_info)) {
case STT_OBJECT:
case STT_FUNC:
if (swap) SWAP(s.st_value);
addr = s.st_value;
if (rel) addr += sec->addr;
break;
}
}
}
else {
Elf32_Sym s = ((Elf32_Sym *)tbl->mSymPool)[n];
if (swap) SWAP(s.st_shndx);
if (s.st_shndx == sec->index) {
switch (ELF32_ST_TYPE(s.st_info)) {
case STT_OBJECT:
case STT_FUNC:
if (swap) SWAP(s.st_value);
addr = s.st_value;
if (rel) addr += sec->addr;
break;
}
}
}
if (addr != 0) {
ELF_SecSymbol * s = NULL;
if (sec->symbols_cnt >= sec->symbols_max) {
sec->symbols_max = sec->symbols_max * 3 / 2;
sec->symbols = (ELF_SecSymbol *)loc_realloc(sec->symbols, sec->symbols_max * sizeof(ELF_SecSymbol));
}
s = sec->symbols + sec->symbols_cnt++;
s->address = addr;
s->parent = tbl;
s->index = n;
}
n++;
}
m++;
}
qsort(sec->symbols, sec->symbols_cnt, sizeof(ELF_SecSymbol), section_symbol_comparator);
}
static int find_by_addr_in_sym_table(DWARFCache * cache, ContextAddress addr, Symbol ** res) {
unsigned m;
unsigned cnt = 0;
Context * prs = context_get_group(sym_ctx, CONTEXT_GROUP_PROCESS);
ELF_File * file = cache->mFile;
for (m = 1; m < file->section_cnt; m++) {
ContextAddress sec_rt_addr;
ContextAddress sym_lt_addr;
ELF_Section * sec = file->sections + m;
if (sec->size == 0) continue;
if ((sec->flags & SHF_ALLOC) == 0) continue;
if (sec->type != SHT_PROGBITS && sec->type != SHT_NOBITS) continue;
sec_rt_addr = elf_map_to_run_time_address(prs, file, file->type == ET_REL ? sec : NULL, sec->addr);
if (addr >= sec_rt_addr && addr < sec_rt_addr + sec->size) {
unsigned l, h;
if (sec->symbols == NULL) create_symbol_addr_search_index(cache, sec);
sym_lt_addr = addr - sec_rt_addr + sec->addr;
l = 0;
h = sec->symbols_cnt;
while (l < h) {
unsigned k = (h + l) / 2;
ELF_SecSymbol * info = sec->symbols + k;
if (info->address > sym_lt_addr) {
h = k;
}
else {
ContextAddress next = k < sec->symbols_cnt - 1 ?
(info + 1)->address : sec->addr + sec->size;
assert(next >= info->address);
if (next <= sym_lt_addr) {
l = k + 1;
}
else {
SymbolInfo sym_info;
Symbol * sym = alloc_symbol();
SymbolSection * tbl = (SymbolSection *)info->parent;
unpack_elf_symbol_info(tbl, info->index, &sym_info);
sym->frame = STACK_NO_FRAME;
sym->ctx = prs;
sym->tbl = tbl;
sym->index = info->index;
switch (sym_info.mType) {
case STT_FUNC:
sym->sym_class = SYM_CLASS_FUNCTION;
break;
case STT_OBJECT:
sym->sym_class = SYM_CLASS_REFERENCE;
break;
}
*res = sym;
cnt++;
break;
}
}
}
}
}
return cnt == 1;
}
static int find_by_addr_in_unit(ObjectInfo * obj, int level, 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:
if (check_in_range(obj, addr)) {
object2symbol(obj, res);
return 1;
}
if (check_in_range(obj, sym_ip)) {
return find_by_addr_in_unit(obj->mChildren, level + 1, addr, res);
}
break;
case TAG_formal_parameter:
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) {
int error = 0;
int found = 0;
ELF_File * file = elf_list_first(sym_ctx, addr, addr);
if (file == NULL) error = errno;
while (error == 0 && file != NULL) {
Trap trap;
if (set_trap(&trap)) {
DWARFCache * cache = get_dwarf_cache(file);
found = find_by_addr_in_sym_table(cache, addr, 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) exception(error);
return found;
}
int find_symbol_by_addr(Context * ctx, int frame, ContextAddress addr, Symbol ** res) {
Trap trap;
int found = 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, NULL);
if (range != NULL) found = find_by_addr_in_unit(range->mUnit->mObject->mChildren, 0, 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, NULL);
if (range != NULL) found = find_by_addr_in_unit(range->mUnit->mObject->mChildren, 0, addr, res);
}
if (!found) exception(ERR_SYM_NOT_FOUND);
clear_trap(&trap);
return 0;
}
static void enumerate_local_vars(ObjectInfo * obj, int level,
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:
if (check_in_range(obj, sym_ip)) {
enumerate_local_vars(obj->mChildren, level + 1, call_back, args);
}
break;
case TAG_formal_parameter:
case TAG_local_variable:
case TAG_variable:
if (level > 0 && obj->mName != NULL) {
Symbol * sym = NULL;
object2symbol(obj, &sym);
call_back(args, sym);
}
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) {
UnitAddressRange * range = elf_find_unit(sym_ctx, sym_ip, sym_ip, NULL);
if (range != NULL) enumerate_local_vars(range->mUnit->mObject->mChildren, 0, 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->size, base);
}
else {
ELF_File * file = NULL;
uint64_t obj_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->mFile;
if (sym->obj != NULL) obj_index = sym->obj->mID;
if (sym->tbl != NULL) tbl_index = sym->tbl->mIndex + 1;
if (frame == STACK_TOP_FRAME) frame = get_top_frame(sym->ctx);
snprintf(id, sizeof(id), "@S%X.%lX.%lX.%"PRIX64".%"PRIX64".%X.%d.%X.%X.%"PRIX64".%s",
sym->sym_class,
file ? (unsigned long)file->dev : 0ul,
file ? (unsigned long)file->ino : 0ul,
file ? file->mtime : (int64_t)0,
obj_index, tbl_index,
frame, sym->index,
sym->dimension, (uint64_t)sym->size,
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;
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->size = (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++;
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->size = (ContextAddress)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 (tbl_index) {
if (tbl_index > cache->mSymSectionsCnt) exception(ERR_INV_CONTEXT);
sym->tbl = cache->mSymSections[tbl_index - 1];
}
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) {
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) {
int i;
Trap trap;
frame->fp = 0;
if (set_trap(&trap)) {
frame->fp = (ContextAddress)evaluate_stack_trace_commands(ctx, frame, info->fp);
clear_trap(&trap);
}
for (i = 0; i < info->reg_cnt; i++) {
if (set_trap(&trap)) {
uint64_t v = evaluate_stack_trace_commands(ctx, frame, info->regs[i]);
clear_trap(&trap);
if (write_reg_value(down, info->regs[i]->reg, v) < 0) {
error = errno;
break;
}
}
}
}
if (error) {
errno = error;
return -1;
}
return 0;
}
void ini_symbols_lib(void) {
}
/*************** Functions for retrieving symbol properties ***************************************/
static ELF_File * file;
static DWARFCache * cache;
static ObjectInfo * obj;
static SymbolSection * tbl;
static unsigned sym_index;
static unsigned dimension;
static SymbolInfo * sym_info;
static int unpack(const Symbol * sym) {
assert(sym->base == NULL);
assert(sym->size == 0);
assert(!is_cardinal_type_pseudo_symbol(sym));
if (get_sym_context(sym->ctx, sym->frame, 0) < 0) return -1;
file = NULL;
cache = NULL;
obj = sym->obj;
tbl = sym->tbl;
sym_index = sym->index;
dimension = sym->dimension;
sym_info = NULL;
if (obj != NULL) file = obj->mCompUnit->mFile;
if (tbl != NULL) file = tbl->mFile;
if (file != NULL) {
cache = (DWARFCache *)file->dwarf_dt_cache;
if (cache == NULL || cache->magic != DWARF_CACHE_MAGIC) {
errno = ERR_INV_CONTEXT;
return -1;
}
if (tbl != NULL) {
static SymbolInfo info;
unpack_elf_symbol_info(tbl, sym_index, &info);
sym_info = &info;
}
}
return 0;
}
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_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 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)) return x + 1 - y;
return x + 1;
}
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, ContextAddress 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)->size = 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) {
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;
assert(sym->magic == SYMBOL_MAGIC);
if (sym->base) {
if (sym->base->sym_class == SYM_CLASS_FUNCTION) *type_class = TYPE_CLASS_FUNCTION;
else if (sym->size > 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:
*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->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_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_info != NULL && sym_info->mType == 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) {
static SymbolInfo info;
unpack_elf_symbol_info(sym->tbl, sym->index, &info);
*name = info.mName;
}
else {
*name = NULL;
}
return 0;
}
int get_symbol_size(const Symbol * sym, ContextAddress * size) {
assert(sym->magic == SYMBOL_MAGIC);
if (sym->base) {
if (sym->size > 0) {
if (get_symbol_size(sym->base, size)) return -1;
*size *= sym->size;
}
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->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 (dimension == 0) ok = get_num_prop(obj, AT_byte_size, &sz);
if (!ok && sym->sym_class == SYM_CLASS_FUNCTION) {
U8_T l, h;
ok = get_num_prop(obj, AT_low_pc, &l) && get_num_prop(obj, AT_high_pc, &h);
if (ok) sz = h - l;
}
else {
Symbol * s = NULL;
ObjectInfo * ref = NULL;
if (!ok && sym->sym_class == SYM_CLASS_REFERENCE && obj->mType != NULL) {
ref = obj;
obj = obj->mType;
if (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 (dimension == 0) ok = get_num_prop(obj, AT_byte_size, &sz);
}
if (!ok && obj->mTag == TAG_array_type) {
U8_T length = 1;
int i = dimension;
ObjectInfo * idx = obj->mChildren;
while (i > 0 && idx != NULL) {
idx = idx->mSibling;
i--;
}
if (idx == NULL) exception(ERR_INV_CONTEXT);
while (idx != NULL) {
length *= get_object_length(idx);
idx = idx->mSibling;
}
if (obj->mType == NULL) exception(ERR_INV_CONTEXT);
obj = obj->mType;
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;
ok = get_num_prop(obj, AT_byte_size, &sz);
}
if (ok) sz *= length;
}
if (!ok && obj->mTag == TAG_pointer_type) {
sz = obj->mCompUnit->mDesc.mAddressSize;
ok = sz > 0;
}
if (!ok && ref && map_to_sym_table(ref, &s) && get_symbol_size(s, size) == 0) ok = 1;
}
if (!ok) str_exception(ERR_INV_DWARF, "Object has no size attribute");
*size = (ContextAddress)sz;
clear_trap(&trap);
}
else if (sym_info != NULL) {
*size = (ContextAddress)sym_info->mSize;
}
return 0;
}
int get_symbol_base_type(const Symbol * sym, Symbol ** base_type) {
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 = 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->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) {
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 = 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) {
assert(sym->magic == SYMBOL_MAGIC);
if (sym->base) {
if (sym->base->sym_class == SYM_CLASS_FUNCTION) {
errno = ERR_INV_CONTEXT;
return -1;
}
*length = sym->size == 0 ? 1 : sym->size;
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 = 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) {
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 = 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 = 0;
return 0;
}
}
errno = ERR_UNSUPPORTED;
return -1;
}
int get_symbol_children(const Symbol * sym, Symbol *** children, int * count) {
int n = 0;
static Symbol ** buf = NULL;
static int buf_len = 0;
assert(sym->magic == SYMBOL_MAGIC);
if (sym->base) {
if (sym->base->sym_class == SYM_CLASS_FUNCTION && sym->base->obj == NULL) {
*children = NULL;
*count = 0;
errno = ERR_SYM_NOT_FOUND;
return -1;
}
if (sym->base->sym_class == SYM_CLASS_FUNCTION) {
ObjectInfo * i = sym->base->obj->mChildren;
if (unpack(sym->base) < 0) return -1;
while (i != NULL) {
if (i->mTag == TAG_formal_parameter) n++;
i = i->mSibling;
}
if (buf_len < n) {
buf = (Symbol **)loc_realloc(buf, sizeof(Symbol *) * n);
buf_len = n;
}
n = 0;
i = obj->mChildren;
while (i != NULL) {
if (i->mTag == TAG_formal_parameter) {
Symbol * x = NULL;
Symbol * y = NULL;
object2symbol(i, &x);
if (get_symbol_type(x, &y) <0) return -1;
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) {
ObjectInfo * i = obj->mChildren;
while (i != NULL) {
i = i->mSibling;
n++;
}
if (buf_len < n) {
buf = (Symbol **)loc_realloc(buf, sizeof(Symbol *) * n);
buf_len = n;
}
n = 0;
i = obj->mChildren;
while (i != NULL) {
Symbol * x = NULL;
object2symbol(i, &x);
buf[n++] = x;
i = i->mSibling;
}
}
*children = buf;
*count = n;
return 0;
}
int get_symbol_offset(const Symbol * sym, ContextAddress * offset) {
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) {
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) {
Trap trap;
PropertyValue v;
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 {
static U1_T bf[sizeof(v.mValue)];
U8_T n = v.mValue;
size_t i = 0;
if (v.mRegister != NULL) exception(ERR_INV_CONTEXT);
for (i = 0; i < sizeof(bf); i++) {
bf[v.mBigEndian ? sizeof(bf) - i - 1 : i] = n & 0xffu;
n = n >> 8;
}
*size = sizeof(bf);
*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.mRegister == NULL) {
exception(ERR_INV_CONTEXT);
}
else {
static U1_T bf[32];
StackFrame * frame = NULL;
RegisterDefinition * def = v.mRegister;
if (v.mSize > sizeof(bf)) exception(ERR_BUFFER_OVERFLOW);
if (get_frame_info(v.mContext, v.mFrame, &frame) < 0) exception(errno);
if (read_reg_bytes(frame, def, 0, def->size, bf) < 0) exception(errno);
*size = v.mSize;
*value = bf;
*big_endian = v.mBigEndian;
}
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;
}
errno = ERR_INV_CONTEXT;
return -1;
}
int get_symbol_address(const Symbol * sym, ContextAddress * address) {
assert(sym->magic == SYMBOL_MAGIC);
if (sym->base || is_cardinal_type_pseudo_symbol(sym)) {
errno = ERR_INV_CONTEXT;
return -1;
}
if (sym->address != 0) {
*address = sym->address;
return 0;
}
if (unpack(sym) < 0) return -1;
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);
}
if (sym_info != NULL) {
if (syminfo2address(sym_ctx, sym_info, address) == 0) return 0;
}
errno = ERR_INV_CONTEXT;
return -1;
}
int get_symbol_register(const Symbol * sym, Context ** ctx, int * frame, RegisterDefinition ** reg) {
assert(sym->magic == SYMBOL_MAGIC);
if (sym->base || is_cardinal_type_pseudo_symbol(sym) || sym->address != 0) {
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;
PropertyValue v;
if (set_trap(&trap)) {
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_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)->size = length;
return 0;
}
#endif /* SERVICE_Symbols && ENABLE_ELF */