Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'agent/system/VxWorks/tcf/context-vxworks.c')
-rw-r--r--agent/system/VxWorks/tcf/context-vxworks.c782
1 files changed, 782 insertions, 0 deletions
diff --git a/agent/system/VxWorks/tcf/context-vxworks.c b/agent/system/VxWorks/tcf/context-vxworks.c
new file mode 100644
index 00000000..42283e24
--- /dev/null
+++ b/agent/system/VxWorks/tcf/context-vxworks.c
@@ -0,0 +1,782 @@
+/*******************************************************************************
+ * 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 <system/VxWorks/tcf/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/framework/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 */

Back to the top