Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEugene Tarassov2012-03-11 03:05:33 -0400
committerEugene Tarassov2012-03-11 03:05:33 -0400
commitb2753ee91316e70e6fbe45890b306a4070ace220 (patch)
treebf5faab6e7d78396cb7014782bf45ad6033e9593
parente1182889f1d75a4905ff0acda37a2d6c4d0cbf70 (diff)
downloadorg.eclipse.tcf.agent-b2753ee91316e70e6fbe45890b306a4070ace220.tar.gz
org.eclipse.tcf.agent-b2753ee91316e70e6fbe45890b306a4070ace220.tar.xz
org.eclipse.tcf.agent-b2753ee91316e70e6fbe45890b306a4070ace220.zip
TCF Agent: added support for function call injection.
-rw-r--r--agent/agent.vcproj8
-rw-r--r--agent/system/Windows/tcf/windbgcache.h2
-rw-r--r--agent/tcf/framework/cache.c9
-rw-r--r--agent/tcf/framework/cache.h5
-rw-r--r--agent/tcf/framework/context.h1
-rw-r--r--agent/tcf/framework/cpudefs.c97
-rw-r--r--agent/tcf/framework/cpudefs.h33
-rw-r--r--agent/tcf/main/test.c15
-rw-r--r--agent/tcf/services/breakpoints.h4
-rw-r--r--agent/tcf/services/dwarfframe.c36
-rw-r--r--agent/tcf/services/expressions.c431
-rw-r--r--agent/tcf/services/filesystem.c3
-rw-r--r--agent/tcf/services/funccall.c229
-rw-r--r--agent/tcf/services/funccall.h79
-rw-r--r--agent/tcf/services/memoryservice.c40
-rw-r--r--agent/tcf/services/processes.c18
-rw-r--r--agent/tcf/services/processes.h1
-rw-r--r--agent/tcf/services/registers.c15
-rw-r--r--agent/tcf/services/runctrl.c86
-rw-r--r--agent/tcf/services/runctrl.h18
-rw-r--r--agent/tcf/services/symbols.c10
-rw-r--r--agent/tcf/services/symbols.h5
-rw-r--r--agent/tcf/services/symbols_elf.c83
-rw-r--r--agent/tcf/services/symbols_proxy.c17
-rw-r--r--agent/tcf/services/symbols_win32.c97
-rw-r--r--agent/tcf/services/sysmon.c3
-rw-r--r--server/server.vcproj8
-rw-r--r--tests/cmd-line/cmd-line.vcproj24
-rw-r--r--tests/mem-leaks/agent.vcproj44
-rw-r--r--tests/test-dwarf/dwarf-test.vcproj12
-rw-r--r--tests/test-dwarf/tcf/backend/backend.c34
31 files changed, 1239 insertions, 228 deletions
diff --git a/agent/agent.vcproj b/agent/agent.vcproj
index 527949d2..b0f25595 100644
--- a/agent/agent.vcproj
+++ b/agent/agent.vcproj
@@ -736,6 +736,14 @@
>
</File>
<File
+ RelativePath=".\tcf\services\funccall.c"
+ >
+ </File>
+ <File
+ RelativePath=".\tcf\services\funccall.h"
+ >
+ </File>
+ <File
RelativePath=".\tcf\services\linenumbers.c"
>
</File>
diff --git a/agent/system/Windows/tcf/windbgcache.h b/agent/system/Windows/tcf/windbgcache.h
index 818e742b..1ec53ddf 100644
--- a/agent/system/Windows/tcf/windbgcache.h
+++ b/agent/system/Windows/tcf/windbgcache.h
@@ -204,6 +204,8 @@ enum DataKind {
DataIsConstant
};
+#define CV_CALL_NEAR_C 0x00
+
#define SymInitialize LocSymInitialize
#define SymGetOptions LocSymGetOptions
#define SymSetOptions LocSymSetOptions
diff --git a/agent/tcf/framework/cache.c b/agent/tcf/framework/cache.c
index 14a133c3..2189f7bc 100644
--- a/agent/tcf/framework/cache.c
+++ b/agent/tcf/framework/cache.c
@@ -28,6 +28,7 @@
#include <tcf/framework/cache.h>
typedef struct WaitingCacheClient {
+ unsigned id;
CacheClient * client;
Channel * channel;
void * args;
@@ -39,11 +40,12 @@ typedef struct WaitingCacheClient {
#endif
} WaitingCacheClient;
-static WaitingCacheClient current_client = {0, 0, 0, 0, 0};
+static WaitingCacheClient current_client = {0, 0, 0, 0, 0, 0};
static int client_exited = 0;
static int cache_miss_cnt = 0;
static WaitingCacheClient * wait_list_buf;
static unsigned wait_list_max;
+static unsigned id_cnt = 0;
static LINK cache_list = TCF_LIST_INIT(cache_list);
static void run_cache_client(void) {
@@ -72,6 +74,7 @@ void cache_enter(CacheClient * client, Channel * channel, void * args, size_t ar
assert(channel != NULL);
assert(!is_channel_closed(channel));
assert(current_client.client == NULL);
+ current_client.id = id_cnt++;
current_client.client = client;
current_client.channel = channel;
current_client.args = args;
@@ -148,6 +151,10 @@ Channel * cache_channel(void) {
return current_client.channel;
}
+unsigned cache_transaction_id(void) {
+ return current_client.id;
+}
+
void cache_dispose(AbstractCache * cache) {
assert(is_dispatch_thread());
assert(cache->wait_list_cnt == 0);
diff --git a/agent/tcf/framework/cache.h b/agent/tcf/framework/cache.h
index d73c002a..8c97f8ba 100644
--- a/agent/tcf/framework/cache.h
+++ b/agent/tcf/framework/cache.h
@@ -149,6 +149,11 @@ extern void cache_notify(AbstractCache * cache);
extern Channel * cache_channel(void);
/*
+ * Return unique ID of current cache client transaction.
+ */
+extern unsigned cache_transaction_id(void);
+
+/*
* Dispose a cache.
*/
extern void cache_dispose(AbstractCache * cache);
diff --git a/agent/tcf/framework/context.h b/agent/tcf/framework/context.h
index 2d6fbbfa..498c221c 100644
--- a/agent/tcf/framework/context.h
+++ b/agent/tcf/framework/context.h
@@ -304,6 +304,7 @@ extern int context_continue(Context * ctx);
* Perform single instruction step on the context.
* Return -1 and set errno if the context cannot be single stepped.
* Return 0 on success.
+ * Deprecated: use context_resume(ctx, RM_STEP_INTO, 0, 0).
*/
extern int context_single_step(Context * ctx);
diff --git a/agent/tcf/framework/cpudefs.c b/agent/tcf/framework/cpudefs.c
index 669eda98..4ff13a49 100644
--- a/agent/tcf/framework/cpudefs.c
+++ b/agent/tcf/framework/cpudefs.c
@@ -230,7 +230,7 @@ LocationExpressionState * evaluate_location_expression(Context * ctx, StackFrame
state->stack_frame = frame;
state->args = args;
state->args_cnt = args_cnt;
- for (i = 0; i < cmd_cnt; i++) {
+ for (i = 0; i < cmd_cnt && state->sft_cmd == NULL; i++) {
LocationExpressionCommand * cmd = cmds + i;
if (stk_pos >= stk_max) {
stk_max += 4;
@@ -240,29 +240,50 @@ LocationExpressionState * evaluate_location_expression(Context * ctx, StackFrame
case SFT_CMD_NUMBER:
stk[stk_pos++] = cmd->args.num;
break;
- case SFT_CMD_REGISTER:
+ case SFT_CMD_RD_REG:
if (read_reg_value(frame, cmd->args.reg, stk + stk_pos) < 0) exception(errno);
stk_pos++;
break;
+ case SFT_CMD_WR_REG:
+ if (stk_pos < 1) location_expression_error();
+ if (write_reg_value(frame, cmd->args.reg, *(stk + stk_pos - 1)) < 0) exception(errno);
+ stk_pos--;
+ break;
case SFT_CMD_FP:
if (frame == NULL) str_exception(ERR_INV_CONTEXT, "Invalid stack frame");
stk[stk_pos++] = frame->fp;
break;
- case SFT_CMD_DEREF:
+ case SFT_CMD_RD_MEM:
if (stk_pos < 1) location_expression_error();
{
size_t j;
- size_t size = cmd->args.deref.size;
+ size_t size = cmd->args.mem.size;
uint64_t n = 0;
uint8_t buf[8];
if (context_read_mem(ctx, (ContextAddress)stk[stk_pos - 1], buf, size) < 0) exception(errno);
for (j = 0; j < size; j++) {
- n = (n << 8) | buf[cmd->args.deref.big_endian ? j : size - j - 1];
+ n = (n << 8) | buf[cmd->args.mem.big_endian ? j : size - j - 1];
}
stk[stk_pos - 1] = n;
}
break;
+ case SFT_CMD_WR_MEM:
+ if (stk_pos < 2) location_expression_error();
+ {
+ size_t j;
+ size_t size = cmd->args.mem.size;
+ uint64_t n = stk[stk_pos - 1];
+ uint8_t buf[8];
+
+ for (j = 0; j < size; j++) {
+ buf[cmd->args.mem.big_endian ? size - j - 1 : j] = n & 0xFFu;
+ n >>= 8;
+ }
+ if (context_write_mem(ctx, (ContextAddress)stk[stk_pos - 2], buf, size) < 0) exception(errno);
+ stk_pos -= 2;
+ }
+ break;
case SFT_CMD_ADD:
if (stk_pos < 2) location_expression_error();
stk[stk_pos - 2] = stk[stk_pos - 2] + stk[stk_pos - 1];
@@ -353,6 +374,9 @@ LocationExpressionState * evaluate_location_expression(Context * ctx, StackFrame
stk_pos = state->stk_pos;
stk = state->stk;
break;
+ case SFT_CMD_FCALL:
+ state->sft_cmd = cmd;
+ break;
default:
location_expression_error();
break;
@@ -364,6 +388,69 @@ LocationExpressionState * evaluate_location_expression(Context * ctx, StackFrame
return state;
}
+static void swap_bytes(void * buf, size_t size) {
+ size_t i, j, n;
+ char * p = (char *)buf;
+ n = size >> 1;
+ for (i = 0, j = size - 1; i < n; i++, j--) {
+ char x = p[i];
+ p[i] = p[j];
+ p[j] = x;
+ }
+}
+
+void read_location_peices(Context * ctx, StackFrame * frame,
+ LocationPiece * pieces, unsigned pieces_cnt, int big_endian,
+ void ** value, size_t * size) {
+ unsigned n = 0;
+ uint8_t * bf = NULL;
+ size_t bf_size = 0;
+ unsigned bf_offs = 0;
+ while (n < pieces_cnt) {
+ unsigned i;
+ LocationPiece * piece = pieces + n++;
+ unsigned piece_size = piece->size ? piece->size : (piece->bit_offs + piece->bit_size + 7) / 8;
+ unsigned piece_bits = piece->bit_size ? piece->bit_size : piece->size * 8;
+ uint8_t * pbf = NULL;
+ if (bf_size < bf_offs / 8 + piece_size + 1) {
+ bf_size = bf_offs / 8 + piece_size + 1;
+ bf = (uint8_t *)tmp_realloc(bf, bf_size);
+ }
+ if (piece->reg) {
+ if (piece->reg->size < piece_size) {
+ pbf = (uint8_t *)tmp_alloc_zero(piece_size);
+ }
+ else {
+ pbf = (uint8_t *)tmp_alloc(piece->reg->size);
+ }
+ if (read_reg_bytes(frame, piece->reg, 0, piece->reg->size, pbf) < 0) exception(errno);
+ if (!piece->reg->big_endian != !big_endian) swap_bytes(pbf, piece->reg->size);
+ }
+ else if (piece->value) {
+ pbf = (uint8_t *)piece->value;
+ }
+ else {
+ pbf = (uint8_t *)tmp_alloc(piece_size);
+ if (context_read_mem(ctx, piece->addr, pbf, piece_size) < 0) exception(errno);
+ }
+ for (i = piece->bit_offs; i < piece->bit_offs + piece_bits; i++) {
+ if (pbf[i / 8] & (1u << (i % 8))) {
+ bf[bf_offs / 8] |= (1u << (bf_offs % 8));
+ }
+ else {
+ bf[bf_offs / 8] &= ~(1u << (bf_offs % 8));
+ }
+ bf_offs++;
+ }
+ }
+ while (bf_offs % 8) {
+ bf[bf_offs / 8] &= ~(1u << (bf_offs % 8));
+ bf_offs++;
+ }
+ *value = bf;
+ *size = bf_offs / 8;
+}
+
#if !defined(ENABLE_HardwareBreakpoints) || !ENABLE_HardwareBreakpoints
int cpu_bp_get_capabilities(Context * ctx) {
return 0;
diff --git a/agent/tcf/framework/cpudefs.h b/agent/tcf/framework/cpudefs.h
index d01d8af0..530798cc 100644
--- a/agent/tcf/framework/cpudefs.h
+++ b/agent/tcf/framework/cpudefs.h
@@ -83,9 +83,9 @@ typedef struct RegisterIdScope {
/* Location expression command codes */
#define SFT_CMD_NUMBER 1
-#define SFT_CMD_REGISTER 2
+#define SFT_CMD_RD_REG 2
#define SFT_CMD_FP 3
-#define SFT_CMD_DEREF 4
+#define SFT_CMD_RD_MEM 4
#define SFT_CMD_ADD 5
#define SFT_CMD_SUB 6
#define SFT_CMD_MUL 7
@@ -102,6 +102,14 @@ typedef struct RegisterIdScope {
#define SFT_CMD_SHR 18
#define SFT_CMD_ARG 19
#define SFT_CMD_LOCATION 20 /* A DWARF location expression */
+#define SFT_CMD_FCALL 21
+#define SFT_CMD_WR_REG 22
+#define SFT_CMD_WR_MEM 23
+
+#define SFT_CMD_REGISTER 2 /* Deprecated, use SFT_CMD_RD_REG */
+#define SFT_CMD_DEREF 4 /* Deprecated, use SFT_CMD_RD_MEM */
+
+typedef struct LocationExpressionCommand LocationExpressionCommand;
typedef struct LocationPiece {
ContextAddress addr;
@@ -130,6 +138,7 @@ typedef struct LocationExpressionState {
void (*client_op)(uint8_t op);
/* Result */
+ LocationExpressionCommand * sft_cmd;
LocationPiece * pieces;
unsigned pieces_cnt;
unsigned pieces_max;
@@ -140,7 +149,6 @@ typedef struct LocationExpressionState {
uint64_t * stk;
} LocationExpressionState;
-typedef struct LocationExpressionCommand LocationExpressionCommand;
typedef int LocationExpressionCallback(LocationExpressionState *);
/* Location expression command */
@@ -152,7 +160,11 @@ struct LocationExpressionCommand {
struct {
size_t size;
int big_endian;
- } deref;
+ } deref; /* Deprecated, use .mem */
+ struct {
+ size_t size;
+ int big_endian;
+ } mem;
struct {
LocationExpressionCallback * func;
RegisterIdScope reg_id_scope;
@@ -232,11 +244,16 @@ extern uint8_t * get_break_instruction(Context * ctx, size_t * size);
*/
extern int crawl_stack_frame(StackFrame * frame, StackFrame * down);
-/* Execute location expression */
-extern LocationExpressionState * evaluate_location_expression(Context * ctx, StackFrame * frame,
- LocationExpressionCommand * cmds, unsigned cmds_cnt,
- uint64_t * args, unsigned args_cnt);
+/* Execute location expression. Throw an exception if error. */
+extern LocationExpressionState * evaluate_location_expression(
+ Context * ctx, StackFrame * frame,
+ LocationExpressionCommand * cmds, unsigned cmds_cnt,
+ uint64_t * args, unsigned args_cnt);
+extern void read_location_peices(
+ Context * ctx, StackFrame * frame,
+ LocationPiece * pieces, unsigned pieces_cnt, int big_endian,
+ void ** value, size_t * size);
/*** CPU hardware breakpoints API ***/
diff --git a/agent/tcf/main/test.c b/agent/tcf/main/test.c
index 865682b4..74ca2a81 100644
--- a/agent/tcf/main/test.c
+++ b/agent/tcf/main/test.c
@@ -103,6 +103,9 @@ typedef struct test_struct {
typedef int test_array[10001];
+extern int tcf_test_func_int(int x, int y);
+extern long tcf_test_func_long(long x, long y);
+extern double tcf_test_func_double(double x, double y);
extern void tcf_test_func3(void);
extern int tcf_test_func2(void);
extern void tcf_test_func1(void);
@@ -113,6 +116,18 @@ char tcf_test_char = 0;
short tcf_test_short = 0;
long tcf_test_long = 0;
+int tcf_test_func_int(int x, int y) {
+ return x + y;
+}
+
+long tcf_test_func_long(long x, long y) {
+ return x + y;
+}
+
+double tcf_test_func_double(double x, double y) {
+ return x + y;
+}
+
void tcf_test_func3(void) {
tcf_test_char++;
usleep(1000);
diff --git a/agent/tcf/services/breakpoints.h b/agent/tcf/services/breakpoints.h
index 1fd99a71..c7f7043b 100644
--- a/agent/tcf/services/breakpoints.h
+++ b/agent/tcf/services/breakpoints.h
@@ -189,6 +189,8 @@ extern BreakpointInfo * create_eventpoint(const char * location, Context * ctx,
/* Unplant and destroy eventpoint */
extern void destroy_eventpoint(BreakpointInfo * eventpoint);
+extern void ini_breakpoints_service(Protocol *, TCFBroadcastGroup *);
+
#else /* SERVICE_Breakpoints */
#define skip_breakpoint(ctx, single_step) 0
@@ -201,6 +203,4 @@ extern void destroy_eventpoint(BreakpointInfo * eventpoint);
#endif /* SERVICE_Breakpoints */
-extern void ini_breakpoints_service(Protocol *, TCFBroadcastGroup *);
-
#endif /* D_breakpoints */
diff --git a/agent/tcf/services/dwarfframe.c b/agent/tcf/services/dwarfframe.c
index 05b9ae45..8d5a42fa 100644
--- a/agent/tcf/services/dwarfframe.c
+++ b/agent/tcf/services/dwarfframe.c
@@ -464,16 +464,16 @@ static void add_dwarf_expression_commands(U8_T cmds_offs, U4_T cmds_size) {
break;
case OP_deref:
{
- LocationExpressionCommand * cmd = add_command(SFT_CMD_DEREF);
- cmd->args.deref.size = rules.address_size;
- cmd->args.deref.big_endian = rules.reg_id_scope.big_endian;
+ LocationExpressionCommand * cmd = add_command(SFT_CMD_RD_MEM);
+ cmd->args.mem.size = rules.address_size;
+ cmd->args.mem.big_endian = rules.reg_id_scope.big_endian;
}
break;
case OP_deref_size:
{
- LocationExpressionCommand * cmd = add_command(SFT_CMD_DEREF);
- cmd->args.deref.size = dio_ReadU1();
- cmd->args.deref.big_endian = rules.reg_id_scope.big_endian;
+ LocationExpressionCommand * cmd = add_command(SFT_CMD_RD_MEM);
+ cmd->args.mem.size = dio_ReadU1();
+ cmd->args.mem.big_endian = rules.reg_id_scope.big_endian;
}
break;
case OP_const1u:
@@ -607,7 +607,7 @@ static void add_dwarf_expression_commands(U8_T cmds_offs, U4_T cmds_size) {
I8_T offs = dio_ReadS8LEB128();
RegisterDefinition * def = get_reg_by_id(rules.ctx, op - OP_breg0, &rules.reg_id_scope);
if (def == NULL) str_exception(errno, "Cannot read DWARF frame info");
- add_command(SFT_CMD_REGISTER)->args.reg = def;
+ add_command(SFT_CMD_RD_REG)->args.reg = def;
if (offs != 0) {
add_command(SFT_CMD_NUMBER)->args.num = offs;
add_command(SFT_CMD_ADD);
@@ -635,20 +635,20 @@ static void generate_register_commands(RegisterRules * reg, RegisterDefinition *
add_command(SFT_CMD_ADD);
}
if (reg->rule == RULE_OFFSET) {
- LocationExpressionCommand * cmd = add_command(SFT_CMD_DEREF);
- cmd->args.deref.size = dst_reg_def->size;
- if (cmd->args.deref.size > rules.address_size) cmd->args.deref.size = rules.address_size;
- cmd->args.deref.big_endian = rules.reg_id_scope.big_endian;
+ LocationExpressionCommand * cmd = add_command(SFT_CMD_RD_MEM);
+ cmd->args.mem.size = dst_reg_def->size;
+ if (cmd->args.mem.size > rules.address_size) cmd->args.mem.size = rules.address_size;
+ cmd->args.mem.big_endian = rules.reg_id_scope.big_endian;
}
break;
case RULE_SAME_VALUE:
if (src_reg_def == NULL) return;
- add_command(SFT_CMD_REGISTER)->args.reg = src_reg_def;
+ add_command(SFT_CMD_RD_REG)->args.reg = src_reg_def;
break;
case RULE_REGISTER:
{
RegisterDefinition * src_sef = get_reg_by_id(rules.ctx, reg->offset, &rules.reg_id_scope);
- if (src_sef != NULL) add_command(SFT_CMD_REGISTER)->args.reg = src_sef;
+ if (src_sef != NULL) add_command(SFT_CMD_RD_REG)->args.reg = src_sef;
}
break;
case RULE_EXPRESSION:
@@ -656,10 +656,10 @@ static void generate_register_commands(RegisterRules * reg, RegisterDefinition *
add_command(SFT_CMD_FP);
add_dwarf_expression_commands(reg->expression, reg->offset);
if (reg->rule == RULE_EXPRESSION) {
- LocationExpressionCommand * cmd = add_command(SFT_CMD_DEREF);
- cmd->args.deref.size = dst_reg_def->size;
- if (cmd->args.deref.size > rules.address_size) cmd->args.deref.size = rules.address_size;
- cmd->args.deref.big_endian = rules.reg_id_scope.big_endian;
+ LocationExpressionCommand * cmd = add_command(SFT_CMD_RD_MEM);
+ cmd->args.mem.size = dst_reg_def->size;
+ if (cmd->args.mem.size > rules.address_size) cmd->args.mem.size = rules.address_size;
+ cmd->args.mem.big_endian = rules.reg_id_scope.big_endian;
}
break;
default:
@@ -699,7 +699,7 @@ static void generate_commands(void) {
case RULE_OFFSET:
reg_def = get_reg_by_id(rules.ctx, rules.cfa_register, &rules.reg_id_scope);
if (reg_def != NULL) {
- add_command(SFT_CMD_REGISTER)->args.reg = reg_def;
+ add_command(SFT_CMD_RD_REG)->args.reg = reg_def;
if (rules.cfa_offset != 0) {
add_command(SFT_CMD_NUMBER)->args.num = rules.cfa_offset;
add_command(SFT_CMD_ADD);
diff --git a/agent/tcf/services/expressions.c b/agent/tcf/services/expressions.c
index a2a5843d..a36a4bb1 100644
--- a/agent/tcf/services/expressions.c
+++ b/agent/tcf/services/expressions.c
@@ -38,12 +38,16 @@
#include <tcf/framework/exceptions.h>
#include <tcf/framework/json.h>
#include <tcf/framework/cache.h>
+#include <tcf/framework/trace.h>
#include <tcf/framework/context.h>
+#include <tcf/services/runctrl.h>
#include <tcf/services/symbols.h>
+#include <tcf/services/funccall.h>
#include <tcf/services/stacktrace.h>
-#include <tcf/services/expressions.h>
#include <tcf/services/memoryservice.h>
+#include <tcf/services/breakpoints.h>
#include <tcf/services/registers.h>
+#include <tcf/services/expressions.h>
#include <tcf/main/test.h>
#define SY_LEQ 256
@@ -94,6 +98,49 @@ static Context * expression_context = NULL;
static int expression_frame = STACK_NO_FRAME;
static ContextAddress expression_addr = 0;
+#ifndef ENABLE_FuncCallInjection
+# define ENABLE_FuncCallInjection (ENABLE_Symbols && SERVICE_RunControl && SERVICE_Breakpoints && ENABLE_DebugContext)
+#endif
+
+#if ENABLE_FuncCallInjection
+typedef struct FuncCallState {
+ struct FuncCallState * next;
+ unsigned id; /* ACPM transaction ID */
+ int pos; /* Text position in the expression */
+ int started; /* Target has started to execute the function call */
+ int intercepted; /* Intercepted during or after the function call */
+ int committed; /* ACPM transaction finished */
+ int finished; /* Target has finished the function call */
+ Context * ctx;
+ ContextAddress func_addr;
+ AbstractCache cache;
+ BreakpointInfo * bp;
+ RunControlEventListener rc_listener;
+ ErrorReport * error;
+
+ /* Actual arguments */
+ Value * args;
+ unsigned args_cnt;
+ unsigned args_max;
+
+ /* Returned value */
+ void * ret_value;
+ size_t ret_size;
+ int ret_big_endian;
+
+ /* After call commands */
+ LocationExpressionCommand * cmds;
+ unsigned cmds_cnt;
+
+ /* Saved registers */
+ RegisterDefinition ** regs;
+ unsigned regs_cnt;
+ uint8_t * regs_data;
+} FuncCallState;
+
+static FuncCallState * func_call_state = NULL;
+#endif /* ENABLE_FuncCallInjection */
+
#define MAX_ID_CALLBACKS 8
static ExpressionIdentifierCallBack * id_callbacks[MAX_ID_CALLBACKS];
static int id_callback_cnt = 0;
@@ -670,13 +717,14 @@ static int sym2value(int mode, Symbol * sym, Value * v) {
case SYM_CLASS_FUNCTION:
{
ContextAddress word = 0;
- v->type_class = TYPE_CLASS_CARDINAL;
+ v->type_class = TYPE_CLASS_POINTER;
if (v->type != NULL) get_array_symbol(v->type, 0, &v->type);
if (mode == MODE_NORMAL && get_symbol_address(sym, &word) < 0) {
error(errno, "Cannot retrieve symbol address");
}
set_ctx_word_value(v, word);
v->function = 1;
+ v->sym = sym;
}
break;
default:
@@ -1297,17 +1345,17 @@ static void evaluate_symbol_address(Symbol * sym, ContextAddress obj_addr, Conte
else {
LocationExpressionState * state = NULL;
LocationInfo * loc_info = NULL;
- StackFrame * stk_info = NULL;
+ StackFrame * frame_info = NULL;
uint64_t args[2];
args[0] = obj_addr;
args[1] = index;
if (get_location_info(sym, &loc_info) < 0) {
error(errno, "Cannot get symbol location expression");
}
- if (expression_frame != STACK_NO_FRAME && get_frame_info(expression_context, expression_frame, &stk_info) < 0) {
+ if (expression_frame != STACK_NO_FRAME && get_frame_info(expression_context, expression_frame, &frame_info) < 0) {
error(errno, "Cannot get stack frame info");
}
- state = evaluate_location_expression(expression_context, stk_info, loc_info->cmds, loc_info->cmds_cnt, args, 2);
+ state = evaluate_location_expression(expression_context, frame_info, loc_info->cmds, loc_info->cmds_cnt, args, 2);
if (state->stk_pos != 1) error(ERR_INV_EXPRESSION, "Cannot evaluate symbol address");
*addr = (ContextAddress)state->stk[0];
}
@@ -1371,11 +1419,12 @@ static void op_field(int mode, Value * v) {
error(errno, "Cannot retrieve symbol class");
}
if (sym_class == SYM_CLASS_FUNCTION) {
- v->type_class = TYPE_CLASS_CARDINAL;
get_symbol_type(sym, &v->type);
+ v->type_class = TYPE_CLASS_POINTER;
if (v->type != NULL) get_array_symbol(v->type, 0, &v->type);
set_ctx_word_value(v, addr);
v->function = 1;
+ v->sym = sym;
}
else {
ContextAddress size = 0;
@@ -1487,8 +1536,7 @@ static void op_index(int mode, Value * v) {
static void op_addr(int mode, Value * v) {
if (mode == MODE_SKIP) return;
if (v->function) {
- v->type_class = TYPE_CLASS_POINTER;
- v->function = 0;
+ assert(v->type_class == TYPE_CLASS_POINTER);
}
else {
if (!v->remote) error(ERR_INV_EXPRESSION, "Invalid '&': value has no address");
@@ -1548,6 +1596,281 @@ static void op_sizeof(int mode, Value * v) {
}
}
+static void funccall_error(const char * msg) {
+ set_errno(ERR_OTHER, msg);
+ set_errno(errno, "Cannot inject a function call");
+ exception(errno);
+}
+
+#if ENABLE_FuncCallInjection
+
+static void free_funccall_state(FuncCallState * state) {
+ assert(!state->started || state->intercepted);
+ assert(state->committed);
+ assert(state->regs_cnt == 0 || state->error);
+ if (state->bp) destroy_eventpoint(state->bp);
+ context_unlock(state->ctx);
+ rem_run_control_event_listener(&state->rc_listener);
+ release_error_report(state->error);
+ loc_free(state->ret_value);
+ loc_free(state->args);
+ loc_free(state->cmds);
+ loc_free(state->regs);
+ loc_free(state);
+}
+
+static void funcccall_breakpoint(Context * ctx, void * args) {
+ Trap trap;
+ FuncCallState * state = (FuncCallState *)args;
+ assert(state->ctx == ctx);
+ assert(state->started);
+ assert(!state->finished);
+ if (set_trap(&trap)) {
+ if (!state->intercepted && state->cmds_cnt > 0) {
+ /* Execute after call commands */
+ StackFrame * frame_info = NULL;
+ LocationExpressionState * vm = NULL;
+ if (get_frame_info(ctx, STACK_TOP_FRAME, &frame_info) < 0) exception(errno);
+ vm = evaluate_location_expression(ctx, frame_info,
+ state->cmds, state->cmds_cnt, NULL, 0);
+ state->cmds_cnt = 0;
+
+ /* Read function call returned value */
+ if (vm->pieces_cnt > 0) {
+ void * value = NULL;
+ read_location_peices(ctx, frame_info, vm->pieces, vm->pieces_cnt,
+ state->ret_big_endian, &value, &state->ret_size);
+ state->ret_value = loc_alloc_zero(state->ret_size);
+ memcpy(state->ret_value, value, state->ret_size);
+ }
+ else if (vm->stk_pos > 0) {
+ state->ret_size = sizeof(uint64_t);
+ state->ret_value = loc_alloc_zero(state->ret_size);
+ memcpy(state->ret_value, vm->stk + vm->stk_pos - 1, state->ret_size);
+ }
+ }
+ if (state->regs_cnt > 0) {
+ /* Restore registers */
+ unsigned i;
+ unsigned offs = 0;
+ for (i = 0; i < state->regs_cnt; i++) {
+ RegisterDefinition * r = state->regs[i];
+ if (context_write_reg(ctx, r, 0, r->size, state->regs_data + offs) < 0) exception(errno);
+ send_event_register_changed(register2id(ctx, STACK_TOP_FRAME, r));
+ offs += r->size;
+ }
+ state->regs_cnt = 0;
+ }
+ clear_trap(&trap);
+ }
+ else {
+ release_error_report(state->error);
+ state->error = get_error_report(trap.error);
+ }
+ if (!state->intercepted) {
+ assert(!state->finished);
+ state->finished = 1;
+ suspend_debug_context(ctx);
+ }
+ else if (state->committed) {
+ if (state->error) trace(LOG_ALWAYS, "Cannot restore state",
+ errno_to_str(set_error_report_errno(state->error)));
+ free_funccall_state(state);
+ }
+}
+
+static void funccall_intercepted(Context * ctx, void * args) {
+ FuncCallState * state = (FuncCallState *)args;
+ if (!state->intercepted) {
+ state->intercepted = 1;
+ if (!state->finished && state->error == NULL) {
+ state->error = get_error_report(set_errno(ERR_OTHER,
+ "Intercepted while executing injected function call"));
+ }
+ cache_notify(&state->cache);
+ }
+}
+
+static void funccall_check_recursion(ContextAddress func_addr) {
+ FuncCallState * state = func_call_state;
+ while (state != NULL) {
+ if (state->started && !state->finished &&
+ state->ctx == expression_context && state->func_addr == func_addr) {
+ funccall_error("Recursive invocation");
+ }
+ state = state->next;
+ }
+}
+
+static void op_call(int mode, Value * v) {
+ unsigned id = cache_transaction_id();
+ FuncCallState * state = func_call_state;
+ Symbol * func = NULL;
+ int type_class = 0;
+
+ if (!context_has_state(expression_context)) funccall_error("Context is not a thread");
+ if (!expression_context->stopped) funccall_error("Context is running");
+ if (is_safe_event()) funccall_error("Called from safe event handler");
+
+ while (state != NULL && (state->id != id || state->pos != text_pos)) state = state->next;
+ if (state != NULL && state->started && !state->intercepted) cache_wait(&state->cache);
+ if (state == NULL) {
+ state = (FuncCallState *)loc_alloc_zero(sizeof(FuncCallState));
+ state->next = func_call_state;
+ state->id = id;
+ state->pos = text_pos;
+ context_lock(state->ctx = expression_context);
+ func_call_state = state;
+ }
+ if (v->function) {
+ func = v->sym;
+ }
+ else if (v->type != NULL && v->type_class == TYPE_CLASS_POINTER) {
+ if (get_symbol_base_type(v->type, &func) < 0) {
+ error(errno, "Cannot retrieve symbol base type");
+ }
+ }
+ if (func != NULL && get_symbol_type_class(func, &type_class) < 0) {
+ error(errno, "Cannot retrieve symbol type class");
+ }
+ if (type_class != TYPE_CLASS_FUNCTION) {
+ error(ERR_INV_EXPRESSION, "Invalid '()': not a function");
+ }
+ if (get_symbol_address(func, &state->func_addr) < 0) {
+ error(errno, "Cannot retrieve function address");
+ }
+ state->args_cnt = 0;
+ if (state->args_max) memset(state->args, 0, sizeof(Value) * state->args_max);
+ if (text_sy != ')') {
+ int args_mode = mode;
+ if (state->started) args_mode = MODE_SKIP;
+ for (;;) {
+ if (state->args_cnt >= state->args_max) {
+ state->args_max += 8;
+ state->args = (Value *)loc_realloc(state->args, sizeof(Value) * state->args_max);
+ }
+ expression(args_mode, state->args + state->args_cnt++);
+ if (text_sy != ',') break;
+ next_sy();
+ }
+ }
+ if (get_symbol_base_type(func, &v->type) < 0) {
+ error(errno, "Cannot retrieve function return type");
+ }
+ if (get_symbol_type_class(v->type, &v->type_class) < 0) {
+ error(errno, "Cannot retrieve function return type class");
+ }
+ if (get_symbol_size(v->type, &v->size) < 0) {
+ error(errno, "Cannot retrieve function return value size");
+ }
+ if (mode == MODE_NORMAL) {
+ if (!state->started) {
+ unsigned i;
+ StackFrame * frame_info = NULL;
+ FunctionCallInfo * call_info = NULL;
+ LocationExpressionState * vm = NULL;
+ const Symbol ** arg_types = (const Symbol **)tmp_alloc_zero(sizeof(Symbol *) * state->args_cnt);
+ uint64_t * arg_vals = (uint64_t *)tmp_alloc_zero(sizeof(uint64_t) * state->args_cnt);
+
+ funccall_check_recursion(state->func_addr);
+ for (i = 0; i < state->args_cnt; i++) arg_types[i] = state->args[i].type;
+ if (get_funccall_info(func, arg_types, state->args_cnt, &call_info) < 0) exception(errno);
+ if (get_frame_info(expression_context, STACK_TOP_FRAME, &frame_info) < 0) exception(errno);
+
+ /* Save registers */
+ if (call_info->saveregs_cnt > 0) {
+ unsigned offs = 0;
+ for (i = 0; i < call_info->saveregs_cnt; i++) offs += call_info->saveregs[i]->size;
+ state->regs = (RegisterDefinition **)loc_alloc(sizeof(RegisterDefinition *) * call_info->saveregs_cnt);
+ state->regs_data = (uint8_t *)loc_alloc_zero(offs);
+ state->regs_cnt = call_info->saveregs_cnt;
+ offs = 0;
+ for (i = 0; i < call_info->saveregs_cnt; i++) {
+ RegisterDefinition * r = call_info->saveregs[i];
+ state->regs[i] = r;
+ if (context_read_reg(expression_context, r, 0, r->size, state->regs_data + offs) < 0) exception(errno);
+ offs += r->size;
+ }
+ }
+
+ /* get values of actual arguments */
+ for (i = 0; i < state->args_cnt; i++) {
+ Value * v = state->args + i;
+ switch (v->type_class) {
+ case TYPE_CLASS_CARDINAL:
+ case TYPE_CLASS_INTEGER:
+ case TYPE_CLASS_POINTER:
+ case TYPE_CLASS_ENUMERATION:
+ arg_vals[i] = to_uns(MODE_NORMAL, v);
+ break;
+ case TYPE_CLASS_ARRAY:
+ case TYPE_CLASS_COMPOSITE:
+ if (!v->remote) funccall_error("Invalid argument type");
+ arg_vals[i] = v->address;
+ break;
+ default:
+ funccall_error("Invalid argument type");
+ break;
+ }
+ }
+
+ /* Execute call injection commands */
+ state->started = 1;
+ vm = evaluate_location_expression(expression_context, frame_info,
+ call_info->cmds, call_info->cmds_cnt, arg_vals, state->args_cnt);
+ state->ret_big_endian = call_info->scope.big_endian;
+ if (vm->sft_cmd != NULL) {
+ char ret_addr[64];
+ uint64_t pc = 0;
+ RegisterDefinition * reg_pc = get_PC_definition(expression_context);
+ if (vm->sft_cmd->cmd != SFT_CMD_FCALL || vm->stk_pos != 0) {
+ funccall_error("Invalid SFT instruction");
+ }
+
+ /* Create breakpoint at current PC - function return address */
+ assert(state->bp == NULL);
+ if (read_reg_value(frame_info, reg_pc, &pc) < 0) exception(errno);
+ snprintf(ret_addr, sizeof(ret_addr), "0x%" PRIX64, pc);
+ state->bp = create_eventpoint(ret_addr, expression_context, funcccall_breakpoint, state);
+
+ /* Set PC to the function address */
+ if (write_reg_value(frame_info, reg_pc, state->func_addr) < 0) exception(errno);
+ expression_context->stopped_by_bp = 0;
+
+ /* Save rest of func call commands to be executed after the function returns */
+ state->cmds_cnt = call_info->cmds_cnt - (vm->sft_cmd - call_info->cmds) - 1;
+ state->cmds = (LocationExpressionCommand *)loc_alloc(sizeof(LocationExpressionCommand) * state->cmds_cnt);
+ memcpy(state->cmds, vm->sft_cmd + 1, sizeof(LocationExpressionCommand) * state->cmds_cnt);
+
+ /* Resume debug context */
+ if (continue_debug_context(expression_context, cache_channel(), RM_RESUME, 1, 0, 0) < 0) exception(errno);
+
+ /* Wait until the function returns */
+ state->rc_listener.context_intercepted = funccall_intercepted;
+ add_run_control_event_listener(&state->rc_listener, state);
+ cache_wait(&state->cache);
+ }
+ else {
+ state->finished = 1;
+ }
+ }
+ assert(state->started);
+ assert(state->intercepted);
+ if (state->error) exception(set_error_report_errno(state->error));
+ set_value(v, state->ret_value, state->ret_size, state->ret_big_endian);
+ }
+ else {
+ set_value(v, NULL, (size_t)v->size, 0);
+ }
+}
+
+#else
+
+static void op_call(int mode, Value * v) {
+ funccall_error("Symbols service not available");
+}
+
+#endif /* ENABLE_FuncCallInjection */
static void postfix_expression(int mode, Value * v) {
primary_expression(mode, v);
@@ -1569,6 +1892,14 @@ static void postfix_expression(int mode, Value * v) {
op_deref(mode, v);
op_field(mode, v);
}
+ else if (text_sy == '(') {
+ next_sy();
+ op_call(mode, v);
+ if (text_sy != ')') {
+ error(ERR_INV_EXPRESSION, "')' expected");
+ }
+ next_sy();
+ }
else {
break;
}
@@ -1873,6 +2204,14 @@ static void additive_expression(int mode, Value * v) {
next_sy();
multiplicative_expression(mode, &x);
if (mode != MODE_SKIP) {
+ if (v->function) {
+ v->type_class = TYPE_CLASS_CARDINAL;
+ v->type = NULL;
+ }
+ if (x.function) {
+ x.type_class = TYPE_CLASS_CARDINAL;
+ x.type = NULL;
+ }
if (sy == '+' && v->type_class == TYPE_CLASS_ARRAY && x.type_class == TYPE_CLASS_ARRAY) {
if (mode == MODE_TYPE) {
v->remote = 0;
@@ -1897,7 +2236,7 @@ static void additive_expression(int mode, Value * v) {
Symbol * base = NULL;
ContextAddress size = 0;
if (v->type == NULL || get_symbol_base_type(v->type, &base) < 0 ||
- base == 0 || get_symbol_size(base, &size) < 0 || size == 0) {
+ base == NULL || get_symbol_size(base, &size) < 0 || size == 0) {
error(ERR_INV_EXPRESSION, "Unknown pointer base type size");
}
switch (sy) {
@@ -1918,7 +2257,7 @@ static void additive_expression(int mode, Value * v) {
Symbol * base = NULL;
ContextAddress size = 0;
if (x.type == NULL || get_symbol_base_type(x.type, &base) < 0 ||
- base == 0 || get_symbol_size(base, &size) < 0 || size == 0) {
+ base == NULL || get_symbol_size(base, &size) < 0 || size == 0) {
error(ERR_INV_EXPRESSION, "Unknown pointer base type size");
}
value = to_uns(mode, &x) + to_uns(mode, v) * size;
@@ -2234,42 +2573,64 @@ static void expression(int mode, Value * v) {
conditional_expression(mode, v);
}
-static int evaluate_type(Context * ctx, int frame, ContextAddress addr, char * s, Value * v) {
+static int evaluate_script(int mode, char * s, int load, Value * v) {
Trap trap;
+ if (set_trap(&trap)) {
+ if (s == NULL || *s == 0) str_exception(ERR_INV_EXPRESSION, "Empty expression");
+ text = s;
+ text_pos = 0;
+ text_len = strlen(s) + 1;
+ next_ch();
+ next_sy();
+ expression(mode, v);
+ if (text_sy != 0) error(ERR_INV_EXPRESSION, "Illegal characters at the end of expression");
+ if (load) load_value(v);
+ clear_trap(&trap);
+ }
+
+#if ENABLE_FuncCallInjection
+ if (get_error_code(trap.error) != ERR_CACHE_MISS) {
+ unsigned id = cache_transaction_id();
+ FuncCallState * n = func_call_state;
+ FuncCallState * p = NULL;
+ while (n != NULL) {
+ if (n->id == id) {
+ FuncCallState * x = n;
+ n = n->next;
+ if (p != NULL) p->next = n;
+ else func_call_state = n;
+ x->committed = 1;
+ if (x->regs_cnt == 0) free_funccall_state(x);
+ }
+ else {
+ p = n;
+ n = p->next;
+ }
+ }
+ }
+#endif /* ENABLE_FuncCallInjection */
+
+ if (trap.error) {
+ errno = trap.error;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int evaluate_type(Context * ctx, int frame, ContextAddress addr, char * s, Value * v) {
expression_context = ctx;
expression_frame = frame;
expression_addr = addr;
- if (!set_trap(&trap)) return -1;
- text = s;
- text_pos = 0;
- text_len = strlen(s) + 1;
- next_ch();
- next_sy();
- expression(MODE_TYPE, v);
- if (text_sy != 0) error(ERR_INV_EXPRESSION, "Illegal characters at the end of expression");
- clear_trap(&trap);
- return 0;
+ return evaluate_script(MODE_TYPE, s, 0, v);
}
int evaluate_expression(Context * ctx, int frame, ContextAddress addr, char * s, int load, Value * v) {
- Trap trap;
-
expression_context = ctx;
expression_frame = frame;
expression_addr = addr;
- if (!set_trap(&trap)) return -1;
- if (s == NULL || *s == 0) str_exception(ERR_INV_EXPRESSION, "Empty expression");
- text = s;
- text_pos = 0;
- text_len = strlen(s) + 1;
- next_ch();
- next_sy();
- expression(MODE_NORMAL, v);
- if (text_sy != 0) error(ERR_INV_EXPRESSION, "Illegal characters at the end of expression");
- if (load) load_value(v);
- clear_trap(&trap);
- return 0;
+ return evaluate_script(MODE_NORMAL, s, load, v);
}
int value_to_boolean(Value * v, int * res) {
diff --git a/agent/tcf/services/filesystem.c b/agent/tcf/services/filesystem.c
index bf6127ad..42a26d68 100644
--- a/agent/tcf/services/filesystem.c
+++ b/agent/tcf/services/filesystem.c
@@ -1221,6 +1221,9 @@ static void command_copy(char * token, Channel * c) {
if (err == 0 && copy_perms && chmod(dst, st.st_mode) < 0) err = errno;
#if !defined(_WIN32) && !defined(_WRS_KERNEL)
if (err == 0 && copy_uidgid && chown(dst, st.st_uid, st.st_gid) < 0) err = errno;
+#else
+ /* disable "set but not used" warning */
+ (void)copy_uidgid;
#endif
write_stringz(&c->out, "R");
diff --git a/agent/tcf/services/funccall.c b/agent/tcf/services/funccall.c
new file mode 100644
index 00000000..565ac3bf
--- /dev/null
+++ b/agent/tcf/services/funccall.c
@@ -0,0 +1,229 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module implements preparation of a new stack before calling a function.
+ * This code is a stub. Downstream code will provide real implementation.
+ */
+
+#include <tcf/config.h>
+
+#if ENABLE_Symbols && ENABLE_DebugContext
+
+#include <assert.h>
+#include <tcf/framework/myalloc.h>
+#include <tcf/framework/cpudefs.h>
+#include <tcf/services/funccall.h>
+#if defined(_WIN32)
+#include <system/Windows/tcf/windbgcache.h>
+#endif
+
+static FunctionCallInfo * info = NULL;
+
+static unsigned trace_cmds_max = 0;
+static unsigned trace_cmds_cnt = 0;
+static LocationExpressionCommand * trace_cmds = NULL;
+
+static LocationExpressionCommand * add_command(int op) {
+ LocationExpressionCommand * cmd = NULL;
+ if (trace_cmds_cnt >= trace_cmds_max) {
+ trace_cmds_max += 16;
+ trace_cmds = (LocationExpressionCommand *)tmp_realloc(trace_cmds, trace_cmds_max * sizeof(LocationExpressionCommand));
+ }
+ cmd = trace_cmds + trace_cmds_cnt++;
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->cmd = op;
+ if (op == SFT_CMD_RD_MEM || op == SFT_CMD_WR_MEM) {
+ cmd->args.mem.big_endian = info->scope.big_endian;
+ }
+ return cmd;
+}
+
+#if 0 /* Not used */
+static LocationExpressionCommand * add_command_location(uint8_t * code, size_t code_size) {
+ LocationExpressionCommand * cmd = NULL;
+ cmd = add_command(SFT_CMD_LOCATION);
+ cmd->args.loc.code_addr = code;
+ cmd->args.loc.code_size = code_size;
+ cmd->args.loc.reg_id_scope = info->scope;
+ cmd->args.loc.addr_size = info->scope.elf64? 64 : 32;
+ return cmd;
+}
+#endif
+
+static int get_stack_pointer_register_id(void) {
+ switch (info->scope.machine) {
+ case 3: /* EM_386 */
+ return 4;
+ case 62: /* EM_X86_64 */
+ return 7;
+ }
+ return -1;
+}
+
+static int get_return_value_register_id(void) {
+ switch (info->scope.machine) {
+ case 3: /* EM_386 */
+ return 0;
+ case 62: /* EM_X86_64 */
+ return 0;
+ }
+ return -1;
+}
+
+static RegisterDefinition * find_register(int id) {
+ if (id < 0) return NULL;
+ return get_reg_by_id(info->ctx, id, &info->scope);
+}
+
+static int c_call_cmds(void) {
+ unsigned i;
+ unsigned sp_offs = 0;
+ unsigned word_size = info->scope.elf64 ? 8 : 4;
+ Symbol * res_type = NULL;
+ ContextAddress res_size = 0;
+ int res_type_class = 0;
+
+ RegisterDefinition * reg_rv = find_register(get_return_value_register_id());
+ RegisterDefinition * reg_sp = find_register(get_stack_pointer_register_id());
+ RegisterDefinition * reg_pc = get_PC_definition(info->ctx);
+
+ if (reg_sp == NULL) {
+ set_errno(ERR_OTHER, "Don't know stack pointer register");
+ return -1;
+ }
+ if (reg_pc == NULL) {
+ set_errno(ERR_OTHER, "Don't know instruction pointer register");
+ return -1;
+ }
+
+ for (i = 0; i < info->args_cnt; i++) {
+ const Symbol * s = info->args[info->args_cnt - i - 1];
+ int type_class = TYPE_CLASS_INTEGER;
+ /* If argument type is not given, assume 'int' */
+ if (s != NULL && get_symbol_type_class(s, &type_class) < 0) return -1;
+ switch (type_class) {
+ case TYPE_CLASS_CARDINAL:
+ case TYPE_CLASS_INTEGER:
+ case TYPE_CLASS_POINTER:
+ case TYPE_CLASS_ENUMERATION:
+ case TYPE_CLASS_ARRAY:
+ case TYPE_CLASS_COMPOSITE:
+ case TYPE_CLASS_FUNCTION:
+ /* Argument is one word, push it to the stack */
+ sp_offs += word_size;
+ add_command(SFT_CMD_RD_REG)->args.reg = reg_sp;
+ add_command(SFT_CMD_NUMBER)->args.num = sp_offs;
+ add_command(SFT_CMD_SUB);
+ add_command(SFT_CMD_ARG)->args.arg_no = info->args_cnt - i - 1;
+ add_command(SFT_CMD_WR_MEM)->args.mem.size = word_size;
+ break;
+ case TYPE_CLASS_REAL:
+ case TYPE_CLASS_MEMBER_PTR:
+ default:
+ set_errno(ERR_OTHER, "Unsupported argument type");
+ return -1;
+ }
+ }
+
+ /* Push current PC to the stack as return address */
+ sp_offs += reg_pc->size;
+ add_command(SFT_CMD_RD_REG)->args.reg = reg_sp;
+ add_command(SFT_CMD_NUMBER)->args.num = sp_offs;
+ add_command(SFT_CMD_SUB);
+ add_command(SFT_CMD_RD_REG)->args.reg = reg_pc;
+ add_command(SFT_CMD_WR_MEM)->args.mem.size = reg_pc->size;
+
+ /* Update stack pointer register */
+ add_command(SFT_CMD_RD_REG)->args.reg = reg_sp;
+ add_command(SFT_CMD_NUMBER)->args.num = sp_offs;
+ add_command(SFT_CMD_SUB);
+ add_command(SFT_CMD_WR_REG)->args.reg = reg_sp;
+
+ /* Execute the call */
+ add_command(SFT_CMD_FCALL);
+
+ /* Get function return value */
+ if (get_symbol_base_type(info->func, &res_type) < 0) return -1;
+ if (get_symbol_size(res_type, &res_size) < 0) return -1;
+ if (res_size == 0) return 0;
+ if (get_symbol_type_class(res_type, &res_type_class) < 0) return -1;
+ switch (res_type_class) {
+ case TYPE_CLASS_CARDINAL:
+ case TYPE_CLASS_INTEGER:
+ case TYPE_CLASS_POINTER:
+ case TYPE_CLASS_ENUMERATION:
+ case TYPE_CLASS_ARRAY:
+ case TYPE_CLASS_COMPOSITE:
+ case TYPE_CLASS_FUNCTION:
+ add_command(SFT_CMD_RD_REG)->args.reg = reg_rv;
+ break;
+ case TYPE_CLASS_REAL:
+ case TYPE_CLASS_MEMBER_PTR:
+ default:
+ set_errno(ERR_OTHER, "Unsupported return type");
+ return -1;
+ }
+ return 0;
+}
+
+static void save_registers(void) {
+ unsigned cnt = 0;
+ RegisterDefinition * r;
+ RegisterDefinition * regs = get_reg_definitions(info->ctx);
+ for (r = regs; r->name != NULL; r++) {
+ if (r->dwarf_id < 0) continue;
+ if (r->size == 0) continue;
+ cnt++;
+ }
+ info->saveregs = (RegisterDefinition **)tmp_alloc(sizeof(RegisterDefinition *) * cnt);
+ for (r = regs; r->name != NULL; r++) {
+ if (r->dwarf_id < 0) continue;
+ if (r->size == 0) continue;
+ info->saveregs[info->saveregs_cnt++] = r;
+ }
+ assert(info->saveregs_cnt == cnt);
+}
+
+int get_function_call_location_expression(FunctionCallInfo * arg_info) {
+ info = arg_info;
+ trace_cmds_cnt = 0;
+ trace_cmds_max = 0;
+ trace_cmds = NULL;
+#if !defined(_WIN32) || ENABLE_ELF
+ if (c_call_cmds() < 0) return -1;
+#else
+ switch (info->scope.os_abi) {
+ case CV_CALL_NEAR_C:
+ /* Specifies a function-calling convention using a near right-to-left push.
+ * The calling function clears the stack */
+ if (c_call_cmds() < 0) return -1;
+ break;
+ default:
+ set_errno(ERR_OTHER, "Unsupported calling convension code");
+ return -1;
+ }
+#endif
+ if (trace_cmds_cnt > 0) {
+ save_registers();
+ info->cmds = trace_cmds;
+ info->cmds_cnt = trace_cmds_cnt;
+ return 0;
+ }
+ set_errno(ERR_OTHER, "Calling functions is not supported");
+ return -1;
+}
+
+#endif /* ENABLE_Symbols && ENABLE_DebugContext */
diff --git a/agent/tcf/services/funccall.h b/agent/tcf/services/funccall.h
new file mode 100644
index 00000000..45b8cca3
--- /dev/null
+++ b/agent/tcf/services/funccall.h
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Wind River Systems, Inc. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * This module contains definitions for enabling function call injection on the target.
+ */
+
+#ifndef D_funccall
+#define D_funccall
+
+#include <tcf/services/symbols.h>
+
+#if ENABLE_Symbols && ENABLE_DebugContext
+
+/*
+ * Input and output parameters for get_function_call_location_expression()
+ */
+struct FunctionCallInfo {
+ /* Inputs */
+ RegisterIdScope scope; /* Information about the target */
+ Context * ctx; /* Execution context of the target */
+ const Symbol * func; /* Function declaration */
+ const Symbol ** args; /* Argument types given in the call */
+ unsigned args_cnt; /* Number of arguments */
+
+ /* Outputs */
+ LocationExpressionCommand * cmds; /* list of location expression commands */
+ unsigned cmds_cnt; /* Number of location expression commands */
+
+ RegisterDefinition ** saveregs; /* List of registers to save before calling the function */
+ unsigned saveregs_cnt; /* Number of registers to save */
+
+ unsigned update_policy; /* Cache update policy, see UPDATE_ON_* in symbols.h */
+};
+
+/*
+ * Order of args array given to evaluate_location_expression() when
+ * evaluating function calls.
+ */
+#define FUNCCALL_ARG_ADDR 0 /* Address of function */
+#define FUNCCALL_ARG_RET 1 /* Return address */
+#define FUNCCALL_ARG_ARGS 2 /* Function arguments */
+
+/*
+ * Get location expressions for calling functions on the target.
+ *
+ * The resulting location expression commands are intended to be used
+ * to perform the function call, using evaluate_location_expression().
+ * to build a LocationExpressionState.
+ *
+ * Memory allocated for the result information, e.g. cmds and
+ * saveregs, should be allocated using tmp_alloc() and related
+ * functions. It is the clients reposibility to copy this information
+ * to permanent storage if necessary.
+ *
+ * When calling the function, the client will save the registers enumerated by
+ * saveregs before the call and restore the same registers after the
+ * call. Before restoring the register it will retrieve the return
+ * value. This allows the location expression commands to temporarily
+ * store return information on the stack when needed.
+ */
+
+extern int get_function_call_location_expression(FunctionCallInfo * info);
+
+#endif /* ENABLE_Symbols && ENABLE_DebugContext */
+
+#endif /* D_funccall */
diff --git a/agent/tcf/services/memoryservice.c b/agent/tcf/services/memoryservice.c
index dbe2ef93..ff34a07d 100644
--- a/agent/tcf/services/memoryservice.c
+++ b/agent/tcf/services/memoryservice.c
@@ -341,32 +341,34 @@ static MemoryCommandArgs * read_command_args(char * token, Channel * c, int cmd)
void send_event_memory_changed(Context * ctx, ContextAddress addr, unsigned long size) {
OutputStream * out = &broadcast_group->out;
- write_stringz(out, "E");
- write_stringz(out, MEMORY);
- write_stringz(out, "memoryChanged");
+ if (is_intercepted(ctx)) {
+ write_stringz(out, "E");
+ write_stringz(out, MEMORY);
+ write_stringz(out, "memoryChanged");
- json_write_string(out, ctx->id);
- write_stream(out, 0);
+ json_write_string(out, ctx->id);
+ write_stream(out, 0);
- /* <array of addres ranges> */
- write_stream(out, '[');
- write_stream(out, '{');
+ /* <array of addres ranges> */
+ write_stream(out, '[');
+ write_stream(out, '{');
- json_write_string(out, "addr");
- write_stream(out, ':');
- json_write_uint64(out, addr);
+ json_write_string(out, "addr");
+ write_stream(out, ':');
+ json_write_uint64(out, addr);
- write_stream(out, ',');
+ write_stream(out, ',');
- json_write_string(out, "size");
- write_stream(out, ':');
- json_write_ulong(out, size);
+ json_write_string(out, "size");
+ write_stream(out, ':');
+ json_write_ulong(out, size);
- write_stream(out, '}');
- write_stream(out, ']');
- write_stream(out, 0);
+ write_stream(out, '}');
+ write_stream(out, ']');
+ write_stream(out, 0);
- write_stream(out, MARKER_EOM);
+ write_stream(out, MARKER_EOM);
+ }
}
static void safe_memory_set(void * parm) {
diff --git a/agent/tcf/services/processes.c b/agent/tcf/services/processes.c
index f353b76a..11f5dfa9 100644
--- a/agent/tcf/services/processes.c
+++ b/agent/tcf/services/processes.c
@@ -646,7 +646,23 @@ static void command_signal(char * token, Channel * c) {
write_stringz(&c->out, token);
#if defined(_WIN32)
- err = ENOSYS;
+ if (parent != 0) {
+ err = ERR_INV_CONTEXT;
+ }
+ else if (signal_code(signal) == 0x40010005) {
+ /* Control-C */
+ HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
+ if (h == NULL) {
+ err = set_win32_errno(GetLastError());
+ }
+ else {
+ if (!TerminateProcess(h, 1)) err = set_win32_errno(GetLastError());
+ if (!CloseHandle(h) && !err) err = set_win32_errno(GetLastError());
+ }
+ }
+ else {
+ err = ENOSYS;
+ }
#elif defined(_WRS_KERNEL)
if (kill(pid, signal) < 0) err = errno;
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
diff --git a/agent/tcf/services/processes.h b/agent/tcf/services/processes.h
index 2c8318e2..ad1bf6d8 100644
--- a/agent/tcf/services/processes.h
+++ b/agent/tcf/services/processes.h
@@ -24,6 +24,7 @@
#ifndef D_processes
#define D_processes
+#include <tcf/framework/events.h>
#include <tcf/framework/protocol.h>
typedef struct ChildProcess ChildProcess;
diff --git a/agent/tcf/services/registers.c b/agent/tcf/services/registers.c
index c86dce46..11afc345 100644
--- a/agent/tcf/services/registers.c
+++ b/agent/tcf/services/registers.c
@@ -31,6 +31,7 @@
#include <tcf/framework/json.h>
#include <tcf/framework/cache.h>
#include <tcf/framework/exceptions.h>
+#include <tcf/services/runctrl.h>
#include <tcf/services/stacktrace.h>
#include <tcf/services/registers.h>
@@ -329,14 +330,16 @@ void send_event_register_changed(const char * id) {
l->func->register_changed(ctx, frame, def, l->args);
}
- write_stringz(out, "E");
- write_stringz(out, REGISTERS);
- write_stringz(out, "registerChanged");
+ if (is_intercepted(ctx)) {
+ write_stringz(out, "E");
+ write_stringz(out, REGISTERS);
+ write_stringz(out, "registerChanged");
- json_write_string(out, id);
- write_stream(out, 0);
+ json_write_string(out, id);
+ write_stream(out, 0);
- write_stream(out, MARKER_EOM);
+ write_stream(out, MARKER_EOM);
+ }
}
typedef struct GetArgs {
diff --git a/agent/tcf/services/runctrl.c b/agent/tcf/services/runctrl.c
index 21391f41..d278d0d2 100644
--- a/agent/tcf/services/runctrl.c
+++ b/agent/tcf/services/runctrl.c
@@ -51,7 +51,7 @@
#define STOP_ALL_MAX_CNT 20
typedef struct Listener {
- RunControlEventListener * func;
+ RunControlEventListener * listener;
void * args;
} Listener;
@@ -104,6 +104,7 @@ typedef struct GetContextArgs {
static SafeEvent * safe_event_list = NULL;
static SafeEvent * safe_event_last = NULL;
+static int safe_event_active = 0;
static int safe_event_pid_count = 0;
static int run_ctrl_lock_cnt = 0;
static int stop_all_timer_cnt = 0;
@@ -827,20 +828,6 @@ static void command_detach(char * token, Channel * c) {
send_simple_result(c, token, err);
}
-static void notify_context_intercepted(Context * ctx) {
- unsigned i;
- ContextExtensionRC * ext = EXT(ctx);
- assert(!ext->intercepted);
- ext->intercepted = 1;
- ctx->pending_intercept = 0;
- for (i = 0; i < listener_cnt; i++) {
- Listener * l = listeners + i;
- if (l->func->context_intercepted == NULL) continue;
- l->func->context_intercepted(ctx, l->args);
- }
- assert(ctx->pending_intercept == 0);
-}
-
static void notify_context_released(Context * ctx) {
unsigned i;
ContextExtensionRC * ext = EXT(ctx);
@@ -848,8 +835,8 @@ static void notify_context_released(Context * ctx) {
ext->intercepted = 0;
for (i = 0; i < listener_cnt; i++) {
Listener * l = listeners + i;
- if (l->func->context_released == NULL) continue;
- l->func->context_released(ctx, l->args);
+ if (l->listener->context_released == NULL) continue;
+ l->listener->context_released(ctx, l->args);
}
}
@@ -907,9 +894,14 @@ static void send_event_context_removed(Context * ctx) {
static void send_event_context_suspended(void) {
LINK p0; /* List of contexts intercepted by breakpoint or exception */
LINK p1; /* List of all other intercepted contexts */
+ LINK p2; /* List for notify_context_intercepted() */
LINK * l = context_root.next;
+ unsigned i;
+
list_init(&p0);
list_init(&p1);
+ list_init(&p2);
+
while (l != &context_root) {
Context * x = ctxl2ctxp(l);
l = l->next;
@@ -920,7 +912,9 @@ static void send_event_context_suspended(void) {
assert(!e->intercepted);
assert(!e->safe_single_step);
cancel_step_mode(x);
- notify_context_intercepted(x);
+ assert(!e->intercepted);
+ e->intercepted = 1;
+ x->pending_intercept = 0;
if (get_context_breakpoint_ids(x) != NULL) e->intercepted_by_bp++;
if (e->intercepted_by_bp || x->stopped_by_exception) n = &p0;
list_add_last(&e->link, n);
@@ -934,6 +928,7 @@ static void send_event_context_suspended(void) {
int container = list_is_empty(&p0) && p1.next != p1.prev;
list_remove(n);
+ list_add_last(n, &p2);
write_stringz(out, "E");
write_stringz(out, RUN_CONTROL);
@@ -947,20 +942,34 @@ static void send_event_context_suspended(void) {
if (container) {
write_stream(out, '[');
json_write_string(out, ctx->id);
- l = p1.next;
- while (l != &p1) {
- Context * x = link2ctx(l);
+ assert(!list_is_empty(&p1));
+ while (!list_is_empty(&p1)) {
+ LINK * m = p1.next;
+ Context * x = link2ctx(m);
+ list_remove(m);
+ list_add_last(m, &p2);
write_stream(out, ',');
json_write_string(out, x->id);
- l = l->next;
}
write_stream(out, ']');
write_stream(out, 0);
- list_init(&p1);
+ assert(list_is_empty(&p1));
}
write_stream(out, MARKER_EOM);
}
+
+ l = p2.next;
+ while (l != &p2) {
+ Context * x = link2ctx(l);
+ l = l->next;
+ for (i = 0; i < listener_cnt; i++) {
+ Listener * l = listeners + i;
+ if (l->listener->context_intercepted == NULL) continue;
+ l->listener->context_intercepted(x, l->args);
+ }
+ assert(x->pending_intercept == 0);
+ }
}
static void send_event_context_resumed(Context * grp) {
@@ -1633,6 +1642,7 @@ static void run_safe_events(void * arg) {
}
assert(is_all_stopped(i->grp));
safe_event_list = i->next;
+ safe_event_active = 1;
if (set_trap(&trap)) {
i->done(i->arg);
clear_trap(&trap);
@@ -1641,6 +1651,7 @@ static void run_safe_events(void * arg) {
trace(LOG_ALWAYS, "Unhandled exception in \"safe\" event dispatch: %d %s",
trap.error, errno_to_str(trap.error));
}
+ safe_event_active = 0;
run_ctrl_unlock();
context_unlock(i->grp);
loc_free(i);
@@ -1678,6 +1689,10 @@ void post_safe_event(Context * ctx, EventCallBack * done, void * arg) {
safe_event_last = i;
}
+int is_safe_event(void) {
+ return safe_event_active;
+}
+
int safe_context_single_step(Context * ctx) {
int res = 0;
ContextExtensionRC * ext = EXT(ctx);
@@ -1719,11 +1734,25 @@ void add_run_control_event_listener(RunControlEventListener * listener, void * a
listener_max += 8;
listeners = (Listener *)loc_realloc(listeners, listener_max * sizeof(Listener));
}
- listeners[listener_cnt].func = listener;
+ listeners[listener_cnt].listener = listener;
listeners[listener_cnt].args = args;
listener_cnt++;
}
+void rem_run_control_event_listener(RunControlEventListener * listener) {
+ unsigned i = 0;
+ while (i < listener_cnt) {
+ if (listeners[i++].listener == listener) {
+ while (i < listener_cnt) {
+ listeners[i - 1] = listeners[i];
+ i++;
+ }
+ listener_cnt--;
+ break;
+ }
+ }
+}
+
static void event_context_created(Context * ctx, void * client_data) {
assert(!ctx->exited);
assert(!ctx->stopped);
@@ -1835,13 +1864,4 @@ void ini_run_ctrl_service(Protocol * proto, TCFBroadcastGroup * bcg) {
add_context_query_comparator("ProcessID", cmp_process_id);
}
-#else
-
-#include <tcf/services/runctrl.h>
-#include <assert.h>
-
-void post_safe_event(Context * ctx, EventCallBack * done, void * arg) {
- post_event(done, arg);
-}
-
#endif /* SERVICE_RunControl */
diff --git a/agent/tcf/services/runctrl.h b/agent/tcf/services/runctrl.h
index 7c13afe0..be383aa3 100644
--- a/agent/tcf/services/runctrl.h
+++ b/agent/tcf/services/runctrl.h
@@ -51,6 +51,8 @@
#include <tcf/framework/context.h>
#include <tcf/framework/protocol.h>
+#if SERVICE_RunControl
+
/*
* Lock run control: don't resume any thread while run control is locked.
* Each call to run_ctrl_lock() increments lock counter.
@@ -74,6 +76,11 @@ extern void run_ctrl_unlock(void);
extern void post_safe_event(Context * ctx, EventCallBack * done, void * arg);
/*
+ * Return 1 if called from safe event handler.
+ */
+extern int is_safe_event(void);
+
+/*
* Single step a context during handling of safe event.
* "Safe" step is executed with all other contexts stopped,
* and it is expected to take only a short time to execute.
@@ -139,13 +146,22 @@ typedef struct RunControlEventListener {
} RunControlEventListener;
/*
- * Add a listener for RunControl service events.
+ * Add/remove a listener for RunControl service events.
*/
extern void add_run_control_event_listener(RunControlEventListener * listener, void * args);
+extern void rem_run_control_event_listener(RunControlEventListener * listener);
/*
* Initialize run control service.
*/
extern void ini_run_ctrl_service(Protocol * proto, TCFBroadcastGroup * bcg);
+#else
+
+#define is_intercepted(x) 0
+#define is_safe_event() 0
+#define post_safe_event(ctx, done, arg) ((void)ctx, post_event(done, arg))
+
+#endif /* SERVICE_RunControl */
+
#endif /* D_runctrl */
diff --git a/agent/tcf/services/symbols.c b/agent/tcf/services/symbols.c
index ec3ffb92..beb5e2c8 100644
--- a/agent/tcf/services/symbols.c
+++ b/agent/tcf/services/symbols.c
@@ -644,15 +644,17 @@ static void write_commands(OutputStream * out, Context * ctx, StackFrameRegister
write_stream(out, ',');
json_write_int64(out, cmd->args.num);
break;
- case SFT_CMD_REGISTER:
+ case SFT_CMD_RD_REG:
+ case SFT_CMD_WR_REG:
write_stream(out, ',');
json_write_string(out, register2id(ctx, STACK_NO_FRAME, cmd->args.reg));
break;
- case SFT_CMD_DEREF:
+ case SFT_CMD_RD_MEM:
+ case SFT_CMD_WR_MEM:
write_stream(out, ',');
- json_write_ulong(out, cmd->args.deref.size);
+ json_write_ulong(out, cmd->args.mem.size);
write_stream(out, ',');
- json_write_boolean(out, cmd->args.deref.big_endian);
+ json_write_boolean(out, cmd->args.mem.big_endian);
break;
case SFT_CMD_LOCATION:
write_stream(out, ',');
diff --git a/agent/tcf/services/symbols.h b/agent/tcf/services/symbols.h
index cbadd841..c60a54d4 100644
--- a/agent/tcf/services/symbols.h
+++ b/agent/tcf/services/symbols.h
@@ -30,6 +30,7 @@
*/
typedef struct Symbol Symbol;
+typedef struct FunctionCallInfo FunctionCallInfo;
#define SYM_CLASS_UNKNOWN 0
#define SYM_CLASS_VALUE 1 /* Symbol represents a constant value */
@@ -252,6 +253,10 @@ extern ContextAddress is_plt_section(Context * ctx, ContextAddress addr);
/* Get object location expression */
extern int get_location_info(const Symbol * sym, LocationInfo ** info);
+/* Get information about function call injection */
+extern int get_funccall_info(const Symbol * func,
+ const Symbol ** args, unsigned args_cnt, FunctionCallInfo ** info);
+
/*
* For given context and its registers in a stack frame,
* compute stack frame location and next frame register values.
diff --git a/agent/tcf/services/symbols_elf.c b/agent/tcf/services/symbols_elf.c
index 4f41b861..ce5922d4 100644
--- a/agent/tcf/services/symbols_elf.c
+++ b/agent/tcf/services/symbols_elf.c
@@ -41,6 +41,7 @@
#include <tcf/services/dwarfecomp.h>
#include <tcf/services/dwarfframe.h>
#include <tcf/services/stacktrace.h>
+#include <tcf/services/funccall.h>
#include <tcf/services/symbols.h>
#include <tcf/services/vm.h>
#if ENABLE_RCBP_TEST
@@ -1609,55 +1610,9 @@ static int get_object_size(ObjectInfo * obj, unsigned dimension, U8_T * byte_siz
static void read_object_value(PropertyValue * v, void ** value, size_t * size, int * big_endian) {
if (v->mPieces != NULL) {
- U4_T n = 0;
- U1_T * bf = NULL;
- size_t bf_size = 0;
- U4_T bf_offs = 0;
- while (n < v->mPieceCnt) {
- U4_T i;
- LocationPiece * piece = v->mPieces + n++;
- U4_T piece_size = piece->size ? piece->size : (piece->bit_offs + piece->bit_size + 7) / 8;
- U4_T piece_bits = piece->bit_size ? piece->bit_size : piece->size * 8;
- U1_T * pbf = NULL;
- if (bf_size < bf_offs / 8 + piece_size + 1) {
- bf_size = bf_offs / 8 + piece_size + 1;
- bf = (U1_T *)tmp_realloc(bf, bf_size);
- }
- if (piece->reg) {
- StackFrame * frame = NULL;
- if (get_frame_info(v->mContext, v->mFrame, &frame) < 0) exception(errno);
- if (piece->reg->size < piece_size) {
- pbf = (U1_T *)tmp_alloc_zero(piece_size);
- }
- else {
- pbf = (U1_T *)tmp_alloc(piece->reg->size);
- }
- if (read_reg_bytes(frame, piece->reg, 0, piece->reg->size, pbf) < 0) exception(errno);
- if (!piece->reg->big_endian != !v->mBigEndian) swap_bytes(pbf, piece->reg->size);
- }
- else if (piece->value) {
- pbf = (U1_T *)piece->value;
- }
- else {
- pbf = (U1_T *)tmp_alloc(piece_size);
- if (context_read_mem(v->mContext, piece->addr, pbf, piece_size) < 0) exception(errno);
- }
- for (i = piece->bit_offs; i < piece->bit_offs + piece_bits; i++) {
- if (pbf[i / 8] & (1u << (i % 8))) {
- bf[bf_offs / 8] |= (1u << (bf_offs % 8));
- }
- else {
- bf[bf_offs / 8] &= ~(1u << (bf_offs % 8));
- }
- bf_offs++;
- }
- }
- while (bf_offs % 8) {
- bf[bf_offs / 8] &= ~(1u << (bf_offs % 8));
- bf_offs++;
- }
- *value = bf;
- *size = bf_offs / 8;
+ StackFrame * frame = NULL;
+ if (get_frame_info(v->mContext, v->mFrame, &frame) < 0) exception(errno);
+ read_location_peices(v->mContext, frame, v->mPieces, v->mPieceCnt, v->mBigEndian, value, size);
*big_endian = v->mBigEndian;
}
else if (v->mAddr != NULL) {
@@ -1938,9 +1893,20 @@ int get_symbol_name(const Symbol * sym, char ** name) {
*name = (char *)sym->obj->mName;
}
else if (sym->tbl != NULL) {
+ size_t i;
ELF_SymbolInfo info;
unpack_elf_symbol_info(sym->tbl, sym->index, &info);
- *name = info.name;
+ for (i = 0;; i++) {
+ if (info.name[i] == 0) {
+ *name = info.name;
+ break;
+ }
+ if (info.name[i] == '@' && info.name[i + 1] == '@') {
+ *name = (char *)tmp_alloc_zero(i + 1);
+ memcpy(*name, info.name, i);
+ break;
+ }
+ }
}
else {
*name = NULL;
@@ -2796,4 +2762,21 @@ int get_array_symbol(const Symbol * sym, ContextAddress length, Symbol ** ptr) {
return 0;
}
+int get_funccall_info(const Symbol * func,
+ const Symbol ** args, unsigned args_cnt, FunctionCallInfo ** res) {
+ if (func->obj != NULL) {
+ FunctionCallInfo * info = (FunctionCallInfo *)tmp_alloc_zero(sizeof(FunctionCallInfo));
+ info->ctx = func->ctx;
+ info->func = func;
+ info->scope = func->obj->mCompUnit->mRegIdScope;
+ info->args_cnt = args_cnt;
+ info->args = args;
+ if (get_function_call_location_expression(info) < 0) return -1;
+ *res = info;
+ return 0;
+ }
+ set_errno(ERR_OTHER, "Func call injection info not available");
+ return -1;
+}
+
#endif /* SERVICE_Symbols && ENABLE_ELF */
diff --git a/agent/tcf/services/symbols_proxy.c b/agent/tcf/services/symbols_proxy.c
index cf86270a..3ac08264 100644
--- a/agent/tcf/services/symbols_proxy.c
+++ b/agent/tcf/services/symbols_proxy.c
@@ -1220,16 +1220,18 @@ static void read_location_command(InputStream * inp, void * args) {
if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX);
cmd->args.num = json_read_int64(inp);
break;
- case SFT_CMD_REGISTER:
+ case SFT_CMD_RD_REG:
+ case SFT_CMD_WR_REG:
if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX);
json_read_string(inp, id, sizeof(id));
if (id2register(id, &ctx, &frame, &cmd->args.reg) < 0) trace_error = errno;
break;
- case SFT_CMD_DEREF:
+ case SFT_CMD_RD_MEM:
+ case SFT_CMD_WR_MEM:
if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX);
- cmd->args.deref.size = json_read_ulong(inp);
+ cmd->args.mem.size = json_read_ulong(inp);
if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX);
- cmd->args.deref.big_endian = json_read_boolean(inp);
+ cmd->args.mem.big_endian = json_read_boolean(inp);
break;
case SFT_CMD_LOCATION:
if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX);
@@ -1409,6 +1411,13 @@ int get_next_stack_frame(StackFrame * frame, StackFrame * down) {
return 0;
}
+int get_funccall_info(const Symbol * func,
+ const Symbol ** args, unsigned args_cnt, FunctionCallInfo ** info) {
+ /* TODO: get_funccall_info() in symbols proxy */
+ set_errno(ERR_OTHER, "get_funccall_info() is not supported yet by TCF server");
+ return -1;
+}
+
const char * get_symbol_file_name(MemoryRegion * module) {
errno = 0;
return NULL;
diff --git a/agent/tcf/services/symbols_win32.c b/agent/tcf/services/symbols_win32.c
index 9ed3a50a..fb145890 100644
--- a/agent/tcf/services/symbols_win32.c
+++ b/agent/tcf/services/symbols_win32.c
@@ -33,6 +33,7 @@
#include <tcf/services/symbols.h>
#include <tcf/services/stacktrace.h>
#include <tcf/services/memorymap.h>
+#include <tcf/services/funccall.h>
#include <system/Windows/tcf/windbgcache.h>
#include <system/Windows/tcf/context-win32.h>
#if ENABLE_RCBP_TEST
@@ -194,11 +195,13 @@ static void tag2symclass(Symbol * sym, int tag) {
case SymTagBaseType:
case SymTagTypedef:
case SymTagBaseClass:
- case SymTagFunctionArgType:
case SymTagCustomType:
case SymTagManagedType:
sym->sym_class = SYM_CLASS_TYPE;
break;
+ case SymTagFunctionArgType:
+ sym->sym_class = SYM_CLASS_REFERENCE;
+ break;
}
}
@@ -230,9 +233,16 @@ static int get_type_tag(Symbol * type, DWORD * tag) {
DWORD dword;
for (;;) {
if (get_type_info(type, TI_GET_SYMTAG, &dword) < 0) return -1;
- if (dword != SymTagTypedef && dword != SymTagFunction && dword != SymTagData) break;
- if (get_type_info(type, TI_GET_TYPE, &dword) < 0) return -1;
- type->index = dword;
+ switch (dword) {
+ case SymTagTypedef:
+ case SymTagFunction:
+ case SymTagData:
+ case SymTagFunctionArgType:
+ if (get_type_info(type, TI_GET_TYPE, &dword) < 0) return -1;
+ type->index = dword;
+ continue;
+ }
+ break;
}
type->sym_class = SYM_CLASS_TYPE;
*tag = dword;
@@ -530,14 +540,23 @@ int get_symbol_type(const Symbol * sym, Symbol ** type) {
assert(sym->magic == SYMBOL_MAGIC);
if (!sym->base && !sym->info) {
DWORD tag = 0;
+ DWORD index = 0;
Symbol * res = alloc_symbol();
*res = *sym;
- if (get_type_tag(res, &tag)) return -1;
- assert(res->sym_class == SYM_CLASS_TYPE);
- if (res->index != sym->index) {
+ if (get_type_info(sym, TI_GET_SYMTAG, &tag) < 0) return -1;
+ switch (tag) {
+ case SymTagTypedef:
+ case SymTagFunction:
+ case SymTagPublicSymbol:
+ case SymTagData:
+ case SymTagFunctionArgType:
+ if (get_type_info(sym, TI_GET_TYPE, &index) < 0) return -1;
+ res->sym_class = SYM_CLASS_TYPE;
+ res->index = index;
*type = res;
return 0;
}
+ assert(sym->sym_class == SYM_CLASS_TYPE);
}
*type = (Symbol *)sym;
return 0;
@@ -572,7 +591,7 @@ int get_symbol_index_type(const Symbol * sym, Symbol ** type) {
Symbol * res = alloc_symbol();
assert(sym->magic == SYMBOL_MAGIC);
- if (sym->base) {
+ if (sym->base && sym->length) {
res->ctx = sym->ctx;
res->sym_class = SYM_CLASS_TYPE;
res->info = basic_type_info + BST_UNSIGNED;
@@ -582,7 +601,7 @@ int get_symbol_index_type(const Symbol * sym, Symbol ** type) {
*type = res;
return 0;
}
- if (sym->info) {
+ if (sym->base || sym->info) {
errno = ERR_INV_CONTEXT;
return -1;
}
@@ -605,19 +624,23 @@ int get_symbol_length(const Symbol * sym, ContextAddress * length) {
DWORD tag = 0;
assert(sym->magic == SYMBOL_MAGIC);
- if (sym->base) {
- *length = sym->length == 0 ? 1 : sym->length;
+ if (sym->base && sym->length) {
+ *length = sym->length;
return 0;
}
- if (sym->info) {
+ if (sym->base || sym->info) {
errno = ERR_INV_CONTEXT;
return -1;
}
if (get_type_tag(&type, &tag)) return -1;
- if (get_type_info(&type, TI_GET_COUNT, &res) < 0) return -1;
-
- *length = res;
- return 0;
+ switch (tag) {
+ case SymTagArrayType:
+ if (get_type_info(&type, TI_GET_COUNT, &res) < 0) return -1;
+ *length = res;
+ return 0;
+ }
+ errno = ERR_INV_CONTEXT;
+ return -1;
}
int get_symbol_lower_bound(const Symbol * sym, int64_t * value) {
@@ -625,11 +648,11 @@ int get_symbol_lower_bound(const Symbol * sym, int64_t * value) {
DWORD tag = 0;
assert(sym->magic == SYMBOL_MAGIC);
- if (sym->base) {
+ if (sym->base && sym->length) {
*value = 0;
return 0;
}
- if (sym->info) {
+ if (sym->base || sym->info) {
errno = ERR_INV_CONTEXT;
return -1;
}
@@ -840,14 +863,20 @@ int get_symbol_register(const Symbol * sym, Context ** ctx, int * frame, Registe
}
int get_symbol_flags(const Symbol * sym, SYM_FLAGS * flags) {
+ DWORD tag = 0;
DWORD dword = 0;
SYMBOL_INFO * info = NULL;
*flags = 0;
assert(sym->magic == SYMBOL_MAGIC);
if (sym->address || sym->base || sym->info) return 0;
+ if (get_type_info(sym, TI_GET_SYMTAG, &tag) < 0) return -1;
if (get_sym_info(sym, sym->index, &info) == 0 && (info->Flags & SYMFLAG_PARAMETER) != 0) *flags |= SYM_FLAG_PARAMETER;
if (get_type_info(sym, TI_GET_IS_REFERENCE, &dword) == 0 && dword) *flags |= SYM_FLAG_REFERENCE;
+ if (tag == SymTagFunctionArgType) *flags |= SYM_FLAG_PARAMETER;
+ if (tag == SymTagPublicSymbol) *flags |= SYM_FLAG_EXTERNAL;
+ if (tag == SymTagTypedef) *flags |= SYM_FLAG_TYPEDEF;
+ if (tag == SymTagEnum) *flags |= SYM_FLAG_ENUM_TYPE;
return 0;
}
@@ -1216,6 +1245,38 @@ int get_next_stack_frame(StackFrame * frame, StackFrame * down) {
return 0;
}
+int get_funccall_info(const Symbol * func,
+ const Symbol ** args, unsigned args_cnt, FunctionCallInfo ** res) {
+ FunctionCallInfo * info = (FunctionCallInfo *)tmp_alloc_zero(sizeof(FunctionCallInfo));
+ Symbol * type = (Symbol *)func;
+ DWORD tag = 0;
+ DWORD cc = 0;
+
+ assert(func->magic == SYMBOL_MAGIC);
+ if (func->base || func->info) {
+ errno = ERR_INV_CONTEXT;
+ return -1;
+ }
+ if (get_type_info(func, TI_GET_SYMTAG, &tag) < 0) return -1;
+ if (tag == SymTagFunction && get_symbol_type(func, &type) < 0) return -1;
+ if (get_type_info(type, TI_GET_CALLING_CONVENTION, &cc) < 0) return -1;
+#if defined(__x86_64__)
+ info->scope.machine = 62; /* EM_X86_64 */
+ info->scope.elf64 = 1;
+#else
+ info->scope.machine = 3; /* EM_386 */
+#endif
+ info->scope.os_abi = (uint8_t)cc;
+ info->scope.id_type = REGNUM_DWARF;
+ info->ctx = func->ctx;
+ info->func = func;
+ info->args_cnt = args_cnt;
+ info->args = args;
+ if (get_function_call_location_expression(info) < 0) return -1;
+ *res = info;
+ return 0;
+}
+
const char * get_symbol_file_name(MemoryRegion * module) {
errno = 0;
return NULL;
diff --git a/agent/tcf/services/sysmon.c b/agent/tcf/services/sysmon.c
index 016b84f6..cacf06e0 100644
--- a/agent/tcf/services/sysmon.c
+++ b/agent/tcf/services/sysmon.c
@@ -386,7 +386,8 @@ static void command_get_command_line(char * token, Channel * c) {
if (err != 0) {
write_stringz(&c->out, "null");
- } else {
+ }
+ else {
write_stringz(&c->out, p->kp_proc.p_comm);
}
diff --git a/server/server.vcproj b/server/server.vcproj
index 46290dd1..7c2ccd82 100644
--- a/server/server.vcproj
+++ b/server/server.vcproj
@@ -451,6 +451,14 @@
>
</File>
<File
+ RelativePath="..\agent\tcf\services\funccall.c"
+ >
+ </File>
+ <File
+ RelativePath="..\agent\tcf\services\funccall.h"
+ >
+ </File>
+ <File
RelativePath="..\agent\tcf\services\linenumbers.c"
>
</File>
diff --git a/tests/cmd-line/cmd-line.vcproj b/tests/cmd-line/cmd-line.vcproj
index a1a5c3ea..204b948d 100644
--- a/tests/cmd-line/cmd-line.vcproj
+++ b/tests/cmd-line/cmd-line.vcproj
@@ -42,7 +42,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=".;..\..\agent;..\..\agent\machine\i386;..\..\agent\system\Windows"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ PreprocessorDefinitions="_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -118,7 +118,7 @@
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories=".;..\..\agent;..\..\agent\machine\i386;..\..\agent\system\Windows"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ PreprocessorDefinitions="NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
@@ -442,6 +442,14 @@
>
</File>
<File
+ RelativePath="..\..\agent\tcf\services\contextquery.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\agent\tcf\services\contextquery.h"
+ >
+ </File>
+ <File
RelativePath="..\..\agent\tcf\services\diagnostics.c"
>
</File>
@@ -530,6 +538,14 @@
>
</File>
<File
+ RelativePath="..\..\agent\tcf\services\funccall.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\agent\tcf\services\funccall.h"
+ >
+ </File>
+ <File
RelativePath="..\..\agent\tcf\services\linenumbers.c"
>
</File>
@@ -677,6 +693,10 @@
Name="i386"
>
<File
+ RelativePath="..\..\agent\machine\i386\tcf\cpudefs-mdep.c"
+ >
+ </File>
+ <File
RelativePath="..\..\agent\machine\i386\tcf\cpudefs-mdep.h"
>
</File>
diff --git a/tests/mem-leaks/agent.vcproj b/tests/mem-leaks/agent.vcproj
index 3127f612..7a4c7e61 100644
--- a/tests/mem-leaks/agent.vcproj
+++ b/tests/mem-leaks/agent.vcproj
@@ -42,7 +42,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=".;..\..\agent;..\..\agent\system\Windows;..\..\agent\machine\i386"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ PreprocessorDefinitions="_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
@@ -117,7 +117,7 @@
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories=".;..\..\agent;..\..\agent\system\Windows;..\..\agent\machine\i386"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ PreprocessorDefinitions="NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
@@ -217,6 +217,14 @@
>
</File>
<File
+ RelativePath="..\..\agent\tcf\services\contextquery.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\agent\tcf\services\contextquery.h"
+ >
+ </File>
+ <File
RelativePath="..\..\agent\tcf\services\diagnostics.c"
>
</File>
@@ -257,6 +265,14 @@
>
</File>
<File
+ RelativePath="..\..\agent\tcf\services\funccall.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\agent\tcf\services\funccall.h"
+ >
+ </File>
+ <File
RelativePath="..\..\agent\tcf\services\linenumbers.c"
>
</File>
@@ -606,6 +622,30 @@
</File>
</Filter>
<Filter
+ Name="machine"
+ >
+ <Filter
+ Name="x86_64"
+ >
+ <File
+ RelativePath="..\..\agent\machine\x86_64\tcf\cpudefs-mdep.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\agent\machine\x86_64\tcf\cpudefs-mdep.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="i386"
+ >
+ <File
+ RelativePath="..\..\agent\machine\i386\tcf\dwarfreloc-mdep.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
Name="system"
>
<Filter
diff --git a/tests/test-dwarf/dwarf-test.vcproj b/tests/test-dwarf/dwarf-test.vcproj
index 1f39d0d4..69d51e24 100644
--- a/tests/test-dwarf/dwarf-test.vcproj
+++ b/tests/test-dwarf/dwarf-test.vcproj
@@ -42,7 +42,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=".;..\..\agent"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ PreprocessorDefinitions="_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
@@ -118,7 +118,7 @@
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories=".;..\..\agent"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ PreprocessorDefinitions="NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
@@ -534,6 +534,14 @@
>
</File>
<File
+ RelativePath="..\..\agent\tcf\services\funccall.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\agent\tcf\services\funccall.h"
+ >
+ </File>
+ <File
RelativePath="..\..\agent\tcf\services\linenumbers.c"
>
</File>
diff --git a/tests/test-dwarf/tcf/backend/backend.c b/tests/test-dwarf/tcf/backend/backend.c
index b45b37ed..80ac96a3 100644
--- a/tests/test-dwarf/tcf/backend/backend.c
+++ b/tests/test-dwarf/tcf/backend/backend.c
@@ -884,6 +884,7 @@ static void next_pc(void) {
if (get_symbol_name(sym, &name) < 0) {
error("get_symbol_name");
}
+ if (name != NULL) name = tmp_strdup(name);
if (get_symbol_address(sym, &addr) < 0) {
error("get_symbol_address");
}
@@ -895,38 +896,39 @@ static void next_pc(void) {
error("invalid symbol address");
}
if (name != NULL) {
- char * name_buf = tmp_strdup(name);
- if (find_symbol_by_name(elf_ctx, STACK_TOP_FRAME, 0, name_buf, &sym) < 0) {
+ Symbol * fnd_sym = NULL;
+ if (find_symbol_by_name(elf_ctx, STACK_TOP_FRAME, 0, name, &fnd_sym) < 0) {
if (get_error_code(errno) != ERR_SYM_NOT_FOUND) {
error("find_symbol_by_name");
}
}
else {
- ContextAddress addr = 0;
- if (get_symbol_name(sym, &name) < 0) {
- error_sym("get_symbol_name", sym);
+ char * fnd_name = NULL;
+ ContextAddress fnd_addr = 0;
+ if (get_symbol_name(fnd_sym, &fnd_name) < 0) {
+ error_sym("get_symbol_name", fnd_sym);
}
- if (name == NULL) {
+ if (fnd_name == NULL) {
errno = ERR_OTHER;
- error_sym("invalid symbol name", sym);
+ error_sym("invalid symbol name", fnd_sym);
}
- if (strcmp(name_buf, name) != 0) {
+ if (strcmp(fnd_name, name) != 0) {
errno = ERR_OTHER;
- error_sym("strcmp(name_buf, name)", sym);
+ error_sym("strcmp(name_buf, name)", fnd_sym);
}
- if (get_symbol_address(sym, &addr) == 0) {
+ if (get_symbol_address(fnd_sym, &fnd_addr) == 0) {
Value v;
SYM_FLAGS flags = 0;
- char * expr = (char *)tmp_alloc(strlen(name_buf) + 16);
- if (get_symbol_flags(sym, &flags) < 0) {
- error_sym("get_symbol_flags", sym);
+ char * expr = (char *)tmp_alloc(strlen(name) + 16);
+ if (get_symbol_flags(fnd_sym, &flags) < 0) {
+ error_sym("get_symbol_flags", fnd_sym);
}
- sprintf(expr, "$\"%s\"", name_buf);
+ sprintf(expr, "$\"%s\"", name);
if (evaluate_expression(elf_ctx, STACK_TOP_FRAME, 0, expr, 0, &v) < 0) {
- error_sym("evaluate_expression", sym);
+ error_sym("evaluate_expression", fnd_sym);
}
if (flags & SYM_FLAG_EXTERNAL) {
- if (find_symbol_by_name(elf_ctx, STACK_NO_FRAME, 0, name_buf, &sym) < 0) {
+ if (find_symbol_by_name(elf_ctx, STACK_NO_FRAME, 0, name, &fnd_sym) < 0) {
error("find_symbol_by_name");
}
}

Back to the top