diff options
author | Eugene Tarassov | 2019-11-21 17:23:57 +0000 |
---|---|---|
committer | Eugene Tarassov | 2019-11-21 17:23:57 +0000 |
commit | 78b751acc5ebdf1d65b2416a8c08b684f1419c84 (patch) | |
tree | eaf22969a23a5faae33fe87d129f06c783effdfc /agent | |
parent | d427a075fa66cbf8d8f70072cd1ab5a1a319e3d8 (diff) | |
download | org.eclipse.tcf.agent-78b751acc5ebdf1d65b2416a8c08b684f1419c84.tar.gz org.eclipse.tcf.agent-78b751acc5ebdf1d65b2416a8c08b684f1419c84.tar.xz org.eclipse.tcf.agent-78b751acc5ebdf1d65b2416a8c08b684f1419c84.zip |
TCF Agent: Expressions service: added built-in function $relocate
The function maps link-time address in a file to run-time address in memory.
Can be used to plant breakpoints on link-time addresses.
Diffstat (limited to 'agent')
-rw-r--r-- | agent/tcf/services/expressions.c | 99 | ||||
-rw-r--r-- | agent/tcf/services/symbols_elf.c | 95 |
2 files changed, 167 insertions, 27 deletions
diff --git a/agent/tcf/services/expressions.c b/agent/tcf/services/expressions.c index 81de0026..67968556 100644 --- a/agent/tcf/services/expressions.c +++ b/agent/tcf/services/expressions.c @@ -1171,6 +1171,79 @@ static unsigned flag_count(SYM_FLAGS flags) { } #endif /* ENABLE_Symbols */ +static void expression(int mode, Value * v); +static uint64_t to_uns(int mode, Value * v); +static void load_value(Value * v); + +static int builtin_identifier(int mode, char * name, Value * v) { + Context * ctx = expression_context; + for (;;) { + RegisterDefinition * def = get_reg_definitions(ctx); + if (def != NULL) { + while (def->name != NULL) { + if (strcmp(name + 1, def->name) == 0) { + int frame = STACK_NO_FRAME; + if (ctx == expression_context) frame = expression_frame; + reg2value(mode, ctx, frame, def, v); + return SYM_CLASS_REFERENCE; + } + def++; + } + } + ctx = ctx->parent; + if (ctx == NULL) break; + } + if (strcmp(name, "$thread") == 0) { + set_string_value(v, expression_context->id); + v->constant = 1; + return SYM_CLASS_VALUE; + } + if (strcmp(name, "$relocate") == 0 && text_sy == '(') { + unsigned cnt; + uint64_t addr = 0; + const char * file_name = ""; + const char * sect_name = ""; + Symbol * sym = NULL; + next_sy(); + for (cnt = 0;; cnt++) { + switch (cnt) { + case 0: + expression(mode, v); + addr = to_uns(mode, v); + break; + case 1: + expression(mode, v); + load_value(v); + file_name = tmp_strndup((char *)v->value, v->size); + break; + case 2: + expression(mode, v); + load_value(v); + sect_name = tmp_strndup((char *)v->value, v->size); + break; + default: + error(ERR_INV_EXPRESSION, "Too many arguments"); + } + if (text_sy != ',') break; + next_sy(); + } + if (text_sy != ')') error(ERR_INV_EXPRESSION, "Missing ')'"); + next_sy(); + ini_value(v); + if (mode != MODE_NORMAL) { + set_ctx_word_value(v, addr); + v->type_class = TYPE_CLASS_POINTER; + return SYM_CLASS_VALUE; + } + if (find_symbol_by_name(expression_context, STACK_NO_FRAME, 0, + tmp_printf("$relocate:%s:%s:%" PRIX64, file_name, sect_name, addr), &sym) < 0) { + error(errno, "Cannot read symbol data"); + } + return sym2value(mode, sym, v); + } + return -1; +} + static int identifier(int mode, Value * scope, char * name, SYM_FLAGS flags, Value * v) { ini_value(v); if (scope == NULL) { @@ -1182,28 +1255,8 @@ static int identifier(int mode, Value * scope, char * name, SYM_FLAGS flags, Val exception(ERR_INV_CONTEXT); } if (name[0] == '$') { - Context * ctx = expression_context; - for (;;) { - RegisterDefinition * def = get_reg_definitions(ctx); - if (def != NULL) { - while (def->name != NULL) { - if (strcmp(name + 1, def->name) == 0) { - int frame = STACK_NO_FRAME; - if (ctx == expression_context) frame = expression_frame; - reg2value(mode, ctx, frame, def, v); - return SYM_CLASS_REFERENCE; - } - def++; - } - } - ctx = ctx->parent; - if (ctx == NULL) break; - } - } - if (strcmp(name, "$thread") == 0) { - set_string_value(v, expression_context->id); - v->constant = 1; - return SYM_CLASS_VALUE; + int id_class = builtin_identifier(mode, name, v); + if (id_class >= 0) return id_class; } } #if ENABLE_Symbols @@ -2029,8 +2082,6 @@ static void set_complex_type(Value * v) { #endif } -static void expression(int mode, Value * v); - static void primary_expression(int mode, Value * v) { if (text_sy == '(') { next_sy(); diff --git a/agent/tcf/services/symbols_elf.c b/agent/tcf/services/symbols_elf.c index 4f241c4d..5c42db43 100644 --- a/agent/tcf/services/symbols_elf.c +++ b/agent/tcf/services/symbols_elf.c @@ -87,6 +87,7 @@ struct Symbol { #define is_array_type_pseudo_symbol(s) (s->sym_class == SYM_CLASS_TYPE && s->obj == NULL && s->base != NULL) #define is_std_type_pseudo_symbol(s) (s->sym_class == SYM_CLASS_TYPE && s->obj == NULL && s->base == NULL) #define is_constant_pseudo_symbol(s) (s->sym_class == SYM_CLASS_VALUE && s->obj == NULL && s->base != NULL) +#define is_pointer_pseudo_symbol(s) (s->sym_class == SYM_CLASS_VALUE && s->obj == NULL && s->base == NULL && s->has_address) static Context * sym_ctx; static int sym_frame; @@ -1548,6 +1549,66 @@ static void find_by_name_in_sym_table(ELF_File * file, const char * name, int gl } } +static void find_relocate(ELF_File * file, const char * name) { + /* Psedo-symbol, which helps debugger to map link-time address to run-time address */ + size_t l = strlen(file->name); + size_t i = 0; + int ok = 0; + if (strncmp(file->name, name, l) == 0 && name[l] == ':') { + i = l + 1; + ok = 1; + } + if (!ok) { + size_t p = l; + while (p > 0 && file->name[p - 1] != '/' && file->name[p - 1] != '\\') p--; + if (strncmp(file->name + p, name, l - p) == 0 && name[l - p] == ':') { + i = l - p + 1; + ok = 1; + } + } + if (ok) { + size_t j = i; + char * section_name = NULL; + while (name[j] != 0 && name[j] != ':') j++; + if (j > i) section_name = tmp_strndup(name + i, j - i); + if (name[j++] == ':') { + ELF_Section * section = NULL; + ContextAddress addr = 0; + for (;;) { + char ch = name[j++]; + if (ch >= '0' && ch <= '9') addr = (addr << 4) | (ch - '0'); + else if (ch >= 'A' && ch <= 'F') addr = (addr << 4) | (ch - 'A' + 10); + else if (ch >= 'a' && ch <= 'f') addr = (addr << 4) | (ch - 'a' + 10); + else break; + } + if (section_name != NULL) { + unsigned n; + for (n = 1; n < file->section_cnt; n++) { + ELF_Section * s = file->sections + n; + if (s->name == NULL) continue; + if (strcmp(s->name, section_name) == 0) { + section = s; + break; + } + } + if (section == NULL) return; + } + addr = elf_map_to_run_time_address(sym_ctx, file, section, addr); + if (errno == 0) { + Symbol * sym = alloc_symbol(); + sym->ctx = context_get_group(sym_ctx, CONTEXT_GROUP_SYMBOLS); + sym->frame = STACK_NO_FRAME; + sym->sym_class = SYM_CLASS_VALUE; + sym->address = addr; + sym->size = file->elf64 ? 8 : 4; + sym->has_address = 1; + assert(is_pointer_pseudo_symbol(sym)); + add_to_find_symbol_buf(sym); + } + } + } +} + int find_symbol_by_name(Context * ctx, int frame, ContextAddress ip, const char * name, Symbol ** res) { int error = 0; ELF_File * curr_file = NULL; @@ -1691,8 +1752,13 @@ int find_symbol_by_name(Context * ctx, int frame, ContextAddress ip, const char Trap trap; if (set_trap(&trap)) { DWARFCache * cache = get_dwarf_cache(get_dwarf_file(file)); - find_by_name_in_pub_names(cache, name); - find_by_name_in_sym_table(file, name, 0); + if (strncmp(name, "$relocate:", 10) == 0) { + find_relocate(file, name + 10); + } + else { + find_by_name_in_pub_names(cache, name); + find_by_name_in_sym_table(file, name, 0); + } clear_trap(&trap); } else { @@ -3193,6 +3259,10 @@ int get_symbol_type_class(const Symbol * sym, int * type_class) { *type_class = sym->dimension; return 0; } + if (is_pointer_pseudo_symbol(sym)) { + *type_class = TYPE_CLASS_POINTER; + return 0; + } if (unpack(sym) < 0) return -1; *type_class = TYPE_CLASS_UNKNOWN; get_object_type_class(sym->obj, type_class); @@ -3315,6 +3385,10 @@ int get_symbol_size(const Symbol * sym, ContextAddress * size) { *size = sym->cardinal; return 0; } + if (is_pointer_pseudo_symbol(sym)) { + *size = sym->size; + return 0; + } if (unpack(sym) < 0) return -1; *size = 0; if (obj != NULL) { @@ -3922,7 +3996,7 @@ int get_location_info(const Symbol * sym, LocationInfo ** res) { assert(sym->magic == SYMBOL_MAGIC); - if (sym->has_address) { + if (sym->has_address && sym->sym_class != SYM_CLASS_VALUE) { info->big_endian = big_endian_host(); add_location_command(info, SFT_CMD_NUMBER)->args.num = sym->address; return 0; @@ -3950,6 +4024,21 @@ int get_location_info(const Symbol * sym, LocationInfo ** res) { return err_wrong_obj(); } + if (is_pointer_pseudo_symbol(sym)) { + void const * value = NULL; + LocationExpressionCommand * cmd = add_location_command(info, SFT_CMD_PIECE); + + info->big_endian = big_endian_host(); + cmd->args.piece.bit_size = (unsigned)(sym->size * 8); + cmd->args.piece.value = tmp_alloc((size_t)sym->size); + value = &sym->address; + if (big_endian_host() && sym->size < sizeof(ContextAddress)) { + value = (uint8_t *)value + (sizeof(ContextAddress) - sym->size); + } + memcpy(cmd->args.piece.value, value, (size_t)sym->size); + return 0; + } + if (unpack(sym) < 0) return -1; if (obj != NULL) { |