Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreutarass2010-04-23 12:56:31 -0400
committereutarass2010-04-23 12:56:31 -0400
commite4fece26f68c8f484856d27e9a4aee1d5c453066 (patch)
treeff6ce5bc48059f67ddff28ce01585cbc829de134 /services
parent68e3e4f97179ba3c67e3fc558542d706a2d9f5aa (diff)
downloadorg.eclipse.tcf.agent-e4fece26f68c8f484856d27e9a4aee1d5c453066.tar.gz
org.eclipse.tcf.agent-e4fece26f68c8f484856d27e9a4aee1d5c453066.tar.xz
org.eclipse.tcf.agent-e4fece26f68c8f484856d27e9a4aee1d5c453066.zip
1. Extended Symbols service to provide stack tracing rules.
2. TCF Agent now can cache and use stack tracing rules that are retrieved from a symbols server.
Diffstat (limited to 'services')
-rw-r--r--services/breakpoints.c1
-rw-r--r--services/dwarfcache.c3
-rw-r--r--services/dwarfexpr.c56
-rw-r--r--services/dwarfframe.c159
-rw-r--r--services/dwarfframe.h25
-rw-r--r--services/linenumbers_proxy.c1
-rw-r--r--services/stacktrace.c224
-rw-r--r--services/stacktrace.h8
-rw-r--r--services/symbols.c96
-rw-r--r--services/symbols.h21
-rw-r--r--services/symbols_elf.c66
-rw-r--r--services/symbols_proxy.c155
-rw-r--r--services/symbols_win32.c5
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->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;
}

Back to the top