diff options
author | eutarass | 2010-04-27 23:38:58 +0000 |
---|---|---|
committer | eutarass | 2010-04-27 23:38:58 +0000 |
commit | f1017722bccf19a6510d84d10a86aa494822b18b (patch) | |
tree | b083886bc87b97383e6e6c8495502960104f61a2 | |
parent | 9bb534d80827bbcb1306f68949e4ea15444c472d (diff) | |
download | org.eclipse.tcf.agent-f1017722bccf19a6510d84d10a86aa494822b18b.tar.gz org.eclipse.tcf.agent-f1017722bccf19a6510d84d10a86aa494822b18b.tar.xz org.eclipse.tcf.agent-f1017722bccf19a6510d84d10a86aa494822b18b.zip |
TCF Agent: added function context_extension() that allows service implementations to extend debug context object with arbitrary service-private data. Services code changed to use the new extension method.
31 files changed, 944 insertions, 583 deletions
diff --git a/agent.vcproj b/agent.vcproj index 20c0aa2e..b2419293 100644 --- a/agent.vcproj +++ b/agent.vcproj @@ -750,6 +750,10 @@ >
</File>
<File
+ RelativePath=".\system\Windows\context-win32.h"
+ >
+ </File>
+ <File
RelativePath=".\system\Windows\regset.h"
>
</File>
@@ -874,10 +878,54 @@ </FileConfiguration>
</File>
<File
+ RelativePath=".\system\VxWorks\context-vxworks.h"
+ >
+ </File>
+ <File
RelativePath=".\system\VxWorks\regset.h"
>
</File>
</Filter>
+ <Filter
+ Name="Cygwin"
+ >
+ <File
+ RelativePath=".\system\Cygwin\context-cygwin.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\system\Cygwin\regset.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Msys"
+ >
+ <File
+ RelativePath=".\system\Msys\context-msys.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\system\Msys\regset.h"
+ >
+ </File>
+ </Filter>
</Filter>
<Filter
Name="machine"
@@ -242,7 +242,7 @@ static void ini_services(Protocol * proto, TCFBroadcastGroup * bcg) { ini_memory_map_service(proto, bcg); #endif #if SERVICE_Registers - ini_registers_service(proto); + ini_registers_service(proto, bcg); #endif #if SERVICE_StackTrace ini_stack_trace_service(proto, bcg); diff --git a/framework/context.c b/framework/context.c index a1c31551..07ca6238 100644 --- a/framework/context.c +++ b/framework/context.c @@ -30,7 +30,14 @@ #include "breakpoints.h" #include "waitpid.h" -static ContextEventListener * event_listeners = NULL; +typedef struct Listener { + ContextEventListener * func; + void * args; +} Listener; + +static Listener * listeners = NULL; +static unsigned listener_cnt = 0; +static unsigned listener_max = 0; char * pid2id(pid_t pid, pid_t parent) { static char s[64]; @@ -78,13 +85,20 @@ pid_t id2pid(const char * id, pid_t * parent) { } void add_context_event_listener(ContextEventListener * listener, void * client_data) { - listener->client_data = client_data; - listener->next = event_listeners; - event_listeners = listener; + if (listener_cnt >= listener_max) { + listener_max += 8; + listeners = (Listener *)loc_realloc(listeners, listener_max * sizeof(Listener)); + } + listeners[listener_cnt].func = listener; + listeners[listener_cnt].args = client_data; + listener_cnt++; } #if ENABLE_DebugContext +static size_t extension_size = 0; +static int context_created = 0; + #if !ENABLE_ContextProxy #define CONTEXT_PID_HASH_SIZE 1024 @@ -130,6 +144,34 @@ Context * id2ctx(const char * id) { return context_find_from_pid(pid, parent != 0); } +#endif /* !ENABLE_ContextProxy */ + +size_t context_extension(size_t size) { + size_t offs = 0; + assert(!context_created); + while (extension_size % sizeof(void *) != 0) extension_size++; + offs = sizeof(Context) + extension_size; + extension_size += size; + return offs; +} + +Context * create_context(pid_t pid, size_t regs_size) { + Context * ctx = (Context *)loc_alloc_zero(sizeof(Context) + extension_size); + + ctx->pid = pid; +#if ENABLE_DebugContext && !ENABLE_ContextProxy + if ((ctx->regs_size = regs_size) > 0) { + ctx->regs = (RegisterData *)loc_alloc_zero(regs_size); + } + list_init(&ctx->pidl); + list_init(&ctx->ctxl); +#endif + list_init(&ctx->children); + list_init(&ctx->cldl); + context_created = 1; + return ctx; +} + void context_lock(Context * ctx) { assert(ctx->ref_count > 0); ctx->ref_count++; @@ -138,43 +180,28 @@ void context_lock(Context * ctx) { void context_unlock(Context * ctx) { assert(ctx->ref_count > 0); if (--(ctx->ref_count) == 0) { + unsigned i; + assert(list_is_empty(&ctx->children)); assert(ctx->parent == NULL); -#if SERVICE_StackTrace - assert(ctx->stack_trace == NULL); -#endif -#if SERVICE_MemoryMap - assert(ctx->memory_map == NULL); -#endif -#if SERVICE_Breakpoints - assert(ctx->breakpoints_state == NULL); - assert(ctx->stepping_over_bp == NULL); -#endif + assert(!ctx->event_notification); + ctx->event_notification = 1; + for (i = 0; i < listener_cnt; i++) { + Listener * l = listeners + i; + if (l->func->context_disposed == NULL) continue; + l->func->context_disposed(ctx, l->args); + } + ctx->event_notification = 0; +#if ENABLE_DebugContext && !ENABLE_ContextProxy list_remove(&ctx->ctxl); list_remove(&ctx->pidl); release_error_report(ctx->regs_error); - loc_free(ctx->bp_ids); loc_free(ctx->regs); +#endif loc_free(ctx); } } -Context * create_context(pid_t pid, size_t regs_size) { - Context * ctx = (Context *)loc_alloc_zero(sizeof(Context)); - - ctx->pid = pid; - if ((ctx->regs_size = regs_size) > 0) { - ctx->regs = (RegisterData *)loc_alloc_zero(regs_size); - } - list_init(&ctx->children); - list_init(&ctx->ctxl); - list_init(&ctx->pidl); - list_init(&ctx->cldl); - return ctx; -} - -#endif /* !ENABLE_ContextProxy */ - const char * context_state_name(Context * ctx) { if (ctx->exited) return "exited"; if (ctx->intercepted) return "intercepted"; @@ -183,59 +210,52 @@ const char * context_state_name(Context * ctx) { } void send_context_created_event(Context * ctx) { - ContextEventListener * listener = event_listeners; + unsigned i; assert(ctx->ref_count > 0); assert(!ctx->event_notification); ctx->event_notification = 1; - while (listener != NULL) { - if (listener->context_created != NULL) { - listener->context_created(ctx, listener->client_data); - } - listener = listener->next; + for (i = 0; i < listener_cnt; i++) { + Listener * l = listeners + i; + if (l->func->context_created == NULL) continue; + l->func->context_created(ctx, l->args); } ctx->event_notification = 0; } void send_context_changed_event(Context * ctx) { - ContextEventListener * listener = event_listeners; + unsigned i; assert(ctx->ref_count > 0); assert(!ctx->event_notification); ctx->event_notification = 1; - while (listener != NULL) { - if (listener->context_changed != NULL) { - listener->context_changed(ctx, listener->client_data); - } - listener = listener->next; + for (i = 0; i < listener_cnt; i++) { + Listener * l = listeners + i; + if (l->func->context_changed == NULL) continue; + l->func->context_changed(ctx, l->args); } ctx->event_notification = 0; } void send_context_stopped_event(Context * ctx) { - ContextEventListener * listener = event_listeners; + unsigned i; assert(ctx->ref_count > 0); assert(ctx->stopped != 0); assert(!ctx->event_notification); ctx->event_notification = 1; #if !ENABLE_ContextProxy - if (ctx->bp_ids != NULL) { - loc_free(ctx->bp_ids); - ctx->bp_ids = NULL; - } if (ctx->stopped_by_bp) { evaluate_breakpoint(ctx); } #endif - while (listener != NULL) { - if (listener->context_stopped != NULL) { - listener->context_stopped(ctx, listener->client_data); - } - listener = listener->next; + for (i = 0; i < listener_cnt; i++) { + Listener * l = listeners + i; + if (l->func->context_stopped == NULL) continue; + l->func->context_stopped(ctx, l->args); } ctx->event_notification = 0; } void send_context_started_event(Context * ctx) { - ContextEventListener * listener = event_listeners; + unsigned i; assert(ctx->ref_count > 0); ctx->stopped = 0; #if !ENABLE_ContextProxy @@ -243,17 +263,16 @@ void send_context_started_event(Context * ctx) { ctx->stopped_by_exception = 0; #endif ctx->event_notification++; - while (listener != NULL) { - if (listener->context_started != NULL) { - listener->context_started(ctx, listener->client_data); - } - listener = listener->next; + for (i = 0; i < listener_cnt; i++) { + Listener * l = listeners + i; + if (l->func->context_started == NULL) continue; + l->func->context_started(ctx, l->args); } ctx->event_notification--; } void send_context_exited_event(Context * ctx) { - ContextEventListener * listener = event_listeners; + unsigned i; assert(!ctx->event_notification); #if !ENABLE_ContextProxy ctx->exiting = 0; @@ -261,11 +280,10 @@ void send_context_exited_event(Context * ctx) { #endif ctx->exited = 1; ctx->event_notification = 1; - while (listener != NULL) { - if (listener->context_exited != NULL) { - listener->context_exited(ctx, listener->client_data); - } - listener = listener->next; + for (i = 0; i < listener_cnt; i++) { + Listener * l = listeners + i; + if (l->func->context_exited == NULL) continue; + l->func->context_exited(ctx, l->args); } ctx->event_notification = 0; if (ctx->parent != NULL) { diff --git a/framework/context.h b/framework/context.h index 144c6e02..fbf4fc5a 100644 --- a/framework/context.h +++ b/framework/context.h @@ -42,31 +42,15 @@ struct Context { int intercepted; /* context is reported to a host as suspended */ int exited; /* context exited */ int event_notification; /* set to 1 when calling one of ContextEventListener call-backs for this context */ -#if SERVICE_StackTrace - void * stack_trace; /* pointer to StackTrace service data cache */ -#endif -#if SERVICE_MemoryMap - void * memory_map; /* pointer to MemoryMap service data cache */ -#endif -#if SERVICE_Breakpoints - void * breakpoints_state; /* pointer to Breakpoints service data cache */ -#endif -#if ENABLE_RCBP_TEST - int test_process; /* if not 0, the process is test process started by Diagnostics service */ -#endif -#if ENABLE_ContextProxy - void * proxy; -#elif ENABLE_DebugContext +#if ENABLE_DebugContext && !ENABLE_ContextProxy LINK ctxl; /* link that used to form a list of all contexts */ LINK pidl; /* link that used to form a list of contexts with same hash code */ int stopped_by_bp; /* stopped by breakpoint */ int stopped_by_exception;/* stopped by runtime exception (like SIGSEGV, etc.) */ void * stepping_over_bp; /* if not NULL context is stepping over a breakpoint */ - char ** bp_ids; /* if stopped by breakpoint, contains NULL-terminated list of breakpoint IDs */ int exiting; /* context is about to exit */ int pending_step; /* context is executing single instruction step */ int pending_intercept; /* host is waiting for this context to be suspended */ - int pending_safe_event; /* safe events are waiting for this context to be stopped */ unsigned long pending_signals; /* bitset of signals that were received, but not handled yet */ unsigned long sig_dont_stop; /* bitset of signals that should not be intercepted by the debugger */ unsigned long sig_dont_pass; /* bitset of signals that should not be delivered to the context */ @@ -75,44 +59,9 @@ struct Context { size_t regs_size; /* size of data pointed by "regs" */ ErrorReport * regs_error; /* if not NULL, 'regs' is invalid */ int regs_dirty; /* if not 0, 'regs' is modified and needs to be saved before context is continued */ -/* OS dependant context attributes */ -# if defined(_WRS_KERNEL) - VXDBG_BP_INFO bp_info; /* breakpoint information */ - pid_t bp_pid; /* process or thread that hit breakpoint */ - int event; -# elif defined(WIN32) - HANDLE handle; - HANDLE file_handle; - DWORD64 base_address; - int module_loaded; - int module_unloaded; - HANDLE module_handle; - DWORD64 module_address; - int debug_started; - EXCEPTION_DEBUG_INFO pending_event; - EXCEPTION_DEBUG_INFO suspend_reason; - int context_stopped_async_pending; -# else /* Linux/Unix/BSD */ - ContextAttachCallBack * attach_callback; - void * attach_data; - int ptrace_flags; - int ptrace_event; - int syscall_enter; - int syscall_exit; - int syscall_id; - ContextAddress syscall_pc; - ContextAddress loader_state; - int end_of_step; -# endif #endif /* ENABLE_DebugContext */ }; -extern void ini_contexts(void); -extern void init_contexts_sys_dep(void); - -extern const char * context_state_name(Context * ctx); -extern const char * context_suspend_reason(Context * ctx); - /* * Convert PID to TCF Context ID */ @@ -136,6 +85,26 @@ extern Context * id2ctx(const char * id); #if ENABLE_DebugContext /* + * Register an extension of struct Context. + * Return offset of extension data area. + * Additional memory of given size will be allocated in each context struct. + * Client are allowed to call this function only during initialization. + */ +extern size_t context_extension(size_t size); + +/* + * Get human redable name of current state of a context. + */ +extern const char * context_state_name(Context * ctx); + +/* + * Get state change reason of a context. + * Reason can be any text, but if it is one of predefined strings, + * a generic client might be able to handle it better. + */ +extern const char * context_suspend_reason(Context * ctx); + +/* * Find a context by PID * Both process and main thread can have same PID. * 'thread' = 0: search for process, otherwise search for a thread. @@ -228,12 +197,8 @@ extern void send_context_exited_event(Context * ctx); extern Context * create_context(pid_t pid, size_t regs_size); extern void link_context(Context * ctx); -#else /* ENABLE_DebugContext */ - -#define context_has_state(ctx) 0 -#define context_read_mem(ctx, address, buf, size) (errno = ERR_INV_CONTEXT, -1) -#define context_write_mem(ctx, address, buf, size) (errno = ERR_INV_CONTEXT, -1) -#define context_word_size(ctx) sizeof(void *) +extern void ini_contexts(void); +extern void init_contexts_sys_dep(void); #endif /* ENABLE_DebugContext */ @@ -243,15 +208,9 @@ typedef struct ContextEventListener { void (*context_stopped)(Context * ctx, void * client_data); void (*context_started)(Context * ctx, void * client_data); void (*context_changed)(Context * ctx, void * client_data); - /* Private: */ - void * client_data; - struct ContextEventListener * next; + void (*context_disposed)(Context * ctx, void * client_data); } ContextEventListener; extern void add_context_event_listener(ContextEventListener * listener, void * client_data); -#ifdef _WRS_KERNEL -extern VXDBG_CLNT_ID vxdbg_clnt_id; -#endif - #endif diff --git a/framework/mdep.h b/framework/mdep.h index db7236e9..dcdca407 100644 --- a/framework/mdep.h +++ b/framework/mdep.h @@ -375,6 +375,12 @@ extern char ** environ; #endif /* BSD */ +#if defined(__APPLE__) +# define CLOCK_REALTIME 1 + typedef int clockid_t; + extern int clock_gettime(clockid_t clock_id, struct timespec * tp); +#endif + extern int tkill(pid_t pid, int signal); #define FILE_PATH_SIZE PATH_MAX diff --git a/machine/x86_64/cpudefs-mdep.h b/machine/x86_64/cpudefs-mdep.h index 724f6e7e..e3dc9a29 100644 --- a/machine/x86_64/cpudefs-mdep.h +++ b/machine/x86_64/cpudefs-mdep.h @@ -47,6 +47,25 @@ RegisterDefinition regs_index[] = { { "edi", REG_OFFSET(__edi), 4, 7, 7, 0}, { "eip", REG_OFFSET(__eip), 4, 8, 8, 1}, { "eflags", REG_OFFSET(__eflags), 4, 9, 9, 0}, +#elif defined(__APPLE__) && defined(__x86_64__) + { "rax", REG_OFFSET(__rax), 8, 0, 0, 0}, + { "rdx", REG_OFFSET(__rdx), 8, 1, 1, 0}, + { "rcx", REG_OFFSET(__rcx), 8, 2, 2, 0}, + { "rbx", REG_OFFSET(__rbx), 8, 3, 3, 0}, + { "rsi", REG_OFFSET(__rsi), 8, 4, 4, 0}, + { "rdi", REG_OFFSET(__rdi), 8, 5, 5, 0}, + { "rbp", REG_OFFSET(__rbp), 8, 6, 6, 1}, + { "rsp", REG_OFFSET(__rsp), 8, 7, 7, 1}, + { "r8", REG_OFFSET(__r8), 8, 8, 8, 0}, + { "r9", REG_OFFSET(__r9), 8, 9, 9, 0}, + { "r10", REG_OFFSET(__r10), 8, 10, 10, 0}, + { "r11", REG_OFFSET(__r11), 8, 11, 11, 0}, + { "r12", REG_OFFSET(__r12), 8, 12, 12, 0}, + { "r13", REG_OFFSET(__r13), 8, 13, 13, 0}, + { "r14", REG_OFFSET(__r14), 8, 14, 14, 0}, + { "r15", REG_OFFSET(__r15), 8, 15, 15, 0}, + { "rip", REG_OFFSET(__rip), 8, -1, -1, 1}, + { "eflags", REG_OFFSET(__rflags), 4, 49, -1, 0}, #elif (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(__i386__) { "eax", REG_OFFSET(r_eax), 4, 0, 0, 0}, { "ecx", REG_OFFSET(r_ecx), 4, 1, 1, 0}, @@ -106,10 +125,14 @@ RegisterDefinition regs_index[] = { # define REG_SP Esp # define REG_BP Ebp # define REG_IP Eip -#elif defined(__APPLE__) +#elif defined(__APPLE__) && defined(__i386__) # define REG_SP __esp # define REG_BP __ebp # define REG_IP __eip +#elif defined(__APPLE__) && defined(__x86_64__) +# define REG_SP __rsp +# define REG_BP __rbp +# define REG_IP __rip #elif defined(__FreeBSD__) || defined(__NetBSD__) # define REG_SP r_esp # define REG_BP r_ebp diff --git a/main/test.c b/main/test.c index 48ed33bb..a34640d3 100644 --- a/main/test.c +++ b/main/test.c @@ -28,8 +28,11 @@ #include "myalloc.h" #include "test.h" #include "trace.h" -#include "context.h" +#include "diagnostics.h" #include "errors.h" +#if defined(WIN32) +# include "system/Windows/context-win32.h" +#endif typedef enum test_enum { enum_val1 = 1, @@ -117,7 +120,7 @@ void test_proc(void) { int find_test_symbol(Context * ctx, char * name, void ** addr, int * sym_class) { /* This code allows to run TCF diagnostic tests when symbols info is not available */ if (ctx->parent != NULL) ctx = ctx->parent; - if (ctx->test_process && strncmp(name, "tcf_test_", 9) == 0) { + if (is_test_process(ctx) && strncmp(name, "tcf_test_", 9) == 0) { *addr = NULL; if (strcmp(name, "tcf_test_array") == 0) { *sym_class = SYM_CLASS_REFERENCE; @@ -146,7 +149,7 @@ typedef struct ContextAttachArgs { static void done_context_attach(int error, Context * ctx, void * data) { ContextAttachArgs * args = (ContextAttachArgs *)data; args->done(error, ctx, args->data); - assert(error || args->process != ctx->handle); + assert(error || args->process != get_context_handle(ctx)); CloseHandle(args->thread); CloseHandle(args->process); loc_free(args); diff --git a/server/services/context-proxy.c b/server/services/context-proxy.c index b2263dd2..f18da6de 100644 --- a/server/services/context-proxy.c +++ b/server/services/context-proxy.c @@ -160,6 +160,10 @@ static char * str_buf = NULL; static unsigned str_buf_max = 0; static unsigned str_buf_pos = 0; +static size_t context_extension_offset = 0; + +#define EXT(ctx) ((ContextCache **)((char *)(ctx) + context_extension_offset)) + static const char RUN_CONTROL[] = "RunControl"; static ContextCache * find_context_cache(PeerCache * p, const char * id) { @@ -176,13 +180,10 @@ static void add_context_cache(PeerCache * p, ContextCache * c) { list_init(&c->stk_cache); list_add_first(&c->link_peer, &p->ctx_cache); c->peer = p; - c->ctx = (Context *)loc_alloc_zero(sizeof(Context)); - list_init(&c->ctx->children); - list_init(&c->ctx->cldl); - c->ctx->pid = id2pid(c->id, NULL); + c->ctx = create_context(id2pid(c->id, NULL), 0); c->ctx->mem = c->ctx->pid; - c->ctx->proxy = c; c->ctx->ref_count = 1; + *EXT(c->ctx) = c; if (c->parent_id[0]) { ContextCache * h = find_context_cache(p, c->parent_id); if (h != NULL) { @@ -268,7 +269,7 @@ static void on_context_suspended(ContextCache * c) { ContextCache * p = NULL; while (ctx->parent != NULL && ctx->parent->mem == ctx->mem) ctx = ctx->parent; - p = (ContextCache *)ctx->proxy; + p = *EXT(ctx); l = p->mem_cache.next; while (l != &p->mem_cache) { @@ -370,7 +371,7 @@ static void read_context_removed_item(InputStream * inp, void * args) { json_read_string(inp, id, sizeof(id)); c = find_context_cache(p, id); if (c != NULL) { - assert(c->ctx->proxy == c); + assert(*EXT(c->ctx) == c); send_context_exited_event(c->ctx); } else if (p->rc_done) { @@ -385,7 +386,7 @@ static void read_container_suspended_item(InputStream * inp, void * args) { json_read_string(inp, id, sizeof(id)); c = find_context_cache(p, id); if (c != NULL) { - assert(c->ctx->proxy == c); + assert(*EXT(c->ctx) == c); if (!c->ctx->stopped) { c->ctx->stopped = 1; c->ctx->intercepted = 1; @@ -405,7 +406,7 @@ static void read_container_resumed_item(InputStream * inp, void * args) { json_read_string(inp, id, sizeof(id)); c = find_context_cache(p, id); if (c != NULL) { - assert(c->ctx->proxy == c); + assert(*EXT(c->ctx) == c); if (c->ctx->stopped) { c->ctx->stopped = 0; c->ctx->intercepted = 0; @@ -472,7 +473,7 @@ static void event_context_suspended(Channel * ch, void * args) { if (read_stream(p->fwd_inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); if (c != &buf) { - assert(c->ctx->proxy == c); + assert(*EXT(c->ctx) == c); c->pc_valid = 1; if (!c->ctx->stopped) { c->ctx->stopped = 1; @@ -501,7 +502,7 @@ static void event_context_resumed(Channel * ch, void * args) { c = find_context_cache(p, id); if (c != NULL) { - assert(c->ctx->proxy == c); + assert(*EXT(c->ctx) == c); if (c->ctx->stopped) { c->ctx->stopped = 0; c->ctx->intercepted = 0; @@ -570,22 +571,6 @@ void create_context_proxy(Channel * host, Channel * target) { add_event_handler2(target, RUN_CONTROL, "containerResumed", event_container_resumed, p); } -void context_lock(Context * ctx) { - ctx->ref_count++; -} - -void context_unlock(Context * ctx) { - assert(ctx->ref_count > 0); - if (--ctx->ref_count == 0) { - ContextCache * c = (ContextCache *)ctx->proxy; - assert(list_is_empty(&ctx->children)); - assert(ctx->parent == NULL); - loc_free(ctx); - c->ctx = NULL; - free_context_cache(c); - } -} - static void validate_peer_cache_context(Channel * c, void * args, int error); static void validate_peer_cache_state(Channel * c, void * args, int error); @@ -782,8 +767,7 @@ Context * id2ctx(const char * id) { } int context_has_state(Context * ctx) { - ContextCache * cache = (ContextCache *)ctx->proxy; - return cache->has_state; + return (*EXT(ctx))->has_state; } static void validate_memory_cache(Channel * c, void * args, int error) { @@ -835,7 +819,7 @@ int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t s while (ctx->parent != NULL && ctx->parent->mem == ctx->mem) ctx = ctx->parent; - cache = (ContextCache *)ctx->proxy; + cache = *EXT(ctx); c = cache->peer->target; for (l = cache->mem_cache.next; l != &cache->mem_cache; l = l->next) { @@ -944,7 +928,7 @@ static void validate_memory_map_cache(Channel * c, void * args, int error) { void memory_map_get_regions(Context * ctx, MemoryRegion ** regions, unsigned * cnt) { ContextCache * cache = NULL; while (ctx->parent != NULL && ctx->parent->mem == ctx->mem) ctx = ctx->parent; - cache = (ContextCache *)ctx->proxy; + cache = *EXT(ctx); assert(cache->ctx == ctx); if (cache->pending_get_mmap != NULL) cache_wait(&cache->mmap_cache); if (cache->mmap_regions == NULL && cache->mmap_error == NULL && cache->peer != NULL) { @@ -1108,20 +1092,20 @@ static void check_registers_cache(ContextCache * cache) { } RegisterDefinition * get_reg_definitions(Context * ctx) { - ContextCache * cache = (ContextCache *)ctx->proxy; + ContextCache * cache = *EXT(ctx); check_registers_cache(cache); return cache->reg_defs; } RegisterDefinition * get_PC_definition(Context * ctx) { - ContextCache * cache = (ContextCache *)ctx->proxy; + ContextCache * cache = *EXT(ctx); check_registers_cache(cache); return cache->pc_def; } RegisterDefinition * get_reg_by_id(Context * ctx, unsigned id, unsigned munbering_convention) { RegisterDefinition * defs; - ContextCache * cache = (ContextCache *)ctx->proxy; + ContextCache * cache = *EXT(ctx); check_registers_cache(cache); defs = cache->reg_defs; while (defs != NULL && defs->name != NULL) { @@ -1321,7 +1305,7 @@ static void validate_stack_frame_cache(Channel * c, void * args, int error) { } int get_frame_info(Context * ctx, int frame, StackFrame ** info) { - ContextCache * cache = (ContextCache *)ctx->proxy; + ContextCache * cache = *EXT(ctx); Channel * c = cache->peer->target; StackFrameCache * s = NULL; LINK * l = NULL; @@ -1405,9 +1389,25 @@ static void channel_close_listener(Channel * c) { } } +void event_context_disposed(Context * ctx, void * args) { + ContextCache * c = *EXT(ctx); + c->ctx = NULL; + free_context_cache(c); +} + void init_contexts_sys_dep(void) { - list_init(&peers); + static ContextEventListener listener = { + NULL, + NULL, + NULL, + NULL, + NULL, + event_context_disposed + }; + add_context_event_listener(&listener, NULL); add_channel_close_listener(channel_close_listener); + context_extension_offset = context_extension(sizeof(ContextCache *)); + list_init(&peers); } #endif /* ENABLE_DebugContext && ENABLE_ContextProxy */ diff --git a/services/breakpoints.c b/services/breakpoints.c index 23f0ed85..ac69f6ee 100644 --- a/services/breakpoints.c +++ b/services/breakpoints.c @@ -46,6 +46,7 @@ #if defined(_WRS_KERNEL) # include <private/vxdbgLibP.h> +# include "system/VxWorks/context-vxworks.h" #endif typedef struct BreakpointClient BreakpointClient; @@ -54,6 +55,7 @@ typedef struct BreakInstruction BreakInstruction; typedef struct EvaluationArgs EvaluationArgs; typedef struct EvaluationRequest EvaluationRequest; typedef struct ConditionEvaluationRequest ConditionEvaluationRequest; +typedef struct ContextExtension ContextExtension; struct BreakpointClient { LINK link_inp; @@ -138,8 +140,17 @@ struct EvaluationRequest { ConditionEvaluationRequest * bp_arr; }; +struct ContextExtension { + char ** bp_ids; /* if stopped by breakpoint, contains NULL-terminated list of breakpoint IDs */ + EvaluationRequest * req; +}; + static const char * BREAKPOINTS = "Breakpoints"; +static size_t context_extension_offset = 0; + +#define EXT(ctx) ((ContextExtension *)((char *)(ctx) + context_extension_offset)) + #define is_readable(ctx) (!(ctx)->exited && !(ctx)->exiting && ((ctx)->stopped || !context_has_state(ctx))) #define is_disabled(bp) (bp->enabled == 0 || bp->client_cnt == 0 || bp->unsupported != NULL) @@ -513,13 +524,13 @@ static void plant_breakpoint_at_address(BreakpointInfo * bp, Context * ctx, Cont static void event_replant_breakpoints(void * arg); static EvaluationRequest * create_evaluation_request(Context * ctx, int bp_cnt) { - EvaluationRequest * req = (EvaluationRequest *)ctx->breakpoints_state; + EvaluationRequest * req = EXT(ctx)->req; if (req == NULL) { req = (EvaluationRequest *)loc_alloc_zero(sizeof(EvaluationRequest)); req->ctx = ctx; list_init(&req->link_posted); list_init(&req->link_active); - ctx->breakpoints_state = req; + EXT(ctx)->req = req; } if (req->bp_max < bp_cnt) { req->bp_max = bp_cnt; @@ -668,6 +679,7 @@ static void done_condition(EvaluationRequest * req, int * need_to_flush) { bp->event_callback(ctx, bp->event_callback_args); } else { + assert(bp->id[0] != 0); req->bp_arr[i].triggered = 1; size += sizeof(char *) + strlen(bp->id) + 1; } @@ -678,7 +690,9 @@ static void done_condition(EvaluationRequest * req, int * need_to_flush) { size_t mem_size = size + sizeof(char *); char ** bp_arr = (char **)loc_alloc(mem_size); char * pool = (char *)bp_arr + mem_size; - ctx->bp_ids = bp_arr; + assert(ctx->stopped); + assert(EXT(ctx)->bp_ids == NULL); + EXT(ctx)->bp_ids = bp_arr; for (i = 0; i < req->bp_cnt; i++) { BreakpointInfo * bp = req->bp_arr[i].bp; if (req->bp_arr[i].triggered) { @@ -693,7 +707,7 @@ static void done_condition(EvaluationRequest * req, int * need_to_flush) { for (i = 0; i < req->bp_cnt; i++) { BreakpointInfo * bp = req->bp_arr[i].bp; if (req->bp_arr[i].triggered && bp->stop_group == NULL) { - suspend_debug_context(broadcast_group, ctx); + suspend_debug_context(ctx); *need_to_flush = 1; } } @@ -734,7 +748,7 @@ static void done_conditions_evaluation(int * need_to_flush) { while (*ids) { Context * c = id2ctx(*ids++); if (c != NULL) { - suspend_debug_context(broadcast_group, c); + suspend_debug_context(c); *need_to_flush = 1; } } @@ -744,13 +758,8 @@ static void done_conditions_evaluation(int * need_to_flush) { req->bp_cnt = 0; list_remove(&req->link_active); if (list_is_empty(&req->link_posted)) { - if (ctx->exited) { - loc_free(req->bp_arr); - loc_free(req); - ctx->breakpoints_state = NULL; - } - else if (ctx->pending_intercept) { - suspend_debug_context(broadcast_group, ctx); + if (!ctx->exited && ctx->pending_intercept) { + suspend_debug_context(ctx); *need_to_flush = 1; } assert(!ctx->pending_intercept || ctx->event_notification); @@ -846,7 +855,7 @@ static void evaluate_condition(void * x) { int i; EvaluationArgs * args = (EvaluationArgs *)x; Context * ctx = args->ctx; - EvaluationRequest * req = (EvaluationRequest *)ctx->breakpoints_state; + EvaluationRequest * req = EXT(ctx)->req; assert(req != NULL); assert(req->bp_cnt > 0); @@ -1679,8 +1688,8 @@ void evaluate_breakpoint(Context * ctx) { assert(ctx->stopped); assert(ctx->stopped_by_bp); assert(ctx->exiting == 0); - assert(ctx->bp_ids == NULL); assert(ctx->intercepted == 0); + assert(EXT(ctx)->bp_ids == NULL); if (bi == NULL || !bi->planted || bi->ref_cnt == 0) return; @@ -1713,6 +1722,10 @@ void evaluate_breakpoint(Context * ctx) { } } +char ** get_context_breakpoint_ids(Context * ctx) { + return EXT(ctx)->bp_ids; +} + #ifndef _WRS_KERNEL static void safe_restore_breakpoint(void * arg) { @@ -1731,7 +1744,7 @@ static void safe_restore_breakpoint(void * arg) { plant_instruction(bi); } if (ctx->pending_intercept) { - suspend_debug_context(broadcast_group, ctx); + suspend_debug_context(ctx); flush_stream(&broadcast_group->out); } } @@ -1826,6 +1839,28 @@ static void event_context_changed(Context * ctx, void * args) { post_location_evaluation_request(ctx); } +static void event_context_started(Context * ctx, void * args) { + ContextExtension * ext = EXT(ctx); + if (ext->bp_ids != NULL) { + loc_free(ext->bp_ids); + ext->bp_ids = NULL; + } +} + +static void event_context_disposed(Context * ctx, void * args) { + ContextExtension * ext = EXT(ctx); + EvaluationRequest * req = ext->req; + if (req != NULL) { + loc_free(req->bp_arr); + loc_free(req); + ext->req = NULL; + } + if (ext->bp_ids != NULL) { + loc_free(ext->bp_ids); + ext->bp_ids = NULL; + } +} + static void event_code_unmapped(Context * ctx, ContextAddress addr, ContextAddress size, void * args) { /* Unmapping a code section unplants all breakpoint instructions in that section as side effect. * This function udates service data structure to reflect that. @@ -1849,7 +1884,7 @@ static void channel_close_listener(Channel * c) { #if !defined(_WRS_KERNEL) static void eventpoint_at_main(Context * ctx, void * args) { - suspend_debug_context(broadcast_group, ctx); + suspend_debug_context(ctx); flush_stream(&broadcast_group->out); } #endif @@ -1863,8 +1898,9 @@ void ini_breakpoints_service(Protocol * proto, TCFBroadcastGroup * bcg) { event_context_changed, event_context_changed, NULL, - NULL, - event_context_changed + event_context_started, + event_context_changed, + event_context_disposed }; add_context_event_listener(&listener, NULL); } @@ -1893,6 +1929,7 @@ void ini_breakpoints_service(Protocol * proto, TCFBroadcastGroup * bcg) { add_command_handler(proto, BREAKPOINTS, "getProperties", command_get_properties); add_command_handler(proto, BREAKPOINTS, "getStatus", command_get_status); add_command_handler(proto, BREAKPOINTS, "getCapabilities", command_get_capabilities); + context_extension_offset = context_extension(sizeof(ContextExtension)); #if !defined(_WRS_KERNEL) create_eventpoint("main", eventpoint_at_main, NULL); #endif diff --git a/services/breakpoints.h b/services/breakpoints.h index 4310cc25..e992f0d8 100644 --- a/services/breakpoints.h +++ b/services/breakpoints.h @@ -36,6 +36,12 @@ typedef struct BreakpointInfo BreakpointInfo; extern void evaluate_breakpoint(Context * ctx); /* + * Return NULL-terminated array of breakpoint IDs if the context is stopped by breakpoint. + * Otherwise return NULL. + */ +extern char ** get_context_breakpoint_ids(Context * ctx); + +/* * When a context is stopped by breakpoint, it is necessary to disable * the breakpoint temporarily before the context can be resumed. * This function function removes break instruction, then does single step diff --git a/services/diagnostics.c b/services/diagnostics.c index 09794aab..b83e3ae2 100644 --- a/services/diagnostics.c +++ b/services/diagnostics.c @@ -42,6 +42,22 @@ static const char * DIAGNOSTICS = "Diagnostics"; +#if ENABLE_RCBP_TEST + +typedef struct ContextExtension { + int test_process; +} ContextExtension; + +static size_t context_extension_offset = 0; + +#define EXT(ctx) ((ContextExtension *)((char *)(ctx) + context_extension_offset)) + +int is_test_process(Context * ctx) { + return EXT(ctx)->test_process; +} + +#endif /* ENABLE_RCBP_TEST */ + typedef struct RunTestDoneArgs RunTestDoneArgs; struct RunTestDoneArgs { @@ -92,7 +108,7 @@ static void run_test_done(int error, Context * ctx, void * arg) { RunTestDoneArgs * data = (RunTestDoneArgs *)arg; Channel * c = data->c; - if (ctx != NULL) ctx->test_process = 1; + if (ctx != NULL) EXT(ctx)->test_process = 1; if (!is_channel_closed(c)) { write_stringz(&c->out, "R"); write_stringz(&c->out, data->token); @@ -368,6 +384,9 @@ void ini_diagnostics_service(Protocol * proto) { add_command_handler(proto, DIAGNOSTICS, "getSymbol", command_get_symbol); add_command_handler(proto, DIAGNOSTICS, "createTestStreams", command_create_test_streams); add_command_handler(proto, DIAGNOSTICS, "disposeTestStream", command_dispose_test_stream); +#if ENABLE_RCBP_TEST + context_extension_offset = context_extension(sizeof(ContextExtension)); +#endif } diff --git a/services/diagnostics.h b/services/diagnostics.h index dbb8f043..34a4d48f 100644 --- a/services/diagnostics.h +++ b/services/diagnostics.h @@ -21,6 +21,9 @@ #define D_diagnostics #include "protocol.h" +#include "context.h" + +extern int is_test_process(Context * ctx); extern void ini_diagnostics_service(Protocol *); diff --git a/services/linenumbers_win32.c b/services/linenumbers_win32.c index ab9f1491..a14c4237 100644 --- a/services/linenumbers_win32.c +++ b/services/linenumbers_win32.c @@ -28,6 +28,7 @@ #include "linenumbers.h" #include "breakpoints.h" #include "windbgcache.h" +#include "context-win32.h" #include "context.h" #include "exceptions.h" #include "symbols.h" @@ -50,7 +51,7 @@ int line_to_address(Context * ctx, char * file, int line, int column, LineNumber memset(&area, 0, sizeof(area)); img_line.SizeOfStruct = sizeof(IMAGEHLP_LINE); - if (!SymGetLineFromName(ctx->handle, NULL, file, line, &offset, &img_line)) { + if (!SymGetLineFromName(get_context_handle(ctx), NULL, file, line, &offset, &img_line)) { DWORD win_err = GetLastError(); if (win_err != ERROR_NOT_FOUND) { err = set_win32_errno(win_err); @@ -59,7 +60,7 @@ int line_to_address(Context * ctx, char * file, int line, int column, LineNumber else { IMAGEHLP_LINE img_next; memcpy(&img_next, &img_line, sizeof(img_next)); - if (!SymGetLineNext(ctx->handle, &img_next)) { + if (!SymGetLineNext(get_context_handle(ctx), &img_next)) { err = set_win32_errno(GetLastError()); } else { @@ -101,7 +102,7 @@ int address_to_line(Context * ctx, ContextAddress addr0, ContextAddress addr1, L line.SizeOfStruct = sizeof(IMAGEHLP_LINE); if (addr0 >= addr1) not_found = 1; - while (err == 0 && not_found == 0 && !SymGetLineFromAddr(ctx->handle, addr0, &offset, &line)) { + while (err == 0 && not_found == 0 && !SymGetLineFromAddr(get_context_handle(ctx), addr0, &offset, &line)) { DWORD w = GetLastError(); if (w == ERROR_MOD_NOT_FOUND) { not_found = 1; @@ -149,7 +150,7 @@ int address_to_line(Context * ctx, ContextAddress addr0, ContextAddress addr1, L } } memcpy(&next, &line, sizeof(next)); - if (err == 0 && !not_found && !SymGetLineNext(ctx->handle, &next)) { + if (err == 0 && !not_found && !SymGetLineNext(get_context_handle(ctx), &next)) { err = set_win32_errno(GetLastError()); } @@ -165,7 +166,7 @@ int address_to_line(Context * ctx, ContextAddress addr0, ContextAddress addr1, L callback(&area, user_args); if (next.Address >= addr1) break; memcpy(&line, &next, sizeof(line)); - if (!SymGetLineNext(ctx->handle, &next)) break; + if (!SymGetLineNext(get_context_handle(ctx), &next)) break; } } diff --git a/services/memorymap.c b/services/memorymap.c index a024107d..c7ae7839 100644 --- a/services/memorymap.c +++ b/services/memorymap.c @@ -35,38 +35,48 @@ #include "events.h" #include "exceptions.h" -typedef struct MemoryMap MemoryMap; - -struct MemoryMap { +typedef struct MemoryMap { + int valid; unsigned region_cnt; unsigned region_max; MemoryRegion * regions; -}; +} MemoryMap; + +typedef struct Listener { + MemoryMapEventListener * listener; + void * args; +} Listener; + +static size_t context_extension_offset = 0; + +#define EXT(ctx) ((MemoryMap *)((char *)(ctx) + context_extension_offset)) static const char * MEMORYMAP = "MemoryMap"; -static MemoryMapEventListener * event_listeners = NULL; + +static Listener * listeners = NULL; +static unsigned listener_cnt = 0; +static unsigned listener_max = 0; + static TCFBroadcastGroup * broadcast_group = NULL; -static void dispose_memory_map(MemoryMap * map) { +static void event_memory_map_changed(Context * ctx, void * args) { unsigned i; + OutputStream * out; + MemoryMap * map = NULL; + + while (ctx->parent != NULL && ctx->parent->mem == ctx->mem) ctx = ctx->parent; + map = EXT(ctx); for (i = 0; i < map->region_cnt; i++) { MemoryRegion * r = map->regions + i; loc_free(r->file_name); loc_free(r->sect_name); } - loc_free(map->regions); - loc_free(map); -} - -static void event_memory_map_changed(Context * ctx, void * args) { - OutputStream * out; + map->region_cnt = 0; - while (ctx->parent != NULL && ctx->parent->mem == ctx->mem) ctx = ctx->parent; - if (ctx->memory_map == NULL) return; + if (!map->valid) return; + map->valid = 0; - dispose_memory_map((MemoryMap *)ctx->memory_map); - ctx->memory_map = NULL; out = &broadcast_group->out; write_stringz(out, "E"); @@ -78,12 +88,24 @@ static void event_memory_map_changed(Context * ctx, void * args) { write_stream(out, MARKER_EOM); } +static void event_context_disposed(Context * ctx, void * args) { + unsigned i; + MemoryMap * map = EXT(ctx); + + for (i = 0; i < map->region_cnt; i++) { + MemoryRegion * r = map->regions + i; + loc_free(r->file_name); + loc_free(r->sect_name); + } + loc_free(map->regions); + memset(map, 0, sizeof(MemoryMap)); +} + #if defined(_WRS_KERNEL) static int hooks_done = 0; -static MemoryMap * map = NULL; -static void add_map_region(void * addr, int size, unsigned flags, char * file, char * sect) { +static void add_map_region(MemoryMap * map, void * addr, int size, unsigned flags, char * file, char * sect) { MemoryRegion * r = NULL; if (map->region_cnt >= map->region_max) { map->region_max += 8; @@ -100,17 +122,19 @@ static void add_map_region(void * addr, int size, unsigned flags, char * file, c static int module_list_proc(MODULE_ID id, int args) { MODULE_INFO info; + MemoryMap * map = (MemoryMap *)args; + memset(&info, 0, sizeof(info)); if (moduleInfoGet(id, &info) == OK) { char * file = id->nameWithPath; if (info.segInfo.textAddr != NULL && info.segInfo.textSize > 0) { - add_map_region(info.segInfo.textAddr, info.segInfo.textSize, MM_FLAG_R | MM_FLAG_X, file, ".text"); + add_map_region(map, info.segInfo.textAddr, info.segInfo.textSize, MM_FLAG_R | MM_FLAG_X, file, ".text"); } if (info.segInfo.dataAddr != NULL && info.segInfo.dataSize > 0) { - add_map_region(info.segInfo.dataAddr, info.segInfo.dataSize, MM_FLAG_R | MM_FLAG_W, file, ".data"); + add_map_region(map, info.segInfo.dataAddr, info.segInfo.dataSize, MM_FLAG_R | MM_FLAG_W, file, ".data"); } if (info.segInfo.bssAddr != NULL && info.segInfo.bssSize > 0) { - add_map_region(info.segInfo.bssAddr, info.segInfo.bssSize, MM_FLAG_R | MM_FLAG_W, file, ".bss"); + add_map_region(map, info.segInfo.bssAddr, info.segInfo.bssSize, MM_FLAG_R | MM_FLAG_W, file, ".bss"); } } return 0; @@ -130,32 +154,32 @@ static int module_create_func(MODULE_ID id) { } static MemoryMap * get_memory_map(Context * ctx) { + MemoryMap * map = NULL; if (!hooks_done) { hooks_done = 1; moduleCreateHookAdd(module_create_func); } while (ctx->parent != NULL && ctx->parent->mem == ctx->mem) ctx = ctx->parent; - if (ctx->memory_map == NULL && !ctx->exited) { - map = loc_alloc_zero(sizeof(MemoryMap)); - moduleEach(module_list_proc, 0); - ctx->memory_map = map; - map = NULL; + map = EXT(ctx); + if (!map->valid && !ctx->exited) { + moduleEach(module_list_proc, (int)map); + map->valid = 1; } - return (MemoryMap *)ctx->memory_map; + return map; } #elif defined(WIN32) static MemoryMap * get_memory_map(Context * ctx) { - errno = 0; - return NULL; + while (ctx->parent != NULL && ctx->parent->mem == ctx->mem) ctx = ctx->parent; + return EXT(ctx); } #elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) static MemoryMap * get_memory_map(Context * ctx) { - errno = 0; - return NULL; + while (ctx->parent != NULL && ctx->parent->mem == ctx->mem) ctx = ctx->parent; + return EXT(ctx); } #else @@ -163,14 +187,14 @@ static MemoryMap * get_memory_map(Context * ctx) { static MemoryMap * get_memory_map(Context * ctx) { char maps_file_name[FILE_PATH_SIZE]; MemoryMap * map = NULL; - FILE * file; + FILE * file = NULL; while (ctx->parent != NULL && ctx->parent->mem == ctx->mem) ctx = ctx->parent; - if (ctx->memory_map != NULL || ctx->exited) return (MemoryMap *)ctx->memory_map; + map = EXT(ctx); + if (map->valid || ctx->exited) return map; snprintf(maps_file_name, sizeof(maps_file_name), "/proc/%d/maps", ctx->pid); - if ((file = fopen(maps_file_name, "r")) == NULL) return NULL; - map = (MemoryMap *)loc_alloc_zero(sizeof(MemoryMap)); + if ((file = fopen(maps_file_name, "r")) == NULL) return map; for (;;) { unsigned long addr0 = 0; unsigned long addr1 = 0; @@ -219,7 +243,7 @@ static MemoryMap * get_memory_map(Context * ctx) { } } fclose(file); - ctx->memory_map = map; + map->valid = 1; return map; } @@ -227,57 +251,53 @@ static MemoryMap * get_memory_map(Context * ctx) { void memory_map_get_regions(Context * ctx, MemoryRegion ** regions, unsigned * cnt) { MemoryMap * map = get_memory_map(ctx); - if (map == NULL) { - *regions = NULL; - *cnt = 0; - } - else { - *regions = map->regions; - *cnt = map->region_cnt; - } + *regions = map->regions; + *cnt = map->region_cnt; } void memory_map_event_module_loaded(Context * ctx) { - MemoryMapEventListener * listener = event_listeners; + unsigned i; assert(ctx->ref_count > 0); assert(ctx->parent == NULL); event_memory_map_changed(ctx, NULL); - while (listener != NULL) { - if (listener->module_loaded != NULL) { - listener->module_loaded(ctx, listener->client_data); - } - listener = listener->next; + for (i = 0; i < listener_cnt; i++) { + Listener * l = listeners + i; + if (l->listener->module_loaded == NULL) continue; + l->listener->module_loaded(ctx, l->args); } } void memory_map_event_code_section_ummapped(Context * ctx, ContextAddress addr, ContextAddress size) { - MemoryMapEventListener * listener = event_listeners; + unsigned i; assert(ctx->ref_count > 0); assert(ctx->parent == NULL); - while (listener != NULL) { - if (listener->code_section_ummapped != NULL) { - listener->code_section_ummapped(ctx, addr, size, listener->client_data); - } - listener = listener->next; + for (i = 0; i < listener_cnt; i++) { + Listener * l = listeners + i; + if (l->listener->code_section_ummapped == NULL) continue; + l->listener->code_section_ummapped(ctx, addr, size, l->args); } } void memory_map_event_module_unloaded(Context * ctx) { - MemoryMapEventListener * listener = event_listeners; + unsigned i; assert(ctx->ref_count > 0); event_memory_map_changed(ctx, NULL); - while (listener != NULL) { - if (listener->module_unloaded != NULL) { - listener->module_unloaded(ctx, listener->client_data); - } - listener = listener->next; + for (i = 0; i < listener_cnt; i++) { + Listener * l = listeners + i; + if (l->listener->module_unloaded == NULL) continue; + l->listener->module_unloaded(ctx, l->args); } } void add_memory_map_event_listener(MemoryMapEventListener * listener, void * client_data) { - listener->client_data = client_data; - listener->next = event_listeners; - event_listeners = listener; + Listener * l = NULL; + if (listener_cnt >= listener_max) { + listener_max += 8; + listeners = (Listener *)loc_realloc(listeners, listener_max * sizeof(Listener)); + } + l = listeners + listener_cnt++; + l->listener = listener; + l->args = client_data; } static void command_get(char * token, Channel * c) { @@ -350,11 +370,13 @@ void ini_memory_map_service(Protocol * proto, TCFBroadcastGroup * bcg) { event_memory_map_changed, NULL, NULL, - event_memory_map_changed + event_memory_map_changed, + event_context_disposed }; broadcast_group = bcg; add_context_event_listener(&listener, NULL); add_command_handler(proto, MEMORYMAP, "get", command_get); + context_extension_offset = context_extension(sizeof(MemoryMap)); } diff --git a/services/memorymap.h b/services/memorymap.h index 3543fd95..e924b71d 100644 --- a/services/memorymap.h +++ b/services/memorymap.h @@ -58,9 +58,6 @@ typedef struct MemoryMapEventListener { void (*module_loaded)(Context * ctx, void * client_data); void (*code_section_ummapped)(Context * ctx, ContextAddress addr, ContextAddress size, void * client_data); void (*module_unloaded)(Context * ctx, void * client_data); - /* Private: */ - void * client_data; - struct MemoryMapEventListener * next; } MemoryMapEventListener; /* diff --git a/services/registers.c b/services/registers.c index 1a89f3b7..90b48b5d 100644 --- a/services/registers.c +++ b/services/registers.c @@ -37,6 +37,8 @@ static const char * REGISTERS = "Registers"; static short endianess_test = 0x0201; #define BIG_ENDIAN_DATA (*(char *)&endianess_test == 0x02) +static TCFBroadcastGroup * broadcast_group = NULL; + static void write_context(OutputStream * out, char * id, Context * ctx, int frame, RegisterDefinition * reg_def) { assert(!ctx->exited); @@ -188,15 +190,16 @@ static void command_get_children(char * token, Channel * c) { write_stream(&c->out, MARKER_EOM); } -static void send_event_register_changed(Channel * c, char * id) { - write_stringz(&c->out, "E"); - write_stringz(&c->out, REGISTERS); - write_stringz(&c->out, "registerChanged"); +static void send_event_register_changed(char * id) { + OutputStream * out = &broadcast_group->out; + write_stringz(out, "E"); + write_stringz(out, REGISTERS); + write_stringz(out, "registerChanged"); - json_write_string(&c->out, id); - write_stream(&c->out, 0); + json_write_string(out, id); + write_stream(out, 0); - write_stream(&c->out, MARKER_EOM); + write_stream(out, MARKER_EOM); } static void command_get(char * token, Channel * c) { @@ -274,7 +277,7 @@ static void command_set(char * token, Channel * c) { else { memcpy(data, val, val_len); ctx->regs_dirty = 1; - send_event_register_changed(c, id); + send_event_register_changed(id); } } @@ -397,7 +400,7 @@ static void command_setm(char * token, Channel * c) { if (rd == 0) break; rd_done += rd; } - send_event_register_changed(c, l->id); + send_event_register_changed(l->id); } } json_read_binary_end(&state); @@ -430,7 +433,8 @@ static void command_search(char * token, Channel * c) { write_stream(&c->out, MARKER_EOM); } -void ini_registers_service(Protocol * proto) { +void ini_registers_service(Protocol * proto, TCFBroadcastGroup * bcg) { + broadcast_group = bcg; add_command_handler(proto, REGISTERS, "getContext", command_get_context); add_command_handler(proto, REGISTERS, "getChildren", command_get_children); add_command_handler(proto, REGISTERS, "get", command_get); diff --git a/services/registers.h b/services/registers.h index 95d145a4..6f167989 100644 --- a/services/registers.h +++ b/services/registers.h @@ -24,7 +24,7 @@ /* * Initialize registers service. */ -extern void ini_registers_service(Protocol *); +extern void ini_registers_service(Protocol *, TCFBroadcastGroup *); #endif /* D_registers */ diff --git a/services/runctrl.c b/services/runctrl.c index c63138d6..72f080d0 100644 --- a/services/runctrl.c +++ b/services/runctrl.c @@ -60,22 +60,27 @@ static const char RUN_CONTROL[] = "RunControl"; -typedef struct SafeEvent SafeEvent; +typedef struct ContextExtension { + int pending_safe_event; /* safe events are waiting for this context to be stopped */ + int intercepted_by_bp; +} ContextExtension; -struct SafeEvent { +static size_t context_extension_offset = 0; + +#define EXT(ctx) ((ContextExtension *)((char *)(ctx) + context_extension_offset)) + +typedef struct SafeEvent { pid_t mem; EventCallBack * done; void * arg; - SafeEvent * next; -}; - -typedef struct GetContextArgs GetContextArgs; + struct SafeEvent * next; +} SafeEvent; -struct GetContextArgs { +typedef struct GetContextArgs { Channel * c; char token[256]; Context * ctx; -}; +} GetContextArgs; static SafeEvent * safe_event_list = NULL; static SafeEvent * safe_event_last = NULL; @@ -83,6 +88,8 @@ static int safe_event_pid_count = 0; static uintptr_t safe_event_generation = 0; static int run_ctrl_lock_cnt = 0; +static TCFBroadcastGroup * broadcast_group = NULL; + #if !defined(WIN32) && !defined(_WRS_KERNEL) static char * get_executable(pid_t pid) { static char s[FILE_PATH_SIZE + 1]; @@ -179,6 +186,7 @@ static void write_context(OutputStream * out, Context * ctx) { static void write_context_state(OutputStream * out, Context * ctx) { int fst = 1; const char * reason = NULL; + char ** bp_ids = NULL; assert(!ctx->exited); if (!ctx->intercepted) { @@ -193,8 +201,9 @@ static void write_context_state(OutputStream * out, Context * ctx) { write_stream(out, 0); /* String: Reason */ - if (ctx->bp_ids != NULL && ctx->bp_ids[0] != NULL) reason = "Breakpoint"; - if (reason == NULL) reason = context_suspend_reason(ctx); + if (EXT(ctx)->intercepted_by_bp == 1) bp_ids = get_context_breakpoint_ids(ctx); + if (bp_ids != NULL) reason = "Breakpoint"; + else reason = context_suspend_reason(ctx); json_write_string(out, reason); write_stream(out, 0); @@ -212,15 +221,15 @@ static void write_context_state(OutputStream * out, Context * ctx) { } fst = 0; } - if (ctx->bp_ids != NULL && ctx->bp_ids[0] != NULL) { + if (bp_ids != NULL) { int i = 0; if (!fst) write_stream(out, ','); json_write_string(out, "BPs"); write_stream(out, ':'); write_stream(out, '['); - while (ctx->bp_ids[i] != NULL) { + while (bp_ids[i] != NULL) { if (i > 0) write_stream(out, ','); - json_write_string(out, ctx->bp_ids[i++]); + json_write_string(out, bp_ids[i++]); } write_stream(out, ']'); fst = 0; @@ -467,7 +476,7 @@ static void command_resume(char * token, Channel * c) { static void send_event_context_suspended(OutputStream * out, Context * ctx); -int suspend_debug_context(TCFBroadcastGroup * bcg, Context * ctx) { +int suspend_debug_context(Context * ctx) { LINK * qp; if (context_has_state(ctx) && !ctx->exited) { if (!ctx->stopped) { @@ -483,12 +492,12 @@ int suspend_debug_context(TCFBroadcastGroup * bcg, Context * ctx) { } else { ctx->pending_step = 0; - send_event_context_suspended(&bcg->out, ctx); + send_event_context_suspended(&broadcast_group->out, ctx); } } } for (qp = ctx->children.next; qp != &ctx->children; qp = qp->next) { - suspend_debug_context(bcg, cldl2ctxp(qp)); + suspend_debug_context(cldl2ctxp(qp)); } return 0; } @@ -512,7 +521,7 @@ static void command_suspend(char * token, Channel * c) { else if (ctx->intercepted) { err = ERR_ALREADY_STOPPED; } - else if (suspend_debug_context(c->bcg, ctx) < 0) { + else if (suspend_debug_context(ctx) < 0) { err = errno; } @@ -630,6 +639,7 @@ static void send_event_context_suspended(OutputStream * out, Context * ctx) { assert(!ctx->pending_step); ctx->intercepted = 1; ctx->pending_intercept = 0; + if (get_context_breakpoint_ids(ctx) != NULL) EXT(ctx)->intercepted_by_bp++; write_stringz(out, "E"); write_stringz(out, RUN_CONTROL); @@ -648,10 +658,6 @@ static void send_event_context_resumed(OutputStream * out, Context * ctx) { assert(!ctx->pending_intercept); assert(!ctx->pending_step); ctx->intercepted = 0; - if (ctx->bp_ids != NULL) { - loc_free(ctx->bp_ids); - ctx->bp_ids = NULL; - } write_stringz(out, "E"); write_stringz(out, RUN_CONTROL); @@ -708,7 +714,7 @@ static void run_safe_events(void * arg) { for (qp = context_root.next; qp != &context_root; qp = qp->next) { int n = 0; Context * ctx = ctxl2ctxp(qp); - ctx->pending_safe_event = 0; + EXT(ctx)->pending_safe_event = 0; if (ctx->exited) continue; if (!ctx->stopped) continue; if (ctx->intercepted) continue; @@ -736,14 +742,14 @@ static void run_safe_events(void * arg) { for (qp = context_root.next; qp != &context_root; qp = qp->next) { Context * ctx = ctxl2ctxp(qp); if (ctx->exited || ctx->exiting || ctx->stopped || !context_has_state(ctx)) { - ctx->pending_safe_event = 0; + EXT(ctx)->pending_safe_event = 0; continue; } if (mem > 0 && ctx->mem != mem) { - ctx->pending_safe_event = 0; + EXT(ctx)->pending_safe_event = 0; continue; } - if (!ctx->pending_step || ctx->pending_safe_event >= STOP_ALL_MAX_CNT / 2) { + if (!ctx->pending_step || EXT(ctx)->pending_safe_event >= STOP_ALL_MAX_CNT / 2) { if (context_stop(ctx) < 0) { int error = errno; #ifdef _WRS_KERNEL @@ -761,13 +767,13 @@ static void run_safe_events(void * arg) { } assert(!ctx->stopped); } - if (ctx->pending_safe_event >= STOP_ALL_MAX_CNT) { + if (EXT(ctx)->pending_safe_event >= STOP_ALL_MAX_CNT) { trace(LOG_ALWAYS, "error: can't temporary stop pid %d; error: timeout", ctx->pid); ctx->exiting = 1; - ctx->pending_safe_event = 0; + EXT(ctx)->pending_safe_event = 0; } else { - ctx->pending_safe_event++; + EXT(ctx)->pending_safe_event++; safe_event_pid_count++; } } @@ -800,9 +806,9 @@ static void run_safe_events(void * arg) { static void check_safe_events(Context * ctx) { assert(ctx->stopped || ctx->exited); - assert(ctx->pending_safe_event); + assert(EXT(ctx)->pending_safe_event); assert(safe_event_pid_count > 0); - ctx->pending_safe_event = 0; + EXT(ctx)->pending_safe_event = 0; safe_event_pid_count--; if (safe_event_pid_count == 0 && run_ctrl_lock_cnt > 0) { post_event(run_safe_events, (void *)++safe_event_generation); @@ -843,67 +849,59 @@ void run_ctrl_unlock(void) { } static void event_context_created(Context * ctx, void * client_data) { - TCFBroadcastGroup * bcg = (TCFBroadcastGroup *)client_data; assert(!ctx->exited); assert(!ctx->intercepted); assert(!ctx->stopped); - send_event_context_added(&bcg->out, ctx); - flush_stream(&bcg->out); + send_event_context_added(&broadcast_group->out, ctx); + flush_stream(&broadcast_group->out); } static void event_context_changed(Context * ctx, void * client_data) { - TCFBroadcastGroup * bcg = (TCFBroadcastGroup *)client_data; - - send_event_context_changed(&bcg->out, ctx); - flush_stream(&bcg->out); + send_event_context_changed(&broadcast_group->out, ctx); + flush_stream(&broadcast_group->out); } static void event_context_stopped(Context * ctx, void * client_data) { - TCFBroadcastGroup * bcg = (TCFBroadcastGroup *)client_data; - assert(ctx->stopped); assert(!ctx->intercepted); assert(!ctx->exited); - if (ctx->pending_safe_event) check_safe_events(ctx); + if (EXT(ctx)->pending_safe_event) check_safe_events(ctx); if (ctx->stopped_by_exception) { - send_event_context_exception(&bcg->out, ctx); + send_event_context_exception(&broadcast_group->out, ctx); } if (ctx->pending_intercept) { - send_event_context_suspended(&bcg->out, ctx); + send_event_context_suspended(&broadcast_group->out, ctx); } if (!ctx->intercepted && run_ctrl_lock_cnt == 0) { context_continue(ctx); } - flush_stream(&bcg->out); + flush_stream(&broadcast_group->out); } static void event_context_started(Context * ctx, void * client_data) { - TCFBroadcastGroup * bcg = (TCFBroadcastGroup *)client_data; - assert(!ctx->stopped); if (ctx->intercepted) { - send_event_context_resumed(&bcg->out, ctx); + send_event_context_resumed(&broadcast_group->out, ctx); } + EXT(ctx)->intercepted_by_bp = 0; if (safe_event_list) { if (!ctx->pending_step) { context_stop(ctx); } - if (!ctx->pending_safe_event) { - ctx->pending_safe_event = 1; + if (!EXT(ctx)->pending_safe_event) { + EXT(ctx)->pending_safe_event = 1; safe_event_pid_count++; } } - flush_stream(&bcg->out); + flush_stream(&broadcast_group->out); } static void event_context_exited(Context * ctx, void * client_data) { - TCFBroadcastGroup * bcg = (TCFBroadcastGroup *)client_data; - assert(!ctx->stopped); assert(!ctx->intercepted); - if (ctx->pending_safe_event) check_safe_events(ctx); - send_event_context_removed(&bcg->out, ctx); - flush_stream(&bcg->out); + if (EXT(ctx)->pending_safe_event) check_safe_events(ctx); + send_event_context_removed(&broadcast_group->out, ctx); + flush_stream(&broadcast_group->out); } void ini_run_ctrl_service(Protocol * proto, TCFBroadcastGroup * bcg) { @@ -914,7 +912,9 @@ void ini_run_ctrl_service(Protocol * proto, TCFBroadcastGroup * bcg) { event_context_started, event_context_changed }; - add_context_event_listener(&listener, bcg); + broadcast_group = bcg; + add_context_event_listener(&listener, NULL); + context_extension_offset = context_extension(sizeof(ContextExtension)); add_command_handler(proto, RUN_CONTROL, "getContext", command_get_context); add_command_handler(proto, RUN_CONTROL, "getChildren", command_get_children); add_command_handler(proto, RUN_CONTROL, "getState", command_get_state); diff --git a/services/runctrl.h b/services/runctrl.h index 7964ef72..8746711e 100644 --- a/services/runctrl.h +++ b/services/runctrl.h @@ -67,11 +67,11 @@ extern int terminate_debug_context(Channel * c, Context * ctx); /* * Suspend (stop and intercept) debug context - thread or process. * If "ctx" is a process, suspend all children. - * RunControl.suspended event is sent if it was not sent berore. + * RunControl.suspended event is sent if it was not sent before. * Returns 0 if no errors, otherwise returns -1 and sets errno. * Note: this function is asynchronous, it returns before contexts are suspended. */ -extern int suspend_debug_context(TCFBroadcastGroup * bcg, Context * ctx); +extern int suspend_debug_context(Context * ctx); /* * Initialize run control service. diff --git a/services/stacktrace.c b/services/stacktrace.c index f5ee9fca..9262805e 100644 --- a/services/stacktrace.c +++ b/services/stacktrace.c @@ -41,33 +41,37 @@ static const char * STACKTRACE = "StackTrace"; -struct StackTrace { +typedef struct StackTrace { ErrorReport * error; + int valid; int frame_cnt; int frame_max; - struct StackFrame frames[1]; /* ordered bottom to top */ -}; + StackFrame * frames; /* ordered bottom to top */ +} StackTrace; -typedef struct StackTrace StackTrace; +static size_t context_extension_offset = 0; -static StackTrace * add_frame(StackTrace * stack_trace, StackFrame * frame) { +#define EXT(ctx) ((StackTrace *)((char *)(ctx) + context_extension_offset)) + +static void 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)); + stack_trace->frame_max += 32; + stack_trace->frames = (StackFrame *)loc_realloc(stack_trace->frames, + stack_trace->frame_max * sizeof(StackFrame)); } stack_trace->frames[stack_trace->frame_cnt++] = *frame; - return stack_trace; } -static void free_stack_trace(StackTrace * stack_trace) { +static void invalidate_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); + stack_trace->error = NULL; + stack_trace->frame_cnt = 0; + stack_trace->valid = 0; } #if defined(_WRS_KERNEL) @@ -76,7 +80,6 @@ static void free_stack_trace(StackTrace * stack_trace) { static Context * client_ctx; static StackTrace * client_trace; -static int frame_cnt; static ContextAddress frame_rp; static void vxworks_stack_trace_callback( @@ -91,7 +94,7 @@ static void vxworks_stack_trace_callback( StackFrame f; memset(&f, 0, sizeof(f)); f.regs_size = client_ctx->regs_size; - if (frame_cnt == 0) { + if (client_trace->frame_cnt == 0) { f.is_top_frame = 1; f.regs = client_ctx->regs; f.mask = loc_alloc(f.regs_size); @@ -104,22 +107,19 @@ static void vxworks_stack_trace_callback( } f.fp = (ContextAddress)args; frame_rp = (ContextAddress)callAdrs; - client_trace = add_frame(client_trace, &f); - frame_cnt++; + add_frame(client_trace, &f); } -static StackTrace * trace_stack(Context * ctx, StackTrace * s) { +static void 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 client_trace; + if (s->frame_cnt == 0) vxworks_stack_trace_callback(NULL, 0, 0, NULL, ctx->pid, 1); } #else -static StackTrace * walk_frames(Context * ctx, StackTrace * stack_trace) { +static void walk_frames(Context * ctx, StackTrace * stack_trace) { int error = 0; unsigned cnt = 0; StackFrame frame; @@ -155,7 +155,7 @@ static StackTrace * walk_frames(Context * ctx, StackTrace * stack_trace) { loc_free(down.mask); break; } - stack_trace = add_frame(stack_trace, &frame); + add_frame(stack_trace, &frame); frame = down; cnt++; } @@ -163,47 +163,38 @@ static StackTrace * walk_frames(Context * ctx, StackTrace * stack_trace) { if (!frame.is_top_frame) loc_free(frame.regs); loc_free(frame.mask); - 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); - } + if (get_error_code(error) == ERR_CACHE_MISS) { + invalidate_stack_trace(stack_trace); + } + else if (error) { + stack_trace->error = get_error_report(error); } - return stack_trace; } -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; - } +static void trace_stack(Context * ctx, StackTrace * s) { + int i; + walk_frames(ctx, s); + 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 s; } #endif static StackTrace * create_stack_trace(Context * ctx) { - 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; - if (ctx->regs_error != NULL) { - stack_trace->error = get_error_report(set_error_report_errno(ctx->regs_error)); - } - else { - stack_trace = trace_stack(ctx, stack_trace); + StackTrace * stack_trace = EXT(ctx); + if (!stack_trace->valid) { + stack_trace->frame_cnt = 0; + if (ctx->regs_error != NULL) { + stack_trace->error = get_error_report(set_error_report_errno(ctx->regs_error)); + } + else { + trace_stack(ctx, stack_trace); + } + stack_trace->valid = 1; } - ctx->stack_trace = stack_trace; return stack_trace; } @@ -298,10 +289,6 @@ static void command_get_context_cache_client(void * x) { break; } s = create_stack_trace(d->ctx); - if (s == NULL) { - err = errno; - break; - } if (s->error) { err = set_error_report_errno(s->error); break; @@ -417,9 +404,6 @@ 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; @@ -442,9 +426,6 @@ 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; @@ -469,29 +450,33 @@ 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 == NULL || stack->error != NULL) return 0; + if (stack->error != NULL) return 0; return frame == stack->frame_cnt - 1; } +static void flush_stack_trace(Context * ctx, void * args) { + invalidate_stack_trace(EXT(ctx)); +} + 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; - } + invalidate_stack_trace(EXT(ctx)); + loc_free(EXT(ctx)->frames); + memset(EXT(ctx), 0, sizeof(StackTrace)); } void ini_stack_trace_service(Protocol * proto, TCFBroadcastGroup * bcg) { static ContextEventListener listener = { NULL, - delete_stack_trace, - delete_stack_trace, - delete_stack_trace, + flush_stack_trace, + flush_stack_trace, + flush_stack_trace, + flush_stack_trace, delete_stack_trace }; add_context_event_listener(&listener, bcg); add_command_handler(proto, STACKTRACE, "getContext", command_get_context); add_command_handler(proto, STACKTRACE, "getChildren", command_get_children); + context_extension_offset = context_extension(sizeof(StackTrace)); } #endif diff --git a/services/symbols_elf.c b/services/symbols_elf.c index d0dd715b..4214eecb 100644 --- a/services/symbols_elf.c +++ b/services/symbols_elf.c @@ -637,7 +637,7 @@ int get_next_stack_frame(Context * ctx, StackFrame * frame, StackFrame * down) { clear_trap(&trap); } else { - error = trap.error; + frame->fp = 0; } } if (error) { diff --git a/services/symbols_proxy.c b/services/symbols_proxy.c index cc200171..fa170314 100644 --- a/services/symbols_proxy.c +++ b/services/symbols_proxy.c @@ -32,6 +32,9 @@ #include "exceptions.h" #include "stacktrace.h" #include "symbols.h" +#if ENABLE_RCBP_TEST +# include "test.h" +#endif #define HASH_SIZE 101 @@ -215,7 +218,6 @@ static SymbolsCache * get_symbols_cache(void) { 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; } @@ -315,6 +317,11 @@ static void free_symbols_cache(SymbolsCache * syms) { loc_free(syms); } +static Channel * get_channel(SymbolsCache * syms) { + if (!syms->service_available) str_exception(ERR_SYM_NOT_FOUND, "Symbols service not available"); + return syms->channel; +} + static void read_context_data(InputStream * inp, const char * name, void * args) { char id[256]; SymInfoCache * s = (SymInfoCache *)args; @@ -445,9 +452,35 @@ int find_symbol(Context * ctx, int frame, char * name, Symbol ** sym) { } } +#if ENABLE_RCBP_TEST + if (f == NULL && !syms->service_available && ctx->parent == NULL) { + void * address = NULL; + int sym_class = 0; + if (find_test_symbol(ctx, name, &address, &sym_class) >= 0) { + SymInfoCache * s = (SymInfoCache *)loc_alloc_zero(sizeof(SymInfoCache)); + f = (FindSymCache *)loc_alloc_zero(sizeof(FindSymCache)); + list_add_first(&f->link_syms, syms->link_find + h); + f->pid = ctx->pid; + f->ip = ip; + f->name = loc_strdup(name); + f->id = loc_strdup(name); + s->magic = SYM_CACHE_MAGIC; + s->id = loc_strdup(name); + s->name = loc_strdup(name); + s->done_context = 1; + s->has_address = 1; + s->address = (ContextAddress)address; + s->sym_class = sym_class; + s->update_policy = UPDATE_ON_MEMORY_MAP_CHANGES; + s->owner_id = loc_strdup(ctx2id(ctx)); + list_add_first(&s->link_syms, syms->link_sym + hash_sym_id(name)); + list_init(&s->array_syms); + } + } +#endif + if (f == NULL) { - Channel * c = cache_channel(); - if (c == NULL) exception(ERR_SYM_NOT_FOUND); + Channel * c = get_channel(syms); f = (FindSymCache *)loc_alloc_zero(sizeof(FindSymCache)); list_add_first(&f->link_syms, syms->link_find + h); f->pid = ctx->pid; @@ -547,8 +580,7 @@ int enumerate_symbols(Context * ctx, int frame, EnumerateSymbolsCallBack * func, } if (f == NULL) { - Channel * c = cache_channel(); - if (c == NULL) exception(ERR_SYM_NOT_FOUND); + Channel * c = get_channel(syms); f = (ListSymCache *)loc_alloc_zero(sizeof(ListSymCache)); list_add_first(&f->link_syms, syms->link_list + h); f->pid = ctx->pid; @@ -1027,8 +1059,7 @@ int get_next_stack_frame(Context * ctx, StackFrame * frame, StackFrame * down) { assert(f == NULL || f->pending == NULL); if (f == NULL) { - Channel * c = cache_channel(); - if (c == NULL) exception(ERR_SYM_NOT_FOUND); + Channel * c = get_channel(syms); f = (StackFrameCache *)loc_alloc_zero(sizeof(StackFrameCache)); list_add_first(&f->link_syms, syms->link_frame + h); f->mem = ctx->mem; diff --git a/services/symbols_win32.c b/services/symbols_win32.c index c6b505a4..a96e5e89 100644 --- a/services/symbols_win32.c +++ b/services/symbols_win32.c @@ -32,8 +32,11 @@ #include "symbols.h" #include "stacktrace.h" #include "windbgcache.h" +#include "context-win32.h" #include "trace.h" -#include "test.h" +#if ENABLE_RCBP_TEST +# include "test.h" +#endif #define SYM_SEARCH_PATH "" /* Path could contain "http://msdl.microsoft.com/download/symbols", @@ -131,7 +134,7 @@ static int get_stack_frame(Context * ctx, int frame, IMAGEHLP_STACK_FRAME * stac static int get_sym_info(const Symbol * sym, DWORD index, SYMBOL_INFO ** res) { static ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; SYMBOL_INFO * info = (SYMBOL_INFO *)buffer; - HANDLE process = sym->ctx->parent == NULL ? sym->ctx->handle : sym->ctx->parent->handle; + HANDLE process = get_context_handle(sym->ctx->parent == NULL ? sym->ctx : sym->ctx->parent); info->SizeOfStruct = sizeof(SYMBOL_INFO); info->MaxNameLen = MAX_SYM_NAME; @@ -144,7 +147,7 @@ static int get_sym_info(const Symbol * sym, DWORD index, SYMBOL_INFO ** res) { } static int get_type_info(const Symbol * sym, int info_tag, void * info) { - HANDLE process = sym->ctx->parent == NULL ? sym->ctx->handle : sym->ctx->parent->handle; + HANDLE process = get_context_handle(sym->ctx->parent == NULL ? sym->ctx : sym->ctx->parent); if (!SymGetTypeInfo(process, sym->module, sym->index, info_tag, info)) { set_win32_errno(GetLastError()); return -1; @@ -811,9 +814,11 @@ static int find_pe_symbol(Context * ctx, int frame, char * name, Symbol * sym) { ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; SYMBOL_INFO * info = (SYMBOL_INFO *)buffer; IMAGEHLP_STACK_FRAME stack_frame; - HANDLE process = ctx->parent == NULL ? ctx->handle : ctx->parent->handle; + HANDLE process = get_context_handle(ctx->parent == NULL ? ctx : ctx->parent); DWORD64 module; + if (frame == STACK_TOP_FRAME) frame = get_top_frame(ctx); + if (frame == STACK_TOP_FRAME) return -1; if (get_stack_frame(ctx, frame, &stack_frame) < 0) return -1; if (find_cache_symbol(process, stack_frame.InstructionOffset, name, sym)) return errno ? -1 : 0; @@ -884,7 +889,13 @@ int find_symbol(Context * ctx, int frame, char * name, Symbol ** sym) { (*sym)->ctx = ctx; if (find_pe_symbol(ctx, frame, name, *sym) >= 0) return 0; if (get_error_code(errno) != ERR_SYM_NOT_FOUND) return -1; - if (find_test_symbol(ctx, name, &(*sym)->address, &(*sym)->sym_class) >= 0) return 0; +#if ENABLE_RCBP_TEST + if (find_test_symbol(ctx, name, &(*sym)->address, &(*sym)->sym_class) >= 0) { + while (ctx->parent != NULL && ctx->parent->mem == ctx->mem) ctx = ctx->parent; + (*sym)->ctx = ctx; + return 0; + } +#endif if (find_basic_type_symbol(ctx, name, *sym) >= 0) return 0; return -1; } @@ -909,7 +920,7 @@ int enumerate_symbols(Context * ctx, int frame, EnumerateSymbolsCallBack * call_ SYMBOL_INFO * symbol = (SYMBOL_INFO *)buffer; IMAGEHLP_STACK_FRAME stack_frame; EnumerateSymbolsContext enum_context; - HANDLE process = ctx->parent == NULL ? ctx->handle : ctx->parent->handle; + HANDLE process = get_context_handle(ctx->parent == NULL ? ctx : ctx->parent); symbol->SizeOfStruct = sizeof(SYMBOL_INFO); symbol->MaxNameLen = MAX_SYM_NAME; @@ -958,12 +969,13 @@ int get_next_stack_frame(Context * ctx, StackFrame * frame, StackFrame * down) { static void event_context_created(Context * ctx, void * client_data) { if (ctx->parent != NULL) return; assert(ctx->pid == ctx->mem); - if (!SymInitialize(ctx->handle, SYM_SEARCH_PATH, FALSE)) { + if (!SymInitialize(get_context_handle(ctx), SYM_SEARCH_PATH, FALSE)) { set_win32_errno(GetLastError()); trace(LOG_ALWAYS, "SymInitialize() error: %d: %s", errno, errno_to_str(errno)); } - if (!SymLoadModule64(ctx->handle, ctx->file_handle, NULL, NULL, ctx->base_address, 0)) { + if (!SymLoadModule64(get_context_handle(ctx), get_context_file_handle(ctx), + NULL, NULL, get_context_base_address(ctx), 0)) { set_win32_errno(GetLastError()); trace(LOG_ALWAYS, "SymLoadModule() error: %d: %s", errno, errno_to_str(errno)); @@ -972,6 +984,7 @@ static void event_context_created(Context * ctx, void * client_data) { static void event_context_exited(Context * ctx, void * client_data) { unsigned i; + HANDLE handle = get_context_handle(ctx); for (i = 0; i < SYMBOL_CACHE_SIZE; i++) { if (symbol_cache[i].sym.ctx == ctx) { release_error_report(symbol_cache[i].error); @@ -979,13 +992,13 @@ static void event_context_exited(Context * ctx, void * client_data) { } } if (ctx->parent != NULL) return; - assert(ctx->handle != NULL); - if (!SymUnloadModule64(ctx->handle, ctx->base_address)) { + assert(handle != NULL); + if (!SymUnloadModule64(handle, get_context_base_address(ctx))) { set_win32_errno(GetLastError()); trace(LOG_ALWAYS, "SymUnloadModule() error: %d: %s", errno, errno_to_str(errno)); } - if (!SymCleanup(ctx->handle)) { + if (!SymCleanup(handle)) { set_win32_errno(GetLastError()); trace(LOG_ALWAYS, "SymCleanup() error: %d: %s", errno, errno_to_str(errno)); @@ -993,27 +1006,29 @@ static void event_context_exited(Context * ctx, void * client_data) { } static void event_context_changed(Context * ctx, void * client_data) { - if (ctx->module_loaded) { + HANDLE handle = get_context_handle(ctx); + if (is_context_module_loaded(ctx)) { unsigned i; assert(ctx->pid == ctx->mem); - assert(ctx->handle != NULL); - if (!SymLoadModule64(ctx->handle, ctx->module_handle, NULL, NULL, ctx->module_address, 0)) { + assert(handle != NULL); + if (!SymLoadModule64(handle, get_context_module_handle(ctx), + NULL, NULL, get_context_module_address(ctx), 0)) { set_win32_errno(GetLastError()); trace(LOG_ALWAYS, "SymLoadModule() error: %d: %s", errno, errno_to_str(errno)); } for (i = 0; i < SYMBOL_CACHE_SIZE; i++) { - if (symbol_cache[i].process == ctx->handle && symbol_cache[i].error) symbol_cache[i].process = NULL; + if (symbol_cache[i].process == handle && symbol_cache[i].error) symbol_cache[i].process = NULL; } } - if (ctx->module_unloaded) { + if (is_context_module_unloaded(ctx)) { unsigned i; assert(ctx->pid == ctx->mem); - assert(ctx->handle != NULL); + assert(handle != NULL); for (i = 0; i < SYMBOL_CACHE_SIZE; i++) { - if (symbol_cache[i].process == ctx->handle) symbol_cache[i].process = NULL; + if (symbol_cache[i].process == handle) symbol_cache[i].process = NULL; } - if (!SymUnloadModule64(ctx->handle, ctx->module_address)) { + if (!SymUnloadModule64(handle, get_context_module_address(ctx))) { set_win32_errno(GetLastError()); trace(LOG_ALWAYS, "SymUnloadModule() error: %d: %s", errno, errno_to_str(errno)); diff --git a/system/Darwin/context-darwin.c b/system/Darwin/context-darwin.c index 709050a1..895203bb 100644 --- a/system/Darwin/context-darwin.c +++ b/system/Darwin/context-darwin.c @@ -42,14 +42,31 @@ #define WORD_SIZE 4 +typedef struct ContextExtension { + ContextAttachCallBack * attach_callback; + void * attach_data; + int ptrace_flags; + int ptrace_event; + int syscall_enter; + int syscall_exit; + int syscall_id; + ContextAddress syscall_pc; + ContextAddress loader_state; + int end_of_step; +} ContextExtension; + +static size_t context_extension_offset = 0; + +#define EXT(ctx) ((ContextExtension *)((char *)(ctx) + context_extension_offset)) + static LINK pending_list; const char * context_suspend_reason(Context * ctx) { static char reason[128]; - if (ctx->end_of_step) return "Step"; - if (ctx->syscall_enter) return "System Call"; - if (ctx->syscall_exit) return "System Return"; + if (EXT(ctx)->end_of_step) return "Step"; + if (EXT(ctx)->syscall_enter) return "System Call"; + if (EXT(ctx)->syscall_exit) return "System Return"; if (ctx->signal == SIGSTOP || ctx->signal == SIGTRAP) { return "Suspended"; } @@ -88,8 +105,8 @@ int context_attach(pid_t pid, ContextAttachCallBack * done, void * data, int sel add_waitpid_process(pid); ctx = create_context(pid, 0); ctx->mem = pid; - ctx->attach_callback = done; - ctx->attach_data = data; + EXT(ctx)->attach_callback = done; + EXT(ctx)->attach_data = data; list_add_first(&ctx->ctxl, &pending_list); /* TODO: context_attach works only for main task in a process */ return 0; @@ -120,8 +137,8 @@ int context_stop(Context * ctx) { } static int syscall_never_returns(Context * ctx) { - if (ctx->syscall_enter) { - switch (ctx->syscall_id) { + if (EXT(ctx)->syscall_enter) { + switch (EXT(ctx)->syscall_id) { case SYS_sigreturn: return 1; } @@ -140,7 +157,7 @@ int context_continue(Context * ctx) { if (skip_breakpoint(ctx, 0)) return 0; - if (!ctx->syscall_enter) { + if (!EXT(ctx)->syscall_enter) { while (ctx->pending_signals != 0) { while ((ctx->pending_signals & (1 << signal)) == 0) signal++; if (ctx->sig_dont_pass & (1 << signal)) { @@ -156,11 +173,16 @@ int context_continue(Context * ctx) { } trace(LOG_CONTEXT, "context: resuming ctx %#lx, pid %d, with signal %d", ctx, ctx->pid, signal); -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) if (((REG_SET *)ctx->regs)->__eflags & 0x100) { ((REG_SET *)ctx->regs)->__eflags &= ~0x100; ctx->regs_dirty = 1; } +#elif defined(__x86_64__) + if (((REG_SET *)ctx->regs)->__rflags & 0x100) { + ((REG_SET *)ctx->regs)->__rflags &= ~0x100; + ctx->regs_dirty = 1; + } #endif if (ctx->regs_dirty) { unsigned int state_count; @@ -188,9 +210,9 @@ int context_continue(Context * ctx) { } ctx->pending_signals &= ~(1 << signal); if (syscall_never_returns(ctx)) { - ctx->syscall_enter = 0; - ctx->syscall_exit = 0; - ctx->syscall_id = 0; + EXT(ctx)->syscall_enter = 0; + EXT(ctx)->syscall_exit = 0; + EXT(ctx)->syscall_id = 0; } send_context_started_event(ctx); return 0; @@ -342,9 +364,9 @@ static void event_pid_exited(pid_t pid, int status, int signal) { } else { assert(ctx->ref_count == 0); - if (ctx->attach_callback != NULL) { + if (EXT(ctx)->attach_callback != NULL) { if (status == 0) status = EINVAL; - ctx->attach_callback(status, ctx, ctx->attach_data); + EXT(ctx)->attach_callback(status, ctx, EXT(ctx)->attach_data); } assert(list_is_empty(&ctx->children)); assert(ctx->parent == NULL); @@ -354,7 +376,7 @@ static void event_pid_exited(pid_t pid, int status, int signal) { } else { if (ctx->parent->pid == ctx->pid) ctx = ctx->parent; - assert(ctx->attach_callback == NULL); + assert(EXT(ctx)->attach_callback == NULL); if (ctx->stopped || ctx->intercepted || ctx->exited) { trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d unexpected, stopped %d, intercepted %d, exited %d", ctx, pid, status, ctx->stopped, ctx->intercepted, ctx->exited); @@ -401,10 +423,10 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { link_context(ctx); send_context_created_event(prs); send_context_created_event(ctx); - if (prs->attach_callback) { - prs->attach_callback(0, prs, prs->attach_data); - prs->attach_callback = NULL; - prs->attach_data = NULL; + if (EXT(prs)->attach_callback) { + EXT(prs)->attach_callback(0, prs, EXT(prs)->attach_data); + EXT(prs)->attach_callback = NULL; + EXT(prs)->attach_data = NULL; } } } @@ -412,7 +434,7 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { if (ctx == NULL) return; assert(!ctx->exited); - assert(!ctx->attach_callback); + assert(!EXT(ctx)->attach_callback); if (signal != SIGSTOP && signal != SIGTRAP) { assert(signal < 32); @@ -443,11 +465,11 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { ctx->pid, errno, errno_to_str(errno)); } - if (!ctx->syscall_enter || ctx->regs_error || pc0 != get_regs_PC(ctx->regs)) { - ctx->syscall_enter = 0; - ctx->syscall_exit = 0; - ctx->syscall_id = 0; - ctx->syscall_pc = 0; + if (!EXT(ctx)->syscall_enter || ctx->regs_error || pc0 != get_regs_PC(ctx->regs)) { + EXT(ctx)->syscall_enter = 0; + EXT(ctx)->syscall_exit = 0; + EXT(ctx)->syscall_id = 0; + EXT(ctx)->syscall_pc = 0; } trace(LOG_EVENTS, "event: pid %d stopped at PC = %#lx", ctx->pid, get_regs_PC(ctx->regs)); @@ -457,15 +479,15 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { } else { ctx->signal = signal; - ctx->ptrace_event = event; + EXT(ctx)->ptrace_event = event; ctx->stopped = 1; ctx->stopped_by_bp = 0; ctx->stopped_by_exception = stopped_by_exception; - ctx->end_of_step = 0; + EXT(ctx)->end_of_step = 0; if (signal == SIGTRAP && event == 0 && !syscall) { ctx->stopped_by_bp = !ctx->regs_error && is_breakpoint_address(ctx, get_regs_PC(ctx->regs) - BREAK_SIZE); - ctx->end_of_step = !ctx->stopped_by_bp && ctx->pending_step; + EXT(ctx)->end_of_step = !ctx->stopped_by_bp && ctx->pending_step; } ctx->pending_step = 0; if (ctx->stopped_by_bp) { @@ -488,6 +510,7 @@ static void waitpid_listener(int pid, int exited, int exit_code, int signal, int void init_contexts_sys_dep(void) { list_init(&pending_list); + context_extension_offset = context_extension(sizeof(ContextExtension)); add_waitpid_listener(waitpid_listener, NULL); } diff --git a/system/Darwin/regset.h b/system/Darwin/regset.h index 5fbb011f..ea0fd27c 100644 --- a/system/Darwin/regset.h +++ b/system/Darwin/regset.h @@ -23,7 +23,11 @@ extern "C" { #if defined(__APPLE__) # include <mach/thread_status.h> - typedef x86_thread_state32_t REG_SET; +# if defined(__i386__) + typedef x86_thread_state32_t REG_SET; +# else + typedef x86_thread_state64_t REG_SET; +# endif #endif #ifdef __cplusplus diff --git a/system/FreeBSD/context-freebsd.c b/system/FreeBSD/context-freebsd.c index 4d36afbe..87fb9e74 100644 --- a/system/FreeBSD/context-freebsd.c +++ b/system/FreeBSD/context-freebsd.c @@ -50,6 +50,23 @@ #define USE_ESRCH_WORKAROUND 1 #define USE_PTRACE_SYSCALL 0 +typedef struct ContextExtension { + ContextAttachCallBack * attach_callback; + void * attach_data; + int ptrace_flags; + int ptrace_event; + int syscall_enter; + int syscall_exit; + int syscall_id; + ContextAddress syscall_pc; + ContextAddress loader_state; + int end_of_step; +} ContextExtension; + +static size_t context_extension_offset = 0; + +#define EXT(ctx) ((ContextExtension *)((char *)(ctx) + context_extension_offset)) + static LINK pending_list; static char * event_name(int event) { @@ -60,10 +77,10 @@ static char * event_name(int event) { const char * context_suspend_reason(Context * ctx) { static char reason[128]; - if (ctx->end_of_step) return "Step"; - if (ctx->ptrace_event != 0) { + if (EXT(ctx)->end_of_step) return "Step"; + if (EXT(ctx)->ptrace_event != 0) { assert(ctx->signal == SIGTRAP); - snprintf(reason, sizeof(reason), "Event: %s", event_name(ctx->ptrace_event)); + snprintf(reason, sizeof(reason), "Event: %s", event_name(EXT(ctx)->ptrace_event)); return reason; } if (ctx->signal == SIGSTOP || ctx->signal == SIGTRAP) { @@ -104,8 +121,8 @@ int context_attach(pid_t pid, ContextAttachCallBack * done, void * data, int sel add_waitpid_process(pid); ctx = create_context(pid, 0); ctx->mem = pid; - ctx->attach_callback = done; - ctx->attach_data = data; + EXT(ctx)->attach_callback = done; + EXT(ctx)->attach_data = data; list_add_first(&ctx->ctxl, &pending_list); /* TODO: context_attach works only for main task in a process */ return 0; @@ -146,7 +163,7 @@ int context_continue(Context * ctx) { if (skip_breakpoint(ctx, 0)) return 0; - if (!ctx->ptrace_event) { + if (!EXT(ctx)->ptrace_event) { while (ctx->pending_signals != 0) { while ((ctx->pending_signals & (1 << signal)) == 0) signal++; if (ctx->sig_dont_pass & (1 << signal)) { @@ -342,9 +359,9 @@ static void event_pid_exited(pid_t pid, int status, int signal) { } else { assert(ctx->ref_count == 0); - if (ctx->attach_callback != NULL) { + if (EXT(ctx)->attach_callback != NULL) { if (status == 0) status = EINVAL; - ctx->attach_callback(status, ctx, ctx->attach_data); + EXT(ctx)->attach_callback(status, ctx, EXT(ctx)->attach_data); } assert(list_is_empty(&ctx->children)); assert(ctx->parent == NULL); @@ -354,7 +371,7 @@ static void event_pid_exited(pid_t pid, int status, int signal) { } else { if (ctx->parent->pid == ctx->pid) ctx = ctx->parent; - assert(ctx->attach_callback == NULL); + assert(EXT(ctx)->attach_callback == NULL); if (ctx->stopped || ctx->intercepted || ctx->exited) { trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d unexpected, stopped %d, intercepted %d, exited %d", ctx, pid, status, ctx->stopped, ctx->intercepted, ctx->exited); @@ -399,10 +416,10 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { link_context(ctx); send_context_created_event(prs); send_context_created_event(ctx); - if (prs->attach_callback) { - prs->attach_callback(0, prs, prs->attach_data); - prs->attach_callback = NULL; - prs->attach_data = NULL; + if (EXT(prs)->attach_callback) { + EXT(prs)->attach_callback(0, prs, EXT(prs)->attach_data); + EXT(prs)->attach_callback = NULL; + EXT(prs)->attach_data = NULL; } } } @@ -410,7 +427,7 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { if (ctx == NULL) return; assert(!ctx->exited); - assert(!ctx->attach_callback); + assert(!EXT(ctx)->attach_callback); if (signal != SIGSTOP && signal != SIGTRAP) { assert(signal < 32); @@ -460,15 +477,15 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { } else { ctx->signal = signal; - ctx->ptrace_event = event; + EXT(ctx)->ptrace_event = event; ctx->stopped = 1; ctx->stopped_by_bp = 0; ctx->stopped_by_exception = stopped_by_exception; - ctx->end_of_step = 0; + EXT(ctx)->end_of_step = 0; if (signal == SIGTRAP && event == 0 && !syscall) { ctx->stopped_by_bp = !ctx->regs_error && is_breakpoint_address(ctx, get_regs_PC(ctx->regs) - BREAK_SIZE); - ctx->end_of_step = !ctx->stopped_by_bp && ctx->pending_step; + EXT(ctx)->end_of_step = !ctx->stopped_by_bp && ctx->pending_step; } ctx->pending_step = 0; if (ctx->stopped_by_bp) { @@ -491,6 +508,7 @@ static void waitpid_listener(int pid, int exited, int exit_code, int signal, int void init_contexts_sys_dep(void) { list_init(&pending_list); + context_extension_offset = context_extension(sizeof(ContextExtension)); add_waitpid_listener(waitpid_listener, NULL); } diff --git a/system/GNU/Linux/context-linux.c b/system/GNU/Linux/context-linux.c index 77f334f3..aa0e181e 100644 --- a/system/GNU/Linux/context-linux.c +++ b/system/GNU/Linux/context-linux.c @@ -86,6 +86,23 @@ PTRACE_O_TRACEEXIT) #endif +typedef struct ContextExtension { + ContextAttachCallBack * attach_callback; + void * attach_data; + int ptrace_flags; + int ptrace_event; + int syscall_enter; + int syscall_exit; + int syscall_id; + ContextAddress syscall_pc; + ContextAddress loader_state; + int end_of_step; +} ContextExtension; + +static size_t context_extension_offset = 0; + +#define EXT(ctx) ((ContextExtension *)((char *)(ctx) + context_extension_offset)) + static LINK pending_list; static const char * event_name(int event) { @@ -105,14 +122,14 @@ static const char * event_name(int event) { const char * context_suspend_reason(Context * ctx) { static char reason[128]; - if (ctx->end_of_step) return "Step"; - if (ctx->ptrace_event != 0) { + if (EXT(ctx)->end_of_step) return "Step"; + if (EXT(ctx)->ptrace_event != 0) { assert(ctx->signal == SIGTRAP); - snprintf(reason, sizeof(reason), "Event: %s", event_name(ctx->ptrace_event)); + snprintf(reason, sizeof(reason), "Event: %s", event_name(EXT(ctx)->ptrace_event)); return reason; } - if (ctx->syscall_enter) return "System Call"; - if (ctx->syscall_exit) return "System Return"; + if (EXT(ctx)->syscall_enter) return "System Call"; + if (EXT(ctx)->syscall_exit) return "System Return"; if (ctx->signal == SIGSTOP || ctx->signal == SIGTRAP) { return "Suspended"; } @@ -151,8 +168,8 @@ int context_attach(pid_t pid, ContextAttachCallBack * done, void * data, int sel add_waitpid_process(pid); ctx = create_context(pid, 0); ctx->mem = pid; - ctx->attach_callback = done; - ctx->attach_data = data; + EXT(ctx)->attach_callback = done; + EXT(ctx)->attach_data = data; list_add_first(&ctx->ctxl, &pending_list); /* TODO: context_attach works only for main task in a process */ return 0; @@ -183,8 +200,8 @@ int context_stop(Context * ctx) { } static int syscall_never_returns(Context * ctx) { - if (ctx->syscall_enter) { - switch (ctx->syscall_id) { + if (EXT(ctx)->syscall_enter) { + switch (EXT(ctx)->syscall_id) { #ifdef __NR_sigreturn case __NR_sigreturn: return 1; @@ -205,7 +222,7 @@ int context_continue(Context * ctx) { if (skip_breakpoint(ctx, 0)) return 0; - if (!ctx->syscall_enter && !ctx->ptrace_event) { + if (!EXT(ctx)->syscall_enter && !EXT(ctx)->ptrace_event) { while (ctx->pending_signals != 0) { while ((ctx->pending_signals & (1 << signal)) == 0) signal++; if (ctx->sig_dont_pass & (1 << signal)) { @@ -263,9 +280,9 @@ int context_continue(Context * ctx) { } ctx->pending_signals &= ~(1 << signal); if (syscall_never_returns(ctx)) { - ctx->syscall_enter = 0; - ctx->syscall_exit = 0; - ctx->syscall_id = 0; + EXT(ctx)->syscall_enter = 0; + EXT(ctx)->syscall_exit = 0; + EXT(ctx)->syscall_id = 0; } send_context_started_event(ctx); return 0; @@ -417,9 +434,9 @@ static void event_pid_exited(pid_t pid, int status, int signal) { } else { assert(ctx->ref_count == 0); - if (ctx->attach_callback != NULL) { + if (EXT(ctx)->attach_callback != NULL) { if (status == 0) status = EINVAL; - ctx->attach_callback(status, ctx, ctx->attach_data); + EXT(ctx)->attach_callback(status, ctx, EXT(ctx)->attach_data); } assert(list_is_empty(&ctx->children)); assert(ctx->parent == NULL); @@ -429,7 +446,7 @@ static void event_pid_exited(pid_t pid, int status, int signal) { } else { if (ctx->parent->pid == ctx->pid) ctx = ctx->parent; - assert(ctx->attach_callback == NULL); + assert(EXT(ctx)->attach_callback == NULL); if (ctx->stopped || ctx->intercepted || ctx->exited) { trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d unexpected, stopped %d, intercepted %d, exited %d", ctx, pid, status, ctx->stopped, ctx->intercepted, ctx->exited); @@ -489,10 +506,10 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { link_context(ctx); send_context_created_event(prs); send_context_created_event(ctx); - if (prs->attach_callback) { - prs->attach_callback(0, prs, prs->attach_data); - prs->attach_callback = NULL; - prs->attach_data = NULL; + if (EXT(prs)->attach_callback) { + EXT(prs)->attach_callback(0, prs, EXT(prs)->attach_data); + EXT(prs)->attach_callback = NULL; + EXT(prs)->attach_data = NULL; } } } @@ -500,15 +517,15 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { if (ctx == NULL) return; assert(!ctx->exited); - assert(!ctx->attach_callback); - if (ctx->ptrace_flags != PTRACE_FLAGS) { + assert(!EXT(ctx)->attach_callback); + if (EXT(ctx)->ptrace_flags != PTRACE_FLAGS) { if (ptrace((enum __ptrace_request)PTRACE_SETOPTIONS, ctx->pid, 0, PTRACE_FLAGS) < 0) { int err = errno; trace(LOG_ALWAYS, "error: ptrace(PTRACE_SETOPTIONS) failed: pid %d, error %d %s", ctx->pid, err, errno_to_str(err)); } else { - ctx->ptrace_flags = PTRACE_FLAGS; + EXT(ctx)->ptrace_flags = PTRACE_FLAGS; } } @@ -595,22 +612,22 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { } if (syscall && !ctx->regs_error) { - if (!ctx->syscall_enter) { - ctx->syscall_id = get_syscall_id(ctx); - ctx->syscall_pc = get_regs_PC(ctx->regs); - ctx->syscall_enter = 1; - ctx->syscall_exit = 0; + if (!EXT(ctx)->syscall_enter) { + EXT(ctx)->syscall_id = get_syscall_id(ctx); + EXT(ctx)->syscall_pc = get_regs_PC(ctx->regs); + EXT(ctx)->syscall_enter = 1; + EXT(ctx)->syscall_exit = 0; trace(LOG_EVENTS, "event: pid %d enter sys call %d, PC = %#lx", - ctx->pid, ctx->syscall_id, ctx->syscall_pc); + ctx->pid, EXT(ctx)->syscall_id, EXT(ctx)->syscall_pc); } else { - if (ctx->syscall_pc != get_regs_PC(ctx->regs)) { + if (EXT(ctx)->syscall_pc != get_regs_PC(ctx->regs)) { trace(LOG_ALWAYS, "Invalid PC at sys call exit: pid %d, sys call %d, PC %#lx, expected PC %#lx", - ctx->pid, ctx->syscall_id, get_regs_PC(ctx->regs), ctx->syscall_pc); + ctx->pid, EXT(ctx)->syscall_id, get_regs_PC(ctx->regs), EXT(ctx)->syscall_pc); } trace(LOG_EVENTS, "event: pid %d exit sys call %d, PC = %#lx", - ctx->pid, ctx->syscall_id, get_regs_PC(ctx->regs)); - switch (ctx->syscall_id) { + ctx->pid, EXT(ctx)->syscall_id, get_regs_PC(ctx->regs)); + switch (EXT(ctx)->syscall_id) { case __NR_mmap: case __NR_munmap: #ifdef __NR_mmap2 @@ -621,16 +638,16 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { send_context_changed_event(ctx); break; } - ctx->syscall_enter = 0; - ctx->syscall_exit = 1; + EXT(ctx)->syscall_enter = 0; + EXT(ctx)->syscall_exit = 1; } } else { - if (!ctx->syscall_enter || ctx->regs_error || pc0 != get_regs_PC(ctx->regs)) { - ctx->syscall_enter = 0; - ctx->syscall_exit = 0; - ctx->syscall_id = 0; - ctx->syscall_pc = 0; + if (!EXT(ctx)->syscall_enter || ctx->regs_error || pc0 != get_regs_PC(ctx->regs)) { + EXT(ctx)->syscall_enter = 0; + EXT(ctx)->syscall_exit = 0; + EXT(ctx)->syscall_id = 0; + EXT(ctx)->syscall_pc = 0; } trace(LOG_EVENTS, "event: pid %d stopped at PC = %#lx", ctx->pid, get_regs_PC(ctx->regs)); } @@ -641,15 +658,15 @@ static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { } else { ctx->signal = signal; - ctx->ptrace_event = event; + EXT(ctx)->ptrace_event = event; ctx->stopped = 1; ctx->stopped_by_bp = 0; ctx->stopped_by_exception = stopped_by_exception; - ctx->end_of_step = 0; + EXT(ctx)->end_of_step = 0; if (signal == SIGTRAP && event == 0 && !syscall) { ctx->stopped_by_bp = !ctx->regs_error && is_breakpoint_address(ctx, get_regs_PC(ctx->regs) - BREAK_SIZE); - ctx->end_of_step = !ctx->stopped_by_bp && ctx->pending_step; + EXT(ctx)->end_of_step = !ctx->stopped_by_bp && ctx->pending_step; } ctx->pending_step = 0; if (ctx->stopped_by_bp) { @@ -727,17 +744,17 @@ static void eventpoint_at_loader(Context * ctx, void * args) { int error = errno; trace(LOG_ALWAYS, "Can't read loader state flag: %d %s", error, errno_to_str(error)); ctx->pending_intercept = 1; - ctx->loader_state = 0; + EXT(ctx)->loader_state = 0; return; } } switch (state) { case RT_CONSISTENT: - if (ctx->loader_state == RT_ADD) { + if (EXT(ctx)->loader_state == RT_ADD) { memory_map_event_module_loaded(ctx); } - else if (ctx->loader_state == RT_DELETE) { + else if (EXT(ctx)->loader_state == RT_DELETE) { memory_map_event_module_unloaded(ctx); } break; @@ -747,13 +764,14 @@ static void eventpoint_at_loader(Context * ctx, void * args) { /* TODO: need to call memory_map_event_code_section_ummapped() */ break; } - ctx->loader_state = state; + EXT(ctx)->loader_state = state; } #endif /* SERVICE_Expressions && ENABLE_ELF */ void init_contexts_sys_dep(void) { list_init(&pending_list); + context_extension_offset = context_extension(sizeof(ContextExtension)); add_waitpid_listener(waitpid_listener, NULL); #if SERVICE_Expressions && ENABLE_ELF add_identifier_callback(expression_identifier_callback); diff --git a/system/VxWorks/context-vxworks.c b/system/VxWorks/context-vxworks.c index bf17b857..99052fe6 100644 --- a/system/VxWorks/context-vxworks.c +++ b/system/VxWorks/context-vxworks.c @@ -26,7 +26,7 @@ #include <assert.h> #include <errno.h> #include <signal.h> -#include "context.h" +#include "context-vxworks.h" #include "events.h" #include "errors.h" #include "trace.h" @@ -42,6 +42,16 @@ #define TRACE_EVENT_STEP 2 +typedef struct ContextExtension { + VXDBG_BP_INFO bp_info; /* breakpoint information */ + pid_t bp_pid; /* process or thread that hit breakpoint */ + int event; +} ContextExtension; + +static size_t context_extension_offset = 0; + +#define EXT(ctx) ((ContextExtension *)((char *)(ctx) + context_extension_offset)) + #define EVENT_HOOK_BREAKPOINT 2 #define EVENT_HOOK_STEP_DONE 3 #define EVENT_HOOK_STOP 4 @@ -70,7 +80,7 @@ static SEM_ID events_signal; static pthread_t events_thread; const char * context_suspend_reason(Context * ctx) { - if (ctx->event == TRACE_EVENT_STEP) return "Step"; + if (EXT(ctx)->event == TRACE_EVENT_STEP) return "Step"; return "Suspended"; } @@ -346,7 +356,7 @@ static void event_handler(void * arg) { memcpy(stopped_ctx->regs, &info->regs, stopped_ctx->regs_size); stopped_ctx->signal = SIGTRAP; assert(get_regs_PC(stopped_ctx->regs) == info->addr); - stopped_ctx->event = 0; + EXT(stopped_ctx)->event = 0; stopped_ctx->pending_step = 0; stopped_ctx->stopped = 1; stopped_ctx->stopped_by_bp = info->bp_info_ok; @@ -356,8 +366,8 @@ static void event_handler(void * arg) { stopped_ctx->stopped_by_bp = 0; stopped_ctx->pending_intercept = 1; } - stopped_ctx->bp_info = info->bp_info; - if (current_ctx != NULL) stopped_ctx->bp_pid = current_ctx->pid; + EXT(stopped_ctx)->bp_info = info->bp_info; + if (current_ctx != NULL) EXT(stopped_ctx)->bp_pid = current_ctx->pid; assert(taskIsStopped(stopped_ctx->pid)); trace(LOG_CONTEXT, "context: stopped by breakpoint: ctx %#lx, id %#x", stopped_ctx, stopped_ctx->pid); @@ -373,8 +383,8 @@ static void event_handler(void * arg) { current_ctx->regs_error = NULL; } memcpy(current_ctx->regs, &info->regs, current_ctx->regs_size); + EXT(current_ctx)->event = TRACE_EVENT_STEP; current_ctx->signal = SIGTRAP; - current_ctx->event = TRACE_EVENT_STEP; current_ctx->pending_step = 0; current_ctx->stopped = 1; current_ctx->stopped_by_bp = 0; @@ -395,8 +405,8 @@ static void event_handler(void * arg) { stopped_ctx->regs_error = get_error_report(errno); assert(stopped_ctx->regs_error != NULL); } + EXT(stopped_ctx)->event = 0; stopped_ctx->signal = SIGSTOP; - stopped_ctx->event = 0; stopped_ctx->pending_step = 0; stopped_ctx->stopped = 1; stopped_ctx->stopped_by_bp = 0; @@ -515,6 +525,7 @@ void init_contexts_sys_dep(void) { if (vxdbg_clnt_id == NULL) { check_error(errno); } + context_extension_offset = context_extension(sizeof(ContextExtension)); taskCreateHookAdd((FUNCPTR)task_create_hook); vxdbgHookAdd(vxdbg_clnt_id, EVT_BP, vxdbg_event_hook); vxdbgHookAdd(vxdbg_clnt_id, EVT_TRACE, vxdbg_event_hook); diff --git a/system/VxWorks/context-vxworks.h b/system/VxWorks/context-vxworks.h new file mode 100644 index 00000000..42787a8b --- /dev/null +++ b/system/VxWorks/context-vxworks.h @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2007, 2009 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. + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ + +/* + * This module handles process/thread OS contexts and their state machine. + */ + +#ifndef D_context_vxworks +#define D_context_vxworks + +#include "config.h" +#include "context.h" + +extern VXDBG_CLNT_ID vxdbg_clnt_id; + +#endif /* D_context_vxworks */ diff --git a/system/Windows/context-win32.c b/system/Windows/context-win32.c index 93d4c476..2068a11d 100644 --- a/system/Windows/context-win32.c +++ b/system/Windows/context-win32.c @@ -35,6 +35,25 @@ #include "waitpid.h" #include "regset.h" #include "signames.h" +#include "context-win32.h" + +typedef struct ContextExtension { + HANDLE handle; + HANDLE file_handle; + DWORD64 base_address; + int module_loaded; + int module_unloaded; + HANDLE module_handle; + DWORD64 module_address; + int debug_started; + EXCEPTION_DEBUG_INFO pending_event; + EXCEPTION_DEBUG_INFO suspend_reason; + int context_stopped_async_pending; +} ContextExtension; + +static size_t context_extension_offset = 0; + +#define EXT(ctx) ((ContextExtension *)((char *)(ctx) + context_extension_offset)) typedef struct DebugThreadArgs { int error; @@ -58,12 +77,12 @@ typedef struct DebugEvent { #define EXCEPTION_DEBUGGER_IO 0x406D1388 const char * context_suspend_reason(Context * ctx) { - DWORD exception_code = ctx->suspend_reason.ExceptionRecord.ExceptionCode; + DWORD exception_code = EXT(ctx)->suspend_reason.ExceptionRecord.ExceptionCode; const char * desc = NULL; static char buf[64]; if (exception_code == 0) return "Suspended"; - if (ctx->debug_started && exception_code == EXCEPTION_BREAKPOINT) return "Suspended"; + if (EXT(ctx)->debug_started && exception_code == EXCEPTION_BREAKPOINT) return "Suspended"; if (exception_code == EXCEPTION_SINGLE_STEP) return "Step"; desc = signal_description(get_signal_from_code(exception_code)); @@ -74,10 +93,10 @@ const char * context_suspend_reason(Context * ctx) { } static int get_signal_index(Context * ctx) { - DWORD exception_code = ctx->suspend_reason.ExceptionRecord.ExceptionCode; + DWORD exception_code = EXT(ctx)->suspend_reason.ExceptionRecord.ExceptionCode; if (exception_code == 0) return 0; - if (ctx->debug_started && exception_code == EXCEPTION_BREAKPOINT) return 0; + if (EXT(ctx)->debug_started && exception_code == EXCEPTION_BREAKPOINT) return 0; return get_signal_from_code(exception_code); } @@ -114,20 +133,20 @@ static int log_error(char * fn, int ok) { static void event_win32_context_exited(Context * ctx); static void event_win32_context_stopped(Context * ctx) { - DWORD exception_code = ctx->pending_event.ExceptionRecord.ExceptionCode; + DWORD exception_code = EXT(ctx)->pending_event.ExceptionRecord.ExceptionCode; if (ctx->exited || ctx->stopped && exception_code == 0) return; - memcpy(&ctx->suspend_reason, &ctx->pending_event, sizeof(EXCEPTION_DEBUG_INFO)); - memset(&ctx->pending_event, 0, sizeof(EXCEPTION_DEBUG_INFO)); + memcpy(&EXT(ctx)->suspend_reason, &EXT(ctx)->pending_event, sizeof(EXCEPTION_DEBUG_INFO)); + memset(&EXT(ctx)->pending_event, 0, sizeof(EXCEPTION_DEBUG_INFO)); trace(LOG_CONTEXT, "context: stopped: ctx %#lx, pid %d, exception %#lx", ctx, ctx->pid, exception_code); assert(is_dispatch_thread()); assert(!ctx->stopped); - assert(ctx->handle != NULL); + assert(EXT(ctx)->handle != NULL); assert(ctx->parent != NULL); - if (SuspendThread(ctx->handle) == (DWORD)-1) { + if (SuspendThread(EXT(ctx)->handle) == (DWORD)-1) { DWORD err = GetLastError(); if (err == ERROR_ACCESS_DENIED && exception_code == 0) { /* Already exited */ @@ -144,7 +163,7 @@ static void event_win32_context_stopped(Context * ctx) { } memset(ctx->regs, 0, ctx->regs_size); ((REG_SET *)ctx->regs)->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; - if (GetThreadContext(ctx->handle, (REG_SET *)ctx->regs) == 0) { + if (GetThreadContext(EXT(ctx)->handle, (REG_SET *)ctx->regs) == 0) { ctx->regs_error = get_error_report(log_error("GetThreadContext", 0)); } else { @@ -174,7 +193,7 @@ static void event_win32_context_stopped(Context * ctx) { break; case EXCEPTION_DEBUGGER_IO: trace(LOG_ALWAYS, "Debugger IO request %#lx", - ctx->suspend_reason.ExceptionRecord.ExceptionInformation[0]); + EXT(ctx)->suspend_reason.ExceptionRecord.ExceptionInformation[0]); break; default: ctx->pending_signals |= 1 << ctx->signal; @@ -189,16 +208,16 @@ static void event_win32_context_stopped(Context * ctx) { static void event_win32_context_stopped_async(void * arg) { Context * ctx = (Context *)arg; - ctx->context_stopped_async_pending = 0; + EXT(ctx)->context_stopped_async_pending = 0; event_win32_context_stopped(ctx); context_unlock(ctx); } static void event_win32_context_started(Context * ctx) { - DWORD exception_code = ctx->suspend_reason.ExceptionRecord.ExceptionCode; + DWORD exception_code = EXT(ctx)->suspend_reason.ExceptionRecord.ExceptionCode; trace(LOG_CONTEXT, "context: started: ctx %#lx, pid %d", ctx, ctx->pid); assert(ctx->stopped); - if (ctx->debug_started && exception_code == EXCEPTION_BREAKPOINT) ctx->debug_started = 0; + if (EXT(ctx)->debug_started && exception_code == EXCEPTION_BREAKPOINT) EXT(ctx)->debug_started = 0; send_context_started_event(ctx); } @@ -214,33 +233,33 @@ static void event_win32_context_exited(Context * ctx) { } context_lock(ctx); send_context_exited_event(ctx); - if (ctx->handle != NULL) { + if (EXT(ctx)->handle != NULL) { if (ctx->mem == ctx->pid) { - log_error("CloseHandle", CloseHandle(ctx->handle)); + log_error("CloseHandle", CloseHandle(EXT(ctx)->handle)); } - ctx->handle = NULL; + EXT(ctx)->handle = NULL; } - if (ctx->file_handle != NULL) { - log_error("CloseHandle", CloseHandle(ctx->file_handle)); - ctx->file_handle = NULL; + if (EXT(ctx)->file_handle != NULL) { + log_error("CloseHandle", CloseHandle(EXT(ctx)->file_handle)); + EXT(ctx)->file_handle = NULL; } context_unlock(ctx); } static int win32_resume(Context * ctx) { - if (ctx->regs_dirty && SetThreadContext(ctx->handle, (REG_SET *)ctx->regs) == 0) { + if (ctx->regs_dirty && SetThreadContext(EXT(ctx)->handle, (REG_SET *)ctx->regs) == 0) { errno = log_error("SetThreadContext", 0); return -1; } ctx->regs_dirty = 0; - if (ctx->pending_event.ExceptionRecord.ExceptionCode != 0) { + if (EXT(ctx)->pending_event.ExceptionRecord.ExceptionCode != 0) { event_win32_context_started(ctx); context_lock(ctx); post_event(event_win32_context_stopped_async, ctx); return 0; } if (ctx->parent->pending_signals & (1 << SIGKILL)) { - if (!ctx->parent->exiting && !TerminateProcess(ctx->parent->handle, 1)) { + if (!ctx->parent->exiting && !TerminateProcess(EXT(ctx->parent)->handle, 1)) { errno = log_error("TerminateProcess", 0); return -1; } @@ -248,7 +267,7 @@ static int win32_resume(Context * ctx) { ctx->parent->exiting = 1; } for (;;) { - DWORD cnt = ResumeThread(ctx->handle); + DWORD cnt = ResumeThread(EXT(ctx)->handle); if (cnt == (DWORD)-1) { errno = log_error("ResumeThread", 0); return -1; @@ -277,10 +296,10 @@ static void debug_event_handler(void * x) { assert(ctx == NULL); prs = create_context(debug_event->dwProcessId, sizeof(REG_SET)); prs->mem = debug_event->dwProcessId; - prs->handle = debug_event->u.CreateProcessInfo.hProcess; - prs->file_handle = debug_event->u.CreateProcessInfo.hFile; - prs->base_address = (unsigned)debug_event->u.CreateProcessInfo.lpBaseOfImage; - assert(prs->handle != NULL); + EXT(prs)->handle = debug_event->u.CreateProcessInfo.hProcess; + EXT(prs)->file_handle = debug_event->u.CreateProcessInfo.hFile; + EXT(prs)->base_address = (uintptr_t)debug_event->u.CreateProcessInfo.lpBaseOfImage; + assert(EXT(prs)->handle != NULL); link_context(prs); send_context_created_event(prs); args->debug_thread_args->attach_callback(0, prs, args->debug_thread_args->attach_data); @@ -288,8 +307,8 @@ static void debug_event_handler(void * x) { args->debug_thread_args->attach_data = NULL; ctx = create_context(debug_event->dwThreadId, sizeof(REG_SET)); ctx->mem = debug_event->dwProcessId; - ctx->handle = debug_event->u.CreateProcessInfo.hThread; - ctx->debug_started = 1; + EXT(ctx)->handle = debug_event->u.CreateProcessInfo.hThread; + EXT(ctx)->debug_started = 1; ctx->parent = prs; prs->ref_count++; list_add_first(&ctx->cldl, &prs->children); @@ -301,7 +320,7 @@ static void debug_event_handler(void * x) { assert(ctx == NULL); ctx = create_context(debug_event->dwThreadId, sizeof(REG_SET)); ctx->mem = debug_event->dwProcessId; - ctx->handle = debug_event->u.CreateThread.hThread; + EXT(ctx)->handle = debug_event->u.CreateThread.hThread; ctx->parent = prs; prs->ref_count++; list_add_first(&ctx->cldl, &prs->children); @@ -313,7 +332,7 @@ static void debug_event_handler(void * x) { assert(prs != NULL); if (ctx == NULL) break; if (args->early_event) break; /* Can anything be done about such exceptions? */ - assert(ctx->pending_event.ExceptionRecord.ExceptionCode == 0); + assert(EXT(ctx)->pending_event.ExceptionRecord.ExceptionCode == 0); switch (args->event.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_SINGLE_STEP: case EXCEPTION_BREAKPOINT: @@ -324,12 +343,12 @@ static void debug_event_handler(void * x) { args->continue_status = DBG_EXCEPTION_NOT_HANDLED; break; } - memcpy(&ctx->pending_event, &args->event.u.Exception, sizeof(EXCEPTION_DEBUG_INFO)); + memcpy(&EXT(ctx)->pending_event, &args->event.u.Exception, sizeof(EXCEPTION_DEBUG_INFO)); if (!ctx->stopped) { int signal = 0; - if (ctx->context_stopped_async_pending) { + if (EXT(ctx)->context_stopped_async_pending) { cancel_event(event_win32_context_stopped_async, ctx, 0); - ctx->context_stopped_async_pending = 0; + EXT(ctx)->context_stopped_async_pending = 0; } else { context_lock(ctx); @@ -353,24 +372,24 @@ static void debug_event_handler(void * x) { break; case LOAD_DLL_DEBUG_EVENT: assert(prs != NULL); - prs->module_loaded = 1; - prs->module_handle = args->event.u.LoadDll.hFile; - prs->module_address = (unsigned)args->event.u.LoadDll.lpBaseOfDll; + EXT(prs)->module_loaded = 1; + EXT(prs)->module_handle = args->event.u.LoadDll.hFile; + EXT(prs)->module_address = (uintptr_t)args->event.u.LoadDll.lpBaseOfDll; send_context_changed_event(prs); - if (prs->module_handle != NULL) { - log_error("CloseHandle", CloseHandle(prs->module_handle)); + if (EXT(prs)->module_handle != NULL) { + log_error("CloseHandle", CloseHandle(EXT(prs)->module_handle)); } - prs->module_handle = NULL; - prs->module_address = 0; - prs->module_loaded = 0; + EXT(prs)->module_handle = NULL; + EXT(prs)->module_address = 0; + EXT(prs)->module_loaded = 0; break; case UNLOAD_DLL_DEBUG_EVENT: assert(prs != NULL); - prs->module_unloaded = 1; - prs->module_address = (unsigned)args->event.u.UnloadDll.lpBaseOfDll; + EXT(prs)->module_unloaded = 1; + EXT(prs)->module_address = (uintptr_t)args->event.u.UnloadDll.lpBaseOfDll; send_context_changed_event(prs); - prs->module_address = 0; - prs->module_unloaded = 0; + EXT(prs)->module_address = 0; + EXT(prs)->module_unloaded = 0; break; case RIP_EVENT: trace(LOG_ALWAYS, "System debugging error: debuggee pid %d, error type %d, error code %d", @@ -594,16 +613,16 @@ int context_stop(Context * ctx) { assert(context_has_state(ctx)); assert(!ctx->stopped); assert(!ctx->exited); - if (SuspendThread(ctx->handle) == (DWORD)-1) { + if (SuspendThread(EXT(ctx)->handle) == (DWORD)-1) { if (GetLastError() != ERROR_ACCESS_DENIED) { errno = log_error("SuspendThread", 0); return -1; } } - if (!ctx->context_stopped_async_pending) { + if (!EXT(ctx)->context_stopped_async_pending) { context_lock(ctx); post_event(event_win32_context_stopped_async, ctx); - ctx->context_stopped_async_pending = 1; + EXT(ctx)->context_stopped_async_pending = 1; } return 0; } @@ -661,7 +680,7 @@ int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t s assert(is_dispatch_thread()); if (ctx->parent != NULL) ctx = ctx->parent; assert(ctx->pid == ctx->mem); - if (ReadProcessMemory(ctx->handle, (LPCVOID)address, buf, size, &bcnt) == 0 || bcnt != size) { + if (ReadProcessMemory(EXT(ctx)->handle, (LPCVOID)address, buf, size, &bcnt) == 0 || bcnt != size) { errno = log_error("ReadProcessMemory", 0); return -1; } @@ -677,20 +696,49 @@ int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t if (ctx->parent != NULL) ctx = ctx->parent; assert(ctx->pid == ctx->mem); check_breakpoints_on_memory_write(ctx, address, buf, size); - if (WriteProcessMemory(ctx->handle, (LPVOID)address, buf, size, &bcnt) == 0 || bcnt != size) { + if (WriteProcessMemory(EXT(ctx)->handle, (LPVOID)address, buf, size, &bcnt) == 0 || bcnt != size) { DWORD err = GetLastError(); if (err == ERROR_ACCESS_DENIED) errno = set_win32_errno(err); else errno = log_error("WriteProcessMemory", 0); return -1; } - if (FlushInstructionCache(ctx->handle, (LPCVOID)address, size) == 0) { + if (FlushInstructionCache(EXT(ctx)->handle, (LPCVOID)address, size) == 0) { errno = log_error("FlushInstructionCache", 0); return -1; } return 0; } +HANDLE get_context_handle(Context * ctx) { + return EXT(ctx)->handle; +} + +HANDLE get_context_file_handle(Context * ctx) { + return EXT(ctx)->file_handle; +} + +HANDLE get_context_module_handle(Context * ctx) { + return EXT(ctx)->module_handle; +} + +DWORD64 get_context_base_address(Context * ctx) { + return EXT(ctx)->base_address; +} + +DWORD64 get_context_module_address(Context * ctx) { + return EXT(ctx)->module_address; +} + +int is_context_module_loaded(Context * ctx) { + return EXT(ctx)->module_loaded; +} + +int is_context_module_unloaded(Context * ctx) { + return EXT(ctx)->module_unloaded; +} + void init_contexts_sys_dep(void) { + context_extension_offset = context_extension(sizeof(ContextExtension)); } #endif /* if ENABLE_DebugContext */ diff --git a/system/Windows/context-win32.h b/system/Windows/context-win32.h new file mode 100644 index 00000000..2fa3de4f --- /dev/null +++ b/system/Windows/context-win32.h @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2007, 2009 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. + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ + +/* + * This module handles process/thread OS contexts and their state machine. + */ + +#ifndef D_context_win32 +#define D_context_win32 + +#include "config.h" +#include "context.h" + +extern HANDLE get_context_handle(Context * ctx); +extern HANDLE get_context_file_handle(Context * ctx); +extern HANDLE get_context_module_handle(Context * ctx); + +extern DWORD64 get_context_base_address(Context * ctx); +extern DWORD64 get_context_module_address(Context * ctx); + +extern int is_context_module_loaded(Context * ctx); +extern int is_context_module_unloaded(Context * ctx); + +#endif /* D_context_win32 */ |