| author | Benoit Perrin | 2012-09-27 11:13:10 (EDT) |
|---|---|---|
| committer | Eugene Tarassov | 2012-10-02 11:36:19 (EDT) |
| commit | 9a8b647992de129297eb2e3c41d3726889f167a2 (patch) (side-by-side diff) | |
| tree | 31b05a51dba8e36200e46a8decaa00be122a820d | |
| parent | ccfe5f44972503042d9498dd6f572bdb59cabbff (diff) | |
| download | org.eclipse.tcf.agent-9a8b647992de129297eb2e3c41d3726889f167a2.zip org.eclipse.tcf.agent-9a8b647992de129297eb2e3c41d3726889f167a2.tar.gz org.eclipse.tcf.agent-9a8b647992de129297eb2e3c41d3726889f167a2.tar.bz2 | |
Add support of the enumeration of ELF symbols.
| -rw-r--r-- | agent/tcf/services/symbols_elf.c | 197 | ||||
| -rw-r--r-- | agent/tcf/services/symbols_elf.h | 54 |
2 files changed, 224 insertions, 27 deletions
diff --git a/agent/tcf/services/symbols_elf.c b/agent/tcf/services/symbols_elf.c index 7816f2c..2612e4f 100644 --- a/agent/tcf/services/symbols_elf.c +++ b/agent/tcf/services/symbols_elf.c @@ -46,6 +46,7 @@ #include <tcf/services/stacktrace.h> #include <tcf/services/funccall.h> #include <tcf/services/symbols.h> +#include <tcf/services/symbols_elf.h> #include <tcf/services/vm.h> #if ENABLE_RCBP_TEST # include <tcf/main/test.h> @@ -219,6 +220,37 @@ static int syminfo2address(Context * ctx, ELF_SymbolInfo * info, ContextAddress return -1; } +static int syminfo2symbol (ELF_SymbolInfo * sym_info, Symbol ** symbol) { + Symbol * sym = alloc_symbol(); + + sym->frame = STACK_NO_FRAME; + sym->ctx = context_get_group(sym_ctx, CONTEXT_GROUP_SYMBOLS); + sym->tbl = sym_info->sym_section; + sym->index = sym_info->sym_index; + + switch (sym_info->type) { + case STT_NOTYPE: + /* Check if the NOTYPE symbol is for a section allocated in memory */ + if (sym_info->section == NULL || (sym_info->section->flags & SHF_ALLOC) == 0) { + sym->sym_class = SYM_CLASS_VALUE; + break; + } + /* fall through */ + case STT_FUNC: + case STT_GNU_IFUNC: + 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; + } + *symbol = sym; + return 0; +} + /* Return 1 if evaluation of symbol properties requires a stack frame. * Return 0 otherwise. * In case of a doubt, should return 1. */ @@ -629,6 +661,12 @@ static void add_obj_to_find_symbol_buf(ObjectInfo * obj, unsigned level) { sym->level = level; } +static void add_elf_to_find_symbol_buf(ELF_SymbolInfo * elf_sym) { + Symbol * sym = NULL; + syminfo2symbol(elf_sym, &sym); + add_to_find_symbol_buf(sym); +} + static void sort_find_symbol_buf(void) { /* Sort find_symbol_list: * 1. inner scope before parent scope @@ -927,33 +965,8 @@ static void find_by_name_in_sym_table(ELF_File * file, const char * name, int gl } } } - { - Symbol * sym = alloc_symbol(); - sym->frame = STACK_NO_FRAME; - sym->ctx = prs; - sym->tbl = tbl; - sym->index = n; - switch (sym_info.type) { - case STT_NOTYPE: - /* Check if the NOTYPE symbol is for a section allocated in memory */ - if (sym_info.section == NULL || (sym_info.section->flags & SHF_ALLOC) == 0) { - sym->sym_class = SYM_CLASS_VALUE; - break; - } - /* fall through */ - case STT_FUNC: - case STT_GNU_IFUNC: - 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; - } - add_to_find_symbol_buf(sym); - } + + add_elf_to_find_symbol_buf(&sym_info); } n = tbl->sym_names_next[n]; } @@ -3241,4 +3254,134 @@ int get_funccall_info(const Symbol * func, return -1; } +/* -------------------------------------------------------------------------- */ + +struct EnumerateSymbols { + int64_t mtime; + ino_t ino; + dev_t dev; + uint32_t batch_idx; + uint32_t sec_idx; + char file_name[FILE_PATH_SIZE]; + char ctxId[256]; +}; + +static int enumerate_symbol_table (ELF_Section * sec, EnumerateSymbols * enum_syms, EnumerateBatchSymbolsCallBack * call_back, void * args) { + uint32_t sym_idx; + int cont = 1; + int has_more = 0; + + for (sym_idx = enum_syms->batch_idx; cont == 1 && sym_idx < sec->sym_count; sym_idx++) { + ELF_SymbolInfo sym_info; + Symbol * sym; + + unpack_elf_symbol_info(sec, sym_idx, &sym_info); + + if (syminfo2symbol (&sym_info, &sym) < 0) exception (errno); + + cont = call_back (args, sym); + } + enum_syms->batch_idx = sym_idx; + if (sym_idx < sec->sym_count && cont != -1) has_more = 1; + return has_more; +} + +int elf_enumerate_symbols (Context * ctx, const char * file_name, EnumerateSymbols ** enum_syms, EnumerateBatchSymbolsCallBack * call_back, void * args) { + Trap trap; + ELF_File * file; + unsigned sec_idx; + int has_more = 0; + + if (!set_trap(&trap)) { + loc_free (*enum_syms); + *enum_syms = NULL; + return -1; + } + + if (ctx == NULL && file_name == NULL) { + assert (*enum_syms != NULL); + + file = elf_open ((*enum_syms)->file_name); + if (file == NULL) exception (errno); + + /* + * Check that the file is identical to the initial file and the context + * still exists. + */ + + if (file->ino != (*enum_syms)->ino || file->dev != (*enum_syms)->dev || file->mtime != (*enum_syms)->mtime) { + str_exception(ERR_OTHER, "The elf symbol file has changed"); + } + else { + ctx = id2ctx((*enum_syms)->ctxId); + if (ctx == NULL) exception (ERR_INV_CONTEXT); + else if (ctx->exited) exception (ERR_ALREADY_EXITED); + } + sec_idx = (*enum_syms)->sec_idx; + } + else { + unsigned symtab_idx = 0; + unsigned dynsym_idx = 0; + unsigned ix; + + assert (file_name != NULL && enum_syms != NULL && *enum_syms == NULL); + + file = elf_open (file_name); + if (file == NULL) exception (errno); + + if (file->sections == NULL) str_exception(ERR_OTHER, "The file does not have sections"); + + /* Look for the symbol table sections */ + + for (ix = 0; ix < file->section_cnt && symtab_idx == 0 && dynsym_idx == 0; ix++) { + ELF_Section * sec = file->sections + ix; + if (sec->type == SHT_SYMTAB) symtab_idx = ix; + else if (sec->type == SHT_DYNSYM) dynsym_idx = ix; + } + + if (symtab_idx == 0 && dynsym_idx == 0) str_exception(ERR_OTHER, "The file does not have a symbol table"); + + /* Set priority to the symbol table */ + + if (symtab_idx != 0) sec_idx = symtab_idx; + else sec_idx = dynsym_idx; + + *enum_syms = loc_alloc_zero (sizeof (EnumerateSymbols)); + strlcpy ((*enum_syms)->file_name, file_name, sizeof ((*enum_syms)->file_name)); + if (strlen (file_name) != strlen ((*enum_syms)->file_name)) str_exception (ERR_OTHER, "File pathname too long"); + + strlcpy ((*enum_syms)->ctxId, ctx->id, sizeof ((*enum_syms)->ctxId)); + (*enum_syms)->dev = file->dev; + (*enum_syms)->ino = file->ino; + (*enum_syms)->mtime = file->mtime; + (*enum_syms)->sec_idx = sec_idx; + } + + if (get_sym_context(ctx, STACK_NO_FRAME, 0) < 0) exception(errno); + + has_more = enumerate_symbol_table(file->sections + sec_idx, *enum_syms, call_back, args); + + clear_trap(&trap); + + if (has_more == 0) { + loc_free (*enum_syms); + *enum_syms = NULL; + } + + return has_more; +} + +int elf_symbol_info (Symbol * sym, ELF_SymbolInfo * elf_sym) { + Trap trap; + + assert (sym != NULL && sym->magic == SYMBOL_MAGIC && sym->tbl != NULL); + + if (!set_trap(&trap)) return -1; + + unpack_elf_symbol_info(sym->tbl, sym->index, elf_sym); + + clear_trap(&trap); + return 0; +} + #endif /* SERVICE_Symbols && ENABLE_ELF */ diff --git a/agent/tcf/services/symbols_elf.h b/agent/tcf/services/symbols_elf.h new file mode 100644 index 0000000..96843e6 --- a/dev/null +++ b/agent/tcf/services/symbols_elf.h @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2012 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 + *******************************************************************************/ + +/* + * This module implements specific ELF symbol's API + */ +#ifndef D_symbols_elf +#define D_symbols_elf + +#include <tcf/config.h> + +#if SERVICE_Symbols && !ENABLE_SymbolsProxy && ENABLE_ELF + +#include <tcf/framework/context.h> +#include <tcf/services/symbols.h> +#include <tcf/services/tcf_elf.h> + +typedef struct EnumerateSymbols EnumerateSymbols; +typedef int EnumerateBatchSymbolsCallBack(void *, Symbol *); + +/* + * Enumerate ELF symbols of a specific file for a given context. + * The API supports enumeration by batchs of symbols. If the callback returns + * 0, the function returns, ending a batch. Subsequent calls with a NULL + * context and file_name is used to enumerate the next batch of symbols. If + * the callback return -1, the enumeration ends. + * On error returns -1 and sets errno. + * On success returns 0 if there isn't more symbols, or a positive value if + * there are other symbols to retrieve. + */ +extern int elf_enumerate_symbols (Context * ctx, const char * file_name, EnumerateSymbols ** enum_syms, EnumerateBatchSymbolsCallBack * call_back, void * args); + +/* + * Get the ELF symbol info from a TCF symbol. + * On error returns -1 and sets errno. + * On success returns 0. + */ +extern int elf_symbol_info (Symbol * sym, ELF_SymbolInfo * elf_sym); + +#endif /* SERVICE_Symbols && !ENABLE_SymbolsProxy && ENABLE_ELF */ + +#endif /* D_symbols_elf */ |

