diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/breakpoints.c | 1 | ||||
-rw-r--r-- | services/dwarfcache.c | 3 | ||||
-rw-r--r-- | services/dwarfexpr.c | 56 | ||||
-rw-r--r-- | services/dwarfframe.c | 159 | ||||
-rw-r--r-- | services/dwarfframe.h | 25 | ||||
-rw-r--r-- | services/linenumbers_proxy.c | 1 | ||||
-rw-r--r-- | services/stacktrace.c | 224 | ||||
-rw-r--r-- | services/stacktrace.h | 8 | ||||
-rw-r--r-- | services/symbols.c | 96 | ||||
-rw-r--r-- | services/symbols.h | 21 | ||||
-rw-r--r-- | services/symbols_elf.c | 66 | ||||
-rw-r--r-- | services/symbols_proxy.c | 155 | ||||
-rw-r--r-- | services/symbols_win32.c | 5 |
13 files changed, 596 insertions, 224 deletions
diff --git a/services/breakpoints.c b/services/breakpoints.c index 6888320d..23f0ed85 100644 --- a/services/breakpoints.c +++ b/services/breakpoints.c @@ -760,6 +760,7 @@ static void done_conditions_evaluation(int * need_to_flush) { } static void done_evaluation(void) { + assert(cache_enter_cnt > 0); cache_enter_cnt--; if (cache_enter_cnt == 0) { int need_to_flush = 0; diff --git a/services/dwarfcache.c b/services/dwarfcache.c index a568ade5..4fbed9be 100644 --- a/services/dwarfcache.c +++ b/services/dwarfcache.c @@ -99,6 +99,7 @@ static ObjectInfo * find_object_info(U8_T ID) { ObjectInfo * Info = find_object(sCache, ID); if (Info == NULL) { U4_T Hash = (U4_T)ID % OBJ_HASH_SIZE; + assert(ID >= sDebugSection->addr + dio_gEntryPos); Info = (ObjectInfo *)loc_alloc_zero(sizeof(ObjectInfo)); Info->mHashNext = sCache->mObjectHash[Hash]; sCache->mObjectHash[Hash] = Info; @@ -234,10 +235,10 @@ static void read_object_attributes(U2_T Tag, U2_T Attr, U2_T Form) { case 0: if (Form) { Info = find_object_info(sDebugSection->addr + dio_gEntryPos); + assert(Info->mTag == 0); Info->mTag = Tag; Info->mCompUnit = sCompUnit; Info->mParent = sParentObject; - /* TODO: Default AT_lower_bound value is language dependand */ Sibling = 0; } else { diff --git a/services/dwarfexpr.c b/services/dwarfexpr.c index 9fa5e8ca..a75015d2 100644 --- a/services/dwarfexpr.c +++ b/services/dwarfexpr.c @@ -62,6 +62,18 @@ static int register_access_func(PropertyValue * Value, int write, U8_T * Data) { return read_reg_value(def, frame, Data); } +static U8_T read_memory(PropertyValue * Value, U8_T Addr, size_t Size) { + size_t i; + U8_T n = 0; + U1_T buf[8]; + + if (context_read_mem(Value->mContext, Addr, buf, Size) < 0) exception(errno); + for (i = 0; i < Size; i++) { + n = (n << 8) | buf[Value->mBigEndian ? i : Size - i - 1]; + } + return n; +} + static void evaluate_expression(U8_T BaseAddress, PropertyValue * Value, ELF_Section * Section, U1_T * Buf, size_t Size) { U8_T StartPos = Buf - (U1_T *)Section->data; CompUnit * Unit = Value->mObject->mCompUnit; @@ -89,35 +101,17 @@ static void evaluate_expression(U8_T BaseAddress, PropertyValue * Value, ELF_Sec case OP_deref: check_e_stack(1); { - U1_T Tmp[8]; U8_T Addr = sExprStack[sExprStackLen - 1]; size_t Size = Unit->mDesc.mAddressSize; - if (context_read_mem(Value->mContext, (ContextAddress)Addr, Tmp, Size) < 0) exception(errno); - switch (Size) { - case 1: Data = *Tmp; break; - case 2: Data = *(U2_T *)Tmp; break; - case 4: Data = *(U4_T *)Tmp; break; - case 8: Data = *(U8_T *)Tmp; break; - default: assert(0); - } - sExprStack[sExprStackLen - 1] = Data; + sExprStack[sExprStackLen - 1] = read_memory(Value, Addr, Size); } break; case OP_deref_size: check_e_stack(1); { - U1_T Tmp[8]; U8_T Addr = sExprStack[sExprStackLen - 1]; U1_T Size = dio_ReadU1(); - if (context_read_mem(Value->mContext, (ContextAddress)Addr, Tmp, Size) < 0) exception(errno); - switch (Size) { - case 1: Data = *Tmp; break; - case 2: Data = *(U2_T *)Tmp; break; - case 4: Data = *(U4_T *)Tmp; break; - case 8: Data = *(U8_T *)Tmp; break; - default: assert(0); - } - sExprStack[sExprStackLen - 1] = Data; + sExprStack[sExprStackLen - 1] = read_memory(Value, Addr, Size); } break; case OP_const1u: @@ -188,36 +182,18 @@ static void evaluate_expression(U8_T BaseAddress, PropertyValue * Value, ELF_Sec case OP_xderef: check_e_stack(2); { - U1_T Tmp[8]; U8_T Addr = sExprStack[sExprStackLen - 1]; size_t Size = Unit->mDesc.mAddressSize; - if (context_read_mem(Value->mContext, (ContextAddress)Addr, Tmp, Size) < 0) exception(errno); - switch (Size) { - case 1: Data = *Tmp; break; - case 2: Data = *(U2_T *)Tmp; break; - case 4: Data = *(U4_T *)Tmp; break; - case 8: Data = *(U8_T *)Tmp; break; - default: assert(0); - } - sExprStack[sExprStackLen - 2] = Data; + sExprStack[sExprStackLen - 2] = read_memory(Value, Addr, Size); sExprStackLen--; } break; case OP_xderef_size: check_e_stack(2); { - U1_T Tmp[8]; U8_T Addr = sExprStack[sExprStackLen - 1]; U1_T Size = dio_ReadU1(); - if (context_read_mem(Value->mContext, (ContextAddress)Addr, Tmp, Size) < 0) exception(errno); - switch (Size) { - case 1: Data = *Tmp; break; - case 2: Data = *(U2_T *)Tmp; break; - case 4: Data = *(U4_T *)Tmp; break; - case 8: Data = *(U8_T *)Tmp; break; - default: assert(0); - } - sExprStack[sExprStackLen - 2] = Data; + sExprStack[sExprStackLen - 2] = read_memory(Value, Addr, Size); sExprStackLen--; } break; diff --git a/services/dwarfframe.c b/services/dwarfframe.c index 2c7b849f..9d73a01b 100644 --- a/services/dwarfframe.c +++ b/services/dwarfframe.c @@ -100,6 +100,19 @@ static int regs_stack_pos = 0; static StackFrameRules rules; +U8_T dwarf_stack_trace_addr = 0; +U8_T dwarf_stack_trace_size = 0; + +StackTracingCommandSequence * dwarf_stack_trace_fp = NULL; + +int dwarf_stack_trace_regs_cnt = 0; +StackTracingCommandSequence ** dwarf_stack_trace_regs = NULL; + +static int trace_regs_max = 0; +static int trace_cmds_max = 0; +static int trace_cmds_cnt = 0; +static StackTracingCommand * trace_cmds = NULL; + static RegisterRules * get_reg(StackFrameRegisters * regs, int reg) { RegisterDefinition * reg_def; while (reg >= regs->regs_max) { @@ -347,83 +360,102 @@ static void exec_stack_frame_instruction(void) { } } -static void fill_frame_register(RegisterRules * reg, RegisterDefinition * reg_def, StackFrame * frame, StackFrame * down) { +static StackTracingCommand * add_command(int op) { + StackTracingCommand * cmd = NULL; + if (trace_cmds_cnt >= trace_cmds_max) { + trace_cmds_max += 16; + trace_cmds = (StackTracingCommand *)loc_realloc(trace_cmds, trace_cmds_max * sizeof(StackTracingCommand)); + } + cmd = trace_cmds + trace_cmds_cnt++; + memset(cmd, 0, sizeof(*cmd)); + cmd->cmd = op; + return cmd; +} + +static void add_command_sequence(StackTracingCommandSequence ** ptr, RegisterDefinition * reg) { + StackTracingCommandSequence * seq = *ptr; + if (seq == NULL || seq->cmds_max < trace_cmds_cnt) { + *ptr = seq = (StackTracingCommandSequence *)loc_realloc(seq, sizeof(StackTracingCommandSequence) + (trace_cmds_cnt - 1) * sizeof(StackTracingCommand)); + seq->cmds_max = trace_cmds_cnt; + } + seq->reg = reg; + seq->cmds_cnt = trace_cmds_cnt; + memcpy(seq->cmds, trace_cmds, trace_cmds_cnt * sizeof(StackTracingCommand)); +} + +static void generate_register_commands(RegisterRules * reg, RegisterDefinition * reg_def) { + if (reg_def == NULL) return; + trace_cmds_cnt = 0; switch (reg->rule) { + case RULE_VAL_OFFSET: case RULE_OFFSET: - if (frame->fp != 0 && reg_def != NULL) { - size_t size = reg_def->size; - if (size <= 8) { - U1_T v[8]; - if (context_read_mem(rules.ctx, frame->fp + reg->offset, v, size) < 0) exception(errno); - switch (size) { - case 1: write_reg_value(reg_def, down, *(U1_T *)v); break; - case 2: write_reg_value(reg_def, down, *(U2_T *)v); break; - case 4: write_reg_value(reg_def, down, *(U4_T *)v); break; - case 8: write_reg_value(reg_def, down, *(U8_T *)v); break; - } - } + add_command(SFT_CMD_FP); + if (reg->offset != 0) { + add_command(SFT_CMD_NUMBER)->num = reg->offset; + add_command(SFT_CMD_ADD); + } + if (reg->rule == RULE_OFFSET) { + StackTracingCommand * cmd = add_command(SFT_CMD_DEREF); + cmd->size = reg_def->size; + cmd->big_endian = rules.section->file->big_endian; } break; case RULE_SAME_VALUE: - if (reg_def != NULL) { - U8_T v = 0; - if (read_reg_value(reg_def, frame, &v) >= 0) { - write_reg_value(reg_def, down, v); - } - } + add_command(SFT_CMD_REGISTER)->reg = reg_def; break; case RULE_REGISTER: - if (reg_def != NULL) { + { RegisterDefinition * src_sef = get_reg_by_id(rules.ctx, reg->offset, rules.eh_frame ? REGNUM_EH_FRAME : REGNUM_DWARF); - if (src_sef != NULL) { - U8_T v = 0; - if (read_reg_value(src_sef, frame, &v) >= 0) { - write_reg_value(reg_def, down, v); - } - } - } - break; - case RULE_VAL_OFFSET: - if (frame->fp != 0 && reg_def != NULL) { - U8_T v = frame->fp + reg->offset; - write_reg_value(reg_def, down, v); + if (src_sef != NULL) add_command(SFT_CMD_REGISTER)->reg = src_sef; } break; - case RULE_EXPRESSION: - case RULE_VAL_EXPRESSION: - /* TODO: RULE_EXPRESSION */ + default: + /* TODO: RULE_EXPRESSION, RULE_VAL_EXPRESSION */ + str_exception(ERR_UNSUPPORTED, "Not implemented yet: expression in .debug_frame"); break; } + if (dwarf_stack_trace_regs_cnt >= trace_regs_max) { + int i; + trace_regs_max += 16; + dwarf_stack_trace_regs = (StackTracingCommandSequence **)loc_realloc(dwarf_stack_trace_regs, trace_regs_max * sizeof(StackTracingCommandSequence *)); + for (i = dwarf_stack_trace_regs_cnt; i < trace_regs_max; i++) dwarf_stack_trace_regs[i] = NULL; + } + if (trace_cmds_cnt == 0) return; + add_command_sequence(dwarf_stack_trace_regs + dwarf_stack_trace_regs_cnt++, reg_def); } -static int fill_stack_frame(StackFrame * frame, StackFrame * down) { +static void generate_commands(void) { int i; - U8_T v = 0; RegisterRules * reg; RegisterDefinition * reg_def; + reg = get_reg(&frame_regs, rules.return_address_register); + if (reg->rule != 0) generate_register_commands(reg, get_PC_definition(rules.ctx)); + for (i = 0; i < frame_regs.regs_cnt; i++) { + if (i == rules.return_address_register) continue; + reg = get_reg(&frame_regs, i); + if (reg->rule == 0) continue; + reg_def = get_reg_by_id(rules.ctx, i, rules.eh_frame ? REGNUM_EH_FRAME : REGNUM_DWARF); + generate_register_commands(reg, reg_def); + } + + trace_cmds_cnt = 0; switch (rules.cfa_rule) { case RULE_OFFSET: reg_def = get_reg_by_id(rules.ctx, rules.cfa_register, rules.eh_frame ? REGNUM_EH_FRAME : REGNUM_DWARF); if (reg_def != NULL) { - if (read_reg_value(reg_def, frame, &v) >= 0) { - frame->fp = (ContextAddress)(v + rules.cfa_offset); + add_command(SFT_CMD_REGISTER)->reg = reg_def; + if (rules.cfa_offset != 0) { + add_command(SFT_CMD_NUMBER)->num = rules.cfa_offset; + add_command(SFT_CMD_ADD); } } break; + default: /* TODO: RULE_EXPRESSION */ + str_exception(ERR_UNSUPPORTED, "Not implemented yet: expression in .debug_frame"); } - - reg = get_reg(&frame_regs, rules.return_address_register); - if (reg->rule != 0) fill_frame_register(reg, get_PC_definition(rules.ctx), frame, down); - for (i = 0; i < frame_regs.regs_cnt; i++) { - if (i == rules.return_address_register) continue; - reg = get_reg(&frame_regs, i); - if (reg->rule == 0) continue; - reg_def = get_reg_by_id(rules.ctx, i, rules.eh_frame ? REGNUM_EH_FRAME : REGNUM_DWARF); - fill_frame_register(reg, reg_def, frame, down); - } - return 0; + add_command_sequence(&dwarf_stack_trace_fp, NULL); } static void read_frame_cie(U8_T pos) { @@ -485,15 +517,23 @@ static void read_frame_cie(U8_T pos) { dio_Skip(saved_pos - dio_GetPos()); } -void get_dwarf_stack_frame_info(Context * ctx, ELF_File * file, StackFrame * frame, StackFrame * down) { +void get_dwarf_stack_frame_info(Context * ctx, ELF_File * file, U8_T IP) { /* TODO: use .eh_frame_hdr section for faster frame data search */ - U8_T IP = 0; DWARFCache * cache = get_dwarf_cache(file); ELF_Section * section = cache->mDebugFrame; + + dwarf_stack_trace_regs_cnt = 0; + if (dwarf_stack_trace_fp == NULL) { + dwarf_stack_trace_fp = (StackTracingCommandSequence *)loc_alloc_zero(sizeof(StackTracingCommandSequence)); + dwarf_stack_trace_fp->cmds_max = 1; + } + dwarf_stack_trace_fp->cmds_cnt = 0; + dwarf_stack_trace_addr = 0; + dwarf_stack_trace_size = 0; + if (section == NULL) section = cache->mEHFrame; if (section == NULL) return; - if (read_reg_value(get_PC_definition(rules.ctx), frame, &IP) < 0) exception(errno); memset(&rules, 0, sizeof(StackFrameRules)); rules.ctx = ctx; rules.section = section; @@ -529,6 +569,7 @@ void get_dwarf_stack_frame_info(Context * ctx, ELF_File * file, StackFrame * fra Range = read_frame_data_pointer(rules.addr_encoding, NULL); AddrRT = elf_map_to_run_time_address(ctx, file, sec, (ContextAddress)Addr); if (AddrRT != 0 && AddrRT <= IP && AddrRT + Range > IP) { + U8_T location0 = Addr; if (rules.cie_aug != NULL && rules.cie_aug[0] == 'z') { rules.fde_aug_length = dio_ReadULEB128(); rules.fde_aug_data = dio_GetDataPtr(); @@ -537,11 +578,19 @@ void get_dwarf_stack_frame_info(Context * ctx, ELF_File * file, StackFrame * fra copy_register_rules(&frame_regs, &cie_regs); rules.location = Addr; regs_stack_pos = 0; - while (dio_GetPos() < fde_end) { + for (;;) { + if (dio_GetPos() >= fde_end) { + rules.location = Addr + Range; + break; + } exec_stack_frame_instruction(); + assert(location0 - Addr + AddrRT <= IP); if (rules.location - Addr + AddrRT > IP) break; + location0 = rules.location; } - fill_stack_frame(frame, down); + dwarf_stack_trace_addr = location0 - Addr + AddrRT; + dwarf_stack_trace_size = rules.location - location0; + generate_commands(); break; } } diff --git a/services/dwarfframe.h b/services/dwarfframe.h index d4939ed8..d90d0eec 100644 --- a/services/dwarfframe.h +++ b/services/dwarfframe.h @@ -27,22 +27,27 @@ #include "context.h" #include "dwarfcache.h" +#include "stacktrace.h" /* - * Lookup stack frame data in ELF file, in .debug_frame and .eh_frame sections. + * Lookup stack tracing information in ELF file, in .debug_frame and .eh_frame sections. * - * "frame" is current frame info, it should have frame->regs and frame->mask filled with - * proper values before this function is called. + * Given register values in one frame, stack tracing information allows to calculate + * frame address and register values in the next frame. * - * "down" is next frame - moving from stack top to the bottom. - * - * The function uses register values in current frame to calculate frame address "frame->fp", - * and calculate register values in the next frame. - * - * If frame data is not found the function does nothing. + * When function returns, dwarf_stack_trace_fp contains commands to calculate frame address, + * and dwarf_stack_trace_regs contains commands to calculate register values. * In case of error reading frame data, the function throws an exception. */ -extern void get_dwarf_stack_frame_info(Context * ctx, ELF_File * file, StackFrame * frame, StackFrame * down); +extern void get_dwarf_stack_frame_info(Context * ctx, ELF_File * file, U8_T ip); + +extern U8_T dwarf_stack_trace_addr; +extern U8_T dwarf_stack_trace_size; + +extern StackTracingCommandSequence * dwarf_stack_trace_fp; + +extern int dwarf_stack_trace_regs_cnt; +extern StackTracingCommandSequence ** dwarf_stack_trace_regs; #endif /* ENABLE_ELF */ diff --git a/services/linenumbers_proxy.c b/services/linenumbers_proxy.c index 7a501113..5ef1076f 100644 --- a/services/linenumbers_proxy.c +++ b/services/linenumbers_proxy.c @@ -194,6 +194,7 @@ static void validate_map_to_memory(Channel * c, void * args, int error) { f->error = get_error_report(error); cache_notify(&f->cache); if (f->disposed) free_line_address_cache(f); + if (trap.error) exception(trap.error); } int line_to_address(Context * ctx, char * file, int line, int column, LineNumbersCallBack * client, void * args) { diff --git a/services/stacktrace.c b/services/stacktrace.c index c7a0c7e7..f5ee9fca 100644 --- a/services/stacktrace.c +++ b/services/stacktrace.c @@ -30,6 +30,7 @@ #include "trace.h" #include "context.h" #include "json.h" +#include "cache.h" #include "exceptions.h" #include "stacktrace.h" #include "breakpoints.h" @@ -40,11 +41,6 @@ static const char * STACKTRACE = "StackTrace"; -struct ContextInterfaceData { - Context * ctx; - int frame; -}; - struct StackTrace { ErrorReport * error; int frame_cnt; @@ -52,20 +48,26 @@ struct StackTrace { struct StackFrame frames[1]; /* ordered bottom to top */ }; -typedef struct ContextInterfaceData ContextInterfaceData; typedef struct StackTrace StackTrace; -#define CTX_DATA(x) ((ContextInterfaceData *)&(x)->private_data) - -static void add_frame(Context * ctx, StackFrame * frame) { - StackTrace * stack_trace = (StackTrace *)ctx->stack_trace; +static StackTrace * add_frame(StackTrace * stack_trace, StackFrame * frame) { if (stack_trace->frame_cnt >= stack_trace->frame_max) { stack_trace->frame_max *= 2; stack_trace = (StackTrace *)loc_realloc(stack_trace, sizeof(StackTrace) + (stack_trace->frame_max - 1) * sizeof(StackFrame)); - ctx->stack_trace = stack_trace; } stack_trace->frames[stack_trace->frame_cnt++] = *frame; + return stack_trace; +} + +static void free_stack_trace(StackTrace * stack_trace) { + int i; + release_error_report(stack_trace->error); + for (i = 0; i < stack_trace->frame_cnt; i++) { + if (!stack_trace->frames[i].is_top_frame) loc_free(stack_trace->frames[i].regs); + loc_free(stack_trace->frames[i].mask); + } + loc_free(stack_trace); } #if defined(_WRS_KERNEL) @@ -73,6 +75,7 @@ static void add_frame(Context * ctx, StackFrame * frame) { #include <trcLib.h> static Context * client_ctx; +static StackTrace * client_trace; static int frame_cnt; static ContextAddress frame_rp; @@ -101,21 +104,22 @@ static void vxworks_stack_trace_callback( } f.fp = (ContextAddress)args; frame_rp = (ContextAddress)callAdrs; - add_frame(client_ctx, &f); + client_trace = add_frame(client_trace, &f); frame_cnt++; } -static int trace_stack(Context * ctx) { +static StackTrace * trace_stack(Context * ctx, StackTrace * s) { client_ctx = ctx; + client_trace = s; frame_cnt = 0; trcStack((REG_SET *)ctx->regs, (FUNCPTR)vxworks_stack_trace_callback, ctx->pid); if (frame_cnt == 0) vxworks_stack_trace_callback(NULL, 0, 0, NULL, ctx->pid, 1); - return 0; + return client_trace; } #else -static int walk_frames(Context * ctx) { +static StackTrace * walk_frames(Context * ctx, StackTrace * stack_trace) { int error = 0; unsigned cnt = 0; StackFrame frame; @@ -132,12 +136,14 @@ static int walk_frames(Context * ctx) { down.regs_size = ctx->regs_size; down.regs = (RegisterData *)loc_alloc_zero(down.regs_size); down.mask = (RegisterData *)loc_alloc_zero(down.regs_size); +#if ENABLE_Symbols if (get_next_stack_frame(ctx, &frame, &down) < 0) { error = errno; loc_free(down.regs); loc_free(down.mask); break; } +#endif if (frame.fp == 0 && crawl_stack_frame(ctx, &frame, &down) < 0) { error = errno; loc_free(down.regs); @@ -149,7 +155,7 @@ static int walk_frames(Context * ctx) { loc_free(down.mask); break; } - add_frame(ctx, &frame); + stack_trace = add_frame(stack_trace, &frame); frame = down; cnt++; } @@ -157,40 +163,47 @@ static int walk_frames(Context * ctx) { if (!frame.is_top_frame) loc_free(frame.regs); loc_free(frame.mask); - errno = error; - return error == 0 ? 0 : -1; + if (error) { + if (get_error_code(error) == ERR_CACHE_MISS) { + free_stack_trace(stack_trace); + stack_trace = NULL; + errno = ERR_CACHE_MISS; + } + else { + stack_trace->error = get_error_report(error); + } + } + return stack_trace; } -static int trace_stack(Context * ctx) { - int i; - StackTrace * s; - if (walk_frames(ctx) < 0) return -1; - s = (StackTrace *)ctx->stack_trace; - for (i = 0; i < s->frame_cnt / 2; i++) { - StackFrame f = s->frames[i]; - s->frames[i] = s->frames[s->frame_cnt - i - 1]; - s->frames[s->frame_cnt - i - 1] = f; +static StackTrace * trace_stack(Context * ctx, StackTrace * s) { + s = walk_frames(ctx, s); + if (s != NULL) { + int i; + for (i = 0; i < s->frame_cnt / 2; i++) { + StackFrame f = s->frames[i]; + s->frames[i] = s->frames[s->frame_cnt - i - 1]; + s->frames[s->frame_cnt - i - 1] = f; + } } - return 0; + return s; } #endif static StackTrace * create_stack_trace(Context * ctx) { - int error = 0; StackTrace * stack_trace = (StackTrace *)ctx->stack_trace; if (stack_trace != NULL) return stack_trace; stack_trace = (StackTrace *)loc_alloc_zero(sizeof(StackTrace) + 31 * sizeof(StackFrame)); stack_trace->frame_max = 32; - ctx->stack_trace = stack_trace; if (ctx->regs_error != NULL) { stack_trace->error = get_error_report(set_error_report_errno(ctx->regs_error)); - return stack_trace; } - if (trace_stack(ctx) < 0) error = errno; - stack_trace = (StackTrace *)ctx->stack_trace; - if (error) stack_trace->error = get_error_report(error); + else { + stack_trace = trace_stack(ctx, stack_trace); + } + ctx->stack_trace = stack_trace; return stack_trace; } @@ -252,60 +265,104 @@ static void write_context(OutputStream * out, char * id, Context * ctx, int leve write_stream(out, '}'); } -static void command_get_context(char * token, Channel * c) { - int err = 0; +typedef struct CommandGetContextData { + Context * ctx; + int frame; + StackFrame * info; + StackFrame * down; +} CommandGetContextData; + +typedef struct CommandGetContextArgs { + char token[256]; + int id_cnt; char ** ids; - int id_cnt = 0; - int i; + CommandGetContextData * data; +} CommandGetContextArgs; - ids = json_read_alloc_string_array(&c->inp, &id_cnt); - if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); - if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); +static void command_get_context_cache_client(void * x) { + int i; + int err = 0; + CommandGetContextArgs * args = (CommandGetContextArgs *)x; + Channel * c = cache_channel(); - write_stringz(&c->out, "R"); - write_stringz(&c->out, token); - write_stream(&c->out, '['); - for (i = 0; i < id_cnt; i++) { + memset(args->data, 0, sizeof(CommandGetContextData) * args->id_cnt); + for (i = 0; i < args->id_cnt; i++) { StackTrace * s = NULL; - Context * ctx = NULL; - int frame = 0; - if (i > 0) write_stream(&c->out, ','); - if (id2frame(ids[i], &ctx, &frame) < 0) { + CommandGetContextData * d = args->data + i; + if (id2frame(args->ids[i], &d->ctx, &d->frame) < 0) { err = errno; + break; } - else if (!ctx->stopped) { + if (!d->ctx->stopped) { err = ERR_IS_RUNNING; + break; } - else { - s = create_stack_trace(ctx); + s = create_stack_trace(d->ctx); + if (s == NULL) { + err = errno; + break; } - if (s == NULL || frame < 0 || frame >= s->frame_cnt) { + if (s->error) { + err = set_error_report_errno(s->error); + break; + } + if (d->frame >= s->frame_cnt) { + err = ERR_INV_CONTEXT; + break; + } + d->info = s->frames + d->frame; + d->down = d->frame > 0 ? d->info - 1 : NULL; + } + + cache_exit(); + + write_stringz(&c->out, "R"); + write_stringz(&c->out, args->token); + write_stream(&c->out, '['); + for (i = 0; i < args->id_cnt; i++) { + CommandGetContextData * d = args->data + i; + if (i > 0) write_stream(&c->out, ','); + if (d->info == NULL) { write_string(&c->out, "null"); } else { - StackFrame * f = s->frames + frame; - StackFrame * d = frame > 0 ? f - 1 : NULL; - write_context(&c->out, ids[i], ctx, frame, f, d); + write_context(&c->out, args->ids[i], d->ctx, d->frame, d->info, d->down); } } write_stream(&c->out, ']'); write_stream(&c->out, 0); write_errno(&c->out, err); write_stream(&c->out, MARKER_EOM); - loc_free(ids); + + loc_free(args->ids); + loc_free(args->data); } -static void command_get_children(char * token, Channel * c) { +static void command_get_context(char * token, Channel * c) { + CommandGetContextArgs args; + + args.ids = json_read_alloc_string_array(&c->inp, &args.id_cnt); + if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); + if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); + + args.data = (CommandGetContextData *)loc_alloc(sizeof(CommandGetContextData) * args.id_cnt); + strlcpy(args.token, token, sizeof(args.token)); + cache_enter(command_get_context_cache_client, c, &args, sizeof(args)); +} + +typedef struct CommandGetChildrenArgs { + char token[256]; char id[256]; +} CommandGetChildrenArgs; + +static void command_get_children_cache_client(void * x) { int err = 0; Context * ctx = NULL; StackTrace * s = NULL; + CommandGetChildrenArgs * args = (CommandGetChildrenArgs *)x; + Channel * c = cache_channel(); - json_read_string(&c->inp, id, sizeof(id)); - if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); - if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); - - ctx = id2ctx(id); + ctx = id2ctx(args->id); if (ctx == NULL || !context_has_state(ctx)) { /* no children */ } @@ -316,8 +373,10 @@ static void command_get_children(char * token, Channel * c) { s = create_stack_trace(ctx); } + cache_exit(); + write_stringz(&c->out, "R"); - write_stringz(&c->out, token); + write_stringz(&c->out, args->token); write_errno(&c->out, s != NULL ? set_error_report_errno(s->error) : err); @@ -338,18 +397,15 @@ static void command_get_children(char * token, Channel * c) { write_stream(&c->out, MARKER_EOM); } -static void delete_stack_trace(Context * ctx, void * client_data) { - StackTrace * stack_trace = (StackTrace *)ctx->stack_trace; - if (stack_trace != NULL) { - int i; - release_error_report(stack_trace->error); - for (i = 0; i < stack_trace->frame_cnt; i++) { - if (!stack_trace->frames[i].is_top_frame) loc_free(stack_trace->frames[i].regs); - loc_free(stack_trace->frames[i].mask); - } - loc_free(stack_trace); - ctx->stack_trace = NULL; - } +static void command_get_children(char * token, Channel * c) { + CommandGetChildrenArgs args; + + json_read_string(&c->inp, args.id, sizeof(args.id)); + if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); + if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); + + strlcpy(args.token, token, sizeof(args.token)); + cache_enter(command_get_children_cache_client, c, &args, sizeof(args)); } int get_top_frame(Context * ctx) { @@ -361,6 +417,9 @@ int get_top_frame(Context * ctx) { } s = create_stack_trace(ctx); + if (s == NULL) { + return STACK_TOP_FRAME; + } if (s->error != NULL) { set_error_report_errno(s->error); return STACK_TOP_FRAME; @@ -383,6 +442,9 @@ int get_frame_info(Context * ctx, int frame, StackFrame ** info) { } stack = create_stack_trace(ctx); + if (stack == NULL) { + return -1; + } if (stack->error != NULL) { set_error_report_errno(stack->error); return -1; @@ -407,10 +469,18 @@ int is_top_frame(Context * ctx, int frame) { if (frame == STACK_TOP_FRAME) return 1; if (!ctx->stopped) return 0; stack = create_stack_trace(ctx); - if (stack->error != NULL) return 0; + if (stack == NULL || stack->error != NULL) return 0; return frame == stack->frame_cnt - 1; } +static void delete_stack_trace(Context * ctx, void * args) { + StackTrace * stack_trace = (StackTrace *)ctx->stack_trace; + if (stack_trace != NULL) { + free_stack_trace(stack_trace); + ctx->stack_trace = NULL; + } +} + void ini_stack_trace_service(Protocol * proto, TCFBroadcastGroup * bcg) { static ContextEventListener listener = { NULL, diff --git a/services/stacktrace.h b/services/stacktrace.h index def3df5f..1ab928a5 100644 --- a/services/stacktrace.h +++ b/services/stacktrace.h @@ -30,14 +30,14 @@ extern int get_top_frame(Context * ctx); /* - * Get information about given stack frame. + * Return 1 if 'frame' is the top frame of the context. */ -extern int get_frame_info(Context * ctx, int frame, StackFrame ** info); +extern int is_top_frame(Context * ctx, int frame); /* - * Return 1 if 'frame' is the top frame of the context. + * Get information about given stack frame. */ -extern int is_top_frame(Context * ctx, int frame); +extern int get_frame_info(Context * ctx, int frame, StackFrame ** info); /* * Initialize stack trace service. diff --git a/services/symbols.c b/services/symbols.c index b422f3a9..ad6820db 100644 --- a/services/symbols.c +++ b/services/symbols.c @@ -431,6 +431,101 @@ static void command_get_array_type(char * token, Channel * c) { cache_enter(command_get_array_type_cache_client, c, &args, sizeof(args)); } +typedef struct CommandFindFrameInfo { + char token[256]; + char id[256]; + ContextAddress addr; +} CommandFindFrameInfo; + +static void write_commands(OutputStream * out, Context * ctx, StackTracingCommandSequence * seq) { + if (seq != NULL) { + int i; + write_stream(out, '['); + for (i = 0; i < seq->cmds_cnt; i++) { + StackTracingCommand * cmd = seq->cmds + i; + if (i > 0) write_stream(out, ','); + json_write_long(out, cmd->cmd); + switch (cmd->cmd) { + case SFT_CMD_NUMBER: + write_stream(out, ','); + json_write_int64(out, cmd->num); + break; + case SFT_CMD_REGISTER: + write_stream(out, ','); + json_write_string(out, register2id(ctx, STACK_NO_FRAME, cmd->reg)); + break; + case SFT_CMD_DEREF: + write_stream(out, ','); + json_write_ulong(out, cmd->size); + write_stream(out, ','); + json_write_boolean(out, cmd->big_endian); + break; + } + } + write_stream(out, ']'); + } + else { + write_string(out, "null"); + } +} + +static void command_find_frame_info_cache_client(void * x) { + CommandFindFrameInfo * args = (CommandFindFrameInfo *)x; + Channel * c = cache_channel(); + Context * ctx = NULL; + StackTracingInfo * info = NULL; + int err = 0; + + ctx = id2ctx(args->id); + if (ctx == NULL) err = ERR_INV_CONTEXT; + else if (get_stack_tracing_info(ctx, args->addr, &info) < 0) err = errno; + + cache_exit(); + + write_stringz(&c->out, "R"); + write_stringz(&c->out, args->token); + write_errno(&c->out, err); + + json_write_uint64(&c->out, info ? info->addr : 0); + write_stream(&c->out, 0); + json_write_uint64(&c->out, info ? info->size : 0); + write_stream(&c->out, 0); + + write_commands(&c->out, ctx, info ? info->fp : NULL); + write_stream(&c->out, 0); + + if (info != NULL && info->regs != NULL) { + int i; + write_stream(&c->out, '{'); + for (i = 0; i < info->reg_cnt; i++) { + if (i > 0) write_stream(&c->out, ','); + json_write_string(&c->out, register2id(ctx, STACK_NO_FRAME, info->regs[i]->reg)); + write_stream(&c->out, ':'); + write_commands(&c->out, ctx, info->regs[i]); + } + write_stream(&c->out, '}'); + } + else { + write_string(&c->out, "null"); + } + write_stream(&c->out, 0); + + write_stream(&c->out, MARKER_EOM); +} + +static void command_find_frame_info(char * token, Channel * c) { + CommandFindFrameInfo args; + + json_read_string(&c->inp, args.id, sizeof(args.id)); + if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); + args.addr = (ContextAddress)json_read_uint64(&c->inp); + if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); + if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); + + strlcpy(args.token, token, sizeof(args.token)); + cache_enter(command_find_frame_info_cache_client, c, &args, sizeof(args)); +} + void ini_symbols_service(Protocol * proto) { static int ini_done = 0; if (!ini_done) { @@ -442,6 +537,7 @@ void ini_symbols_service(Protocol * proto) { add_command_handler(proto, SYMBOLS, "find", command_find); add_command_handler(proto, SYMBOLS, "list", command_list); add_command_handler(proto, SYMBOLS, "getArrayType", command_get_array_type); + add_command_handler(proto, SYMBOLS, "findFrameInfo", command_find_frame_info); } #endif /* SERVICE_Symbols */ diff --git a/services/symbols.h b/services/symbols.h index 381a6699..1766dcf0 100644 --- a/services/symbols.h +++ b/services/symbols.h @@ -52,6 +52,8 @@ typedef struct Symbol Symbol; typedef void EnumerateSymbolsCallBack(void *, Symbol *); +#if ENABLE_Symbols + /* * Find symbol information for given symbol name in given context. * On error, returns -1 and sets errno. @@ -148,17 +150,11 @@ extern int get_array_symbol(const Symbol * sym, ContextAddress length, Symbol ** /*************************************************************************************************/ - /* * Check if given address is inside a PLT section, then return address of the section. * If not a PLT address return 0; */ -#if ENABLE_Symbols extern ContextAddress is_plt_section(Context * ctx, ContextAddress addr); -#else -#define is_plt_section(ctx, addr) 0 -#endif - /* * For given context and its registers in a stack frame, @@ -166,11 +162,14 @@ extern ContextAddress is_plt_section(Context * ctx, ContextAddress addr); * If frame info is not available, do nothing. * Return -1 and set errno in case of an error. */ -#if ENABLE_Symbols extern int get_next_stack_frame(Context * ctx, StackFrame * frame, StackFrame * down); -#else -#define get_next_stack_frame(ctx, frame, down) 0 -#endif + +/* + * For given context and instruction address, + * search for stack tracing information. + * Return -1 and set errno in case of an error. + */ +extern int get_stack_tracing_info(Context * ctx, ContextAddress addr, StackTracingInfo ** info); /* * Initialize symbol service. @@ -178,4 +177,6 @@ extern int get_next_stack_frame(Context * ctx, StackFrame * frame, StackFrame * extern void ini_symbols_service(Protocol * proto); extern void ini_symbols_lib(void); +#endif /* ENABLE_Symbols */ + #endif /* D_symbols */ diff --git a/services/symbols_elf.c b/services/symbols_elf.c index 04c67a16..d0dd715b 100644 --- a/services/symbols_elf.c +++ b/services/symbols_elf.c @@ -578,29 +578,67 @@ ContextAddress is_plt_section(Context * ctx, ContextAddress addr) { return res; } +int get_stack_tracing_info(Context * ctx, ContextAddress addr, StackTracingInfo ** info) { + ELF_File * file = elf_list_first(ctx, (ContextAddress)addr, (ContextAddress)(addr + 1)); + int error = 0; + + *info = NULL; + + while (error == 0 && file != NULL) { + Trap trap; + if (set_trap(&trap)) { + get_dwarf_stack_frame_info(ctx, file, addr); + if (dwarf_stack_trace_fp->cmds_cnt > 0) { + static StackTracingInfo buf; + buf.addr = (ContextAddress)dwarf_stack_trace_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 || *info != NULL) break; + file = elf_list_next(ctx); + if (file == NULL) error = errno; + } + elf_list_done(ctx); + if (error) { + errno = error; + return -1; + } + return 0; +} + int get_next_stack_frame(Context * ctx, StackFrame * frame, StackFrame * down) { int error = 0; uint64_t ip = 0; + StackTracingInfo * info = NULL; if (read_reg_value(get_PC_definition(ctx), frame, &ip) < 0) { if (frame->is_top_frame) error = errno; } - else { - ELF_File * file = elf_list_first(ctx, (ContextAddress)ip, (ContextAddress)(ip + 1)); - while (error == 0 && file != NULL) { - Trap trap; - if (set_trap(&trap)) { - get_dwarf_stack_frame_info(ctx, file, frame, down); - clear_trap(&trap); - } - else { - error = trap.error; + 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, dwarf_stack_trace_fp); + for (i = 0; i < dwarf_stack_trace_regs_cnt; i++) { + uint64_t v = evaluate_stack_trace_commands(ctx, frame, dwarf_stack_trace_regs[i]); + if (write_reg_value(dwarf_stack_trace_regs[i]->reg, down, v) < 0) exception(errno); } - if (error || frame->fp != 0) break; - file = elf_list_next(ctx); - if (file == NULL) error = errno; + clear_trap(&trap); + } + else { + error = trap.error; } - elf_list_done(ctx); } if (error) { errno = error; diff --git a/services/symbols_proxy.c b/services/symbols_proxy.c index fa0e05f4..cc200171 100644 --- a/services/symbols_proxy.c +++ b/services/symbols_proxy.c @@ -33,7 +33,7 @@ #include "stacktrace.h" #include "symbols.h" -#define HASH_SIZE 511 +#define HASH_SIZE 101 /* Symbols cahce, one per channel */ typedef struct SymbolsCache { @@ -43,6 +43,7 @@ typedef struct SymbolsCache { LINK link_find[HASH_SIZE]; LINK link_list[HASH_SIZE]; LINK link_frame[HASH_SIZE]; + int service_available; } SymbolsCache; /* Symbol properties cache */ @@ -133,6 +134,10 @@ typedef struct StackFrameCache { uint64_t address; uint64_t size; + StackTracingCommandSequence * fp; + StackTracingCommandSequence ** regs; + int regs_cnt; + int disposed; } StackFrameCache; @@ -154,6 +159,8 @@ struct Symbol { static LINK root; +static const char * SYMBOLS = "Symbols"; + static unsigned hash_sym_id(const char * id) { int i; unsigned h = 0; @@ -182,7 +189,9 @@ static SymbolsCache * get_symbols_cache(void) { LINK * l = NULL; SymbolsCache * syms = NULL; Channel * c = cache_channel(); - if (c == NULL) exception(ERR_SYM_NOT_FOUND); + if (c == NULL) { + str_exception(ERR_SYM_NOT_FOUND, "Illegal cache access"); + } for (l = root.next; l != &root; l = l->next) { SymbolsCache * x = root2syms(l); if (x->channel == c) { @@ -199,9 +208,14 @@ static SymbolsCache * get_symbols_cache(void) { list_init(syms->link_sym + i); list_init(syms->link_find + i); list_init(syms->link_list + i); + list_init(syms->link_frame + i); } channel_lock(c); + for (i = 0; i < c->peer_service_cnt; i++) { + if (strcmp(c->peer_service_list[i], SYMBOLS) == 0) syms->service_available = 1; + } } + if (!syms->service_available) str_exception(ERR_SYM_NOT_FOUND, "Symbols service not available"); return syms; } @@ -270,8 +284,12 @@ static void free_stack_frame_cache(StackFrameCache * c) { list_remove(&c->link_syms); c->disposed = 1; if (c->pending == NULL) { + int i; cache_dispose(&c->cache); release_error_report(c->error); + for (i = 0; i < c->regs_cnt; i++) loc_free(c->regs[i]); + loc_free(c->regs); + loc_free(c->fp); loc_free(c); } } @@ -342,6 +360,7 @@ static void validate_context(Channel * c, void * args, int error) { s->error_get_context = get_error_report(error); cache_notify(&s->cache); if (s->disposed) free_sym_info_cache(s); + if (trap.error) exception(trap.error); } static SymInfoCache * get_sym_info_cache(const Symbol * sym) { @@ -360,7 +379,7 @@ static SymInfoCache * get_sym_info_cache(const Symbol * sym) { else if (!s->done_context) { Channel * c = cache_channel(); if (c == NULL) exception(ERR_SYM_NOT_FOUND); - s->pending_get_context = protocol_send_command(c, "Symbols", "getContext", validate_context, s); + s->pending_get_context = protocol_send_command(c, SYMBOLS, "getContext", validate_context, s); json_write_string(&c->out, s->id); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); @@ -393,6 +412,7 @@ static void validate_find(Channel * c, void * args, int error) { assert(f->error != NULL || f->id != NULL); cache_notify(&f->cache); if (f->disposed) free_find_sym_cache(f); + if (trap.error) exception(trap.error); } int find_symbol(Context * ctx, int frame, char * name, Symbol ** sym) { @@ -433,7 +453,7 @@ int find_symbol(Context * ctx, int frame, char * name, Symbol ** sym) { f->pid = ctx->pid; f->ip = ip; f->name = loc_strdup(name); - f->pending = protocol_send_command(c, "Symbols", "find", validate_find, f); + f->pending = protocol_send_command(c, SYMBOLS, "find", validate_find, f); if (frame != STACK_NO_FRAME) { json_write_string(&c->out, frame2id(ctx, frame)); } @@ -493,6 +513,7 @@ static void validate_list(Channel * c, void * args, int error) { f->error = get_error_report(error); cache_notify(&f->cache); if (f->disposed) free_list_sym_cache(f); + if (trap.error) exception(trap.error); } int enumerate_symbols(Context * ctx, int frame, EnumerateSymbolsCallBack * func, void * args) { @@ -532,7 +553,7 @@ int enumerate_symbols(Context * ctx, int frame, EnumerateSymbolsCallBack * func, list_add_first(&f->link_syms, syms->link_list + h); f->pid = ctx->pid; f->ip = ip; - f->pending = protocol_send_command(c, "Symbols", "list", validate_list, f); + f->pending = protocol_send_command(c, SYMBOLS, "list", validate_list, f); if (frame != STACK_NO_FRAME) { json_write_string(&c->out, frame2id(ctx, frame)); } @@ -739,6 +760,7 @@ static void validate_children(Channel * c, void * args, int error) { s->error_get_children = get_error_report(error); cache_notify(&s->cache); if (s->disposed) free_sym_info_cache(s); + if (trap.error) exception(trap.error); } int get_symbol_children(const Symbol * sym, Symbol *** children, int * count) { @@ -757,7 +779,7 @@ int get_symbol_children(const Symbol * sym, Symbol *** children, int * count) { else if (!s->done_children) { Channel * c = cache_channel(); if (c == NULL) exception(ERR_SYM_NOT_FOUND); - s->pending_get_children = protocol_send_command(c, "Symbols", "getChildren", validate_children, s); + s->pending_get_children = protocol_send_command(c, SYMBOLS, "getChildren", validate_children, s); json_write_string(&c->out, s->id); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); @@ -804,6 +826,7 @@ static void validate_type_id(Channel * c, void * args, int error) { s->error = get_error_report(error); cache_notify(&s->cache); if (s->disposed) free_arr_sym_cache(s); + if (trap.error) exception(trap.error); } int get_array_symbol(const Symbol * sym, ContextAddress length, Symbol ** ptr) { @@ -826,7 +849,7 @@ int get_array_symbol(const Symbol * sym, ContextAddress length, Symbol ** ptr) { a = (ArraySymCache *)loc_alloc_zero(sizeof(*a)); list_add_first(&a->link_sym, &s->array_syms); a->length = length; - a->pending = protocol_send_command(c, "Symbols", "getArrayType", validate_type_id, a); + a->pending = protocol_send_command(c, SYMBOLS, "getArrayType", validate_type_id, a); json_write_string(&c->out, s->id); write_stream(&c->out, 0); json_write_uint64(&c->out, length); @@ -850,11 +873,76 @@ int get_array_symbol(const Symbol * sym, ContextAddress length, Symbol ** ptr) { /*************************************************************************************************/ +static int trace_cmds_cnt = 0; +static int trace_cmds_max = 0; +static StackTracingCommand * trace_cmds = NULL; + +static int trace_regs_cnt = 0; +static int trace_regs_max = 0; +static StackTracingCommandSequence ** trace_regs = NULL; + +static int trace_error = 0; + ContextAddress is_plt_section(Context * ctx, ContextAddress addr) { /* TODO: is_plt_section() in symbols proxy */ return 0; } +static void read_stack_trace_command(InputStream * inp, void * args) { + char id[256]; + Context * ctx = NULL; + int frame = STACK_NO_FRAME; + StackTracingCommand * cmd = NULL; + if (trace_cmds_cnt >= trace_cmds_max) { + trace_cmds_max += 16; + trace_cmds = (StackTracingCommand *)loc_realloc(trace_cmds, trace_cmds_max * sizeof(StackTracingCommand)); + } + cmd = trace_cmds + trace_cmds_cnt++; + memset(cmd, 0, sizeof(*cmd)); + cmd->cmd = json_read_long(inp); + switch (cmd->cmd) { + case SFT_CMD_NUMBER: + if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX); + cmd->num = json_read_int64(inp); + break; + case SFT_CMD_REGISTER: + if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX); + json_read_string(inp, id, sizeof(id)); + if (id2register(id, &ctx, &frame, &cmd->reg) < 0) trace_error = errno; + break; + case SFT_CMD_DEREF: + if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX); + cmd->size = json_read_ulong(inp); + if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX); + cmd->big_endian = json_read_boolean(inp); + break; + } +} + +static void read_stack_trace_register(InputStream * inp, const char * id, void * args) { + if (trace_regs_cnt >= trace_regs_max) { + trace_regs_max += 16; + trace_regs = (StackTracingCommandSequence **)loc_realloc(trace_regs, trace_regs_max * sizeof(StackTracingCommandSequence *)); + } + trace_cmds_cnt = 0; + if (json_read_array(inp, read_stack_trace_command, NULL)) { + Context * ctx = NULL; + int frame = STACK_NO_FRAME; + StackTracingCommandSequence * reg = (StackTracingCommandSequence *)loc_alloc( + sizeof(StackTracingCommandSequence) + (trace_cmds_cnt - 1) * sizeof(StackTracingCommand)); + if (id2register(id, &ctx, &frame, ®->reg) < 0) { + trace_error = errno; + loc_free(reg); + } + else { + reg->cmds_cnt = trace_cmds_cnt; + reg->cmds_max = trace_cmds_cnt; + memcpy(reg->cmds, trace_cmds, trace_cmds_cnt * sizeof(StackTracingCommand)); + trace_regs[trace_regs_cnt++] = reg; + } + } +} + static void validate_frame(Channel * c, void * args, int error) { Trap trap; StackFrameCache * f = (StackFrameCache *)args; @@ -863,20 +951,45 @@ static void validate_frame(Channel * c, void * args, int error) { if (set_trap(&trap)) { f->pending = NULL; if (!error) { + uint64_t addr, size; + trace_error = 0; error = read_errno(&c->inp); - - + addr = json_read_uint64(&c->inp); + if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); + size = json_read_uint64(&c->inp); + if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); + if (!error && addr != 0 && size != 0) { + f->address = addr; + f->size = size; + } + trace_cmds_cnt = 0; + if (json_read_array(&c->inp, read_stack_trace_command, NULL)) { + f->fp = (StackTracingCommandSequence *)loc_alloc(sizeof(StackTracingCommandSequence) + (trace_cmds_cnt - 1) * sizeof(StackTracingCommand)); + f->fp->reg = NULL; + f->fp->cmds_cnt = trace_cmds_cnt; + f->fp->cmds_max = trace_cmds_cnt; + memcpy(f->fp->cmds, trace_cmds, trace_cmds_cnt * sizeof(StackTracingCommand)); + } + if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); + trace_regs_cnt = 0; + if (json_read_struct(&c->inp, read_stack_trace_register, NULL)) { + f->regs_cnt = trace_regs_cnt; + f->regs = (StackTracingCommandSequence **)loc_alloc(trace_regs_cnt * sizeof(StackTracingCommandSequence *)); + memcpy(f->regs, trace_regs, trace_regs_cnt * sizeof(StackTracingCommandSequence *)); + } if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); + if (!error && trace_error) error = trace_error; } clear_trap(&trap); } else { error = trap.error; } - f->error = get_error_report(error); + if (get_error_code(error) != ERR_INV_COMMAND) f->error = get_error_report(error); cache_notify(&f->cache); if (f->disposed) free_stack_frame_cache(f); + if (trap.error) exception(trap.error); } int get_next_stack_frame(Context * ctx, StackFrame * frame, StackFrame * down) { @@ -899,6 +1012,7 @@ int get_next_stack_frame(Context * ctx, StackFrame * frame, StackFrame * down) { syms = get_symbols_cache(); for (l = syms->link_frame[h].next; l != syms->link_frame + h; l = l->next) { StackFrameCache * c = syms2frame(l); + /* Here we assume that stack tracing info is valid for all threads in same memory space */ if (c->mem == ctx->mem) { if (c->pending != NULL) { cache_wait(&c->cache); @@ -920,8 +1034,8 @@ int get_next_stack_frame(Context * ctx, StackFrame * frame, StackFrame * down) { f->mem = ctx->mem; f->address = ip; f->size = 1; - f->pending = protocol_send_command(c, "Symbols", "getFrameInfo", validate_frame, f); - json_write_string(&c->out, pid2id(ctx->mem, 0)); + f->pending = protocol_send_command(c, SYMBOLS, "findFrameInfo", validate_frame, f); + json_write_string(&c->out, ctx2id(ctx)); write_stream(&c->out, 0); json_write_uint64(&c->out, ip); write_stream(&c->out, 0); @@ -932,7 +1046,13 @@ int get_next_stack_frame(Context * ctx, StackFrame * frame, StackFrame * down) { else if (f->error != NULL) { exception(set_error_report_errno(f->error)); } - else { + else if (f->fp != NULL) { + int i; + frame->fp = (ContextAddress)evaluate_stack_trace_commands(ctx, frame, f->fp); + for (i = 0; i < f->regs_cnt; i++) { + uint64_t v = evaluate_stack_trace_commands(ctx, frame, f->regs[i]); + if (write_reg_value(f->regs[i]->reg, down, v) < 0) exception(errno); + } } clear_trap(&trap); @@ -980,6 +1100,15 @@ static void flush_syms(Context * ctx, int mode, int keep_pending) { if (c->pid == ctx->pid && (c->pending == NULL || !keep_pending)) free_list_sym_cache(c); } + if ((mode & (1 << UPDATE_ON_MEMORY_MAP_CHANGES)) != 0) { + l = syms->link_frame[i].next; + while (l != syms->link_frame + i) { + StackFrameCache * c = syms2frame(l); + l = l->next; + if (c->mem == ctx->mem && (c->pending == NULL || !keep_pending)) + free_stack_frame_cache(c); + } + } } } } diff --git a/services/symbols_win32.c b/services/symbols_win32.c index f051ce69..c187df02 100644 --- a/services/symbols_win32.c +++ b/services/symbols_win32.c @@ -945,6 +945,11 @@ ContextAddress is_plt_section(Context * ctx, ContextAddress addr) { return 0; } +int get_stack_tracing_info(Context * ctx, ContextAddress addr, StackTracingInfo ** info) { + *info = NULL; + return 0; +} + int get_next_stack_frame(Context * ctx, StackFrame * frame, StackFrame * down) { return 0; } |