diff options
author | Eugene Tarassov | 2011-11-24 21:29:24 +0000 |
---|---|---|
committer | Eugene Tarassov | 2011-11-24 21:29:24 +0000 |
commit | f3647b55e7958eb89dece294d99ac8389c9cb57b (patch) | |
tree | 817b9703820880e224e27c4c85e30ecfa352cd17 /agent/tcf/system | |
parent | dafe1eefa355d67b2f9de21b90914077c1194ef0 (diff) | |
download | org.eclipse.tcf.agent-f3647b55e7958eb89dece294d99ac8389c9cb57b.tar.gz org.eclipse.tcf.agent-f3647b55e7958eb89dece294d99ac8389c9cb57b.tar.xz org.eclipse.tcf.agent-f3647b55e7958eb89dece294d99ac8389c9cb57b.zip |
TCF Agent: added "tcf/" prefix to system and machine dependent header files.
Diffstat (limited to 'agent/tcf/system')
20 files changed, 0 insertions, 6079 deletions
diff --git a/agent/tcf/system/Cygwin/regset.h b/agent/tcf/system/Cygwin/regset.h deleted file mode 100644 index 08e2895d..00000000 --- a/agent/tcf/system/Cygwin/regset.h +++ /dev/null @@ -1,23 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2010 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This header file provides definition of REG_SET - a structure that can - * hold values of target CPU registers. - */ - -#if defined(__CYGWIN__) - typedef CONTEXT REG_SET; -#endif diff --git a/agent/tcf/system/Darwin/context-darwin.c b/agent/tcf/system/Darwin/context-darwin.c deleted file mode 100644 index 50464b77..00000000 --- a/agent/tcf/system/Darwin/context-darwin.c +++ /dev/null @@ -1,663 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This module handles process/thread OS contexts and their state machine. - */ - -#include <tcf/config.h> - -#if defined(__APPLE__) - -#if ENABLE_DebugContext && !ENABLE_ContextProxy - -#include <stdlib.h> -#include <assert.h> -#include <errno.h> -#include <signal.h> -#include <sched.h> -#include <sys/syscall.h> -#include <sys/ptrace.h> -#include <mach/thread_status.h> -#include <tcf/framework/context.h> -#include <tcf/framework/events.h> -#include <tcf/framework/errors.h> -#include <tcf/framework/trace.h> -#include <tcf/framework/myalloc.h> -#include <tcf/framework/waitpid.h> -#include <tcf/framework/signames.h> -#include <tcf/services/breakpoints.h> -#include <tcf/system/Darwin/regset.h> - -#define WORD_SIZE 4 - -typedef struct ContextExtensionDarwin { - pid_t pid; - 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; - REG_SET * regs; /* copy of context registers, updated when context stops */ - 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 */ - int pending_step; -} ContextExtensionDarwin; - -static size_t context_extension_offset = 0; - -#define EXT(ctx) ((ContextExtensionDarwin *)((char *)(ctx) + context_extension_offset)) - -#include <tcf/system/pid-hash.h> - -static LINK pending_list = TCF_LIST_INIT(pending_list); - -static MemoryErrorInfo mem_err_info; - -const char * context_suspend_reason(Context * ctx) { - static char reason[128]; - - if (EXT(ctx)->end_of_step) return REASON_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 REASON_USER_REQUEST; - snprintf(reason, sizeof(reason), "Signal %d", ctx->signal); - return reason; -} - -int context_attach_self(void) { - if (ptrace(PT_TRACE_ME, 0, 0, 0) < 0) { - int err = errno; - trace(LOG_ALWAYS, "error: ptrace(PT_TRACE_ME) failed: pid %d, error %d %s", - getpid(), err, errno_to_str(err)); - errno = err; - return -1; - } - return 0; -} - -int context_attach(pid_t pid, ContextAttachCallBack * done, void * data, int mode) { - Context * ctx = NULL; - - assert(done != NULL); - trace(LOG_CONTEXT, "context: attaching pid %d", pid); - if ((mode & CONTEXT_ATTACH_SELF) == 0 && ptrace(PT_ATTACH, pid, 0, 0) < 0) { - int err = errno; - trace(LOG_ALWAYS, "error: ptrace(PT_ATTACH) failed: pid %d, error %d %s", - pid, err, errno_to_str(err)); - errno = err; - return -1; - } - add_waitpid_process(pid); - ctx = create_context(pid2id(pid, 0)); - ctx->mem = ctx; - ctx->mem_access |= MEM_ACCESS_INSTRUCTION; - ctx->mem_access |= MEM_ACCESS_DATA; - ctx->mem_access |= MEM_ACCESS_USER; - ctx->big_endian = big_endian_host(); - EXT(ctx)->pid = pid; - 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; -} - -int context_has_state(Context * ctx) { - return ctx != NULL && ctx->parent != NULL; -} - -int context_stop(Context * ctx) { - trace(LOG_CONTEXT, "context:%s suspending ctx %#lx, id %s", - ctx->pending_intercept ? "" : " temporary", ctx, ctx->id); - assert(is_dispatch_thread()); - assert(!ctx->exited); - assert(!ctx->stopped); - assert(!EXT(ctx)->regs_dirty); - if (kill(EXT(ctx)->pid, SIGSTOP) < 0) { - int err = errno; - if (err == ESRCH) { - ctx->exiting = 1; - return 0; - } - trace(LOG_ALWAYS, "error: tkill(SIGSTOP) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - return 0; -} - -static int syscall_never_returns(Context * ctx) { - if (EXT(ctx)->syscall_enter) { - switch (EXT(ctx)->syscall_id) { - case SYS_sigreturn: - return 1; - } - } - return 0; -} - -int context_continue(Context * ctx) { - int signal = 0; - - assert(is_dispatch_thread()); - assert(ctx->stopped); - assert(!ctx->exited); - assert(!ctx->pending_intercept); - assert(!EXT(ctx)->pending_step); - - if (skip_breakpoint(ctx, 0)) return 0; - - 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)) { - ctx->pending_signals &= ~(1 << signal); - signal = 0; - } - else { - break; - } - } - assert(signal != SIGSTOP); - assert(signal != SIGTRAP); - } - - trace(LOG_CONTEXT, "context: resuming ctx %#lx, id %s, with signal %d", ctx, ctx->id, signal); -#if defined(__i386__) - if (EXT(ctx)->regs->__eflags & 0x100) { - EXT(ctx)->regs->__eflags &= ~0x100; - EXT(ctx)->regs_dirty = 1; - } -#elif defined(__x86_64__) - if (EXT(ctx)->regs->__rflags & 0x100) { - EXT(ctx)->regs->__rflags &= ~0x100; - EXT(ctx)->regs_dirty = 1; - } -#endif - if (EXT(ctx)->regs_dirty) { - unsigned int state_count; - if (thread_set_state(EXT(ctx)->pid, x86_THREAD_STATE32, EXT(ctx)->regs, &state_count) != KERN_SUCCESS) { - int err = errno; - trace(LOG_ALWAYS, "error: thread_set_state failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - EXT(ctx)->regs_dirty = 0; - } - if (ptrace(PT_CONTINUE, EXT(ctx)->pid, 0, signal) < 0) { - int err = errno; - if (err == ESRCH) { - send_context_started_event(ctx); - return 0; - } - trace(LOG_ALWAYS, "error: ptrace(PT_CONTINUE, ...) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - ctx->pending_signals &= ~(1 << signal); - if (syscall_never_returns(ctx)) { - EXT(ctx)->syscall_enter = 0; - EXT(ctx)->syscall_exit = 0; - EXT(ctx)->syscall_id = 0; - } - send_context_started_event(ctx); - return 0; -} - -int context_single_step(Context * ctx) { - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(ctx->stopped); - assert(!ctx->exited); - assert(!EXT(ctx)->pending_step); - - if (skip_breakpoint(ctx, 1)) return 0; - - if (syscall_never_returns(ctx)) return context_continue(ctx); - trace(LOG_CONTEXT, "context: single step ctx %#lx, id %S", ctx, ctx->id); - if (EXT(ctx)->regs_dirty) { - unsigned int state_count; - if (thread_set_state(EXT(ctx)->pid, x86_THREAD_STATE32, EXT(ctx)->regs, &state_count) != KERN_SUCCESS) { - int err = errno; - trace(LOG_ALWAYS, "error: thread_set_state failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - EXT(ctx)->regs_dirty = 0; - } - if (ptrace(PT_STEP, EXT(ctx)->pid, 0, 0) < 0) { - int err = errno; - if (err == ESRCH) { - EXT(ctx)->pending_step = 1; - send_context_started_event(ctx); - return 0; - } - trace(LOG_ALWAYS, "error: ptrace(PT_STEP, ...) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - EXT(ctx)->pending_step = 1; - send_context_started_event(ctx); - return 0; -} - -int context_resume(Context * ctx, int mode, ContextAddress range_start, ContextAddress range_end) { - switch (mode) { - case RM_RESUME: - return context_continue(ctx); - case RM_STEP_INTO: - return context_single_step(ctx); - case RM_TERMINATE: - ctx->pending_signals |= 1 << SIGKILL; - return context_continue(ctx); - } - errno = ERR_UNSUPPORTED; - return -1; -} - -int context_can_resume(Context * ctx, int mode) { - switch (mode) { - case RM_RESUME: - return 1; - case RM_STEP_INTO: - case RM_TERMINATE: - return context_has_state(ctx); - } - return 0; -} - -int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { - /* - ContextAddress word_addr; - assert(is_dispatch_thread()); - assert(!ctx->exited); - trace(LOG_CONTEXT, "context: write memory ctx %#lx, id %s, address %#lx, size %zu", - ctx, ctx->id, address, size); - assert(WORD_SIZE == sizeof(unsigned)); - check_breakpoints_on_memory_write(ctx, address, buf, size); - for (word_addr = address & ~(WORD_SIZE - 1); word_addr < address + size; word_addr += WORD_SIZE) { - unsigned word = 0; - if (word_addr < address || word_addr + WORD_SIZE > address + size) { - int i; - errno = 0; - word = ptrace(PT_PEEKDATA, EXT(ctx)->pid, word_addr, 0); - if (errno != 0) { - int err = errno; - trace(LOG_CONTEXT, "error: ptrace(PT_PEEKDATA, ...) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - for (i = 0; i < WORD_SIZE; i++) { - if (word_addr + i >= address && word_addr + i < address + size) { - ((char *)&word)[i] = ((char *)buf)[word_addr + i - address]; - } - } - } - else { - word = *(unsigned *)((char *)buf + (word_addr - address)); - } - if (ptrace(PT_POKEDATA, EXT(ctx)->pid, word_addr, word) < 0) { - int err = errno; - trace(LOG_ALWAYS, "error: ptrace(PT_POKEDATA, ...) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - } - */ - return 0; -} - -int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { - /* - ContextAddress word_addr; - assert(is_dispatch_thread()); - assert(!ctx->exited); - trace(LOG_CONTEXT, "context: read memory ctx %#lx, id %s, address %#lx, size %zu", - ctx, ctx->id, address, size); - assert(WORD_SIZE == sizeof(unsigned)); - for (word_addr = address & ~(WORD_SIZE - 1); word_addr < address + size; word_addr += WORD_SIZE) { - unsigned word = 0; - errno = 0; - word = ptrace(PT_PEEKDATA, EXT(ctx)->pid, word_addr, 0); - if (errno != 0) { - int err = errno; - trace(LOG_CONTEXT, "error: ptrace(PT_PEEKDATA, ...) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - if (word_addr < address || word_addr + WORD_SIZE > address + size) { - int i; - for (i = 0; i < WORD_SIZE; i++) { - if (word_addr + i >= address && word_addr + i < address + size) { - ((char *)buf)[word_addr + i - address] = ((char *)&word)[i]; - } - } - } - else { - *(unsigned *)((char *)buf + (word_addr - address)) = word; - } - } - check_breakpoints_on_memory_read(ctx, address, buf, size); - */ - return 0; -} - -#if ENABLE_ExtendedMemoryErrorReports -int context_get_mem_error_info(MemoryErrorInfo * info) { - if (mem_err_info.error == 0) { - set_errno(ERR_OTHER, "Extended memory error info not available"); - return -1; - } - *info = mem_err_info; - return 0; -} -#endif - -int context_write_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) { - ContextExtensionDarwin * ext = EXT(ctx); - - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(ctx->stopped); - assert(!ctx->exited); - assert(offs + size <= def->size); - - if (ext->regs_error) { - set_error_report_errno(ext->regs_error); - return -1; - } - memcpy((uint8_t *)ext->regs + def->offset + offs, buf, size); - ext->regs_dirty = 1; - return 0; -} - -int context_read_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) { - ContextExtensionDarwin * ext = EXT(ctx); - - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(ctx->stopped); - assert(!ctx->exited); - assert(offs + size <= def->size); - - if (ext->regs_error) { - set_error_report_errno(ext->regs_error); - return -1; - } - memcpy(buf, (uint8_t *)ext->regs + def->offset + offs, size); - return 0; -} - -unsigned context_word_size(Context * ctx) { - return sizeof(void *); -} - -int context_get_canonical_addr(Context * ctx, ContextAddress addr, - Context ** canonical_ctx, ContextAddress * canonical_addr, - ContextAddress * block_addr, ContextAddress * block_size) { - /* Direct mapping, page size is irrelevant */ - ContextAddress page_size = 0x100000; - assert(is_dispatch_thread()); - *canonical_ctx = ctx->mem; - if (canonical_addr != NULL) *canonical_addr = addr; - if (block_addr != NULL) *block_addr = addr & ~(page_size - 1); - if (block_size != NULL) *block_size = page_size; - return 0; -} - -Context * context_get_group(Context * ctx, int group) { - static Context * cpu_group = NULL; - switch (group) { - case CONTEXT_GROUP_INTERCEPT: - return ctx; - case CONTEXT_GROUP_CPU: - if (cpu_group == NULL) cpu_group = create_context("CPU"); - return cpu_group; - } - return ctx->mem; -} - -int context_get_supported_bp_access_types(Context * ctx) { - return 0; -} - -int context_plant_breakpoint(ContextBreakpoint * bp) { - errno = ERR_UNSUPPORTED; - return -1; -} - -int context_unplant_breakpoint(ContextBreakpoint * bp) { - errno = ERR_UNSUPPORTED; - return -1; -} - -int context_get_memory_map(Context * ctx, MemoryMap * map) { - ctx = ctx->mem; - assert(!ctx->exited); - return 0; -} - -static Context * find_pending(pid_t pid) { - LINK * l = pending_list.next; - while (l != &pending_list) { - Context * c = ctxl2ctxp(l); - if (EXT(c)->pid == pid) { - list_remove(&c->ctxl); - return c; - } - l = l->next; - } - return NULL; -} - -static void event_pid_exited(pid_t pid, int status, int signal) { - Context * ctx; - - ctx = context_find_from_pid(pid, 1); - if (ctx == NULL) { - ctx = find_pending(pid); - if (ctx == NULL) { - trace(LOG_EVENTS, "event: ctx not found, pid %d, exit status %d, term signal %d", pid, status, signal); - } - else { - assert(ctx->ref_count == 0); - if (EXT(ctx)->attach_callback != NULL) { - if (status == 0) status = EINVAL; - EXT(ctx)->attach_callback(status, ctx, EXT(ctx)->attach_data); - } - assert(list_is_empty(&ctx->children)); - assert(ctx->parent == NULL); - ctx->exited = 1; - ctx->ref_count = 1; - context_unlock(ctx); - } - } - else { - /* Note: ctx->exiting should be 1 here. However, PTRACE_EVENT_EXIT can be lost by PTRACE because of racing - * between PTRACE_CONT (or PTRACE_SYSCALL) and SIGTRAP/PTRACE_EVENT_EXIT. So, ctx->exiting can be 0. - */ - if (EXT(ctx->parent)->pid == pid) ctx = ctx->parent; - assert(EXT(ctx)->attach_callback == NULL); - if (ctx->exited) { - trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d unexpected, stopped %d, exited %d", - ctx, pid, status, ctx->stopped, ctx->exited); - } - else { - trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d, term signal %d", ctx, pid, status, signal); - ctx->exiting = 1; - if (ctx->stopped) send_context_started_event(ctx); - if (!list_is_empty(&ctx->children)) { - LINK * l = ctx->children.next; - while (l != &ctx->children) { - Context * c = cldl2ctxp(l); - l = l->next; - assert(c->parent == ctx); - if (!c->exited) { - c->exiting = 1; - if (c->stopped) send_context_started_event(c); - release_error_report(EXT(c)->regs_error); - loc_free(EXT(c)->regs); - EXT(c)->regs_error = NULL; - EXT(c)->regs = NULL; - send_context_exited_event(c); - } - } - } - release_error_report(EXT(ctx)->regs_error); - loc_free(EXT(ctx)->regs); - EXT(ctx)->regs_error = NULL; - EXT(ctx)->regs = NULL; - send_context_exited_event(ctx); - } - } -} - -static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { - int stopped_by_exception = 0; - unsigned long msg = 0; - Context * ctx = NULL; - Context * ctx2 = NULL; - - trace(LOG_EVENTS, "event: pid %d stopped, signal %d", pid, signal); - - ctx = context_find_from_pid(pid, 1); - - if (ctx == NULL) { - ctx = find_pending(pid); - if (ctx != NULL) { - Context * prs = ctx; - assert(prs->ref_count == 0); - ctx = create_context(pid2id(pid, pid)); - EXT(ctx)->pid = pid; - EXT(ctx)->regs = (REG_SET *)loc_alloc(sizeof(REG_SET)); - ctx->pending_intercept = 1; - ctx->mem = prs; - ctx->parent = prs; - ctx->big_endian = prs->big_endian; - prs->ref_count++; - list_add_last(&ctx->cldl, &prs->children); - link_context(prs); - link_context(ctx); - send_context_created_event(prs); - send_context_created_event(ctx); - 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; - } - } - } - - if (ctx == NULL) return; - - assert(!ctx->exited); - assert(!EXT(ctx)->attach_callback); - - if (signal != SIGSTOP && signal != SIGTRAP) { - assert(signal < 32); - ctx->pending_signals |= 1 << signal; - if ((ctx->sig_dont_stop & (1 << signal)) == 0) { - ctx->pending_intercept = 1; - stopped_by_exception = 1; - } - } - - if (ctx->stopped) { - send_context_changed_event(ctx); - } - else { - thread_state_t state; - unsigned int state_count; - ContextAddress pc0 = 0; - ContextAddress pc1 = 0; - - assert(!EXT(ctx)->regs_dirty); - - EXT(ctx)->end_of_step = 0; - EXT(ctx)->ptrace_event = event; - ctx->signal = signal; - ctx->stopped_by_bp = 0; - ctx->stopped_by_exception = stopped_by_exception; - ctx->stopped = 1; - - if (EXT(ctx)->regs_error) { - release_error_report(EXT(ctx)->regs_error); - EXT(ctx)->regs_error = NULL; - } - else { - pc0 = get_regs_PC(ctx); - } - - if (thread_get_state(EXT(ctx)->pid, x86_THREAD_STATE32, EXT(ctx)->regs, &state_count) != KERN_SUCCESS) { - assert(errno != 0); - EXT(ctx)->regs_error = get_error_report(errno); - trace(LOG_ALWAYS, "error: thread_get_state failed; id %s, error %d %s", - ctx->id, errno, errno_to_str(errno)); - } - else { - pc1 = get_regs_PC(ctx); - } - - if (!EXT(ctx)->syscall_enter || EXT(ctx)->regs_error || pc0 != pc1) { - 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", pid, pc1); - - if (signal == SIGTRAP && event == 0 && !syscall) { - size_t break_size = 0; - get_break_instruction(ctx, &break_size); - ctx->stopped_by_bp = !EXT(ctx)->regs_error && is_breakpoint_address(ctx, pc1 - break_size); - EXT(ctx)->end_of_step = !ctx->stopped_by_bp && EXT(ctx)->pending_step; - if (ctx->stopped_by_bp) set_regs_PC(ctx, pc1 - break_size); - } - EXT(ctx)->pending_step = 0; - send_context_stopped_event(ctx); - } -} - -static void waitpid_listener(int pid, int exited, int exit_code, int signal, int event_code, int syscall, void * args) { - if (exited) { - event_pid_exited(pid, exit_code, signal); - } - else { - event_pid_stopped(pid, signal, event_code, syscall); - } -} - -void init_contexts_sys_dep(void) { - context_extension_offset = context_extension(sizeof(ContextExtensionDarwin)); - add_waitpid_listener(waitpid_listener, NULL); - ini_context_pid_hash(); -} - -#endif /* if ENABLE_DebugContext */ -#endif /* __APPLE__ */ diff --git a/agent/tcf/system/Darwin/regset.h b/agent/tcf/system/Darwin/regset.h deleted file mode 100644 index 0422799e..00000000 --- a/agent/tcf/system/Darwin/regset.h +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2010 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This header file provides definition of REG_SET - a structure that can - * hold values of target CPU registers. - */ - -#if defined(__APPLE__) -# include <mach/thread_status.h> -# if defined(__i386__) - typedef x86_thread_state32_t REG_SET; -# else - typedef x86_thread_state64_t REG_SET; -# endif -#endif diff --git a/agent/tcf/system/FreeBSD/context-freebsd.c b/agent/tcf/system/FreeBSD/context-freebsd.c deleted file mode 100644 index 9f01aaa0..00000000 --- a/agent/tcf/system/FreeBSD/context-freebsd.c +++ /dev/null @@ -1,659 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This module handles process/thread OS contexts and their state machine. - */ - -#include <tcf/config.h> - -#if defined(__FreeBSD__) - -#if ENABLE_DebugContext && !ENABLE_ContextProxy - -#include <stdlib.h> -#include <assert.h> -#include <errno.h> -#include <signal.h> -#include <sched.h> -#include <sys/ptrace.h> -#include <tcf/framework/context.h> -#include <tcf/framework/events.h> -#include <tcf/framework/errors.h> -#include <tcf/framework/trace.h> -#include <tcf/framework/myalloc.h> -#include <tcf/framework/waitpid.h> -#include <tcf/framework/signames.h> -#include <tcf/services/breakpoints.h> -#include <tcf/system/FreeBSD/regset.h> - -#define PTRACE_TRACEME PT_TRACE_ME -#define PTRACE_ATTACH PT_ATTACH -#define PTRACE_GETREGS PT_GETREGS -#define PTRACE_SETREGS PT_SETREGS -#define PTRACE_PEEKDATA PT_READ_D -#define PTRACE_POKEDATA PT_WRITE_D -#define PTRACE_CONT PT_CONTINUE -#define PTRACE_SINGLESTEP PT_STEP - -#define USE_PTRACE_SYSCALL 0 - -typedef struct ContextExtensionBSD { - pid_t pid; - 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; - REG_SET * regs; /* copy of context registers, updated when context stops */ - 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 */ - int pending_step; -} ContextExtensionBSD; - -static size_t context_extension_offset = 0; - -#define EXT(ctx) ((ContextExtensionBSD *)((char *)(ctx) + context_extension_offset)) - -#include <tcf/system/pid-hash.h> - -static LINK pending_list = TCF_LIST_INIT(pending_list); - -static MemoryErrorInfo mem_err_info; - -static const char * event_name(int event) { - trace(LOG_ALWAYS, "event_name(): unexpected event code %d", event); - return "unknown"; -} - -const char * context_suspend_reason(Context * ctx) { - static char reason[128]; - - if (EXT(ctx)->end_of_step) return REASON_STEP; - if (EXT(ctx)->ptrace_event != 0) { - assert(ctx->signal == SIGTRAP); - snprintf(reason, sizeof(reason), "Event: %s", event_name(EXT(ctx)->ptrace_event)); - return reason; - } - if (ctx->signal == SIGSTOP || ctx->signal == SIGTRAP) return REASON_USER_REQUEST; - snprintf(reason, sizeof(reason), "Signal %d", ctx->signal); - return reason; -} - -int context_attach_self(void) { - if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { - int err = errno; - trace(LOG_ALWAYS, "error: ptrace(PTRACE_TRACEME) failed: pid %d, error %d %s", - getpid(), err, errno_to_str(err)); - errno = err; - return -1; - } - return 0; -} - -int context_attach(pid_t pid, ContextAttachCallBack * done, void * data, int mode) { - Context * ctx = NULL; - - assert(done != NULL); - trace(LOG_CONTEXT, "context: attaching pid %d", pid); - if ((mode & CONTEXT_ATTACH_SELF) == 0 && ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) { - int err = errno; - trace(LOG_ALWAYS, "error: ptrace(PTRACE_ATTACH) failed: pid %d, error %d %s", - pid, err, errno_to_str(err)); - errno = err; - return -1; - } - add_waitpid_process(pid); - ctx = create_context(pid2id(pid, 0)); - ctx->mem = ctx; - ctx->mem_access |= MEM_ACCESS_INSTRUCTION; - ctx->mem_access |= MEM_ACCESS_DATA; - ctx->mem_access |= MEM_ACCESS_USER; - ctx->big_endian = big_endian_host(); - EXT(ctx)->pid = pid; - 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; -} - -int context_has_state(Context * ctx) { - return ctx != NULL && ctx->parent != NULL; -} - -int context_stop(Context * ctx) { - trace(LOG_CONTEXT, "context:%s suspending ctx %#lx id %s", - ctx->pending_intercept ? "" : " temporary", ctx, ctx->id); - assert(is_dispatch_thread()); - assert(!ctx->exited); - assert(!ctx->stopped); - assert(!EXT(ctx)->regs_dirty); - if (tkill(EXT(ctx)->pid, SIGSTOP) < 0) { - int err = errno; - if (err == ESRCH) { - ctx->exiting = 1; - return 0; - } - trace(LOG_ALWAYS, "error: tkill(SIGSTOP) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - return 0; -} - -int context_continue(Context * ctx) { - int signal = 0; - - assert(is_dispatch_thread()); - assert(ctx->stopped); - assert(!ctx->pending_intercept); - assert(!EXT(ctx)->pending_step); - assert(!ctx->exited); - - if (skip_breakpoint(ctx, 0)) return 0; - - 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)) { - ctx->pending_signals &= ~(1 << signal); - signal = 0; - } - else { - break; - } - } - assert(signal != SIGSTOP); - assert(signal != SIGTRAP); - } - - trace(LOG_CONTEXT, "context: resuming ctx %#lx, id %s, with signal %d", ctx, ctx->id, signal); - if (EXT(ctx)->regs_dirty) { - if (ptrace(PTRACE_SETREGS, EXT(ctx)->pid, 0, (int)EXT(ctx)->regs) < 0) { - int err = errno; - if (err == ESRCH) { - EXT(ctx)->regs_dirty = 0; - send_context_started_event(ctx); - return 0; - } - trace(LOG_ALWAYS, "error: ptrace(PTRACE_SETREGS) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - EXT(ctx)->regs_dirty = 0; - } - if (ptrace(PTRACE_CONT, EXT(ctx)->pid, 0, signal) < 0) { - int err = errno; - if (err == ESRCH) { - send_context_started_event(ctx); - return 0; - } - trace(LOG_ALWAYS, "error: ptrace(PTRACE_CONT, ...) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - ctx->pending_signals &= ~(1 << signal); - send_context_started_event(ctx); - return 0; -} - -int context_single_step(Context * ctx) { - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(ctx->stopped); - assert(!ctx->exited); - assert(!EXT(ctx)->pending_step); - - if (skip_breakpoint(ctx, 1)) return 0; - - trace(LOG_CONTEXT, "context: single step ctx %#lx, id %s", ctx, ctx->id); - if (EXT(ctx)->regs_dirty) { - if (ptrace(PTRACE_SETREGS, EXT(ctx)->pid, 0, (int)EXT(ctx)->regs) < 0) { - int err = errno; - if (err == ESRCH) { - EXT(ctx)->regs_dirty = 0; - EXT(ctx)->pending_step = 1; - send_context_started_event(ctx); - return 0; - } - trace(LOG_ALWAYS, "error: ptrace(PTRACE_SETREGS) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - EXT(ctx)->regs_dirty = 0; - } - if (ptrace(PTRACE_SINGLESTEP, EXT(ctx)->pid, 0, 0) < 0) { - int err = errno; - if (err == ESRCH) { - EXT(ctx)->pending_step = 1; - send_context_started_event(ctx); - return 0; - } - trace(LOG_ALWAYS, "error: ptrace(PTRACE_SINGLESTEP, ...) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - EXT(ctx)->pending_step = 1; - send_context_started_event(ctx); - return 0; -} - -int context_resume(Context * ctx, int mode, ContextAddress range_start, ContextAddress range_end) { - switch (mode) { - case RM_RESUME: - return context_continue(ctx); - case RM_STEP_INTO: - return context_single_step(ctx); - case RM_TERMINATE: - ctx->pending_signals |= 1 << SIGKILL; - return context_continue(ctx); - } - errno = ERR_UNSUPPORTED; - return -1; -} - -int context_can_resume(Context * ctx, int mode) { - switch (mode) { - case RM_RESUME: - return 1; - case RM_STEP_INTO: - case RM_TERMINATE: - return context_has_state(ctx); - } - return 0; -} - -int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { - ContextAddress word_addr; - unsigned word_size = context_word_size(ctx); - assert(is_dispatch_thread()); - assert(!ctx->exited); - trace(LOG_CONTEXT, "context: write memory ctx %#lx, id %s, address %#lx, size %zu", - ctx, ctx->id, address, size); - assert(word_size <= sizeof(unsigned long)); - if (check_breakpoints_on_memory_write(ctx, address, buf, size) < 0) return -1; - for (word_addr = address & ~((ContextAddress)word_size - 1); word_addr < address + size; word_addr += word_size) { - unsigned long word = 0; - if (word_addr < address || word_addr + word_size > address + size) { - size_t i; - errno = 0; - word = ptrace(PTRACE_PEEKDATA, EXT(ctx)->pid, (char *)word_addr, 0); - if (errno != 0) { - int err = errno; - trace(LOG_CONTEXT, "error: ptrace(PTRACE_PEEKDATA, ...) failed: ctx %#lx, id %s, addr %#lx, error %d %s", - ctx, ctx->id, word_addr, err, errno_to_str(err)); - errno = err; - return -1; - } - for (i = 0; i < word_size; i++) { - if (word_addr + i >= address && word_addr + i < address + size) { - ((char *)&word)[i] = ((char *)buf)[word_addr + i - address]; - } - } - } - else { - memcpy(&word, (char *)buf + (word_addr - address), word_size); - } - if (ptrace(PTRACE_POKEDATA, EXT(ctx)->pid, (char *)word_addr, word) < 0) { - int err = errno; - trace(LOG_ALWAYS, "error: ptrace(PTRACE_POKEDATA, ...) failed: ctx %#lx, id %s, addr %#lx, error %d %s", - ctx, ctx->id, word_addr, err, errno_to_str(err)); - errno = err; - return -1; - } - } - return 0; -} - -int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { - ContextAddress word_addr; - unsigned word_size = context_word_size(ctx); - assert(is_dispatch_thread()); - assert(!ctx->exited); - trace(LOG_CONTEXT, "context: read memory ctx %#lx, id %s, address %#lx, size %zu", - ctx, ctx->id, address, size); - assert(word_size <= sizeof(unsigned long)); - for (word_addr = address & ~((ContextAddress)word_size - 1); word_addr < address + size; word_addr += word_size) { - unsigned long word = 0; - errno = 0; - word = ptrace(PTRACE_PEEKDATA, EXT(ctx)->pid, (char *)word_addr, 0); - if (errno != 0) { - int err = errno; - trace(LOG_CONTEXT, "error: ptrace(PTRACE_PEEKDATA, ...) failed: ctx %#lx, id %s, addr %#lx, error %d %s", - ctx, ctx->id, word_addr, err, errno_to_str(err)); - errno = err; - return -1; - } - if (word_addr < address || word_addr + word_size > address + size) { - size_t i; - for (i = 0; i < word_size; i++) { - if (word_addr + i >= address && word_addr + i < address + size) { - ((char *)buf)[word_addr + i - address] = ((char *)&word)[i]; - } - } - } - else { - memcpy((char *)buf + (word_addr - address), &word, word_size); - } - } - return check_breakpoints_on_memory_read(ctx, address, buf, size); -} - -#if ENABLE_ExtendedMemoryErrorReports -int context_get_mem_error_info(MemoryErrorInfo * info) { - if (mem_err_info.error == 0) { - set_errno(ERR_OTHER, "Extended memory error info not available"); - return -1; - } - *info = mem_err_info; - return 0; -} -#endif - -int context_write_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) { - ContextExtensionBSD * ext = EXT(ctx); - - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(ctx->stopped); - assert(!ctx->exited); - assert(offs + size <= def->size); - - if (ext->regs_error) { - set_error_report_errno(ext->regs_error); - return -1; - } - memcpy((uint8_t *)ext->regs + def->offset + offs, buf, size); - ext->regs_dirty = 1; - return 0; -} - -int context_read_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) { - ContextExtensionBSD * ext = EXT(ctx); - - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(ctx->stopped); - assert(!ctx->exited); - assert(offs + size <= def->size); - - if (ext->regs_error) { - set_error_report_errno(ext->regs_error); - return -1; - } - memcpy(buf, (uint8_t *)ext->regs + def->offset + offs, size); - return 0; -} - -unsigned context_word_size(Context * ctx) { - return sizeof(void *); -} - -int context_get_canonical_addr(Context * ctx, ContextAddress addr, - Context ** canonical_ctx, ContextAddress * canonical_addr, - ContextAddress * block_addr, ContextAddress * block_size) { - /* Direct mapping, page size is irrelevant */ - ContextAddress page_size = 0x100000; - assert(is_dispatch_thread()); - *canonical_ctx = ctx->mem; - if (canonical_addr != NULL) *canonical_addr = addr; - if (block_addr != NULL) *block_addr = addr & ~(page_size - 1); - if (block_size != NULL) *block_size = page_size; - return 0; -} - -Context * context_get_group(Context * ctx, int group) { - static Context * cpu_group = NULL; - switch (group) { - case CONTEXT_GROUP_INTERCEPT: - return ctx; - case CONTEXT_GROUP_CPU: - if (cpu_group == NULL) cpu_group = create_context("CPU"); - return cpu_group; - } - return ctx->mem; -} - -int context_get_supported_bp_access_types(Context * ctx) { - return 0; -} - -int context_plant_breakpoint(ContextBreakpoint * bp) { - errno = ERR_UNSUPPORTED; - return -1; -} - -int context_unplant_breakpoint(ContextBreakpoint * bp) { - errno = ERR_UNSUPPORTED; - return -1; -} - -int context_get_memory_map(Context * ctx, MemoryMap * map) { - ctx = ctx->mem; - assert(!ctx->exited); - return 0; -} - -static Context * find_pending(pid_t pid) { - LINK * l = pending_list.next; - while (l != &pending_list) { - Context * c = ctxl2ctxp(l); - if (EXT(c)->pid == pid) { - list_remove(&c->ctxl); - return c; - } - l = l->next; - } - return NULL; -} - -static void event_pid_exited(pid_t pid, int status, int signal) { - Context * ctx; - - ctx = context_find_from_pid(pid, 1); - if (ctx == NULL) { - ctx = find_pending(pid); - if (ctx == NULL) { - trace(LOG_EVENTS, "event: ctx not found, pid %d, exit status %d, term signal %d", pid, status, signal); - } - else { - assert(ctx->ref_count == 0); - if (EXT(ctx)->attach_callback != NULL) { - if (status == 0) status = EINVAL; - EXT(ctx)->attach_callback(status, ctx, EXT(ctx)->attach_data); - } - assert(list_is_empty(&ctx->children)); - assert(ctx->parent == NULL); - ctx->exited = 1; - ctx->ref_count = 1; - context_unlock(ctx); - } - } - else { - /* Note: ctx->exiting should be 1 here. However, PTRACE_EVENT_EXIT can be lost by PTRACE because of racing - * between PTRACE_CONT (or PTRACE_SYSCALL) and SIGTRAP/PTRACE_EVENT_EXIT. So, ctx->exiting can be 0. - */ - if (EXT(ctx->parent)->pid == pid) ctx = ctx->parent; - assert(EXT(ctx)->attach_callback == NULL); - if (ctx->exited) { - trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d unexpected, stopped %d, exited %d", - ctx, pid, status, ctx->stopped, ctx->exited); - } - else { - trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d, term signal %d", ctx, pid, status, signal); - ctx->exiting = 1; - if (ctx->stopped) send_context_started_event(ctx); - if (!list_is_empty(&ctx->children)) { - LINK * l = ctx->children.next; - while (l != &ctx->children) { - Context * c = cldl2ctxp(l); - l = l->next; - assert(c->parent == ctx); - if (!c->exited) { - c->exiting = 1; - if (c->stopped) send_context_started_event(c); - release_error_report(EXT(c)->regs_error); - loc_free(EXT(c)->regs); - EXT(c)->regs_error = NULL; - EXT(c)->regs = NULL; - send_context_exited_event(c); - } - } - } - release_error_report(EXT(ctx)->regs_error); - loc_free(EXT(ctx)->regs); - EXT(ctx)->regs_error = NULL; - EXT(ctx)->regs = NULL; - send_context_exited_event(ctx); - } - } -} - -static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { - int stopped_by_exception = 0; - Context * ctx = NULL; - - trace(LOG_EVENTS, "event: pid %d stopped, signal %d, event %s", pid, signal, event_name(event)); - - ctx = context_find_from_pid(pid, 1); - - if (ctx == NULL) { - ctx = find_pending(pid); - if (ctx != NULL) { - Context * prs = ctx; - assert(prs->ref_count == 0); - ctx = create_context(pid2id(pid, pid)); - EXT(ctx)->pid = pid; - EXT(ctx)->regs = (REG_SET *)loc_alloc(sizeof(REG_SET)); - ctx->pending_intercept = 1; - ctx->mem = prs; - ctx->parent = prs; - ctx->big_endian = prs->big_endian; - prs->ref_count++; - list_add_last(&ctx->cldl, &prs->children); - link_context(prs); - link_context(ctx); - send_context_created_event(prs); - send_context_created_event(ctx); - 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; - } - } - } - - if (ctx == NULL) return; - - assert(!ctx->exited); - assert(!EXT(ctx)->attach_callback); - - if (signal != SIGSTOP && signal != SIGTRAP) { - assert(signal < 32); - ctx->pending_signals |= 1 << signal; - if ((ctx->sig_dont_stop & (1 << signal)) == 0) { - ctx->pending_intercept = 1; - stopped_by_exception = 1; - } - } - - if (ctx->stopped) { - send_context_changed_event(ctx); - } - else { - ContextAddress pc0 = 0; - ContextAddress pc1 = 0; - - assert(!EXT(ctx)->regs_dirty); - - EXT(ctx)->end_of_step = 0; - EXT(ctx)->ptrace_event = event; - ctx->signal = signal; - ctx->stopped_by_bp = 0; - ctx->stopped_by_exception = stopped_by_exception; - ctx->stopped = 1; - - if (EXT(ctx)->regs_error) { - release_error_report(EXT(ctx)->regs_error); - EXT(ctx)->regs_error = NULL; - } - else { - pc0 = get_regs_PC(ctx); - } - - if (ptrace(PTRACE_GETREGS, EXT(ctx)->pid, 0, (int)EXT(ctx)->regs) < 0) { - assert(errno != 0); - if (errno == ESRCH) { - /* Racing condition: somebody resumed this context while we are handling stop event. - * - * One possible cause: main thread has exited forcing children to exit too. - * I beleive it is a bug in PTRACE implementation - PTRACE should delay exiting of - * a context while it is stopped, but it does not, which causes a nasty racing. - * - * Workaround: Ignore current event, assume context is running. - */ - ctx->stopped = 0; - return; - } - EXT(ctx)->regs_error = get_error_report(errno); - trace(LOG_ALWAYS, "error: ptrace(PTRACE_GETREGS) failed; id %s, error %d %s", - ctx->id, errno, errno_to_str(errno)); - } - else { - pc1 = get_regs_PC(ctx); - } - - trace(LOG_EVENTS, "event: pid %d stopped at PC = %#lx", pid, pc1); - - if (signal == SIGTRAP && event == 0 && !syscall) { - size_t break_size = 0; - get_break_instruction(ctx, &break_size); - ctx->stopped_by_bp = !EXT(ctx)->regs_error && is_breakpoint_address(ctx, pc1 - break_size); - EXT(ctx)->end_of_step = !ctx->stopped_by_bp && EXT(ctx)->pending_step; - if (ctx->stopped_by_bp) set_regs_PC(ctx, pc1 - break_size); - } - EXT(ctx)->pending_step = 0; - send_context_stopped_event(ctx); - } -} - -static void waitpid_listener(int pid, int exited, int exit_code, int signal, int event_code, int syscall, void * args) { - if (exited) { - event_pid_exited(pid, exit_code, signal); - } - else { - event_pid_stopped(pid, signal, event_code, syscall); - } -} - -void init_contexts_sys_dep(void) { - context_extension_offset = context_extension(sizeof(ContextExtensionBSD)); - add_waitpid_listener(waitpid_listener, NULL); - ini_context_pid_hash(); -} - -#endif /* if ENABLE_DebugContext */ -#endif /* __FreeBSD__ */ diff --git a/agent/tcf/system/FreeBSD/regset.h b/agent/tcf/system/FreeBSD/regset.h deleted file mode 100644 index add029bd..00000000 --- a/agent/tcf/system/FreeBSD/regset.h +++ /dev/null @@ -1,24 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2010 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This header file provides definition of REG_SET - a structure that can - * hold values of target CPU registers. - */ - -#if defined(__FreeBSD__) -# include <machine/reg.h> - typedef struct reg REG_SET; -#endif diff --git a/agent/tcf/system/GNU/Linux/context-linux.c b/agent/tcf/system/GNU/Linux/context-linux.c deleted file mode 100644 index b8b5b198..00000000 --- a/agent/tcf/system/GNU/Linux/context-linux.c +++ /dev/null @@ -1,1187 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This module handles process/thread OS contexts and their state machine. - */ - -#include <tcf/config.h> - -#if defined(__linux__) - -#if ENABLE_DebugContext && !ENABLE_ContextProxy - -#include <stdlib.h> -#include <assert.h> -#include <errno.h> -#include <signal.h> -#include <sched.h> -#include <dirent.h> -#include <asm/unistd.h> -#include <sys/ptrace.h> -#include <linux/kdev_t.h> -#include <tcf/framework/context.h> -#include <tcf/framework/events.h> -#include <tcf/framework/errors.h> -#include <tcf/framework/trace.h> -#include <tcf/framework/myalloc.h> -#include <tcf/framework/waitpid.h> -#include <tcf/framework/signames.h> -#include <tcf/services/breakpoints.h> -#include <tcf/services/expressions.h> -#include <tcf/services/memorymap.h> -#include <tcf/services/runctrl.h> -#include <tcf/services/tcf_elf.h> -#include <tcf/system/GNU/Linux/regset.h> - -#if !defined(PTRACE_SETOPTIONS) -#define PTRACE_SETOPTIONS 0x4200 -#define PTRACE_GETEVENTMSG 0x4201 -#define PTRACE_GETSIGINFO 0x4202 -#define PTRACE_SETSIGINFO 0x4203 - -#define PTRACE_O_TRACESYSGOOD 0x00000001 -#define PTRACE_O_TRACEFORK 0x00000002 -#define PTRACE_O_TRACEVFORK 0x00000004 -#define PTRACE_O_TRACECLONE 0x00000008 -#define PTRACE_O_TRACEEXEC 0x00000010 -#define PTRACE_O_TRACEVFORKDONE 0x00000020 -#define PTRACE_O_TRACEEXIT 0x00000040 - -#define PTRACE_EVENT_FORK 1 -#define PTRACE_EVENT_VFORK 2 -#define PTRACE_EVENT_CLONE 3 -#define PTRACE_EVENT_EXEC 4 -#define PTRACE_EVENT_VFORK_DONE 5 -#define PTRACE_EVENT_EXIT 6 -#endif - -#define USE_PTRACE_SYSCALL 0 - -static const int PTRACE_FLAGS = -#if USE_PTRACE_SYSCALL - PTRACE_O_TRACESYSGOOD | -#endif - PTRACE_O_TRACECLONE | - PTRACE_O_TRACEEXEC | - PTRACE_O_TRACEFORK | - PTRACE_O_TRACEVFORK | - PTRACE_O_TRACEVFORKDONE | - PTRACE_O_TRACEEXIT; - -typedef struct ContextExtensionLinux { - pid_t pid; - ContextAttachCallBack * attach_callback; - void * attach_data; - int attach_children; - 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; - REG_SET * regs; /* copy of context registers, updated when context stops */ - 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 */ - int pending_step; - int tkill_cnt; -} ContextExtensionLinux; - -static size_t context_extension_offset = 0; - -#define EXT(ctx) ((ContextExtensionLinux *)((char *)(ctx) + context_extension_offset)) - -#include <tcf/system/pid-hash.h> - -static LINK pending_list = TCF_LIST_INIT(pending_list); -static LINK detach_list = TCF_LIST_INIT(detach_list); - -static MemoryErrorInfo mem_err_info; - -static const char * event_name(int event) { - switch (event) { - case 0: return "none"; - case PTRACE_EVENT_FORK: return "fork"; - case PTRACE_EVENT_VFORK: return "vfork"; - case PTRACE_EVENT_CLONE: return "clone"; - case PTRACE_EVENT_EXEC: return "exec"; - case PTRACE_EVENT_VFORK_DONE: return "vfork-done"; - case PTRACE_EVENT_EXIT: return "exit"; - } - trace(LOG_ALWAYS, "event_name(): unexpected event code %d", event); - return "unknown"; -} - -const char * context_suspend_reason(Context * ctx) { - static char reason[128]; - - if (EXT(ctx)->end_of_step) return REASON_STEP; - if (EXT(ctx)->ptrace_event != 0) { - assert(ctx->signal == SIGTRAP); - snprintf(reason, sizeof(reason), "Event: %s", event_name(EXT(ctx)->ptrace_event)); - return reason; - } - if (EXT(ctx)->syscall_enter) return "System Call"; - if (EXT(ctx)->syscall_exit) return "System Return"; - if (ctx->signal == SIGSTOP || ctx->signal == SIGTRAP) return REASON_USER_REQUEST; - snprintf(reason, sizeof(reason), "Signal %d", ctx->signal); - return reason; -} - -int context_attach_self(void) { - if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { - int err = errno; - trace(LOG_ALWAYS, "error: ptrace(PTRACE_TRACEME) failed: pid %d, error %d %s", - getpid(), err, errno_to_str(err)); - errno = err; - return -1; - } - return 0; -} - -int context_attach(pid_t pid, ContextAttachCallBack * done, void * data, int mode) { - Context * ctx = NULL; - ContextExtensionLinux * ext = NULL; - - assert(done != NULL); - trace(LOG_CONTEXT, "context: attaching pid %d", pid); - if ((mode & CONTEXT_ATTACH_SELF) == 0 && ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) { - int err = errno; - trace(LOG_ALWAYS, "error: ptrace(PTRACE_ATTACH) failed: pid %d, error %d %s", - pid, err, errno_to_str(err)); - errno = err; - return -1; - } - add_waitpid_process(pid); - ctx = create_context(pid2id(pid, 0)); - ctx->mem = ctx; - ctx->mem_access |= MEM_ACCESS_INSTRUCTION; - ctx->mem_access |= MEM_ACCESS_DATA; - ctx->mem_access |= MEM_ACCESS_USER; - ctx->big_endian = big_endian_host(); - ext = EXT(ctx); - ext->pid = pid; - ext->attach_callback = done; - ext->attach_data = data; - ext->attach_children = (mode & CONTEXT_ATTACH_CHILDREN) != 0; - list_add_first(&ctx->ctxl, &pending_list); - /* TODO: context_attach works only for main task in a process */ - return 0; -} - -int context_has_state(Context * ctx) { - return ctx != NULL && ctx->parent != NULL; -} - -int context_stop(Context * ctx) { - ContextExtensionLinux * ext = EXT(ctx); - trace(LOG_CONTEXT, "context:%s suspending ctx %#lx id %s", - ctx->pending_intercept ? "" : " temporary", ctx, ctx->id); - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(!ctx->exited); - assert(!ctx->exiting); - assert(!ctx->stopped); - assert(!ext->regs_dirty); - if (ext->tkill_cnt > 4) { - /* Check for zombies */ - int ch = 0; - FILE * file = NULL; - char file_name[FILE_PATH_SIZE]; - snprintf(file_name, sizeof(file_name), "/proc/%d/stat", ext->pid); - if ((file = fopen(file_name, "r")) == NULL) return -1; - while (ch != EOF && ch != ')') ch = fgetc(file); - if (ch == EOF || fgetc(file) != ' ' || fgetc(file) == 'Z') { - /* Zombie found */ - fclose(file); - ctx->exiting = 1; - return 0; - } - fclose(file); - ext->tkill_cnt = 0; - } - if (tkill(ext->pid, SIGSTOP) < 0) { - int err = errno; - if (err == ESRCH) { - ctx->exiting = 1; - return 0; - } - trace(LOG_ALWAYS, "error: tkill(SIGSTOP) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - ext->tkill_cnt++; - return 0; -} - -static int syscall_never_returns(Context * ctx) { - if (EXT(ctx)->syscall_enter) { - switch (EXT(ctx)->syscall_id) { -#ifdef __NR_sigreturn - case __NR_sigreturn: - return 1; -#endif - } - } - return 0; -} - -int context_continue(Context * ctx) { - int signal = 0; - ContextExtensionLinux * ext = EXT(ctx); - - assert(is_dispatch_thread()); - assert(ctx->stopped); - assert(!ctx->pending_intercept); - assert(!ext->pending_step); - assert(!ctx->exited); - - if (skip_breakpoint(ctx, 0)) return 0; - - if (!ext->syscall_enter && !ext->ptrace_event) { - while (ctx->pending_signals != 0) { - while ((ctx->pending_signals & (1 << signal)) == 0) signal++; - if (ctx->sig_dont_pass & (1 << signal)) { - ctx->pending_signals &= ~(1 << signal); - signal = 0; - } - else { - break; - } - } - assert(signal != SIGSTOP); - assert(signal != SIGTRAP); - } - - trace(LOG_CONTEXT, "context: resuming ctx %#lx, id %s, with signal %d", ctx, ctx->id, signal); -#if defined(__i386__) || defined(__x86_64__) - if (ext->regs->eflags & 0x100) { - ext->regs->eflags &= ~0x100; - ext->regs_dirty = 1; - } -#endif - if (ext->regs_dirty) { - if (ptrace(PTRACE_SETREGS, ext->pid, 0, ext->regs) < 0) { - int err = errno; - if (err == ESRCH) { - ext->regs_dirty = 0; - ctx->exiting = 1; - send_context_started_event(ctx); - return 0; - } - trace(LOG_ALWAYS, "error: ptrace(PTRACE_SETREGS) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - ext->regs_dirty = 0; - } -#if USE_PTRACE_SYSCALL - if (ptrace(PTRACE_SYSCALL, ext->pid, 0, signal) < 0) { -#else - if (ptrace(PTRACE_CONT, ext->pid, 0, signal) < 0) { -#endif - int err = errno; - if (err == ESRCH) { - ctx->exiting = 1; - send_context_started_event(ctx); - return 0; - } - trace(LOG_ALWAYS, "error: ptrace(PTRACE_CONT, ...) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - ctx->pending_signals &= ~(1 << signal); - if (syscall_never_returns(ctx)) { - ext->syscall_enter = 0; - ext->syscall_exit = 0; - ext->syscall_id = 0; - } - send_context_started_event(ctx); - return 0; -} - -int context_single_step(Context * ctx) { - ContextExtensionLinux * ext = EXT(ctx); - - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(ctx->stopped); - assert(!ctx->exited); - assert(!ext->pending_step); - - if (skip_breakpoint(ctx, 1)) return 0; - - if (syscall_never_returns(ctx)) return context_continue(ctx); - trace(LOG_CONTEXT, "context: single step ctx %#lx, id %s", ctx, ctx->id); - if (ext->regs_dirty) { - if (ptrace(PTRACE_SETREGS, ext->pid, 0, ext->regs) < 0) { - int err = errno; - if (err == ESRCH) { - ext->regs_dirty = 0; - ctx->exiting = 1; - send_context_started_event(ctx); - return 0; - } - trace(LOG_ALWAYS, "error: ptrace(PTRACE_SETREGS) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - ext->regs_dirty = 0; - } - if (ptrace(PTRACE_SINGLESTEP, ext->pid, 0, 0) < 0) { - int err = errno; - if (err == ESRCH) { - ctx->exiting = 1; - send_context_started_event(ctx); - return 0; - } - trace(LOG_ALWAYS, "error: ptrace(PTRACE_SINGLESTEP, ...) failed: ctx %#lx, id %s, error %d %s", - ctx, ctx->id, err, errno_to_str(err)); - errno = err; - return -1; - } - ext->pending_step = 1; - send_context_started_event(ctx); - return 0; -} - -int context_resume(Context * ctx, int mode, ContextAddress range_start, ContextAddress range_end) { - switch (mode) { - case RM_RESUME: - return context_continue(ctx); - case RM_STEP_INTO: - return context_single_step(ctx); - case RM_TERMINATE: - ctx->pending_signals |= 1 << SIGKILL; - return context_continue(ctx); - } - errno = ERR_UNSUPPORTED; - return -1; -} - -int context_can_resume(Context * ctx, int mode) { - switch (mode) { - case RM_RESUME: - return 1; - case RM_STEP_INTO: - case RM_TERMINATE: - return context_has_state(ctx); - } - return 0; -} - -int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { - ContextAddress word_addr; - unsigned word_size = context_word_size(ctx); - ContextExtensionLinux * ext = EXT(ctx); - int error = 0; - - assert(word_size <= sizeof(unsigned long)); - assert(is_dispatch_thread()); - assert(!ctx->exited); - trace(LOG_CONTEXT, - "context: write memory ctx %#lx, id %s, address %#lx, size %zu", - ctx, ctx->id, address, size); - mem_err_info.error = 0; - if (size == 0) return 0; - if (check_breakpoints_on_memory_write(ctx, address, buf, size) < 0) return -1; - for (word_addr = address & ~((ContextAddress)word_size - 1); word_addr < address + size; word_addr += word_size) { - unsigned long word = 0; - if (word_addr < address || word_addr + word_size > address + size) { - unsigned i = 0; - errno = 0; - word = ptrace(PTRACE_PEEKDATA, ext->pid, (void *)word_addr, 0); - if (errno != 0) { - error = errno; - trace(LOG_CONTEXT, - "error: ptrace(PTRACE_PEEKDATA, ...) failed: ctx %#lx, id %s, addr %#lx, error %d %s", - ctx, ctx->id, word_addr, error, errno_to_str(error)); - break; - } - for (i = 0; i < word_size; i++) { - if (word_addr + i >= address && word_addr + i < address + size) { - ((char *)&word)[i] = ((char *)buf)[word_addr + i - address]; - } - } - } - else { - memcpy(&word, (char *)buf + (word_addr - address), word_size); - } - if (ptrace(PTRACE_POKEDATA, ext->pid, (void *)word_addr, word) < 0) { - error = errno; - trace(LOG_ALWAYS, - "error: ptrace(PTRACE_POKEDATA, ...) failed: ctx %#lx, id %s, addr %#lx, error %d %s", - ctx, ctx->id, word_addr, error, errno_to_str(error)); - break; - } - } - if (error) { -#if ENABLE_ExtendedMemoryErrorReports - size_t size_valid = 0; - size_t size_error = word_size; - if (word_addr > address) size_valid = (size_t)(word_addr - address); - /* Find number of invalid bytes */ - /* Note: cannot write memory here, read instead */ - while (size_error < 0x1000 && size_valid + size_error < size) { - errno = 0; - ptrace(PTRACE_PEEKDATA, ext->pid, (void *)(word_addr + size_error), 0); - if (errno != error) break; - size_error += word_size; - } - mem_err_info.error = error; - mem_err_info.size_valid = size_valid; - mem_err_info.size_error = size_error; -#endif - errno = error; - return -1; - } - return 0; -} - -int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { - ContextAddress word_addr; - unsigned word_size = context_word_size(ctx); - ContextExtensionLinux * ext = EXT(ctx); - size_t size_valid = 0; - int error = 0; - - assert(word_size <= sizeof(unsigned long)); - assert(is_dispatch_thread()); - assert(!ctx->exited); - trace(LOG_CONTEXT, - "context: read memory ctx %#lx, id %s, address %#lx, size %zu", - ctx, ctx->id, address, size); - mem_err_info.error = 0; - if (size == 0) return 0; - for (word_addr = address & ~((ContextAddress)word_size - 1); word_addr < address + size; word_addr += word_size) { - unsigned long word = 0; - errno = 0; - word = ptrace(PTRACE_PEEKDATA, ext->pid, (void *)word_addr, 0); - if (errno != 0) { - error = errno; - trace(LOG_CONTEXT, - "error: ptrace(PTRACE_PEEKDATA, ...) failed: ctx %#lx, id %s, addr %#lx, error %d %s", - ctx, ctx->id, word_addr, error, errno_to_str(error)); - break; - } - if (word_addr < address || word_addr + word_size > address + size) { - unsigned i = 0; - for (i = 0; i < word_size; i++) { - if (word_addr + i >= address && word_addr + i < address + size) { - ((char *)buf)[word_addr + i - address] = ((char *)&word)[i]; - } - } - } - else { - memcpy((char *)buf + (word_addr - address), &word, word_size); - } - } - if (word_addr > address) size_valid = (size_t)(word_addr - address); - if (size_valid > size) size_valid = size; - if (check_breakpoints_on_memory_read(ctx, address, buf, size_valid) < 0) return -1; - if (error) { -#if ENABLE_ExtendedMemoryErrorReports - size_t size_error = word_size; - /* Find number of unreadable bytes */ - while (size_error < 0x1000 && size_valid + size_error < size) { - errno = 0; - ptrace(PTRACE_PEEKDATA, ext->pid, (void *)(word_addr + size_error), 0); - if (errno != error) break; - size_error += word_size; - } - mem_err_info.error = error; - mem_err_info.size_valid = size_valid; - mem_err_info.size_error = size_error; -#endif - errno = error; - return -1; - } - return 0; -} - -#if ENABLE_ExtendedMemoryErrorReports -int context_get_mem_error_info(MemoryErrorInfo * info) { - if (mem_err_info.error == 0) { - set_errno(ERR_OTHER, "Extended memory error info not available"); - return -1; - } - *info = mem_err_info; - return 0; -} -#endif - -int context_write_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) { - ContextExtensionLinux * ext = EXT(ctx); - - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(ctx->stopped); - assert(!ctx->exited); - assert(offs + size <= def->size); - - if (ext->regs_error) { - set_error_report_errno(ext->regs_error); - return -1; - } - memcpy((uint8_t *)ext->regs + def->offset + offs, buf, size); - ext->regs_dirty = 1; - return 0; -} - -int context_read_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) { - ContextExtensionLinux * ext = EXT(ctx); - - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(ctx->stopped); - assert(!ctx->exited); - assert(offs + size <= def->size); - - if (ext->regs_error) { - set_error_report_errno(ext->regs_error); - return -1; - } - memcpy(buf, (uint8_t *)ext->regs + def->offset + offs, size); - return 0; -} - -unsigned context_word_size(Context * ctx) { - return sizeof(void *); -} - -int context_get_canonical_addr(Context * ctx, ContextAddress addr, - Context ** canonical_ctx, ContextAddress * canonical_addr, - ContextAddress * block_addr, ContextAddress * block_size) { - /* Direct mapping, page size is irrelevant */ - ContextAddress page_size = 0x100000; - assert(is_dispatch_thread()); - *canonical_ctx = ctx->mem; - if (canonical_addr != NULL) *canonical_addr = addr; - if (block_addr != NULL) *block_addr = addr & ~(page_size - 1); - if (block_size != NULL) *block_size = page_size; - return 0; -} - -Context * context_get_group(Context * ctx, int group) { - static Context * cpu_group = NULL; - switch (group) { - case CONTEXT_GROUP_INTERCEPT: - return ctx; - case CONTEXT_GROUP_CPU: - if (cpu_group == NULL) cpu_group = create_context("CPU"); - return cpu_group; - } - return ctx->mem; -} - -int context_get_supported_bp_access_types(Context * ctx) { - return 0; -} - -int context_plant_breakpoint(ContextBreakpoint * bp) { - errno = ERR_UNSUPPORTED; - return -1; -} - -int context_unplant_breakpoint(ContextBreakpoint * bp) { - errno = ERR_UNSUPPORTED; - return -1; -} - -int context_get_memory_map(Context * ctx, MemoryMap * map) { - char maps_file_name[FILE_PATH_SIZE]; - FILE * file = NULL; - - ctx = ctx->mem; - assert(!ctx->exited); - assert(map->region_cnt == 0); - - snprintf(maps_file_name, sizeof(maps_file_name), "/proc/%d/maps", EXT(ctx)->pid); - if ((file = fopen(maps_file_name, "r")) == NULL) return -1; - for (;;) { - MemoryRegion * prev = NULL; - unsigned long addr0 = 0; - unsigned long addr1 = 0; - unsigned long offset = 0; - unsigned long dev_ma = 0; - unsigned long dev_mi = 0; - unsigned long inode = 0; - char permissions[16]; - char file_name[FILE_PATH_SIZE]; - unsigned i = 0; - int flags = 0; - - int cnt = fscanf(file, "%lx-%lx %s %lx %lx:%lx %ld", - &addr0, &addr1, permissions, &offset, &dev_ma, &dev_mi, &inode); - if (cnt == 0 || cnt == EOF) break; - - for (;;) { - int ch = fgetc(file); - if (ch == '\n' || ch == EOF) break; - if (i < FILE_PATH_SIZE - 1 && (ch != ' ' || i > 0)) { - file_name[i++] = ch; - } - } - file_name[i++] = 0; - - if (map->region_cnt >= map->region_max) { - map->region_max = map->region_max < 8 ? 8 : map->region_max * 2; - map->regions = (MemoryRegion *)loc_realloc(map->regions, sizeof(MemoryRegion) * map->region_max); - } - - for (i = 0; permissions[i]; i++) { - switch (permissions[i]) { - case 'r': flags |= MM_FLAG_R; break; - case 'w': flags |= MM_FLAG_W; break; - case 'x': flags |= MM_FLAG_X; break; - } - } - - if (map->region_cnt > 0) prev = map->regions + (map->region_cnt - 1); - - if (inode != 0 && file_name[0] && file_name[0] != '[') { - MemoryRegion * r = map->regions + map->region_cnt++; - memset(r, 0, sizeof(MemoryRegion)); - r->addr = addr0; - r->size = addr1 - addr0; - r->flags = flags; - r->file_offs = offset; - r->dev = MKDEV(dev_ma, dev_mi); - r->ino = (ino_t)inode; - r->file_name = loc_strdup(file_name); - } - else if (file_name[0] == 0 && prev != NULL && prev->addr + prev->size == addr0) { - MemoryRegion * r = map->regions + map->region_cnt++; - memset(r, 0, sizeof(MemoryRegion)); - r->bss = 1; - r->addr = addr0; - r->size = addr1 - addr0; - r->flags = flags; - r->file_offs = prev->file_offs + prev->size; - r->dev = prev->dev; - r->ino = prev->ino; - r->file_name = loc_strdup(prev->file_name); - } - } - fclose(file); - return 0; -} - -static Context * find_pending(pid_t pid) { - LINK * l = pending_list.next; - while (l != &pending_list) { - Context * c = ctxl2ctxp(l); - if (EXT(c)->pid == pid) { - list_remove(&c->ctxl); - return c; - } - l = l->next; - } - return NULL; -} - -static void event_pid_exited(pid_t pid, int status, int signal) { - Context * ctx; - - ctx = context_find_from_pid(pid, 1); - if (ctx == NULL) { - ctx = find_pending(pid); - if (ctx == NULL) { - trace(LOG_EVENTS, "event: ctx not found, pid %d, exit status %d, term signal %d", pid, status, signal); - } - else { - assert(ctx->ref_count == 0); - if (EXT(ctx)->attach_callback != NULL) { - if (status == 0) status = EINVAL; - EXT(ctx)->attach_callback(status, ctx, EXT(ctx)->attach_data); - } - assert(list_is_empty(&ctx->children)); - assert(ctx->parent == NULL); - ctx->exited = 1; - ctx->ref_count = 1; - context_unlock(ctx); - } - } - else { - /* Note: ctx->exiting should be 1 here. However, PTRACE_EVENT_EXIT can be lost by PTRACE because of racing - * between PTRACE_CONT (or PTRACE_SYSCALL) and SIGTRAP/PTRACE_EVENT_EXIT. So, ctx->exiting can be 0. - */ - if (EXT(ctx->parent)->pid == pid) ctx = ctx->parent; - trace(LOG_EVENTS, "event: ctx %#lx, pid %d, exit status %d, term signal %d", ctx, pid, status, signal); - assert(EXT(ctx)->attach_callback == NULL); - assert(!ctx->exited); - ctx->exiting = 1; - if (ctx->stopped) send_context_started_event(ctx); - if (!list_is_empty(&ctx->children)) { - LINK * l = ctx->children.next; - while (l != &ctx->children) { - Context * c = cldl2ctxp(l); - l = l->next; - assert(c->parent == ctx); - if (!c->exited) { - c->exiting = 1; - if (c->stopped) send_context_started_event(c); - release_error_report(EXT(c)->regs_error); - loc_free(EXT(c)->regs); - EXT(c)->regs_error = NULL; - EXT(c)->regs = NULL; - send_context_exited_event(c); - } - } - } - release_error_report(EXT(ctx)->regs_error); - loc_free(EXT(ctx)->regs); - EXT(ctx)->regs_error = NULL; - EXT(ctx)->regs = NULL; - send_context_exited_event(ctx); - } - assert(context_find_from_pid(pid, 1) == NULL); - assert(context_find_from_pid(pid, 0) == NULL); -} - -#if !USE_PTRACE_SYSCALL -# define get_syscall_id(ctx) 0 -#elif defined(__x86_64__) -# define get_syscall_id(ctx) (EXT(ctx)->regs->orig_rax) -#elif defined(__i386__) -# define get_syscall_id(ctx) (EXT(ctx)->regs->orig_eax) -#else -# error "get_syscall_id() is not implemented for CPU other then X86" -#endif - -static unsigned long get_child_pid(pid_t parent_pid) { - unsigned long child_pid = 0; - DIR * dir = NULL; - char task_file_name[FILE_PATH_SIZE]; - snprintf(task_file_name, sizeof(task_file_name), "/proc/%d/task", parent_pid); - dir = opendir(task_file_name); - if (dir == NULL) { - trace(LOG_ALWAYS, "error: opendir(%s) failed; error %d %s", - task_file_name, errno, errno_to_str(errno)); - } - else { - struct dirent * e; - for (;;) { - int n = 0; - e = readdir(dir); - if (e == NULL) break; - n = atoi(e->d_name); - if (n != 0 && context_find_from_pid(n, 1) == NULL) { - child_pid = n; - break; - } - } - closedir(dir); - } - return child_pid; -} - -static void event_pid_stopped(pid_t pid, int signal, int event, int syscall) { - int stopped_by_exception = 0; - unsigned long msg = 0; - Context * ctx = NULL; - ContextExtensionLinux * ext = NULL; - - trace(LOG_EVENTS, "event: pid %d stopped, signal %d, event %s", pid, signal, event_name(event)); - - ctx = context_find_from_pid(pid, 1); - - if (ctx == NULL) { - ctx = find_pending(pid); - if (ctx != NULL) { - Context * prs = ctx; - assert(prs->ref_count == 0); - ctx = create_context(pid2id(pid, pid)); - EXT(ctx)->pid = pid; - EXT(ctx)->regs = (REG_SET *)loc_alloc(sizeof(REG_SET)); - ctx->pending_intercept = 1; - ctx->mem = prs; - ctx->big_endian = prs->big_endian; - EXT(ctx)->attach_children = EXT(prs)->attach_children; - (ctx->parent = prs)->ref_count++; - list_add_last(&ctx->cldl, &prs->children); - link_context(prs); - link_context(ctx); - send_context_created_event(prs); - send_context_created_event(ctx); - 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; - } - } - } - - if (ctx == NULL) { - ctx = context_find_from_pid(pid, 0); - if (ctx != NULL) { - /* Fork child that we don't want to attach */ - unplant_breakpoints(ctx); - assert(ctx->ref_count == 1); - ctx->exited = 1; - if (ptrace((enum __ptrace_request)PTRACE_DETACH, pid, 0, 0) < 0) { - trace(LOG_ALWAYS, "error: ptrace(PTRACE_DETACH) failed: pid %d, error %d %s", - pid, errno, errno_to_str(errno)); - } - list_remove(ctx2pidlink(ctx)); - context_unlock(ctx); - } - detach_waitpid_process(); - return; - } - - ext = EXT(ctx); - assert(!ctx->exited); - assert(!ext->attach_callback); - ext->tkill_cnt = 0; - if (ext->ptrace_flags == 0) { - if (ptrace((enum __ptrace_request)PTRACE_SETOPTIONS, ext->pid, 0, PTRACE_FLAGS) < 0 && errno != ESRCH) { - int err = errno; - trace(LOG_ALWAYS, "error: ptrace(PTRACE_SETOPTIONS) failed: pid %d, error %d %s", - ext->pid, err, errno_to_str(err)); - } - else { - ext->ptrace_flags = PTRACE_FLAGS; - } - } - - switch (event) { - case PTRACE_EVENT_FORK: - case PTRACE_EVENT_VFORK: - case PTRACE_EVENT_CLONE: - if (ptrace((enum __ptrace_request)PTRACE_GETEVENTMSG, pid, 0, &msg) < 0) { - if (errno == ESRCH) { - msg = SIGKILL; - } - else { - trace(LOG_ALWAYS, "error: ptrace(PTRACE_GETEVENTMSG) failed; pid %d, error %d %s", - pid, errno, errno_to_str(errno)); - break; - } - } - { - Context * prs2 = NULL; - Context * ctx2 = NULL; - /* Check the thread is not killed already by SIGKILL */ - if (msg == SIGKILL) { - unsigned long child_pid = get_child_pid(EXT(ctx->parent)->pid); - if (child_pid) { - msg = child_pid; - } - else { - trace(LOG_ALWAYS, "cannot trace %s - aborted by SIGKILL", event_name(event)); - break; - } - } - assert(msg != 0); - add_waitpid_process(msg); - if (event == PTRACE_EVENT_CLONE) { - /* TODO: using the PTRACE_EVENT_CLONE to determine if the new context is a thread is not correct. - * The only way I know of is to look at the Tgid field of /proc/<pid>/status */ - prs2 = ctx->parent; - } - else { - prs2 = create_context(pid2id(msg, 0)); - EXT(prs2)->pid = msg; - EXT(prs2)->attach_children = ext->attach_children; - prs2->mem = prs2; - prs2->mem_access |= MEM_ACCESS_INSTRUCTION; - prs2->mem_access |= MEM_ACCESS_DATA; - prs2->mem_access |= MEM_ACCESS_USER; - prs2->big_endian = ctx->parent->big_endian; - (prs2->creator = ctx)->ref_count++; - prs2->sig_dont_stop = ctx->sig_dont_stop; - prs2->sig_dont_pass = ctx->sig_dont_pass; - link_context(prs2); - clone_breakpoints_on_process_fork(ctx, prs2); - if (!ext->attach_children) { - list_remove(&prs2->ctxl); - list_add_first(&prs2->ctxl, &detach_list); - break; - } - send_context_created_event(prs2); - } - - ctx2 = create_context(pid2id(msg, EXT(prs2)->pid)); - EXT(ctx2)->pid = msg; - EXT(ctx2)->attach_children = EXT(prs2)->attach_children; - EXT(ctx2)->regs = (REG_SET *)loc_alloc(sizeof(REG_SET)); - ctx2->mem = prs2; - ctx2->big_endian = prs2->big_endian; - ctx2->sig_dont_stop = ctx->sig_dont_stop; - ctx2->sig_dont_pass = ctx->sig_dont_pass; - (ctx2->creator = ctx)->ref_count++; - (ctx2->parent = prs2)->ref_count++; - list_add_last(&ctx2->cldl, &prs2->children); - link_context(ctx2); - trace(LOG_EVENTS, "event: new context 0x%x, id %s", ctx2, ctx2->id); - send_context_created_event(ctx2); - } - break; - case PTRACE_EVENT_EXEC: - send_context_changed_event(ctx); - memory_map_event_mapping_changed(ctx->mem); - break; - case PTRACE_EVENT_EXIT: - { - /* SIGKILL can override PTRACE_EVENT_CLONE event with PTRACE_EVENT_EXIT */ - unsigned long child_pid = get_child_pid(EXT(ctx->parent)->pid); - if (child_pid) { - Context * prs = ctx->parent; - Context * ctx2 = create_context(pid2id(child_pid, EXT(prs)->pid)); - EXT(ctx2)->pid = child_pid; - EXT(ctx2)->attach_children = EXT(prs)->attach_children; - EXT(ctx2)->regs = (REG_SET *)loc_alloc(sizeof(REG_SET)); - ctx2->mem = prs; - ctx2->big_endian = prs->big_endian; - ctx2->sig_dont_stop = ctx->sig_dont_stop; - ctx2->sig_dont_pass = ctx->sig_dont_pass; - ctx2->exiting = 1; - (ctx2->creator = ctx)->ref_count++; - (ctx2->parent = prs)->ref_count++; - list_add_last(&ctx2->cldl, &prs->children); - link_context(ctx2); - trace(LOG_EVENTS, "event: new context 0x%x, id %s", ctx2, ctx2->id); - send_context_created_event(ctx2); - event_pid_stopped(child_pid, SIGTRAP, 0, 0); - add_waitpid_process(child_pid); - } - } - ctx->exiting = 1; - ext->regs_dirty = 0; - break; - } - - if (signal != SIGSTOP && signal != SIGTRAP) { - assert(signal < 32); - ctx->pending_signals |= 1 << signal; - if ((ctx->sig_dont_stop & (1 << signal)) == 0) { - ctx->pending_intercept = 1; - stopped_by_exception = 1; - } - } - - if (ctx->stopped) { - if (event != PTRACE_EVENT_EXEC) send_context_changed_event(ctx); - } - else { - ContextAddress pc0 = 0; - ContextAddress pc1 = 0; - - assert(!ext->regs_dirty); - - ext->end_of_step = 0; - ext->ptrace_event = event; - ctx->signal = signal; - ctx->stopped_by_bp = 0; - ctx->stopped_by_exception = stopped_by_exception; - ctx->stopped = 1; - - if (ext->regs_error) { - release_error_report(ext->regs_error); - ext->regs_error = NULL; - } - else { - pc0 = get_regs_PC(ctx); - } - - if (ptrace(PTRACE_GETREGS, ext->pid, 0, ext->regs) < 0) { - assert(errno != 0); - if (errno == ESRCH) { - ctx->stopped = 0; - ctx->exiting = 1; - return; - } - ext->regs_error = get_error_report(errno); - trace(LOG_ALWAYS, "error: ptrace(PTRACE_GETREGS) failed; pid %d, error %d %s", - ext->pid, errno, errno_to_str(errno)); - } - else { - pc1 = get_regs_PC(ctx); - } - - if (syscall && !ext->regs_error) { - if (!ext->syscall_enter) { - ext->syscall_id = get_syscall_id(ctx); - ext->syscall_pc = pc1; - ext->syscall_enter = 1; - ext->syscall_exit = 0; - trace(LOG_EVENTS, "event: pid %d enter sys call %d, PC = %#lx", - pid, ext->syscall_id, ext->syscall_pc); - } - else { - if (ext->syscall_pc != pc1) { - trace(LOG_ALWAYS, "Invalid PC at sys call exit: pid %d, sys call %d, PC %#lx, expected PC %#lx", - ext->pid, ext->syscall_id, pc1, ext->syscall_pc); - } - trace(LOG_EVENTS, "event: pid %d exit sys call %d, PC = %#lx", - pid, ext->syscall_id, pc1); - switch (ext->syscall_id) { - case __NR_mmap: - case __NR_munmap: -#ifdef __NR_mmap2 - case __NR_mmap2: -#endif - case __NR_mremap: - case __NR_remap_file_pages: - memory_map_event_mapping_changed(ctx->mem); - break; - } - ext->syscall_enter = 0; - ext->syscall_exit = 1; - } - } - else { - if (!ext->syscall_enter || ext->regs_error || pc0 != pc1) { - ext->syscall_enter = 0; - ext->syscall_exit = 0; - ext->syscall_id = 0; - ext->syscall_pc = 0; - } - trace(LOG_EVENTS, "event: pid %d stopped at PC = %#lx", pid, pc1); - } - - if (signal == SIGTRAP && event == 0 && !syscall) { - size_t break_size = 0; - get_break_instruction(ctx, &break_size); - ctx->stopped_by_bp = !ext->regs_error && is_breakpoint_address(ctx, pc1 - break_size); - ext->end_of_step = !ctx->stopped_by_bp && ext->pending_step; - if (ctx->stopped_by_bp) set_regs_PC(ctx, pc1 - break_size); - } - ext->pending_step = 0; - send_context_stopped_event(ctx); - } -} - -static void waitpid_listener(int pid, int exited, int exit_code, int signal, int event_code, int syscall, void * args) { - if (exited) { - event_pid_exited(pid, exit_code, signal); - } - else { - event_pid_stopped(pid, signal, event_code, syscall); - } -} - -#if SERVICE_Expressions && ENABLE_ELF - -static int expression_identifier_callback(Context * ctx, int frame, char * name, Value * v) { - if (ctx == NULL) return 0; - if (strcmp(name, "$loader_brk") == 0) { - v->address = elf_get_debug_structure_address(ctx, NULL); - v->type_class = TYPE_CLASS_POINTER; - v->size = context_word_size(ctx); - if (v->address != 0) { - v->big_endian = ctx->big_endian; - switch (v->size) { - case 4: v->address += 8; break; - case 8: v->address += 16; break; - default: assert(0); - } - v->remote = 1; - } - else { - set_value(v, NULL, v->size, 0); - } - return 1; - } - if (strcmp(name, "$loader_state") == 0) { - v->address = elf_get_debug_structure_address(ctx, NULL); - v->type_class = TYPE_CLASS_CARDINAL; - v->size = context_word_size(ctx); - if (v->address != 0) { - switch (v->size) { - case 4: v->address += 12; break; - case 8: v->address += 24; break; - default: assert(0); - } - } - v->remote = 1; - return 1; - } - return 0; -} - -static void eventpoint_at_loader(Context * ctx, void * args) { - typedef enum { RT_CONSISTENT, RT_ADD, RT_DELETE } r_state; - ELF_File * file = NULL; - ContextAddress addr = elf_get_debug_structure_address(ctx, &file); - unsigned size = context_word_size(ctx); - ContextAddress state = 0; - ContextExtensionLinux * ext = NULL; - - - if (ctx->parent != NULL) ctx = ctx->parent; - ext = EXT(ctx); - - if (addr != 0) { - switch (size) { - case 4: addr += 12; break; - case 8: addr += 24; break; - default: assert(0); - } - if (elf_read_memory_word(ctx, file, addr, &state) < 0) { - int error = errno; - trace(LOG_ALWAYS, "Can't read loader state flag: %d %s", error, errno_to_str(error)); - ctx->pending_intercept = 1; - ext->loader_state = 0; - return; - } - } - - switch (state) { - case RT_CONSISTENT: - if (ext->loader_state == RT_ADD) { - memory_map_event_module_loaded(ctx); - } - else if (ext->loader_state == RT_DELETE) { - memory_map_event_module_unloaded(ctx); - } - break; - case RT_ADD: - break; - case RT_DELETE: - /* TODO: need to call memory_map_event_code_section_ummapped() */ - break; - } - ext->loader_state = state; -} - -#endif /* SERVICE_Expressions && ENABLE_ELF */ - -static void eventpoint_at_main(Context * ctx, void * args) { - send_context_changed_event(ctx->mem); - memory_map_event_mapping_changed(ctx->mem); - suspend_debug_context(ctx); -} - -void init_contexts_sys_dep(void) { - context_extension_offset = context_extension(sizeof(ContextExtensionLinux)); - add_waitpid_listener(waitpid_listener, NULL); - ini_context_pid_hash(); -#if SERVICE_Expressions && ENABLE_ELF - add_identifier_callback(expression_identifier_callback); - create_eventpoint("$loader_brk", NULL, eventpoint_at_loader, NULL); -#endif /* SERVICE_Expressions && ENABLE_ELF */ - create_eventpoint("main", NULL, eventpoint_at_main, NULL); -} - -#endif /* if ENABLE_DebugContext */ -#endif /* __linux__ */ diff --git a/agent/tcf/system/GNU/Linux/regset.h b/agent/tcf/system/GNU/Linux/regset.h deleted file mode 100644 index 9c6474e3..00000000 --- a/agent/tcf/system/GNU/Linux/regset.h +++ /dev/null @@ -1,24 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2010 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This header file provides definition of REG_SET - a structure that can - * hold values of target CPU registers. - */ - -#if defined(__linux__) -# include <sys/user.h> - typedef struct user_regs_struct REG_SET; -#endif diff --git a/agent/tcf/system/MinGW/regset.h b/agent/tcf/system/MinGW/regset.h deleted file mode 100644 index fb4eab83..00000000 --- a/agent/tcf/system/MinGW/regset.h +++ /dev/null @@ -1,23 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2010 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This header file provides definition of REG_SET - a structure that can - * hold values of target CPU registers. - */ - -#if defined(WIN32) - typedef CONTEXT REG_SET; -#endif diff --git a/agent/tcf/system/Msys/regset.h b/agent/tcf/system/Msys/regset.h deleted file mode 100644 index fb4eab83..00000000 --- a/agent/tcf/system/Msys/regset.h +++ /dev/null @@ -1,23 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2010 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This header file provides definition of REG_SET - a structure that can - * hold values of target CPU registers. - */ - -#if defined(WIN32) - typedef CONTEXT REG_SET; -#endif diff --git a/agent/tcf/system/VxWorks/context-vxworks.c b/agent/tcf/system/VxWorks/context-vxworks.c deleted file mode 100644 index 18fb927d..00000000 --- a/agent/tcf/system/VxWorks/context-vxworks.c +++ /dev/null @@ -1,782 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This module handles process/thread OS contexts and their state machine. - */ - -#include <tcf/config.h> - -#if defined(_WRS_KERNEL) - -#if ENABLE_DebugContext && !ENABLE_ContextProxy - -#include <stdlib.h> -#include <assert.h> -#include <errno.h> -#include <signal.h> -#include <tcf/framework/mdep-threads.h> -#include <tcf/framework/events.h> -#include <tcf/framework/errors.h> -#include <tcf/framework/trace.h> -#include <tcf/framework/myalloc.h> -#include <tcf/framework/waitpid.h> -#include <tcf/framework/signames.h> -#include <tcf/services/breakpoints.h> -#include <tcf/services/memorymap.h> -#include <tcf/system/VxWorks/context-vxworks.h> - -/* TODO: VxWorks RTP support */ - -#include <moduleLib.h> -#include <taskHookLib.h> -#include <spinLockLib.h> -#include <private/vxdbgLibP.h> - -#define TRACE_EVENT_STEP 2 - -typedef struct ContextExtensionVxWorks { - pid_t pid; - VXDBG_BP_INFO bp_info; /* breakpoint information */ - pid_t bp_pid; /* process or thread that hit breakpoint */ - int event; - REG_SET * regs; /* copy of context registers, updated when context stops */ - 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 */ -} ContextExtensionVxWorks; - -static size_t context_extension_offset = 0; - -#define EXT(ctx) ((ContextExtensionVxWorks *)((char *)(ctx) + context_extension_offset)) - -#include <tcf/system/pid-hash.h> - -#define EVENT_HOOK_BREAKPOINT 2 -#define EVENT_HOOK_STEP_DONE 3 -#define EVENT_HOOK_STOP 4 -#define EVENT_HOOK_TASK_ADD 5 - -struct event_info { - int event; - VXDBG_CTX current_ctx; /* context that hit breakpoint */ - VXDBG_CTX stopped_ctx; /* context stopped by the breakpoint */ - REG_SET regs; /* task registers before exception */ - UINT32 addr; /* breakpoint addr */ - int bp_info_ok; /* breakpoint information available */ - VXDBG_BP_INFO bp_info; /* breakpoint information */ -}; - -static VXDBG_CLNT_ID vxdbg_clnt_id = 0; - -#define MAX_EVENTS 64 -static struct event_info events[MAX_EVENTS]; -static int events_cnt = 0; -static int events_inp = 0; -static int events_out = 0; -static int events_buf_overflow = 0; -static spinlockIsr_t events_lock; -static VX_COUNTING_SEMAPHORE(events_signal_mem); -static SEM_ID events_signal; -static pthread_t events_thread; -static Context * parent_ctx = NULL; -static MemoryErrorInfo mem_err_info; - -const char * context_suspend_reason(Context * ctx) { - if (EXT(ctx)->event == TRACE_EVENT_STEP) return REASON_STEP; - return REASON_USER_REQUEST; -} - -static struct event_info * event_info_alloc(int event) { - int nxt; - struct event_info * info; - SPIN_LOCK_ISR_TAKE(&events_lock); - if (events_buf_overflow) { - SPIN_LOCK_ISR_GIVE(&events_lock); - return NULL; - } - info = events + events_inp; - nxt = (events_inp + 1) % MAX_EVENTS; - if (nxt == events_out) { - events_buf_overflow = 1; - semGive(events_signal); - SPIN_LOCK_ISR_GIVE(&events_lock); - return NULL; - } - memset(info, 0, sizeof(struct event_info)); - info->event = event; - events_inp = nxt; - events_cnt++; - return info; -} - -static void event_info_post(struct event_info * info) { - assert(info != NULL); - semGive(events_signal); - SPIN_LOCK_ISR_GIVE(&events_lock); -} - -typedef struct AttachDoneArgs { - pid_t pid; - ContextAttachCallBack * done; - void * data; -} AttachDoneArgs; - -static void event_attach_done(void * x) { - AttachDoneArgs * args = (AttachDoneArgs *)x; - if (context_find_from_pid(args->pid, 0) != NULL) { - args->done(ERR_ALREADY_ATTACHED, NULL, args->data); - } - else { - Context * ctx = NULL; - if (parent_ctx == NULL) { - pid_t pid = taskIdSelf(); - parent_ctx = create_context(pid2id(pid, 0)); - EXT(parent_ctx)->pid = pid; - parent_ctx->mem = parent_ctx; - parent_ctx->mem_access |= MEM_ACCESS_INSTRUCTION; - parent_ctx->mem_access |= MEM_ACCESS_DATA; - parent_ctx->big_endian = big_endian_host(); - link_context(parent_ctx); - send_context_created_event(parent_ctx); - } - assert(parent_ctx->ref_count > 0); - ctx = create_context(pid2id(args->pid, EXT(parent_ctx)->pid)); - EXT(ctx)->pid = args->pid; - EXT(ctx)->regs = (REG_SET *)loc_alloc(sizeof(REG_SET)); - ctx->mem = parent_ctx; - ctx->big_endian = parent_ctx->big_endian; - (ctx->parent = parent_ctx)->ref_count++; - list_add_last(&ctx->cldl, &parent_ctx->children); - link_context(ctx); - trace(LOG_CONTEXT, "context: attached: ctx %#lx, id %#x", ctx, EXT(ctx)->pid); - send_context_created_event(ctx); - args->done(0, ctx, args->data); - if (taskIsStopped(args->pid)) { - struct event_info * info; - ctx->pending_intercept = 1; - info = event_info_alloc(EVENT_HOOK_STOP); - if (info != NULL) { - info->stopped_ctx.ctxId = args->pid; - event_info_post(info); - } - } - } - loc_free(x); -} - -int context_attach(pid_t pid, ContextAttachCallBack * done, void * data, int mode) { - AttachDoneArgs * args = (AttachDoneArgs *)loc_alloc(sizeof(AttachDoneArgs)); - - assert(done != NULL); - assert((mode & CONTEXT_ATTACH_SELF) == 0); - args->pid = pid; - args->done = done; - args->data = data; - post_event(event_attach_done, args); - - return 0; -} - -int context_has_state(Context * ctx) { - return ctx != NULL && ctx->parent != NULL; -} - -int context_stop(Context * ctx) { - ContextExtensionVxWorks * ext = EXT(ctx); - struct event_info * info; - VXDBG_CTX vxdbg_ctx; - - assert(is_dispatch_thread()); - assert(ctx->parent != NULL); - assert(!ctx->stopped); - assert(!ctx->exited); - assert(!ext->regs_dirty); - if (ctx->pending_intercept) { - trace(LOG_CONTEXT, "context: stop ctx %#lx, id %#x", ctx, ext->pid); - } - else { - trace(LOG_CONTEXT, "context: temporary stop ctx %#lx, id %#x", ctx, ext->pid); - } - - taskLock(); - if (taskIsStopped(ext->pid)) { - /* Workaround for situation when a task was stopped without notifying TCF agent */ - int n = 0; - SPIN_LOCK_ISR_TAKE(&events_lock); - n = events_cnt; - SPIN_LOCK_ISR_GIVE(&events_lock); - if (n > 0) { - trace(LOG_CONTEXT, "context: already stopped ctx %#lx, id %#x", ctx, ext->pid); - taskUnlock(); - return 0; - } - } - else { - vxdbg_ctx.ctxId = ext->pid; - vxdbg_ctx.ctxType = VXDBG_CTX_TASK; - if (vxdbgStop(vxdbg_clnt_id, &vxdbg_ctx) != OK) { - int error = errno; - taskUnlock(); - if (error == S_vxdbgLib_INVALID_CTX) return 0; - trace(LOG_ALWAYS, "context: can't stop ctx %#lx, id %#x: %s", - ctx, ext->pid, errno_to_str(error)); - return -1; - } - } - assert(taskIsStopped(ext->pid)); - info = event_info_alloc(EVENT_HOOK_STOP); - if (info != NULL) { - info->stopped_ctx.ctxId = ext->pid; - event_info_post(info); - } - taskUnlock(); - return 0; -} - -static int kill_context(Context * ctx) { - ContextExtensionVxWorks * ext = EXT(ctx); - - assert(ctx->stopped); - assert(ctx->parent != NULL); - - if (taskDelete(ext->pid) != OK) { - int error = errno; - trace(LOG_ALWAYS, "context: can't kill ctx %#lx, id %#x: %s", - ctx, ext->pid, errno_to_str(error)); - return -1; - } - send_context_started_event(ctx); - trace(LOG_CONTEXT, "context: killed ctx %#lx, id %#x", ctx, ext->pid); - release_error_report(ext->regs_error); - loc_free(ext->regs); - ext->regs_error = NULL; - ext->regs = NULL; - send_context_exited_event(ctx); - return 0; -} - -int context_continue(Context * ctx) { - ContextExtensionVxWorks * ext = EXT(ctx); - VXDBG_CTX vxdbg_ctx; - - assert(is_dispatch_thread()); - assert(ctx->parent != NULL); - assert(ctx->stopped); - assert(!ctx->pending_intercept); - assert(!ctx->exited); - assert(taskIsStopped(ext->pid)); - - trace(LOG_CONTEXT, "context: continue ctx %#lx, id %#x", ctx, ext->pid); - - if (ext->regs_dirty) { - if (taskRegsSet(ext->pid, ext->regs) != OK) { - int error = errno; - trace(LOG_ALWAYS, "context: can't set regs ctx %#lx, id %#x: %s", - ctx, ext->pid, errno_to_str(error)); - return -1; - } - ext->regs_dirty = 0; - } - - vxdbg_ctx.ctxId = ext->pid; - vxdbg_ctx.ctxType = VXDBG_CTX_TASK; - taskLock(); - if (vxdbgCont(vxdbg_clnt_id, &vxdbg_ctx) != OK) { - int error = errno; - taskUnlock(); - trace(LOG_ALWAYS, "context: can't continue ctx %#lx, id %#x: %s", - ctx, ext->pid, errno_to_str(error)); - return -1; - } - assert(!taskIsStopped(ext->pid)); - taskUnlock(); - send_context_started_event(ctx); - return 0; -} - -int context_single_step(Context * ctx) { - ContextExtensionVxWorks * ext = EXT(ctx); - VXDBG_CTX vxdbg_ctx; - - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(ctx->parent != NULL); - assert(ctx->stopped); - assert(!ctx->exited); - assert(taskIsStopped(ext->pid)); - - trace(LOG_CONTEXT, "context: single step ctx %#lx, id %#x", ctx, ext->pid); - - if (ext->regs_dirty) { - if (taskRegsSet(ext->pid, ext->regs) != OK) { - int error = errno; - trace(LOG_ALWAYS, "context: can't set regs ctx %#lx, id %#x: %s", - ctx, ext->pid, errno_to_str(error)); - return -1; - } - ext->regs_dirty = 0; - } - - vxdbg_ctx.ctxId = ext->pid; - vxdbg_ctx.ctxType = VXDBG_CTX_TASK; - taskLock(); - if (vxdbgStep(vxdbg_clnt_id, &vxdbg_ctx, NULL, NULL) != OK) { - int error = errno; - taskUnlock(); - trace(LOG_ALWAYS, "context: can't step ctx %#lx, id %#x: %d", - ctx, ext->pid, errno_to_str(error)); - return -1; - } - taskUnlock(); - send_context_started_event(ctx); - return 0; -} - -static int context_terminate(Context * ctx) { - ContextExtensionVxWorks * ext = EXT(ctx); - VXDBG_CTX vxdbg_ctx; - - assert(is_dispatch_thread()); - assert(ctx->parent != NULL); - assert(ctx->stopped); - assert(!ctx->pending_intercept); - assert(!ctx->exited); - assert(taskIsStopped(ext->pid)); - - trace(LOG_CONTEXT, "context: terminate ctx %#lx, id %#x", ctx, ext->pid); - - if (ext->regs_dirty) { - taskRegsSet(ext->pid, ext->regs); - ext->regs_dirty = 0; - } - - return kill_context(ctx); -} - -int context_resume(Context * ctx, int mode, ContextAddress range_start, ContextAddress range_end) { - switch (mode) { - case RM_RESUME: - return context_continue(ctx); - case RM_STEP_INTO: - return context_single_step(ctx); - case RM_TERMINATE: - return context_terminate(ctx); - } - errno = ERR_UNSUPPORTED; - return -1; -} - -int context_can_resume(Context * ctx, int mode) { - switch (mode) { - case RM_RESUME: - return 1; - case RM_STEP_INTO: - case RM_TERMINATE: - return context_has_state(ctx); - } - return 0; -} - -int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { - if (address < 0x100) { - /* TODO: need proper handling of Access Violation exception in VxWorks version of context_read_mem() */ - errno = ERR_INV_ADDRESS; - return -1; - } -#ifdef _WRS_PERSISTENT_SW_BP - vxdbgMemRead((void *)address, buf, size); -#else - bcopy((void *)address, buf, size); -#endif - if (check_breakpoints_on_memory_read(ctx, address, buf, size) < 0) return -1; - return 0; -} - -int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { - if (address < 0x100) { - errno = ERR_INV_ADDRESS; - return -1; - } - if (check_breakpoints_on_memory_write(ctx, address, buf, size) < 0) return -1; -#ifdef _WRS_PERSISTENT_SW_BP - vxdbgMemWrite((void *)address, buf, size); -#else - bcopy(buf, (void *)address, size); -#endif - return 0; -} - -#if ENABLE_ExtendedMemoryErrorReports -int context_get_mem_error_info(MemoryErrorInfo * info) { - if (mem_err_info.error == 0) { - set_errno(ERR_OTHER, "Extended memory error info not available"); - return -1; - } - *info = mem_err_info; - return 0; -} -#endif - -int context_write_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) { - ContextExtensionVxWorks * ext = EXT(ctx); - - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(ctx->stopped); - assert(!ctx->exited); - assert(offs + size <= def->size); - - if (ext->regs_error) { - set_error_report_errno(ext->regs_error); - return -1; - } - memcpy((uint8_t *)ext->regs + def->offset + offs, buf, size); - ext->regs_dirty = 1; - return 0; -} - -int context_read_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) { - ContextExtensionVxWorks * ext = EXT(ctx); - - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(ctx->stopped); - assert(!ctx->exited); - assert(offs + size <= def->size); - - if (ext->regs_error) { - set_error_report_errno(ext->regs_error); - return -1; - } - memcpy(buf, (uint8_t *)ext->regs + def->offset + offs, size); - return 0; -} - -int context_get_canonical_addr(Context * ctx, ContextAddress addr, - Context ** canonical_ctx, ContextAddress * canonical_addr, - ContextAddress * block_addr, ContextAddress * block_size) { - /* Direct mapping, page size is irrelevant */ - ContextAddress page_size = 0x100000; - assert(is_dispatch_thread()); - *canonical_ctx = parent_ctx; - if (canonical_addr != NULL) *canonical_addr = addr; - if (block_addr != NULL) *block_addr = addr & ~(page_size - 1); - if (block_size != NULL) *block_size = page_size; - return 0; -} - -Context * context_get_group(Context * ctx, int group) { - switch (group) { - case CONTEXT_GROUP_INTERCEPT: - return ctx; - } - return parent_ctx; -} - -int context_get_supported_bp_access_types(Context * ctx) { - return 0; -} - -int context_plant_breakpoint(ContextBreakpoint * bp) { - VXDBG_CTX vxdbg_ctx; - VXDBG_BP_ID bp_id = 0; - if (bp->access_types != CTX_BP_ACCESS_INSTRUCTION) { - errno = ERR_INV_FORMAT; - return -1; - } - if (bp->length != 1) { - errno = ERR_INV_FORMAT; - return -1; - } - memset(&vxdbg_ctx, 0, sizeof(vxdbg_ctx)); - vxdbg_ctx.ctxType = VXDBG_CTX_TASK; - if (vxdbgBpAdd(vxdbg_clnt_id, - &vxdbg_ctx, 0, BP_ACTION_STOP | BP_ACTION_NOTIFY, - 0, 0, (INSTR *)bp->address, 0, 0, &bp_id) != OK) return -1; - bp->id = bp_id; - return 0; -} - -int context_unplant_breakpoint(ContextBreakpoint * bp) { - VXDBG_BP_DEL_INFO info; - memset(&info, 0, sizeof(info)); - info.pClnt = vxdbg_clnt_id; - info.type = BP_BY_ID_DELETE; - info.info.id.bpId = bp->id; - if (vxdbgBpDelete(info) != OK) return -1; - return 0; -} - -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; - map->regions = (MemoryRegion *)loc_realloc(map->regions, sizeof(MemoryRegion) * map->region_max); - } - r = map->regions + map->region_cnt++; - memset(r, 0, sizeof(MemoryRegion)); - r->addr = (ContextAddress)addr; - r->size = (ContextAddress)size; - r->flags = flags; - if (file != NULL) r->file_name = loc_strdup(file); - if (sect != NULL) r->sect_name = loc_strdup(sect); -} - -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(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(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(map, info.segInfo.bssAddr, info.segInfo.bssSize, MM_FLAG_R | MM_FLAG_W, file, ".bss"); - } - } - return 0; -} - -static void module_create_event(void * args) { - memory_map_event_module_loaded(parent_ctx); -} - -static int module_create_func(MODULE_ID id) { - post_event(module_create_event, NULL); - return 0; -} - -int context_get_memory_map(Context * ctx, MemoryMap * map) { - static int hooks_done = 0; - if (!hooks_done) { - hooks_done = 1; - moduleCreateHookAdd(module_create_func); - } - moduleEach(module_list_proc, (int)map); - return 0; -} - -unsigned context_word_size(Context * ctx) { - return sizeof(void *); -} - -int get_context_task_id(Context * ctx) { - return EXT(ctx)->pid; -} - -static void event_handler(void * arg) { - struct event_info * info = (struct event_info *)arg; - Context * current_ctx = context_find_from_pid(info->current_ctx.ctxId, 1); - Context * stopped_ctx = context_find_from_pid(info->stopped_ctx.ctxId, 1); - - switch (info->event) { - case EVENT_HOOK_BREAKPOINT: - if (stopped_ctx == NULL) break; - assert(!stopped_ctx->stopped); - assert(!EXT(stopped_ctx)->regs_dirty); - if (EXT(stopped_ctx)->regs_error) { - release_error_report(EXT(stopped_ctx)->regs_error); - EXT(stopped_ctx)->regs_error = NULL; - } - memcpy(EXT(stopped_ctx)->regs, &info->regs, sizeof(REG_SET)); - EXT(stopped_ctx)->event = 0; - stopped_ctx->signal = SIGTRAP; - stopped_ctx->stopped = 1; - stopped_ctx->stopped_by_bp = info->bp_info_ok; - stopped_ctx->stopped_by_exception = 0; - assert(get_regs_PC(stopped_ctx) == info->addr); - if (stopped_ctx->stopped_by_bp && !is_breakpoint_address(stopped_ctx, info->addr)) { - /* Break instruction that is not planted by us */ - stopped_ctx->stopped_by_bp = 0; - stopped_ctx->pending_intercept = 1; - } - EXT(stopped_ctx)->bp_info = info->bp_info; - if (current_ctx != NULL) EXT(stopped_ctx)->bp_pid = EXT(current_ctx)->pid; - assert(taskIsStopped(EXT(stopped_ctx)->pid)); - trace(LOG_CONTEXT, "context: stopped by breakpoint: ctx %#lx, id %#x", - stopped_ctx, EXT(stopped_ctx)->pid); - send_context_stopped_event(stopped_ctx); - break; - case EVENT_HOOK_STEP_DONE: - if (current_ctx == NULL) break; - assert(!current_ctx->stopped); - assert(!EXT(current_ctx)->regs_dirty); - if (EXT(current_ctx)->regs_error) { - release_error_report(EXT(current_ctx)->regs_error); - EXT(current_ctx)->regs_error = NULL; - } - memcpy(EXT(current_ctx)->regs, &info->regs, sizeof(REG_SET)); - EXT(current_ctx)->event = TRACE_EVENT_STEP; - current_ctx->signal = SIGTRAP; - current_ctx->stopped = 1; - current_ctx->stopped_by_bp = 0; - current_ctx->stopped_by_exception = 0; - assert(taskIsStopped(EXT(current_ctx)->pid)); - trace(LOG_CONTEXT, "context: stopped by end of step: ctx %#lx, id %#x", - current_ctx, EXT(current_ctx)->pid); - send_context_stopped_event(current_ctx); - break; - case EVENT_HOOK_STOP: - if (stopped_ctx == NULL) break; - assert(!stopped_ctx->exited); - if (stopped_ctx->stopped) break; - if (EXT(stopped_ctx)->regs_error) { - release_error_report(EXT(stopped_ctx)->regs_error); - EXT(stopped_ctx)->regs_error = NULL; - } - if (taskRegsGet(EXT(stopped_ctx)->pid, EXT(stopped_ctx)->regs) != OK) { - EXT(stopped_ctx)->regs_error = get_error_report(errno); - assert(EXT(stopped_ctx)->regs_error != NULL); - } - EXT(stopped_ctx)->event = 0; - stopped_ctx->signal = SIGSTOP; - stopped_ctx->stopped = 1; - stopped_ctx->stopped_by_bp = 0; - stopped_ctx->stopped_by_exception = 0; - assert(taskIsStopped(EXT(stopped_ctx)->pid)); - trace(LOG_CONTEXT, "context: stopped by sofware request: ctx %#lx, id %#x", - stopped_ctx, EXT(stopped_ctx)->pid); - send_context_stopped_event(stopped_ctx); - break; - case EVENT_HOOK_TASK_ADD: - if (current_ctx == NULL) break; - assert(stopped_ctx == NULL); - stopped_ctx = create_context(pid2id((pid_t)info->stopped_ctx.ctxId, EXT(current_ctx->parent)->pid)); - EXT(stopped_ctx)->pid = (pid_t)info->stopped_ctx.ctxId; - EXT(stopped_ctx)->regs = (REG_SET *)loc_alloc(sizeof(REG_SET)); - stopped_ctx->mem = current_ctx->mem; - stopped_ctx->big_endian = current_ctx->mem->big_endian; - (stopped_ctx->creator = current_ctx)->ref_count++; - (stopped_ctx->parent = current_ctx->parent)->ref_count++; - assert(stopped_ctx->mem == stopped_ctx->parent->mem); - list_add_last(&stopped_ctx->cldl, &stopped_ctx->parent->children); - link_context(stopped_ctx); - trace(LOG_CONTEXT, "context: created: ctx %#lx, id %#x", - stopped_ctx, EXT(stopped_ctx)->pid); - send_context_created_event(stopped_ctx); - break; - default: - assert(0); - break; - } - loc_free(info); - SPIN_LOCK_ISR_TAKE(&events_lock); - events_cnt--; - SPIN_LOCK_ISR_GIVE(&events_lock); -} - -static void event_error(void * arg) { - trace(LOG_ALWAYS, "Fatal error: VXDBG events buffer overflow"); - exit(1); -} - -static void * event_thread_func(void * arg) { - taskPrioritySet(0, VX_TASK_PRIORITY_MIN); - for (;;) { - struct event_info * info = loc_alloc(sizeof(struct event_info)); - semTake(events_signal, WAIT_FOREVER); - - SPIN_LOCK_ISR_TAKE(&events_lock); - if (events_buf_overflow && events_inp == events_out) { - SPIN_LOCK_ISR_GIVE(&events_lock); - loc_free(info); - break; - } - assert(events_inp != events_out); - *info = events[events_out]; - events_out = (events_out + 1) % MAX_EVENTS; - SPIN_LOCK_ISR_GIVE(&events_lock); - - post_event(event_handler, info); - } - post_event(event_error, NULL); - return NULL; -} - -static void vxdbg_event_hook( - VXDBG_CTX * current_ctx, /* context that hit breakpoint */ - VXDBG_CTX * stopped_ctx, /* context stopped by the breakpoint */ - REG_SET * regs, /* task registers before exception */ - UINT32 addr, /* breakpoint addr */ - VXDBG_BP_INFO * bp_info) { /* breakpoint information */ - - struct event_info * info = event_info_alloc(EVENT_HOOK_BREAKPOINT); - if (info != NULL) { - if (stopped_ctx == NULL) info->event = EVENT_HOOK_STEP_DONE; - if (current_ctx != NULL) info->current_ctx = *current_ctx; - if (stopped_ctx != NULL) info->stopped_ctx = *stopped_ctx; - if (regs != NULL) info->regs = *regs; - info->addr = addr; - if (bp_info != NULL) { - info->bp_info_ok = 1; - info->bp_info = *bp_info; - } - event_info_post(info); - } -} - -static void task_create_hook(WIND_TCB * tcb) { - struct event_info * info = event_info_alloc(EVENT_HOOK_TASK_ADD); - if (info != NULL) { - info->current_ctx.ctxId = taskIdSelf(); - info->stopped_ctx.ctxId = (UINT32)tcb; - event_info_post(info); - } -} - -static void waitpid_listener(int pid, int exited, int exit_code, int signal, int event_code, int syscall, void * args) { - if (exited) { - Context * stopped_ctx = context_find_from_pid(pid, 1); - if (stopped_ctx != NULL) { - /* TODO: need call back for vxdbgCont() - * assert(!stopped_ctx->stopped) can fail if a task is resumed outside TCF agent. - */ - assert(!stopped_ctx->stopped); - assert(!stopped_ctx->exited); - trace(LOG_CONTEXT, "context: exited ctx %#lx, id %#x", stopped_ctx, EXT(stopped_ctx)->pid); - release_error_report(EXT(stopped_ctx)->regs_error); - loc_free(EXT(stopped_ctx)->regs); - EXT(stopped_ctx)->regs_error = NULL; - EXT(stopped_ctx)->regs = NULL; - send_context_exited_event(stopped_ctx); - } - } -} - -void init_contexts_sys_dep(void) { - SPIN_LOCK_ISR_INIT(&events_lock, 0); - if ((events_signal = semCInitialize(events_signal_mem, SEM_Q_FIFO, 0)) == NULL) { - check_error(errno); - } - vxdbg_clnt_id = vxdbgClntRegister(EVT_BP); - if (vxdbg_clnt_id == NULL) { - check_error(errno); - } - context_extension_offset = context_extension(sizeof(ContextExtensionVxWorks)); - taskCreateHookAdd((FUNCPTR)task_create_hook); - vxdbgHookAdd(vxdbg_clnt_id, EVT_BP, vxdbg_event_hook); - vxdbgHookAdd(vxdbg_clnt_id, EVT_TRACE, vxdbg_event_hook); - check_error(pthread_create(&events_thread, &pthread_create_attr, event_thread_func, NULL)); - add_waitpid_listener(waitpid_listener, NULL); - ini_context_pid_hash(); -} - -#endif /* if ENABLE_DebugContext */ -#endif /* _WRS_KERNEL */ diff --git a/agent/tcf/system/VxWorks/context-vxworks.h b/agent/tcf/system/VxWorks/context-vxworks.h deleted file mode 100644 index 0fd81105..00000000 --- a/agent/tcf/system/VxWorks/context-vxworks.h +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This module handles process/thread OS contexts and their state machine. - */ - -#ifndef D_context_vxworks -#define D_context_vxworks - -#include <tcf/config.h> -#include <tcf/framework/context.h> - -extern int get_context_task_id(Context * ctx); - -#endif /* D_context_vxworks */ diff --git a/agent/tcf/system/VxWorks/regset.h b/agent/tcf/system/VxWorks/regset.h deleted file mode 100644 index 0a12cb92..00000000 --- a/agent/tcf/system/VxWorks/regset.h +++ /dev/null @@ -1,23 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2010 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This header file provides definition of REG_SET - a structure that can - * hold values of target CPU registers. - */ - -#if defined(_WRS_KERNEL) -# include <regs.h> -#endif diff --git a/agent/tcf/system/Windows/context-win32.c b/agent/tcf/system/Windows/context-win32.c deleted file mode 100644 index e85cbb11..00000000 --- a/agent/tcf/system/Windows/context-win32.c +++ /dev/null @@ -1,1434 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This module handles process/thread OS contexts and their state machine. - */ - -#include <tcf/config.h> - -#if defined(WIN32) - -#if ENABLE_DebugContext && !ENABLE_ContextProxy - -#include <stdlib.h> -#include <assert.h> -#include <errno.h> -#include <signal.h> -#include <tcf/framework/context.h> -#include <tcf/framework/events.h> -#include <tcf/framework/errors.h> -#include <tcf/framework/trace.h> -#include <tcf/framework/myalloc.h> -#include <tcf/framework/waitpid.h> -#include <tcf/framework/signames.h> -#include <tcf/services/breakpoints.h> -#include <tcf/services/memorymap.h> -#include <tcf/services/runctrl.h> -#include <tcf/system/Windows/context-win32.h> -#include <tcf/system/Windows/regset.h> -#include <tcf/system/Windows/windbgcache.h> - -#if !defined(USE_HW_BPS) -# define USE_HW_BPS 1 -#endif -#if USE_HW_BPS -# define MAX_HW_BPS 4 -#endif - -typedef struct ContextExtensionWin32 { - pid_t pid; - HANDLE handle; - DEBUG_EVENT debug_event; - EXCEPTION_DEBUG_INFO suspend_reason; - int stop_pending; - int start_pending; - REG_SET * regs; /* copy of context registers, updated when context stops */ - 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 */ - int trace_flag; - uint8_t step_opcodes[4]; - SIZE_T step_opcodes_len; - ContextAddress step_opcodes_addr; - struct DebugState * debug_state; -#if USE_HW_BPS - ContextBreakpoint * triggered_hw_bps[MAX_HW_BPS + 1]; - unsigned hw_bps_regs_generation; - DWORD skip_hw_bp_addr; -#endif -} ContextExtensionWin32; - -static size_t context_extension_offset = 0; - -#define EXT(ctx) ((ContextExtensionWin32 *)((char *)(ctx) + context_extension_offset)) - -typedef struct DebugState { - int error; - int state; - DWORD process_id; - DWORD debug_thread_id; - HANDLE debug_thread; - HANDLE debug_thread_semaphore; - HANDLE debug_event_inp; - HANDLE debug_event_out; - DWORD ini_thread_id; - HANDLE ini_thread_handle; - DWORD main_thread_id; - HANDLE main_thread_handle; - int reporting_debug_event; - int break_posted; - HANDLE break_thread; - LPVOID break_thread_code; - DWORD break_thread_id; - HANDLE file_handle; - DWORD64 base_address; - HANDLE module_handle; - DWORD64 module_address; - ContextAttachCallBack * attach_callback; - void * attach_data; -#if USE_HW_BPS - int ok_to_use_hw_bp; /* NtContinue() changes Dr6 and Dr7, so HW breakpoints should be disabled until NtContinue() is done */ - ContextBreakpoint * hw_bps[MAX_HW_BPS]; - unsigned hw_bps_generation; -#endif -} DebugState; - -#define DEBUG_STATE_INIT 0 -#define DEBUG_STATE_PRS_CREATED 1 -#define DEBUG_STATE_PRS_ATTACHED 2 - -typedef struct DebugEvent { - DebugState * debug_state; - DEBUG_EVENT win32_event; - DWORD continue_status; -} DebugEvent; - -static OSVERSIONINFOEX os_version; - -#define MAX_EXCEPTION_HANDLERS 8 -static ContextExceptionHandler * exception_handlers[MAX_EXCEPTION_HANDLERS]; -static unsigned exception_handler_cnt = 0; - -static MemoryErrorInfo mem_err_info; - -#include <tcf/system/pid-hash.h> - -#define EXCEPTION_DEBUGGER_IO 0x406D1388 - -const char * context_suspend_reason(Context * ctx) { - ContextExtensionWin32 * ext = EXT(ctx); - DWORD exception_code = ext->suspend_reason.ExceptionRecord.ExceptionCode; - static char buf[64]; - - if (exception_code == 0) return REASON_USER_REQUEST; - if (ext->suspend_reason.dwFirstChance) { - if (exception_code == EXCEPTION_SINGLE_STEP) return REASON_STEP; - if (exception_code == EXCEPTION_BREAKPOINT) return "Break Instruction"; - snprintf(buf, sizeof(buf), "Exception %#lx", exception_code); - } - else { - snprintf(buf, sizeof(buf), "Unhandled exception %#lx", exception_code); - } - return buf; -} - -static int get_signal_index(Context * ctx) { - ContextExtensionWin32 * ext = EXT(ctx); - DWORD exception_code = ext->suspend_reason.ExceptionRecord.ExceptionCode; - - if (exception_code == 0) return 0; - return get_signal_from_code(exception_code); -} - -static const char * win32_debug_event_name(int event) { - switch (event) { - case CREATE_PROCESS_DEBUG_EVENT: - return "CREATE_PROCESS_DEBUG_EVENT"; - case CREATE_THREAD_DEBUG_EVENT: - return "CREATE_THREAD_DEBUG_EVENT"; - case EXCEPTION_DEBUG_EVENT: - return "EXCEPTION_DEBUG_EVENT"; - case EXIT_PROCESS_DEBUG_EVENT: - return "EXIT_PROCESS_DEBUG_EVENT"; - case EXIT_THREAD_DEBUG_EVENT: - return "EXIT_THREAD_DEBUG_EVENT"; - case LOAD_DLL_DEBUG_EVENT: - return "LOAD_DLL_DEBUG_EVENT"; - case OUTPUT_DEBUG_STRING_EVENT: - return "OUTPUT_DEBUG_STRING_EVENT"; - case UNLOAD_DLL_DEBUG_EVENT: - return "UNLOAD_DLL_DEBUG_EVENT"; - } - return "Unknown"; -} - -static int log_error(const char * fn, int ok) { - int err; - if (ok) return 0; - assert(is_dispatch_thread()); - err = set_win32_errno(GetLastError()); - trace(LOG_ALWAYS, "context: %s: %s", fn, errno_to_str(errno)); - return err; -} - -static void event_win32_context_exited(Context * ctx); - -static void get_registers(Context * ctx) { - ContextExtensionWin32 * ext = EXT(ctx); - - if (ext->regs->ContextFlags) return; - - assert(!ctx->exited); - assert(context_has_state(ctx)); - assert(ctx->stopped); - - ext->regs->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT; -#if USE_HW_BPS - ext->regs->ContextFlags |= CONTEXT_DEBUG_REGISTERS; -#endif - if (GetThreadContext(ext->handle, ext->regs) == 0) { - ext->regs_error = get_error_report(log_error("GetThreadContext", 0)); - } - else { - ext->trace_flag = (ext->regs->EFlags & 0x100) != 0; - trace(LOG_CONTEXT, "context: get regs OK: ctx %#lx, id %s, PC %#lx", - ctx, ctx->id, ext->regs->Eip); - } -} - -static DWORD event_win32_context_stopped(Context * ctx) { - ContextExtensionWin32 * ext = EXT(ctx); - DebugState * debug_state = EXT(ctx->mem)->debug_state; - ContextAddress exception_addr = (ContextAddress)ext->suspend_reason.ExceptionRecord.ExceptionAddress; - DWORD exception_code = ext->suspend_reason.ExceptionRecord.ExceptionCode; - DWORD continue_status = DBG_CONTINUE; - - assert(is_dispatch_thread()); - assert(!ctx->exited); - assert(!ctx->stopped); - assert(ext->handle != NULL); - assert(ctx->parent != NULL); - - ext->stop_pending = 0; - ext->start_pending = 0; - - trace(LOG_CONTEXT, "context: stopped: ctx %#lx, id %s, exception %#lx", - ctx, ctx->id, exception_code); - - if (SuspendThread(ext->handle) == (DWORD)-1) { - DWORD err = GetLastError(); - ctx->exiting = 1; - if (err == ERROR_ACCESS_DENIED) { - /* Already exited */ - return DBG_CONTINUE; - } - log_error("SuspendThread", 0); - return DBG_EXCEPTION_NOT_HANDLED; - } - - if (ext->regs_error) { - release_error_report(ext->regs_error); - ext->regs_error = NULL; - } - memset(ext->regs, 0, sizeof(REG_SET)); - - ctx->signal = get_signal_index(ctx); - ctx->pending_signals = 0; - ctx->stopped = 1; - ctx->stopped_by_bp = 0; - ctx->stopped_by_cb = NULL; - if (exception_code == 0) { - ctx->stopped_by_exception = 0; - } - else if (ext->suspend_reason.dwFirstChance) { - ctx->stopped_by_exception = 0; - switch (exception_code) { - case EXCEPTION_SINGLE_STEP: - get_registers(ctx); - if (!ext->regs_error) { -#if USE_HW_BPS - if (ext->regs->Eip != ext->skip_hw_bp_addr) ext->skip_hw_bp_addr = 0; - if (ext->regs->Dr6 & 0xfu) { - int i, j = 0; - for (i = 0; i < MAX_HW_BPS; i++) { - if (ext->regs->Dr6 & (1u << i)) { - ContextBreakpoint * bp = debug_state->hw_bps[i]; - if (bp == NULL) continue; - if (bp->address == ext->regs->Eip && (bp->access_types & CTX_BP_ACCESS_INSTRUCTION)) { - ext->skip_hw_bp_addr = ext->regs->Eip; - } - ctx->stopped_by_cb = ext->triggered_hw_bps; - ctx->stopped_by_cb[j++] = bp; - ctx->stopped_by_cb[j] = NULL; - } - } - } -#endif - if (ext->step_opcodes_len > 0 && ext->step_opcodes[0] == 0x9c && ext->step_opcodes_addr != ext->regs->Eip) { - /* PUSHF instruction: need to clear trace flag from top of the stack */ - SIZE_T bcnt = 0; - ContextAddress buf = 0; - assert(ext->regs->EFlags & 0x100); - assert(ext->step_opcodes_addr == ext->regs->Eip - 1); - if (!ReadProcessMemory(EXT(ctx->mem)->handle, (LPCVOID)ext->regs->Esp, &buf, sizeof(ContextAddress), &bcnt) || bcnt != sizeof(ContextAddress)) { - log_error("ReadProcessMemory", 0); - } - else { - assert(buf & 0x100); - buf &= ~0x100; - if (!WriteProcessMemory(EXT(ctx->mem)->handle, (LPVOID)ext->regs->Esp, &buf, sizeof(ContextAddress), &bcnt) || bcnt != sizeof(ContextAddress)) { - log_error("WriteProcessMemory", 0); - } - } - } - } - if ((!ctx->stopped_by_cb && ext->step_opcodes_len == 0) || ext->regs_error) { - continue_status = DBG_EXCEPTION_NOT_HANDLED; - } - ext->step_opcodes_len = 0; - ext->step_opcodes_addr = 0; - break; - case EXCEPTION_BREAKPOINT: - get_registers(ctx); - if (!ext->regs_error) { - if (is_breakpoint_address(ctx, exception_addr)) { - ext->regs->Eip = exception_addr; - ext->regs_dirty = 1; - ctx->stopped_by_bp = 1; -#if USE_HW_BPS - if (!debug_state->ok_to_use_hw_bp) { - debug_state->ok_to_use_hw_bp = 1; - send_context_changed_event(ctx->mem); - memory_map_event_mapping_changed(ctx->mem); - } -#endif - } - else { - ext->regs->Eip = exception_addr; - ext->regs_dirty = 1; - } - } - else { - continue_status = DBG_EXCEPTION_NOT_HANDLED; - } - break; - case EXCEPTION_DEBUGGER_IO: - trace(LOG_ALWAYS, "Debugger IO request %#lx", - ext->suspend_reason.ExceptionRecord.ExceptionInformation[0]); - break; - default: - continue_status = DBG_EXCEPTION_NOT_HANDLED; - break; - } - if (continue_status == DBG_EXCEPTION_NOT_HANDLED) { - unsigned i; - for (i = 0; i < exception_handler_cnt; i++) { - if (exception_handlers[i](ctx, &ext->suspend_reason)) { - continue_status = DBG_CONTINUE; - } - } - } - if (continue_status == DBG_EXCEPTION_NOT_HANDLED) { - int intercept = 1; - ctx->stopped_by_exception = 1; - if (ctx->signal) { - ctx->pending_signals |= 1 << ctx->signal; - if (ctx->sig_dont_pass & (1 << ctx->signal)) { - continue_status = DBG_CONTINUE; - } - if (ctx->sig_dont_stop & (1 << ctx->signal)) { - intercept = 0; - } - } - if (intercept) ctx->pending_intercept = 1; - } - } - else { - ctx->stopped_by_exception = 1; - if (!ctx->mem->exiting) ctx->pending_intercept = 1; - continue_status = DBG_EXCEPTION_NOT_HANDLED; - } - send_context_stopped_event(ctx); - return continue_status; -} - -static void event_win32_context_started(Context * ctx) { - ContextExtensionWin32 * ext = EXT(ctx); - trace(LOG_CONTEXT, "context: started: ctx %#lx, id %s", ctx, ctx->id); - assert(ctx->stopped); - ext->stop_pending = 0; - send_context_started_event(ctx); -} - -static void event_win32_context_exited(Context * ctx) { - ContextExtensionWin32 * ext = EXT(ctx); - LINK * l = NULL; - trace(LOG_CONTEXT, "context: exited: ctx %#lx, id %s", ctx, ctx->id); - assert(!ctx->exited); - context_lock(ctx); - ctx->exiting = 1; - ext->stop_pending = 0; - if (ctx->stopped) send_context_started_event(ctx); - l = ctx->children.next; - while (l != &ctx->children) { - Context * c = cldl2ctxp(l); - l = l->next; - assert(c->parent == ctx); - if (!c->exited) event_win32_context_exited(c); - } - release_error_report(ext->regs_error); - loc_free(ext->regs); - ext->regs_error = NULL; - ext->regs = NULL; - send_context_exited_event(ctx); - if (ext->handle != NULL) { - if (ctx->mem != ctx) { - log_error("CloseHandle", CloseHandle(ext->handle)); - } - else if (os_version.dwMajorVersion <= 5) { - /* Bug in Windows XP: ContinueDebugEvent() does not close exited process handle */ - log_error("CloseHandle", CloseHandle(ext->handle)); - } - ext->handle = NULL; - } - if (ext->debug_state != NULL && ext->debug_state->file_handle != NULL) { - log_error("CloseHandle", CloseHandle(ext->debug_state->file_handle)); - ext->debug_state->file_handle = NULL; - } - ext->debug_state = NULL; - context_unlock(ctx); -} - -static DWORD WINAPI remote_thread_func(LPVOID args) { - return 0; -} - -static void break_process_event(void * args) { - Context * ctx = (Context *)args; - ContextExtensionWin32 * ext = EXT(ctx); - - if (ext->debug_state != NULL) { - LINK * l; - int cnt = 0; - DebugState * debug_state = ext->debug_state; - - if (!ctx->exited && debug_state->break_thread == NULL) { - for (l = ctx->children.next; l != &ctx->children; l = l->next) { - ContextExtensionWin32 * x = EXT(cldl2ctxp(l)); - if (x->stop_pending && SuspendThread(x->handle) != (DWORD)-1) cnt++; - } - if (cnt > 0) { - const SIZE_T buf_size = 0x100; - DWORD size = 0; - int error = 0; - - trace(LOG_CONTEXT, "context: creating remote thread in process %#lx, id %s", ctx, ctx->id); - if (debug_state->break_thread_code == NULL) { - debug_state->break_thread_code = VirtualAllocEx(ext->handle, - NULL, buf_size, MEM_COMMIT, PAGE_EXECUTE); - error = log_error("VirtualAllocEx", debug_state->break_thread_code != NULL); - } - - if (!error) error = log_error("WriteProcessMemory", WriteProcessMemory(ext->handle, - debug_state->break_thread_code, (LPCVOID)remote_thread_func, buf_size, &size) && size == buf_size); - - if (!error) error = log_error("CreateRemoteThread", (debug_state->break_thread = CreateRemoteThread(ext->handle, - 0, 0, (DWORD (WINAPI*)(LPVOID))debug_state->break_thread_code, NULL, 0, &debug_state->break_thread_id)) != NULL); - - if (error) { - debug_state->break_thread = NULL; - debug_state->break_thread_id = 0; - } - } - } - debug_state->break_posted = 0; - } - context_unlock(ctx); -} - -static int win32_resume(Context * ctx, int step) { - Context * prs = ctx->parent; - ContextExtensionWin32 * ext = EXT(ctx); - ContextExtensionWin32 * prs_ext = EXT(prs); - DebugState * debug_state = prs_ext->debug_state; - - assert(ctx->stopped); - assert(!ctx->exited); - - if (debug_state->reporting_debug_event) { - debug_state->reporting_debug_event++; - } - -#if USE_HW_BPS - - if (ext->skip_hw_bp_addr == 0 && skip_breakpoint(ctx, step)) return 0; - - /* Update debug registers */ - if (ext->skip_hw_bp_addr != 0 || ext->hw_bps_regs_generation != debug_state->hw_bps_generation) { - int i; - DWORD Dr7 = 0; - int step_over_hw_bp = 0; - - get_registers(ctx); - if (ext->regs_error) { - errno = set_error_report_errno(ext->regs_error); - return -1; - } - Dr7 = ext->regs->Dr7; - for (i = 0; i < MAX_HW_BPS; i++) { - ContextBreakpoint * bp = debug_state->hw_bps[i]; - if (bp != NULL && - ext->skip_hw_bp_addr == bp->address && - (bp->access_types & CTX_BP_ACCESS_INSTRUCTION)) { - /* Skipping the breakpoint */ - step_over_hw_bp = 1; - bp = NULL; - } - Dr7 &= ~(3u << (i * 2)); - if (bp != NULL) { - switch (i) { - case 0: - if (ext->regs->Dr0 != bp->address) { - ext->regs->Dr0 = bp->address; - ext->regs_dirty = 1; - } - break; - case 1: - if (ext->regs->Dr1 != bp->address) { - ext->regs->Dr1 = bp->address; - ext->regs_dirty = 1; - } - break; - case 2: - if (ext->regs->Dr2 != bp->address) { - ext->regs->Dr2 = bp->address; - ext->regs_dirty = 1; - } - break; - case 3: - if (ext->regs->Dr3 != bp->address) { - ext->regs->Dr3 = bp->address; - ext->regs_dirty = 1; - } - break; - } - Dr7 |= 1u << (i * 2); - if (bp->access_types == (CTX_BP_ACCESS_INSTRUCTION | CTX_BP_ACCESS_VIRTUAL)) { - Dr7 &= ~(3u << (i * 4 + 16)); - } - else if (bp->access_types == (CTX_BP_ACCESS_DATA_WRITE | CTX_BP_ACCESS_VIRTUAL)) { - Dr7 &= ~(3u << (i * 4 + 16)); - Dr7 |= 1u << (i * 4 + 16); - } - else if (bp->access_types == (CTX_BP_ACCESS_DATA_READ | CTX_BP_ACCESS_DATA_WRITE | CTX_BP_ACCESS_VIRTUAL)) { - Dr7 |= 3u << (i * 4 + 16); - } - else { - errno = set_errno(ERR_UNSUPPORTED, "Invalid hardware breakpoint: unsupported access mode"); - return -1; - } - if (bp->length == 1) { - Dr7 &= ~(3u << (i * 4 + 18)); - } - else if (bp->length == 2) { - Dr7 &= ~(3u << (i * 4 + 18)); - Dr7 |= 1u << (i * 4 + 18); - } - else if (bp->length == 4) { - Dr7 |= 3u << (i * 4 + 18); - } - else if (bp->length == 8) { - Dr7 &= ~(3u << (i * 4 + 18)); - Dr7 |= 2u << (i * 4 + 18); - } - else { - errno = set_errno(ERR_UNSUPPORTED, "Invalid hardware breakpoint: unsupported length"); - return -1; - } - } - } - if (ext->regs->Dr7 != Dr7) { - ext->regs->Dr7 = Dr7; - ext->regs_dirty = 1; - } - ext->hw_bps_regs_generation = debug_state->hw_bps_generation; - if (step_over_hw_bp) { - step = 1; - ext->hw_bps_regs_generation--; - } - else { - ext->skip_hw_bp_addr = 0; - } - } - -#else - - if (skip_breakpoint(ctx, step)) return 0; - -#endif - - /* Update CPU trace flag */ - if (!step && ext->trace_flag) { - get_registers(ctx); - ext->regs->EFlags &= ~0x100; - ext->regs_dirty = 1; - } - else if (step && !ext->trace_flag) { - get_registers(ctx); - ext->regs->EFlags |= 0x100; - ext->regs_dirty = 1; - } - - /* Flash registers if dirty */ - if (ext->regs_dirty) { - assert(ext->regs->ContextFlags); - if (ext->regs_error) { - trace(LOG_ALWAYS, "Can't resume thread, registers copy is invalid: ctx %#lx, id %s", ctx, ctx->id); - errno = set_error_report_errno(ext->regs_error); - return -1; - } - if (SetThreadContext(ext->handle, ext->regs) == 0) { - errno = log_error("SetThreadContext", 0); - return -1; - } - ext->trace_flag = (ext->regs->EFlags & 0x100) != 0; - ext->regs_dirty = 0; - } - - if (ext->trace_flag) { - get_registers(ctx); - if (ext->regs_error) { - set_error_report_errno(ext->regs_error); - return -1; - } - ext->step_opcodes_addr = ext->regs->Eip; - if (!ReadProcessMemory(prs_ext->handle, (LPCVOID)ext->regs->Eip, &ext->step_opcodes, - sizeof(ext->step_opcodes), &ext->step_opcodes_len) || ext->step_opcodes_len == 0) { - errno = log_error("ReadProcessMemory", 0); - return -1; - } - } - if (debug_state->reporting_debug_event) { - ext->start_pending = 1; - } - else { - for (;;) { - DWORD cnt = ResumeThread(ext->handle); - if (cnt == (DWORD)-1) { - errno = log_error("ResumeThread", 0); - return -1; - } - if (cnt <= 1) break; - } - } - - event_win32_context_started(ctx); - return 0; -} - -static int win32_terminate(Context * ctx) { - LINK * l; - ContextExtensionWin32 * ext = EXT(ctx); - DebugState * debug_state = ext->debug_state; - - if (debug_state->reporting_debug_event) { - debug_state->reporting_debug_event++; - } - - trace(LOG_CONTEXT, "context: terminating process %#lx, id %s", ctx, ctx->id); - if (!ctx->exiting) { - if (!TerminateProcess(ext->handle, 1)) { - errno = log_error("TerminateProcess", 0); - return -1; - } - ctx->exiting = 1; - for (l = ctx->children.next; l != &ctx->children; l = l->next) { - Context * c = cldl2ctxp(l); - if (!c->stopped) continue; - event_win32_context_started(c); - c->exiting = 1; - } - } - - return 0; -} - -static void debug_event_handler(DebugEvent * debug_event) { - DebugState * debug_state = debug_event->debug_state; - DEBUG_EVENT * win32_event = &debug_event->win32_event; - Context * prs = context_find_from_pid(win32_event->dwProcessId, 0); - Context * ctx = context_find_from_pid(win32_event->dwThreadId, 1); - ContextExtensionWin32 * ext = NULL; - - assert(ctx == NULL || ctx->parent == prs); - - switch (win32_event->dwDebugEventCode) { - case CREATE_PROCESS_DEBUG_EVENT: - if (debug_state->state == DEBUG_STATE_INIT) { - debug_state->state = DEBUG_STATE_PRS_CREATED; - debug_state->main_thread_id = win32_event->dwThreadId; - debug_state->main_thread_handle = win32_event->u.CreateProcessInfo.hThread; - debug_state->file_handle = win32_event->u.CreateProcessInfo.hFile; - debug_state->base_address = (uintptr_t)win32_event->u.CreateProcessInfo.lpBaseOfImage; - assert(prs == NULL); - assert(ctx == NULL); - ext = EXT(prs = create_context(pid2id(win32_event->dwProcessId, 0))); - prs->mem = prs; - prs->mem_access |= MEM_ACCESS_INSTRUCTION; - prs->mem_access |= MEM_ACCESS_DATA; - prs->mem_access |= MEM_ACCESS_USER; - prs->big_endian = big_endian_host(); - ext->pid = win32_event->dwProcessId; - ext->handle = win32_event->u.CreateProcessInfo.hProcess; - ext->debug_state = debug_state; - assert(ext->handle != NULL); - link_context(prs); - send_context_created_event(prs); - } - else { - /* This looks like a bug in Windows XP: */ - /* 1. according to the documentation, we should get only one CREATE_PROCESS_DEBUG_EVENT. */ - /* 2. if we don't suspend second process, debugee crashes. */ - assert(debug_state->ini_thread_handle == NULL); - debug_state->ini_thread_id = win32_event->dwThreadId; - debug_state->ini_thread_handle = win32_event->u.CreateProcessInfo.hThread; - SuspendThread(debug_state->ini_thread_handle); - CloseHandle(win32_event->u.CreateProcessInfo.hFile); - ResumeThread(debug_state->main_thread_handle); - } - break; - case CREATE_THREAD_DEBUG_EVENT: - assert(prs != NULL); - assert(ctx == NULL); - if (debug_state->state < DEBUG_STATE_PRS_ATTACHED) break; - if (debug_state->break_thread_id == win32_event->dwThreadId) break; - ext = EXT(ctx = create_context(pid2id(win32_event->dwThreadId, win32_event->dwProcessId))); - ext->regs = (REG_SET *)loc_alloc_zero(sizeof(REG_SET)); - ext->pid = win32_event->dwThreadId; - ext->handle = OpenThread(THREAD_ALL_ACCESS, FALSE, win32_event->dwThreadId); - ext->debug_state = debug_state; - ctx->mem = prs; - ctx->big_endian = prs->big_endian; - (ctx->parent = prs)->ref_count++; - list_add_last(&ctx->cldl, &prs->children); - link_context(ctx); - send_context_created_event(ctx); - debug_event->continue_status = event_win32_context_stopped(ctx); - ext->debug_event = *win32_event; - break; - case EXCEPTION_DEBUG_EVENT: - if (debug_state->state == DEBUG_STATE_PRS_CREATED && win32_event->u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) { - if (debug_state->ini_thread_handle != NULL) ResumeThread(debug_state->ini_thread_handle); - debug_state->attach_callback(0, prs, debug_state->attach_data); - debug_state->attach_callback = NULL; - debug_state->attach_data = NULL; - debug_state->state = DEBUG_STATE_PRS_ATTACHED; - ext = EXT(ctx = create_context(pid2id(debug_state->main_thread_id, win32_event->dwProcessId))); - ext->regs = (REG_SET *)loc_alloc_zero(sizeof(REG_SET)); - ext->pid = debug_state->main_thread_id; - ext->handle = OpenThread(THREAD_ALL_ACCESS, FALSE, debug_state->main_thread_id); - ext->debug_state = debug_state; - ctx->mem = prs; - ctx->big_endian = prs->big_endian; - (ctx->parent = prs)->ref_count++; - list_add_last(&ctx->cldl, &prs->children); - link_context(ctx); - send_context_created_event(ctx); - ctx->pending_intercept = 1; - debug_event->continue_status = event_win32_context_stopped(ctx); - ext->debug_event = *win32_event; - } - else if (ctx == NULL || ctx->exiting) { - /* Does not work as expected: debug_event->continue_status = DBG_EXCEPTION_NOT_HANDLED; */ - } - else { - assert(prs != NULL); - assert(!ctx->exited); - if (ctx->stopped) { - DWORD exception_code = win32_event->u.Exception.ExceptionRecord.ExceptionCode; -#if USE_HW_BPS - if (exception_code == EXCEPTION_SINGLE_STEP && win32_event->u.Exception.dwFirstChance) { - /* This event appears to be caused by a hardware breakpoint. - * It is safe to ignore the event - the breakpoint will be triggered again - * when the context resumed. */ - debug_event->continue_status = DBG_CONTINUE; - break; - } -#endif - trace(LOG_ALWAYS, "context: already stopped, id %s, exception 0x%08x", ctx->id, exception_code); - send_context_started_event(ctx); - } - ext = EXT(ctx); - memcpy(&ext->suspend_reason, &win32_event->u.Exception, sizeof(EXCEPTION_DEBUG_INFO)); - debug_event->continue_status = event_win32_context_stopped(ctx); - ext->debug_event = *win32_event; - } - break; - case EXIT_THREAD_DEBUG_EVENT: - assert(prs != NULL); - if (ctx && !ctx->exited) event_win32_context_exited(ctx); - if (debug_state->ini_thread_id == win32_event->dwThreadId) { - debug_state->ini_thread_id = 0; - debug_state->ini_thread_handle = NULL; - } - else if (debug_state->break_thread_id == win32_event->dwThreadId) { - ext = EXT(prs); - log_error("CloseHandle", CloseHandle(debug_state->break_thread)); - debug_state->break_thread = NULL; - debug_state->break_thread_id = 0; - } - break; - case EXIT_PROCESS_DEBUG_EVENT: - assert(prs != NULL); - if (ctx && !ctx->exited) event_win32_context_exited(ctx); - event_win32_context_exited(prs); - prs = NULL; - if (debug_state->attach_callback != NULL) { - int error = set_win32_errno(win32_event->u.ExitProcess.dwExitCode); - debug_state->attach_callback(error, NULL, debug_state->attach_data); - debug_state->attach_callback = NULL; - debug_state->attach_data = NULL; - } - break; - case LOAD_DLL_DEBUG_EVENT: - assert(prs != NULL); - debug_state->module_handle = win32_event->u.LoadDll.hFile; - debug_state->module_address = (uintptr_t)win32_event->u.LoadDll.lpBaseOfDll; - memory_map_event_module_loaded(prs); - if (debug_state->module_handle != NULL) { - log_error("CloseHandle", CloseHandle(debug_state->module_handle)); - } - debug_state->module_handle = NULL; - debug_state->module_address = 0; - break; - case UNLOAD_DLL_DEBUG_EVENT: - assert(prs != NULL); - debug_state->module_address = (uintptr_t)win32_event->u.UnloadDll.lpBaseOfDll; - memory_map_event_module_unloaded(prs); - debug_state->module_address = 0; - break; - case RIP_EVENT: - trace(LOG_ALWAYS, "System debugging error: debuggee pid %d, error type %d, error code %d", - win32_event->dwProcessId, win32_event->u.RipInfo.dwType, win32_event->u.RipInfo.dwError); - break; - } -} - -static void continue_debug_event(void * args) { - DebugEvent * debug_event = (DebugEvent *)args; - DebugState * debug_state = debug_event->debug_state; - Context * prs = context_find_from_pid(debug_state->process_id, 0); - - assert(debug_state->reporting_debug_event); - if (debug_state->reporting_debug_event > 1) { - debug_state->reporting_debug_event = 1; - post_event(continue_debug_event, debug_event); - return; - } - - trace(LOG_WAITPID, "continue debug event 1, process id %u", debug_state->process_id); - - if (prs != NULL && !prs->exited) { - LINK * l; - for (l = prs->children.next; l != &prs->children; l = l->next) { - Context * ctx = cldl2ctxp(l); - ContextExtensionWin32 * ext = EXT(ctx); - if (ctx->stopped || ctx->exited) { - ext->stop_pending = 0; - ext->start_pending = 0; - continue; - } - if (ext->stop_pending) { - memset(&ext->suspend_reason, 0, sizeof(ext->suspend_reason)); - event_win32_context_stopped(ctx); - ext->debug_event = debug_event->win32_event; - } - if (ext->start_pending) { - for (;;) { - DWORD cnt = ResumeThread(ext->handle); - if (cnt <= 1) break; - } - ext->start_pending = 0; - } - } - } - - trace(LOG_WAITPID, "continue debug event, process id %u", debug_state->process_id); - log_error("ReleaseSemaphore", SetEvent(debug_state->debug_event_inp)); - log_error("WaitForSingleObject", WaitForSingleObject(debug_state->debug_event_out, INFINITE) != WAIT_FAILED); - debug_state->reporting_debug_event = 0; - - if (prs != NULL && !prs->exited) { - LINK * l; - for (l = prs->children.next; l != &prs->children; l = l->next) { - Context * ctx = cldl2ctxp(l); - ContextExtensionWin32 * ext = EXT(ctx); - if (ext->start_pending) { - for (;;) { - DWORD cnt = ResumeThread(ext->handle); - if (cnt <= 1) break; - } - ext->start_pending = 0; - } - } - } - - log_error("ReleaseSemaphore", SetEvent(debug_state->debug_event_inp)); -} - -static void early_debug_event_handler(void * x) { - DebugEvent * debug_event = (DebugEvent *)x; - DebugState * debug_state = debug_event->debug_state; - DEBUG_EVENT * win32_event = &debug_event->win32_event; - - if (win32_event->dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { - trace(LOG_WAITPID, "%s, process %d, thread %d, code %#lx", - win32_debug_event_name(win32_event->dwDebugEventCode), - win32_event->dwProcessId, win32_event->dwThreadId, - win32_event->u.Exception.ExceptionRecord.ExceptionCode); - } - else { - trace(LOG_WAITPID, "%s, process %d, thread %d", - win32_debug_event_name(win32_event->dwDebugEventCode), - win32_event->dwProcessId, win32_event->dwThreadId); - } - - debug_state->reporting_debug_event = 1; - debug_event_handler(debug_event); - post_event(continue_debug_event, debug_event); -} - -static void debugger_exit_handler(void * x) { - DebugState * debug_state = (DebugState *)x; - Context * prs = context_find_from_pid(debug_state->process_id, 0); - - trace(LOG_WAITPID, "debugger thread %d exited, debuggee pid %d", debug_state->debug_thread_id, debug_state->process_id); - - log_error("WaitForSingleObject", WaitForSingleObject(debug_state->debug_thread, INFINITE) != WAIT_FAILED); - log_error("CloseHandle", CloseHandle(debug_state->debug_thread)); - log_error("CloseHandle", CloseHandle(debug_state->debug_event_inp)); - log_error("CloseHandle", CloseHandle(debug_state->debug_event_out)); - - if (prs != NULL && !prs->exited) event_win32_context_exited(prs); - - loc_free(debug_state); -} - -static DWORD WINAPI debugger_thread_func(LPVOID x) { - DebugState * debug_state = (DebugState *)x; - DebugEvent debug_event; - - if (DebugActiveProcess(debug_state->process_id) == 0) { - debug_state->error = GetLastError(); - trace(LOG_ALWAYS, "Can't attach to a process: error %d", debug_state->error); - ReleaseSemaphore(debug_state->debug_thread_semaphore, 1, 0); - return 0; - } - - trace(LOG_WAITPID, "debugger thread %d started", GetCurrentThreadId()); - ReleaseSemaphore(debug_state->debug_thread_semaphore, 1, 0); - - memset(&debug_event, 0, sizeof(debug_event)); - - debug_event.debug_state = debug_state; - - for (;;) { - DEBUG_EVENT * win32_event = &debug_event.win32_event; - - memset(win32_event, 0, sizeof(DEBUG_EVENT)); - if (WaitForDebugEvent(win32_event, INFINITE) == 0) { - trace(LOG_ALWAYS, "WaitForDebugEvent() error %d", GetLastError()); - break; - } - - assert(debug_state->process_id == win32_event->dwProcessId); - debug_event.continue_status = DBG_CONTINUE; - - post_event(early_debug_event_handler, &debug_event); - WaitForSingleObject(debug_state->debug_event_inp, INFINITE); - if (ContinueDebugEvent(win32_event->dwProcessId, win32_event->dwThreadId, debug_event.continue_status) == 0) { - trace(LOG_ALWAYS, "Can't continue debug event: process %d, thread %d: error %d", - win32_event->dwProcessId, win32_event->dwThreadId, GetLastError()); - } - SetEvent(debug_state->debug_event_out); - WaitForSingleObject(debug_state->debug_event_inp, INFINITE); - - if (win32_event->dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break; - if (win32_event->dwDebugEventCode == RIP_EVENT) break; - } - - post_event(debugger_exit_handler, debug_state); - return 0; -} - -int context_attach(pid_t pid, ContextAttachCallBack * done, void * data, int mode) { - int error = 0; - DebugState * debug_state = (DebugState *)loc_alloc_zero(sizeof(DebugState)); - - assert(done != NULL); - assert((mode & CONTEXT_ATTACH_SELF) == 0); - debug_state->process_id = pid; - debug_state->attach_callback = done; - debug_state->attach_data = data; - - debug_state->debug_event_inp = CreateEvent(NULL, 0, 0, NULL); - if (debug_state->debug_event_inp == NULL) error = log_error("CreateEvent", 0); - - if (!error) { - debug_state->debug_event_out = CreateEvent(NULL, 0, 0, NULL); - if (debug_state->debug_event_out == NULL) error = log_error("CreateEvent", 0); - } - - if (!error) { - debug_state->debug_thread_semaphore = CreateSemaphore(NULL, 0, 1, NULL); - if (debug_state->debug_thread_semaphore == NULL) error = log_error("CreateSemaphore", 0); - } - - if (!error) { - debug_state->debug_thread = CreateThread(NULL, 0, debugger_thread_func, debug_state, 0, &debug_state->debug_thread_id); - if (debug_state->debug_thread == NULL) error = log_error("CreateThread", 0); - } - - if (!error) { - error = log_error("WaitForSingleObject", WaitForSingleObject(debug_state->debug_thread_semaphore, INFINITE) != WAIT_FAILED); - } - - if (!error) { - error = log_error("CloseHandle", CloseHandle(debug_state->debug_thread_semaphore)); - debug_state->debug_thread_semaphore = NULL; - } - - if (!error) { - error = set_win32_errno(debug_state->error); - } - - if (error) { - if (debug_state->debug_thread) log_error("WaitForSingleObject", WaitForSingleObject(debug_state->debug_thread, INFINITE) != WAIT_FAILED); - if (debug_state->debug_thread) log_error("CloseHandle", CloseHandle(debug_state->debug_thread)); - if (debug_state->debug_event_inp) log_error("CloseHandle", CloseHandle(debug_state->debug_event_inp)); - if (debug_state->debug_event_out) log_error("CloseHandle", CloseHandle(debug_state->debug_event_out)); - if (debug_state->debug_thread_semaphore) log_error("CloseHandle", CloseHandle(debug_state->debug_thread_semaphore)); - loc_free(debug_state); - errno = error; - return -1; - } - - add_waitpid_process(pid); - return 0; -} - -int context_has_state(Context * ctx) { - return ctx != NULL && ctx->parent != NULL; -} - -int context_stop(Context * ctx) { - ContextExtensionWin32 * ext = EXT(ctx); - DebugState * debug_state = EXT(ctx->parent)->debug_state; - - trace(LOG_CONTEXT, "context:%s suspending ctx %#lx id %s", - ctx->pending_intercept ? "" : " temporary", ctx, ctx->id); - assert(context_has_state(ctx)); - assert(!ctx->stopped); - assert(!ctx->exited); - if (debug_state->reporting_debug_event) { - debug_state->reporting_debug_event++; - } - else if (!debug_state->break_posted) { - context_lock(ctx->parent); - post_event_with_delay(break_process_event, ctx->parent, 10000); - debug_state->break_posted = 1; - } - ext->stop_pending = 1; - return 0; -} - -int context_continue(Context * ctx) { - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(ctx->stopped); - assert(!ctx->exited); - - trace(LOG_CONTEXT, "context: resuming ctx %#lx, id %s", ctx, ctx->id); - return win32_resume(ctx, 0); -} - -int context_single_step(Context * ctx) { - assert(is_dispatch_thread()); - assert(context_has_state(ctx)); - assert(ctx->stopped); - assert(!ctx->exited); - - trace(LOG_CONTEXT, "context: single step ctx %#lx, id %s", ctx, ctx->id); - return win32_resume(ctx, 1); -} - -static int context_terminate(Context * ctx) { - assert(is_dispatch_thread()); - assert(!context_has_state(ctx)); - assert(!ctx->exited); - - trace(LOG_CONTEXT, "context: terminate ctx %#lx, id %s", ctx, ctx->id); - return win32_terminate(ctx); -} - -int context_resume(Context * ctx, int mode, ContextAddress range_start, ContextAddress range_end) { - switch (mode) { - case RM_RESUME: - return context_continue(ctx); - case RM_STEP_INTO: - return context_single_step(ctx); - case RM_TERMINATE: - return context_terminate(ctx); - } - errno = ERR_UNSUPPORTED; - return -1; -} - -int context_can_resume(Context * ctx, int mode) { - switch (mode) { - case RM_RESUME: - return 1; - case RM_STEP_INTO: - return context_has_state(ctx); - case RM_TERMINATE: - return ctx != NULL && ctx->parent == NULL; - } - return 0; -} - -int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { - ContextExtensionWin32 * ext = EXT(ctx = ctx->mem); - SIZE_T bcnt = 0; - - trace(LOG_CONTEXT, - "context: read memory ctx %#lx, id %s, address %#lx, size %d", - ctx, ctx->id, address, (int)size); - assert(is_dispatch_thread()); - mem_err_info.error = 0; - if (ReadProcessMemory(ext->handle, (LPCVOID)address, buf, size, &bcnt) == 0 || bcnt != size) { - DWORD error = GetLastError(); - size_t size_next = size; - size_t size_error = 1; - /* Check if a smaller block is readable */ - while (bcnt == 0) { - if (size_next <= 1) break; - size_next /= 2; - ReadProcessMemory(ext->handle, (LPCVOID)address, buf, size_next, &bcnt); - } - /* Find upper bound of the readable memory */ - while (bcnt < size) { - if (!ReadProcessMemory(ext->handle, (LPCVOID)(address + bcnt), - (char *)buf + bcnt, 1, NULL)) { - error = GetLastError(); - break; - } - bcnt++; - } - if (check_breakpoints_on_memory_read(ctx, address, buf, bcnt) < 0) return -1; - /* Find number of unreadable bytes */ - while (size_error < 0x100 && bcnt + size_error < size) { - if (ReadProcessMemory(ext->handle, (LPCVOID)(address + bcnt + size_error), - (char *)buf + bcnt + size_error, 1, NULL)) break; - if (error != GetLastError()) break; - size_error++; - } - mem_err_info.error = set_win32_errno(error); - mem_err_info.size_valid = bcnt; - mem_err_info.size_error = size_error; - return -1; - } - return check_breakpoints_on_memory_read(ctx, address, buf, size); -} - -int context_write_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { - ContextExtensionWin32 * ext = EXT(ctx = ctx->mem); - SIZE_T bcnt = 0; - - trace(LOG_CONTEXT, - "context: write memory ctx %#lx, id %s, address %#lx, size %d", - ctx, ctx->id, address, (int)size); - assert(is_dispatch_thread()); - mem_err_info.error = 0; - if (check_breakpoints_on_memory_write(ctx, address, buf, size) < 0) return -1; - if (WriteProcessMemory(ext->handle, (LPVOID)address, buf, size, &bcnt) == 0 || bcnt != size) { - mem_err_info.error = set_win32_errno(GetLastError()); - mem_err_info.size_valid = bcnt; - mem_err_info.size_error = 1; - } - if (FlushInstructionCache(ext->handle, (LPCVOID)address, bcnt) == 0) { - mem_err_info.error = 0; - errno = log_error("FlushInstructionCache", 0); - return -1; - } - if (mem_err_info.error) { - errno = mem_err_info.error; - return -1; - } - return 0; -} - -#if ENABLE_ExtendedMemoryErrorReports -int context_get_mem_error_info(MemoryErrorInfo * info) { - if (mem_err_info.error == 0) { - set_errno(ERR_OTHER, "Extended memory error info not available"); - return -1; - } - *info = mem_err_info; - return 0; -} -#endif - -int context_write_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) { - ContextExtensionWin32 * ext = EXT(ctx); - - assert(is_dispatch_thread()); - assert(offs + size <= def->size); - - get_registers(ctx); - if (ext->regs_error) { - set_error_report_errno(ext->regs_error); - return -1; - } - memcpy((uint8_t *)ext->regs + def->offset + offs, buf, size); - ext->regs_dirty = 1; - return 0; -} - -int context_read_reg(Context * ctx, RegisterDefinition * def, unsigned offs, unsigned size, void * buf) { - ContextExtensionWin32 * ext = EXT(ctx); - - assert(is_dispatch_thread()); - assert(offs + size <= def->size); - - get_registers(ctx); - if (ext->regs_error) { - set_error_report_errno(ext->regs_error); - return -1; - } - memcpy(buf, (uint8_t *)ext->regs + def->offset + offs, size); - return 0; -} - -unsigned context_word_size(Context * ctx) { - return sizeof(void *); -} - -int context_get_canonical_addr(Context * ctx, ContextAddress addr, - Context ** canonical_ctx, ContextAddress * canonical_addr, - ContextAddress * block_addr, ContextAddress * block_size) { - /* Direct mapping, page size is irrelevant */ - ContextAddress page_size = 0x100000; - assert(is_dispatch_thread()); - *canonical_ctx = ctx->mem; - if (canonical_addr != NULL) *canonical_addr = addr; - if (block_addr != NULL) *block_addr = addr & ~(page_size - 1); - if (block_size != NULL) *block_size = page_size; - return 0; -} - -Context * context_get_group(Context * ctx, int group) { - static Context * cpu_group = NULL; - switch (group) { - case CONTEXT_GROUP_INTERCEPT: - return ctx; - case CONTEXT_GROUP_CPU: - if (cpu_group == NULL) cpu_group = create_context("CPU"); - return cpu_group; - } - return ctx->mem; -} - -int context_get_supported_bp_access_types(Context * ctx) { -#if USE_HW_BPS - if (ctx->mem == ctx) return - CTX_BP_ACCESS_DATA_READ | - CTX_BP_ACCESS_DATA_WRITE | - CTX_BP_ACCESS_INSTRUCTION | - CTX_BP_ACCESS_VIRTUAL; -#endif - return 0; -} - -int context_plant_breakpoint(ContextBreakpoint * bp) { -#if USE_HW_BPS - int i; - Context * ctx = bp->ctx; - assert(bp->access_types); - if (ctx->mem == ctx && (bp->access_types & CTX_BP_ACCESS_VIRTUAL)) { - ContextExtensionWin32 * ext = EXT(ctx); - DebugState * debug_state = ext->debug_state; - if (debug_state->ok_to_use_hw_bp && bp->length <= 8 && ((1u << bp->length) & 0x116u)) { - if (bp->access_types == (CTX_BP_ACCESS_INSTRUCTION | CTX_BP_ACCESS_VIRTUAL)) { - /* Don't use more then 2 HW slots for regular instruction breakpoints */ - int cnt = 0; - for (i = 0; i < MAX_HW_BPS; i++) { - assert(debug_state->hw_bps[i] != bp); - if (debug_state->hw_bps[i] == NULL) continue; - if ((debug_state->hw_bps[i]->access_types & CTX_BP_ACCESS_INSTRUCTION) == 0) continue; - cnt++; - } - if (cnt >= MAX_HW_BPS / 2) { - errno = ERR_UNSUPPORTED; - return -1; - } - } - else if (bp->access_types != (CTX_BP_ACCESS_DATA_WRITE | CTX_BP_ACCESS_VIRTUAL) && - bp->access_types != (CTX_BP_ACCESS_DATA_READ | CTX_BP_ACCESS_DATA_WRITE | CTX_BP_ACCESS_VIRTUAL)) { - errno = ERR_UNSUPPORTED; - return -1; - } - for (i = 0; i < MAX_HW_BPS; i++) { - if (debug_state->hw_bps[i] == NULL || debug_state->hw_bps[i] == bp) { - debug_state->hw_bps[i] = bp; - debug_state->hw_bps_generation++; - return 0; - } - } - } - } -#endif - errno = ERR_UNSUPPORTED; - return -1; -} - -int context_unplant_breakpoint(ContextBreakpoint * bp) { -#if USE_HW_BPS - int i; - Context * ctx = bp->ctx; - if (ctx->mem == ctx && !ctx->exited) { - ContextExtensionWin32 * ext = EXT(ctx); - DebugState * debug_state = ext->debug_state; - for (i = 0; i < MAX_HW_BPS; i++) { - if (debug_state->hw_bps[i] == bp) { - debug_state->hw_bps[i] = NULL; - debug_state->hw_bps_generation++; - } - } - } -#endif - return 0; -} - -#if defined(_MSC_VER) - -static void add_map_region(MemoryMap * map, DWORD64 addr, ULONG size, char * file) { - MemoryRegion * r = NULL; - if (map->region_cnt >= map->region_max) { - map->region_max += 8; - map->regions = (MemoryRegion *)loc_realloc(map->regions, sizeof(MemoryRegion) * map->region_max); - } - r = map->regions + map->region_cnt++; - memset(r, 0, sizeof(MemoryRegion)); - r->addr = (ContextAddress)addr; - r->size = (ContextAddress)size; - r->file_name = loc_strdup(file); -} - -static BOOL CALLBACK modules_callback(PCWSTR ModuleName, DWORD64 ModuleBase, ULONG ModuleSize, PVOID UserContext) { - MemoryMap * map = (MemoryMap *)UserContext; - static char * fnm_buf = NULL; - static int fnm_max = 0; - int fnm_len = 0; - int fnm_err = 0; - - if (fnm_buf == NULL) { - fnm_max = 256; - fnm_buf = (char *)loc_alloc(fnm_max); - } - for (;;) { - fnm_len = WideCharToMultiByte(CP_UTF8, 0, ModuleName, -1, fnm_buf, fnm_max - 1, NULL, NULL); - if (fnm_len != 0) break; - fnm_err = GetLastError(); - if (fnm_err != ERROR_INSUFFICIENT_BUFFER) { - set_win32_errno(fnm_err); - trace(LOG_ALWAYS, "Can't get module name: %s", errno_to_str(errno)); - return TRUE; - } - fnm_max *= 2; - fnm_buf = (char *)loc_realloc(fnm_buf, fnm_max); - } - fnm_buf[fnm_len] = 0; - - add_map_region(map, ModuleBase, ModuleSize, fnm_buf); - - return TRUE; -} - -#endif - -int context_get_memory_map(Context * ctx, MemoryMap * map) { - ctx = ctx->mem; - assert(!ctx->exited); -#if defined(_MSC_VER) - { - ContextExtensionWin32 * ext = EXT(ctx); - if (!EnumerateLoadedModulesW64(ext->handle, modules_callback, map)) { - set_win32_errno(GetLastError()); - return -1; - } - } -#endif - return 0; -} - -HANDLE get_context_handle(Context * ctx) { - ContextExtensionWin32 * ext = EXT(ctx); - return ext->handle; -} - -HANDLE get_context_file_handle(Context * ctx) { - ContextExtensionWin32 * ext = EXT(ctx); - return ext->debug_state->file_handle; -} - -DWORD64 get_context_base_address(Context * ctx) { - ContextExtensionWin32 * ext = EXT(ctx); - return ext->debug_state->base_address; -} - -HANDLE get_context_module_handle(Context * ctx) { - ContextExtensionWin32 * ext = EXT(ctx); - return ext->debug_state->module_handle; -} - -DWORD64 get_context_module_address(Context * ctx) { - ContextExtensionWin32 * ext = EXT(ctx); - return ext->debug_state->module_address; -} - -void add_context_exception_handler(ContextExceptionHandler * h) { - assert(exception_handler_cnt < MAX_EXCEPTION_HANDLERS); - exception_handlers[exception_handler_cnt++] = h; -} - -static void eventpoint_at_main(Context * ctx, void * args) { - suspend_debug_context(ctx); -} - -static void waitpid_listener(int pid, int exited, int exit_code, int signal, int event_code, int syscall, void * args) { -} - -void init_contexts_sys_dep(void) { - context_extension_offset = context_extension(sizeof(ContextExtensionWin32)); - ini_context_pid_hash(); - add_waitpid_listener(waitpid_listener, NULL); - memset(&os_version, 0, sizeof(os_version)); - os_version.dwOSVersionInfoSize = sizeof(os_version); - GetVersionEx((OSVERSIONINFO *)&os_version); - create_eventpoint("main", NULL, eventpoint_at_main, NULL); -} - -#endif /* if ENABLE_DebugContext */ -#endif /* WIN32 */ diff --git a/agent/tcf/system/Windows/context-win32.h b/agent/tcf/system/Windows/context-win32.h deleted file mode 100644 index 8c49751e..00000000 --- a/agent/tcf/system/Windows/context-win32.h +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This module handles process/thread OS contexts and their state machine. - */ - -#ifndef D_context_win32 -#define D_context_win32 - -#include <tcf/config.h> -#include <tcf/framework/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); - -typedef int ContextExceptionHandler(Context *, EXCEPTION_DEBUG_INFO *); -extern void add_context_exception_handler(ContextExceptionHandler * h); - -#endif /* D_context_win32 */ diff --git a/agent/tcf/system/Windows/pthreads-win32.c b/agent/tcf/system/Windows/pthreads-win32.c deleted file mode 100644 index e6118798..00000000 --- a/agent/tcf/system/Windows/pthreads-win32.c +++ /dev/null @@ -1,311 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2011 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -#include <tcf/config.h> - -#if defined(WIN32) && !defined(DISABLE_PTHREADS_WIN32) - -#include <assert.h> -#include <tcf/framework/myalloc.h> -#include <tcf/framework/errors.h> -#include <tcf/system/Windows/pthreads-win32.h> - -/********************************************************************* - Support of pthreads on Windows is implemented according to - recommendations from the paper: - - Strategies for Implementing POSIX Condition Variables on Win32 - C++ Report, SIGS, Vol. 10, No. 5, June, 1998 - - Douglas C. Schmidt and Irfan Pyarali - Department of Computer Science - Washington University, St. Louis, Missouri -**********************************************************************/ - -/* TODO: POSIX pthread functions don't set errno */ - -typedef struct { - int waiters_count; - CRITICAL_SECTION waiters_count_lock; - HANDLE sema; - HANDLE waiters_done; - size_t was_broadcast; -} PThreadCond; - -int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr) { - assert(attr == NULL); - *mutex = (pthread_mutex_t)CreateMutex(NULL, FALSE, NULL); - if (*mutex == NULL) return set_win32_errno(GetLastError()); - return 0; -} - -int pthread_mutex_lock(pthread_mutex_t * mutex) { - assert(mutex != NULL); - assert(*mutex != NULL); - if (WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED) return set_win32_errno(GetLastError()); - return 0; -} - -int pthread_mutex_unlock(pthread_mutex_t * mutex) { - assert(mutex != NULL); - assert(*mutex != NULL); - if (!ReleaseMutex(*mutex)) return set_win32_errno(GetLastError()); - return 0; -} - -int pthread_mutex_destroy(pthread_mutex_t *mutex) { - assert(mutex != NULL); - assert(*mutex != NULL); - if (!CloseHandle(*mutex)) return set_win32_errno(GetLastError()); - return 0; -} - -int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr) { - PThreadCond * p = (PThreadCond *)loc_alloc_zero(sizeof(PThreadCond)); - assert(attr == NULL); - p->waiters_count = 0; - p->was_broadcast = 0; - p->sema = CreateSemaphore(NULL, 0, 0x7fffffff, NULL); - if (p->sema == NULL) return set_win32_errno(GetLastError()); - InitializeCriticalSection(&p->waiters_count_lock); - p->waiters_done = CreateEvent(NULL, FALSE, FALSE, NULL); - if (p->waiters_done == NULL) return set_win32_errno(GetLastError()); - *cond = (pthread_cond_t)p; - return 0; -} - -int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) { - DWORD res = 0; - int last_waiter = 0; - PThreadCond * p = (PThreadCond *)*cond; - - EnterCriticalSection(&p->waiters_count_lock); - p->waiters_count++; - LeaveCriticalSection(&p->waiters_count_lock); - - /* This call atomically releases the mutex and waits on the */ - /* semaphore until <pthread_cond_signal> or <pthread_cond_broadcast> */ - /* are called by another thread. */ - res = SignalObjectAndWait(*mutex, p->sema, INFINITE, FALSE); - if (res == WAIT_FAILED) return set_win32_errno(GetLastError()); - - /* Re-acquire lock to avoid race conditions. */ - EnterCriticalSection(&p->waiters_count_lock); - - /* We're no longer waiting... */ - p->waiters_count--; - - /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */ - last_waiter = p->was_broadcast && p->waiters_count == 0; - - LeaveCriticalSection(&p->waiters_count_lock); - - /* If we're the last waiter thread during this particular broadcast */ - /* then let all the other threads proceed. */ - if (last_waiter) { - /* This call atomically signals the <waiters_done_> event and waits until */ - /* it can acquire the <mutex>. This is required to ensure fairness. */ - DWORD err = SignalObjectAndWait(p->waiters_done, *mutex, INFINITE, FALSE); - if (err == WAIT_FAILED) return set_win32_errno(GetLastError()); - } - else { - /* Always regain the external mutex since that's the guarantee we */ - /* give to our callers. */ - DWORD err = WaitForSingleObject(*mutex, INFINITE); - if (err == WAIT_FAILED) return set_win32_errno(GetLastError()); - } - assert(res == WAIT_OBJECT_0); - return 0; -} - -int pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec * abstime) { - DWORD res = 0; - int last_waiter = 0; - PThreadCond * p = (PThreadCond *)*cond; - DWORD timeout = 0; - struct timespec timenow; - - if (clock_gettime(CLOCK_REALTIME, &timenow)) return errno; - if (abstime->tv_sec < timenow.tv_sec) return ETIMEDOUT; - if (abstime->tv_sec == timenow.tv_sec) { - if (abstime->tv_nsec <= timenow.tv_nsec) return ETIMEDOUT; - } - timeout = (DWORD)((abstime->tv_sec - timenow.tv_sec) * 1000 + (abstime->tv_nsec - timenow.tv_nsec) / 1000000 + 5); - - EnterCriticalSection(&p->waiters_count_lock); - p->waiters_count++; - LeaveCriticalSection(&p->waiters_count_lock); - - /* This call atomically releases the mutex and waits on the */ - /* semaphore until <pthread_cond_signal> or <pthread_cond_broadcast> */ - /* are called by another thread. */ - res = SignalObjectAndWait(*mutex, p->sema, timeout, FALSE); - if (res == WAIT_FAILED) return set_win32_errno(GetLastError()); - - /* Re-acquire lock to avoid race conditions. */ - EnterCriticalSection(&p->waiters_count_lock); - - /* We're no longer waiting... */ - p->waiters_count--; - - /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */ - last_waiter = p->was_broadcast && p->waiters_count == 0; - - LeaveCriticalSection(&p->waiters_count_lock); - - /* If we're the last waiter thread during this particular broadcast */ - /* then let all the other threads proceed. */ - if (last_waiter) { - /* This call atomically signals the <waiters_done> event and waits until */ - /* it can acquire the <mutex>. This is required to ensure fairness. */ - DWORD err = SignalObjectAndWait(p->waiters_done, *mutex, INFINITE, FALSE); - if (err == WAIT_FAILED) return set_win32_errno(GetLastError()); - } - else { - /* Always regain the external mutex since that's the guarantee we */ - /* give to our callers. */ - DWORD err = WaitForSingleObject(*mutex, INFINITE); - if (err == WAIT_FAILED) return set_win32_errno(GetLastError()); - } - - if (res == WAIT_TIMEOUT) return errno = ETIMEDOUT; - assert(res == WAIT_OBJECT_0); - return 0; -} - -int pthread_cond_signal(pthread_cond_t * cond) { - int have_waiters = 0; - PThreadCond * p = (PThreadCond *)*cond; - - EnterCriticalSection(&p->waiters_count_lock); - have_waiters = p->waiters_count > 0; - LeaveCriticalSection(&p->waiters_count_lock); - - /* If there aren't any waiters, then this is a no-op. */ - if (have_waiters) { - if (!ReleaseSemaphore(p->sema, 1, 0)) return set_win32_errno(GetLastError()); - } - return 0; -} - -int pthread_cond_broadcast(pthread_cond_t * cond) { - int have_waiters = 0; - PThreadCond * p = (PThreadCond *)*cond; - - /* This is needed to ensure that <waiters_count_> and <was_broadcast_> are */ - /* consistent relative to each other. */ - EnterCriticalSection(&p->waiters_count_lock); - - if (p->waiters_count > 0) { - /* We are broadcasting, even if there is just one waiter... */ - /* Record that we are broadcasting, which helps optimize */ - /* <pthread_cond_wait> for the non-broadcast case. */ - p->was_broadcast = 1; - have_waiters = 1; - } - - if (have_waiters) { - /* Wake up all the waiters atomically. */ - if (!ReleaseSemaphore(p->sema, p->waiters_count, 0)) return set_win32_errno(GetLastError()); - - LeaveCriticalSection(&p->waiters_count_lock); - - /* Wait for all the awakened threads to acquire the counting */ - /* semaphore. */ - if (WaitForSingleObject(p->waiters_done, INFINITE) == WAIT_FAILED) return set_win32_errno(GetLastError()); - /* This assignment is okay, even without the <waiters_count_lock_> held */ - /* because no other waiter threads can wake up to access it. */ - p->was_broadcast = 0; - } - else { - LeaveCriticalSection(&p->waiters_count_lock); - } - return 0; -} - -int pthread_cond_destroy(pthread_cond_t * cond) { - PThreadCond * p = (PThreadCond *)*cond; - - DeleteCriticalSection(&p->waiters_count_lock); - if (!CloseHandle(p->sema)) return set_win32_errno(GetLastError()); - if (!CloseHandle(p->waiters_done)) return set_win32_errno(GetLastError()); - - loc_free(p); - *cond = NULL; - return 0; -} - -typedef struct ThreadArgs ThreadArgs; - -struct ThreadArgs { - void * (*start)(void *); - void * args; -}; - -static void start_thread(void * x) { - ThreadArgs a = *(ThreadArgs *)x; - - loc_free(x); - ExitThread((DWORD)a.start(a.args)); -} - -int pthread_create(pthread_t * res, const pthread_attr_t * attr, - void * (*start)(void *), void * args) { - HANDLE thread = NULL; - DWORD thread_id = 0; - ThreadArgs * a = (ThreadArgs *)loc_alloc(sizeof(ThreadArgs)); - - a->start = start; - a->args = args; - thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)start_thread, a, 0, &thread_id); - if (thread == NULL) { - int err = set_win32_errno(GetLastError()); - loc_free(a); - return errno = err; - } - if (!CloseHandle(thread)) return set_win32_errno(GetLastError()); - *res = (pthread_t)thread_id; - return 0; -} - -int pthread_join(pthread_t thread_id, void ** value_ptr) { - int error = 0; - HANDLE thread = OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, FALSE, (DWORD)thread_id); - - if (thread == NULL) return set_win32_errno(GetLastError()); - if (WaitForSingleObject(thread, INFINITE) == WAIT_FAILED) error = set_win32_errno(GetLastError()); - if (!error && value_ptr != NULL && !GetExitCodeThread(thread, (LPDWORD)value_ptr)) error = set_win32_errno(GetLastError()); - if (!CloseHandle(thread) && !error) error = set_win32_errno(GetLastError()); - return error; -} - -int pthread_detach(pthread_t thread_id) { - return 0; -} - -pthread_t pthread_self(void) { - return (pthread_t)GetCurrentThreadId(); -} - -int pthread_equal(pthread_t thread1, pthread_t thread2) { - return thread1 == thread2; -} - -int pthread_attr_init(pthread_attr_t * attr) { - *attr = NULL; - return 0; -} - -#endif diff --git a/agent/tcf/system/Windows/pthreads-win32.h b/agent/tcf/system/Windows/pthreads-win32.h deleted file mode 100644 index e98874e0..00000000 --- a/agent/tcf/system/Windows/pthreads-win32.h +++ /dev/null @@ -1,56 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * PThreads emulation for Windows. - */ - -#ifndef D_pthreads_win32 -#define D_pthreads_win32 - -#if defined(__CYGWIN__) -# include <cygwin/types.h> -#else -typedef struct pthread_struct * pthread_t; -typedef struct pthread_attr_struct * pthread_attr_t; -typedef struct pthread_mutex_struct * pthread_mutex_t; -typedef struct pthread_cond_struct * pthread_cond_t; -typedef struct pthread_mutexattr_struct * pthread_mutexattr_t; -typedef struct pthread_condattr_struct * pthread_condattr_t; -#endif - -extern int pthread_attr_init(pthread_attr_t * attr); - -extern int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr); -extern int pthread_cond_signal(pthread_cond_t * cond); -extern int pthread_cond_broadcast(pthread_cond_t * cond); -extern int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex); -extern int pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, - const struct timespec * abstime); -extern int pthread_cond_destroy(pthread_cond_t * cond); - -extern int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr); -extern int pthread_mutex_lock(pthread_mutex_t * mutex); -extern int pthread_mutex_unlock(pthread_mutex_t * mutex); -extern int pthread_mutex_destroy(pthread_mutex_t *mutex); - -extern pthread_t pthread_self(void); -extern int pthread_create(pthread_t * thread, const pthread_attr_t * attr, - void * (*start_routine)(void *), void * arg); -extern int pthread_join(pthread_t thread, void **value_ptr); -extern int pthread_detach(pthread_t thread); -extern int pthread_equal(pthread_t thread1, pthread_t thread2); - -#endif /* D_pthreads_win32 */ diff --git a/agent/tcf/system/Windows/regset.h b/agent/tcf/system/Windows/regset.h deleted file mode 100644 index fb4eab83..00000000 --- a/agent/tcf/system/Windows/regset.h +++ /dev/null @@ -1,23 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2010 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This header file provides definition of REG_SET - a structure that can - * hold values of target CPU registers. - */ - -#if defined(WIN32) - typedef CONTEXT REG_SET; -#endif diff --git a/agent/tcf/system/Windows/windbgcache.c b/agent/tcf/system/Windows/windbgcache.c deleted file mode 100644 index e6f094f2..00000000 --- a/agent/tcf/system/Windows/windbgcache.c +++ /dev/null @@ -1,405 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This module provides access to Windows Portable Executable debug information. - * Current implementation delegates all its job to DBGHELP.DLL. - */ - -#include <tcf/config.h> - -#if defined(WIN32) && !ENABLE_ELF -# define ENABLE_PE_Symbols ((SERVICE_LineNumbers && !ENABLE_LineNumbersProxy) || (SERVICE_Symbols && !ENABLE_SymbolsProxy)) -# define ENABLE_EnumerateModules (SERVICE_MemoryMap && !ENABLE_ContextProxy) -#else -# define ENABLE_PE_Symbols 0 -# define ENABLE_EnumerateModules 0 -#endif - -#if ENABLE_PE_Symbols || ENABLE_EnumerateModules - -#include <assert.h> -#include <stdio.h> -#include <wchar.h> -#include <tcf/system/Windows/windbgcache.h> -#include <tcf/system/Windows/context-win32.h> -#include <tcf/framework/trace.h> -#include <tcf/framework/myalloc.h> -#include <tcf/services/memorymap.h> - -static HINSTANCE dbghelp_dll = NULL; - -#define SYM_SEARCH_PATH "" -/* Path could contain "http://msdl.microsoft.com/download/symbols", - but access to Microsoft debug info server is too slow, - and dbghelp.dll caching is inadequate -*/ - -static wchar_t * pathes[] = { - L"%\\Debugging Tools for Windows (x86)\\dbghelp.dll", - L"%\\Debugging Tools for Windows\\dbghelp.dll", - L".\\dbghelp.dll", - L"dbghelp.dll", - NULL -}; - -#if ENABLE_PE_Symbols - -static void event_context_created(Context * ctx, void * client_data) { - HANDLE handle = NULL; - if (ctx->parent != NULL) return; - handle = get_context_handle(ctx); - assert(handle != NULL); - assert(ctx->mem == ctx); - if (!SymInitialize(handle, SYM_SEARCH_PATH, FALSE)) { - set_win32_errno(GetLastError()); - trace(LOG_ALWAYS, "SymInitialize() error: %s", errno_to_str(errno)); - } - if (!SymLoadModule64(handle, get_context_file_handle(ctx), - NULL, NULL, get_context_base_address(ctx), 0)) { - set_win32_errno(GetLastError()); - trace(LOG_ALWAYS, "SymLoadModule64() error: %s", errno_to_str(errno)); - } -} - -static void event_context_exited(Context * ctx, void * client_data) { - HANDLE handle = NULL; - if (ctx->parent != NULL) return; - handle = get_context_handle(ctx); - assert(handle != NULL); - assert(ctx->mem == ctx); - if (!SymUnloadModule64(handle, get_context_base_address(ctx))) { - set_win32_errno(GetLastError()); - trace(LOG_ALWAYS, "SymUnloadModule64(0x%Ix,0x%I64x) (context exit) error: %s", - handle, get_context_base_address(ctx), errno_to_str(errno)); - } - if (!SymCleanup(handle)) { - set_win32_errno(GetLastError()); - trace(LOG_ALWAYS, "SymCleanup() error: %s", errno_to_str(errno)); - } -} - -static void event_module_loaded(Context * ctx, void * client_data) { - HANDLE handle = get_context_handle(ctx); - assert(handle != NULL); - assert(ctx->mem == ctx); - if (!SymLoadModule64(handle, get_context_module_handle(ctx), - NULL, NULL, get_context_module_address(ctx), 0)) { - set_win32_errno(GetLastError()); - trace(LOG_ALWAYS, "SymLoadModule64() error: %s", errno_to_str(errno)); - } -} - -static void event_module_unloaded(Context * ctx, void * client_data) { - HANDLE handle = get_context_handle(ctx); - assert(handle != NULL); - assert(ctx->mem == ctx); - if (!SymUnloadModule64(handle, get_context_module_address(ctx))) { - DWORD err = GetLastError(); - /* Workaround: - * On Windows 7 first few UNLOAD_DLL_DEBUG_EVENT come without matching LOAD_DLL_DEBUG_EVENT, - * SymUnloadModule64() returns error 0x57 "The parameter is incorrect" for such events. - * No proper fix is found for this issue. */ - if (err != 0x57) { - int n = set_win32_errno(err); - trace(LOG_ALWAYS, "SymUnloadModule64(0x%Ix,0x%I64x) (unload DLL) error: %s", - handle, get_context_module_address(ctx), errno_to_str(n)); - } - } -} - -static ContextEventListener ctx_listener = { - event_context_created, - event_context_exited, -}; - -static MemoryMapEventListener map_listener = { - event_module_loaded, - NULL, - event_module_unloaded -}; - -#endif - -static void CheckDLLVersion(void) { - DWORD handle = 0; - WCHAR fnm[_MAX_PATH]; - BYTE * version_info = NULL; - DWORD size = GetModuleFileNameW(dbghelp_dll, fnm, _MAX_PATH); - fnm[size] = 0; - size = GetFileVersionInfoSizeW(fnm, &handle); - version_info = (BYTE *)loc_alloc_zero(size); - if (!GetFileVersionInfoW(fnm, handle, size, version_info)) { - trace(LOG_ALWAYS, "Cannot get DBGHELP.DLL version info: %s", - errno_to_str(set_win32_errno(GetLastError()))); - } - else { - UINT vsfi_len = 0; - VS_FIXEDFILEINFO * vsfi = NULL; - VerQueryValueW(version_info, L"\\", (void**)&vsfi, &vsfi_len); - if (HIWORD(vsfi->dwFileVersionMS) < 6 || HIWORD(vsfi->dwFileVersionMS) == 6 && LOWORD(vsfi->dwFileVersionMS) < 9) { - char path[_MAX_PATH * 2]; - trace(LOG_ALWAYS, "DBGHELP.DLL version is less then 6.9 - debug services might not work properly"); - if (WideCharToMultiByte(CP_UTF8, 0, fnm, -1, path, sizeof(path), NULL, NULL)) { - trace(LOG_ALWAYS, "%s", path); - } - trace(LOG_ALWAYS, "DBGHELP.DLL version %d.%d.%d.%d", - HIWORD(vsfi->dwFileVersionMS), LOWORD(vsfi->dwFileVersionMS), - HIWORD(vsfi->dwFileVersionLS), LOWORD(vsfi->dwFileVersionLS)); - } - } - loc_free(version_info); -} - -static FARPROC GetProc(char * name) { - if (dbghelp_dll == NULL) { - wchar_t ** p = pathes; - while (dbghelp_dll == NULL && *p != NULL) { - if (**p == '%') { - HKEY key; - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion", - 0, KEY_READ, &key) == ERROR_SUCCESS) { - wchar_t buf[FILE_PATH_SIZE]; - DWORD size = sizeof(buf); - memset(buf, 0, sizeof(buf)); - if (RegQueryValueExW(key, - L"ProgramFilesDir (x86)", - NULL, NULL, (LPBYTE)buf, &size) == ERROR_SUCCESS) { - wcsncat(buf, *p + 1, FILE_PATH_SIZE - size / sizeof(wchar_t)); - dbghelp_dll = LoadLibraryW(buf); - } - if (dbghelp_dll == NULL) { - size = sizeof(buf); - memset(buf, 0, sizeof(buf)); - if (RegQueryValueExW(key, - L"ProgramFilesDir", - NULL, NULL, (LPBYTE)buf, &size) == ERROR_SUCCESS) { - wcsncat(buf, *p + 1, FILE_PATH_SIZE - size / sizeof(wchar_t)); - dbghelp_dll = LoadLibraryW(buf); - } - } - RegCloseKey(key); - } - } - else { - dbghelp_dll = LoadLibraryW(*p); - } - p++; - } - if (dbghelp_dll == NULL) { - assert(GetLastError() != 0); - return NULL; - } - CheckDLLVersion(); -#if ENABLE_PE_Symbols - add_context_event_listener(&ctx_listener, NULL); - add_memory_map_event_listener(&map_listener, NULL); -#endif - } - return GetProcAddress(dbghelp_dll, name); -} - -#endif - -#if ENABLE_PE_Symbols - -BOOL SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE, PCSTR, BOOL); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymInitialize"); - if (proc == NULL) return 0; - } - return proc(hProcess, UserSearchPath, fInvadeProcess); -} - -DWORD SymGetOptions(void) { - typedef DWORD (FAR WINAPI * ProcType)(void); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymGetOptions"); - if (proc == NULL) return 0; - } - return proc(); -} - -BOOL SymSetOptions(DWORD Options) { - typedef BOOL (FAR WINAPI * ProcType)(DWORD); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymSetOptions"); - if (proc == NULL) return 0; - } - return proc(Options); -} - -BOOL SymGetLineFromName(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName, DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINE Line) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE, PCSTR, PCSTR, DWORD, PLONG, PIMAGEHLP_LINE); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymGetLineFromName"); - if (proc == NULL) return 0; - } - return proc(hProcess, ModuleName, FileName, dwLineNumber, plDisplacement, Line); -} - -BOOL SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE Line) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymGetLineFromAddr"); - if (proc == NULL) return 0; - } - return proc(hProcess, dwAddr, pdwDisplacement, Line); -} - -BOOL SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE, PIMAGEHLP_LINE); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymGetLineNext"); - if (proc == NULL) return 0; - } - assert(Line != NULL); - assert(Line->Address != 0); - return proc(hProcess, Line); -} - -BOOL SymGetTypeInfo(HANDLE hProcess, DWORD64 ModBase, ULONG TypeId, IMAGEHLP_SYMBOL_TYPE_INFO GetType, PVOID pInfo) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE, DWORD64, ULONG, IMAGEHLP_SYMBOL_TYPE_INFO, PVOID); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymGetTypeInfo"); - if (proc == NULL) return 0; - } - return proc(hProcess, ModBase, TypeId, GetType, pInfo); -} - -BOOL SymFromIndex(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index, PSYMBOL_INFO Symbol) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE, ULONG64, DWORD, PSYMBOL_INFO); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymFromIndex"); - if (proc == NULL) return 0; - } - return proc(hProcess, BaseOfDll, Index, Symbol); -} - -BOOL SymFromAddr(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymFromAddr"); - if (proc == NULL) return 0; - } - return proc(hProcess, Address, Displacement, Symbol); -} - -BOOL SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame, PIMAGEHLP_CONTEXT Context) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE, PIMAGEHLP_STACK_FRAME, PIMAGEHLP_CONTEXT); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymSetContext"); - if (proc == NULL) return 0; - } - return proc(hProcess, StackFrame, Context); -} - -BOOL SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE, PCSTR, PSYMBOL_INFO); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymFromName"); - if (proc == NULL) return 0; - } - return proc(hProcess, Name, Symbol); -} - -BOOL SymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask, PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, PVOID UserContext) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE, ULONG64, PCSTR, PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymEnumSymbols"); - if (proc == NULL) return 0; - } - return proc(hProcess, BaseOfDll, Mask, EnumSymbolsCallback, UserContext); -} - -BOOL SymGetTypeFromName(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Name, PSYMBOL_INFO Symbol) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE, ULONG64, PCSTR, PSYMBOL_INFO); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymGetTypeFromName"); - if (proc == NULL) return 0; - } - return proc(hProcess, BaseOfDll, Name, Symbol); -} - -DWORD64 SymGetModuleBase64(HANDLE hProcess, ULONG64 Address) { - typedef DWORD64 (FAR WINAPI * ProcType)(HANDLE, ULONG64); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymGetModuleBase64"); - if (proc == NULL) return 0; - } - return proc(hProcess, Address); -} - -BOOL SymLoadModule64(HANDLE hProcess, HANDLE hFile, PCSTR ImageName, PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE, HANDLE, PCSTR, PCSTR, DWORD64, DWORD); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymLoadModule64"); - if (proc == NULL) return 0; - } - return proc(hProcess, hFile, ImageName, ModuleName, BaseOfDll, SizeOfDll); -} - -BOOL SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE, DWORD64); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymUnloadModule64"); - if (proc == NULL) return 0; - } - return proc(hProcess, BaseOfDll); -} - -BOOL SymCleanup(HANDLE hProcess) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("SymCleanup"); - if (proc == NULL) return 0; - } - return proc(hProcess); -} - -#endif - -#if ENABLE_EnumerateModules - -BOOL LocEnumerateLoadedModulesW64(HANDLE hProcess, PENUMLOADED_MODULES_CALLBACKW64 Callback, PVOID UserContext) { - typedef BOOL (FAR WINAPI * ProcType)(HANDLE, PENUMLOADED_MODULES_CALLBACKW64, PVOID); - static ProcType proc = NULL; - if (proc == NULL) { - proc = (ProcType)GetProc("EnumerateLoadedModulesW64"); - if (proc == NULL) return 0; - } - return proc(hProcess, Callback, UserContext); -} - -#endif diff --git a/agent/tcf/system/Windows/windbgcache.h b/agent/tcf/system/Windows/windbgcache.h deleted file mode 100644 index 670cad7d..00000000 --- a/agent/tcf/system/Windows/windbgcache.h +++ /dev/null @@ -1,251 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This module provides access to Windows Portable Executable debug information. - */ - -#ifndef D_windbgcache -#define D_windbgcache - -#include <tcf/config.h> - -#if defined(WIN32) - -#if defined(__GNUC__) -# include <imagehlp.h> -#else -# define _NO_CVCONST_H -# include <dbghelp.h> -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(__GNUC__) -typedef enum _IMAGEHLP_SYMBOL_TYPE_INFO { - TI_GET_SYMTAG, - TI_GET_SYMNAME, - TI_GET_LENGTH, - TI_GET_TYPE, - TI_GET_TYPEID, - TI_GET_BASETYPE, - TI_GET_ARRAYINDEXTYPEID, - TI_FINDCHILDREN, - TI_GET_DATAKIND, - TI_GET_ADDRESSOFFSET, - TI_GET_OFFSET, - TI_GET_VALUE, - TI_GET_COUNT, - TI_GET_CHILDRENCOUNT, - TI_GET_BITPOSITION, - TI_GET_VIRTUALBASECLASS, - TI_GET_VIRTUALTABLESHAPEID, - TI_GET_VIRTUALBASEPOINTEROFFSET, - TI_GET_CLASSPARENTID, - TI_GET_NESTED, - TI_GET_SYMINDEX, - TI_GET_LEXICALPARENT, - TI_GET_ADDRESS, - TI_GET_THISADJUST, - TI_GET_UDTKIND, - TI_IS_EQUIV_TO, - TI_GET_CALLING_CONVENTION, - TI_IS_CLOSE_EQUIV_TO, - TI_GTIEX_REQS_VALID, - TI_GET_VIRTUALBASEOFFSET, - TI_GET_VIRTUALBASEDISPINDEX, - TI_GET_IS_REFERENCE, - IMAGEHLP_SYMBOL_TYPE_INFO_MAX, -} IMAGEHLP_SYMBOL_TYPE_INFO; - -typedef struct _TI_FINDCHILDREN_PARAMS { - ULONG Count; - ULONG Start; - ULONG ChildId[1]; -} TI_FINDCHILDREN_PARAMS; - -enum SymTagEnum { - SymTagNull, - SymTagExe, - SymTagCompiland, - SymTagCompilandDetails, - SymTagCompilandEnv, - SymTagFunction, - SymTagBlock, - SymTagData, - SymTagAnnotation, - SymTagLabel, - SymTagPublicSymbol, - SymTagUDT, - SymTagEnum, - SymTagFunctionType, - SymTagPointerType, - SymTagArrayType, - SymTagBaseType, - SymTagTypedef, - SymTagBaseClass, - SymTagFriend, - SymTagFunctionArgType, - SymTagFuncDebugStart, - SymTagFuncDebugEnd, - SymTagUsingNamespace, - SymTagVTableShape, - SymTagVTable, - SymTagCustom, - SymTagThunk, - SymTagCustomType, - SymTagManagedType, - SymTagDimension, - SymTagMax -}; - -#define SYMFLAG_VALUEPRESENT 0x00000001 -#define SYMFLAG_REGISTER 0x00000008 -#define SYMFLAG_REGREL 0x00000010 -#define SYMFLAG_FRAMEREL 0x00000020 -#define SYMFLAG_PARAMETER 0x00000040 -#define SYMFLAG_LOCAL 0x00000080 -#define SYMFLAG_CONSTANT 0x00000100 -#define SYMFLAG_EXPORT 0x00000200 -#define SYMFLAG_FORWARDER 0x00000400 -#define SYMFLAG_FUNCTION 0x00000800 -#define SYMFLAG_VIRTUAL 0x00001000 -#define SYMFLAG_THUNK 0x00002000 -#define SYMFLAG_TLSREL 0x00004000 -#define SYMFLAG_SLOT 0x00008000 -#define SYMFLAG_ILREL 0x00010000 -#define SYMFLAG_METADATA 0x00020000 -#define SYMFLAG_CLR_TOKEN 0x00040000 - -typedef struct _SYMBOL_INFO { - ULONG SizeOfStruct; - ULONG TypeIndex; - ULONG64 Reserved[2]; - ULONG Index; - ULONG Size; - ULONG64 ModBase; - ULONG Flags; - ULONG64 Value; - ULONG64 Address; - ULONG Register; - ULONG Scope; - ULONG Tag; - ULONG NameLen; - ULONG MaxNameLen; - CHAR Name[1]; -} SYMBOL_INFO, *PSYMBOL_INFO; - -typedef struct _IMAGEHLP_STACK_FRAME { - ULONG64 InstructionOffset; - ULONG64 ReturnOffset; - ULONG64 FrameOffset; - ULONG64 StackOffset; - ULONG64 BackingStoreOffset; - ULONG64 FuncTableEntry; - ULONG64 Params[4]; - ULONG64 Reserved[5]; - BOOL Virtual; - ULONG Reserved2; -} IMAGEHLP_STACK_FRAME, *PIMAGEHLP_STACK_FRAME; - -typedef VOID IMAGEHLP_CONTEXT, *PIMAGEHLP_CONTEXT; - -typedef BOOL (CALLBACK *PSYM_ENUMERATESYMBOLS_CALLBACK)(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext); -typedef BOOL (CALLBACK *PENUMLOADED_MODULES_CALLBACKW64)(PCWSTR ModuleName, DWORD64 ModuleBase, ULONG ModuleSize, PVOID UserContext); - -#endif /* defined(__GNUC__) */ - -enum BasicType { - btNoType = 0, - btVoid = 1, - btChar = 2, - btWChar = 3, - btInt = 6, - btUInt = 7, - btFloat = 8, - btBCD = 9, - btBool = 10, - btLong = 13, - btULong = 14, - btCurrency = 25, - btDate = 26, - btVariant = 27, - btComplex = 28, - btBit = 29, - btBSTR = 30, - btHresult = 31 -}; - -enum DataKind { - DataIsUnknown, - DataIsLocal, - DataIsStaticLocal, - DataIsParam, - DataIsObjectPtr, - DataIsFileStatic, - DataIsGlobal, - DataIsMember, - DataIsStaticMember, - DataIsConstant -}; - -#define SymInitialize LocSymInitialize -#define SymGetOptions LocSymGetOptions -#define SymSetOptions LocSymSetOptions -#define SymGetLineFromName LocSymGetLineFromName -#define SymGetLineFromAddr LocSymGetLineFromAddr -#define SymGetLineNext LocSymGetLineNext -#define SymGetTypeInfo LocSymGetTypeInfo -#define SymFromIndex LocSymFromIndex -#define SymFromAddr LocSymFromAddr -#define SymSetContext LocSymSetContext -#define SymFromName LocSymFromName -#define SymEnumSymbols LocSymEnumSymbols -#define SymGetTypeFromName LocSymGetTypeFromName -#define SymGetModuleBase64 LocSymGetModuleBase64 -#define SymLoadModule64 LocSymLoadModule64 -#define SymUnloadModule64 LocSymUnloadModule64 -#define SymCleanup LocSymCleanup - -#define EnumerateLoadedModulesW64 LocEnumerateLoadedModulesW64 - -extern BOOL SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess); -extern DWORD SymGetOptions(void); -extern BOOL SymSetOptions(DWORD Options); -extern BOOL SymGetLineFromName(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName, DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINE Line); -extern BOOL SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE Line); -extern BOOL SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line); -extern BOOL SymGetTypeInfo(HANDLE hProcess, DWORD64 ModBase, ULONG TypeId, IMAGEHLP_SYMBOL_TYPE_INFO GetType, PVOID pInfo); -extern BOOL SymFromIndex(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index, PSYMBOL_INFO Symbol); -extern BOOL SymFromAddr(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol); -extern BOOL SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame, PIMAGEHLP_CONTEXT Context); -extern BOOL SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol); -extern BOOL SymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask, PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, PVOID UserContext); -extern BOOL SymGetTypeFromName(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Name, PSYMBOL_INFO Symbol); -extern DWORD64 SymGetModuleBase64(HANDLE hProcess, ULONG64 Address); -extern BOOL SymLoadModule64(HANDLE hProcess, HANDLE hFile, PCSTR ImageName, PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll); -extern BOOL SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll); -extern BOOL SymCleanup(HANDLE hProcess); - -extern BOOL LocEnumerateLoadedModulesW64(HANDLE hProcess, PENUMLOADED_MODULES_CALLBACKW64 Callback, PVOID UserContext); - -#ifdef __cplusplus -} -#endif - -#endif /* defined(WIN32) */ -#endif /* D_windbgcache */ diff --git a/agent/tcf/system/pid-hash.h b/agent/tcf/system/pid-hash.h deleted file mode 100644 index 4843ec8c..00000000 --- a/agent/tcf/system/pid-hash.h +++ /dev/null @@ -1,76 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v1.0 which accompany this distribution. - * The Eclipse Public License is available at - * http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * You may elect to redistribute this code under either of these licenses. - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -/* - * This is utility module that contains context PID hash table implementation. - * System specific debug context code can use this module to implement context lookup. - */ - -/* TODO: consider splitting the code into two files: some clients might want to reuse PID hash table for context_find_from_pid(), - * but use some other means to implement id2ctx() */ - -#define CONTEXT_PID_HASH_SIZE (32 * MEM_USAGE_FACTOR - 1) -#define CONTEXT_PID_HASH(PID) ((unsigned)(PID) % CONTEXT_PID_HASH_SIZE) - -static LINK context_pid_hash[CONTEXT_PID_HASH_SIZE]; -static size_t pid_hash_link_offset = 0; - -#define ctx2pidlink(ctx) ((LINK *)((char *)(ctx) + pid_hash_link_offset)) -#define pidlink2ctx(lnk) ((Context *)((char *)(lnk) - pid_hash_link_offset)) - -static void link_context(Context * ctx) { - LINK * h = context_pid_hash + CONTEXT_PID_HASH(EXT(ctx)->pid); - - assert(ctx->mem != NULL); - assert(EXT(ctx)->pid != 0); - assert(context_find_from_pid(EXT(ctx)->pid, ctx->parent != NULL) == NULL); - list_add_first(&ctx->ctxl, &context_root); - list_add_first(ctx2pidlink(ctx), h); - ctx->ref_count++; -} - -Context * context_find_from_pid(pid_t pid, int thread) { - LINK * h = context_pid_hash + CONTEXT_PID_HASH(pid); - LINK * l = h->next; - - assert(is_dispatch_thread()); - if (l == NULL) return NULL; - while (l != h) { - Context * ctx = pidlink2ctx(l); - if (EXT(ctx)->pid == pid && - (ctx->parent != NULL) == (thread != 0)) return ctx; - l = l->next; - } - return NULL; -} - -Context * id2ctx(const char * id) { - pid_t parent = 0; - pid_t pid = id2pid(id, &parent); - if (pid == 0) return NULL; - return context_find_from_pid(pid, parent != 0); -} - -static void pid_hash_context_exited(Context * ctx, void * args) { - list_remove(ctx2pidlink(ctx)); -} - -static void ini_context_pid_hash(void) { - int i; - static ContextEventListener l = { NULL, pid_hash_context_exited }; - for (i = 0; i < CONTEXT_PID_HASH_SIZE; i++) list_init(context_pid_hash + i); - pid_hash_link_offset = context_extension(sizeof(LINK)); - add_context_event_listener(&l, NULL); -} |