/******************************************************************************* * 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 contains definitions of target CPU registers and stack frames. */ #include #if ENABLE_DebugContext #include #include #include #include #include #include #include #include #include #include int read_reg_value(StackFrame * frame, RegisterDefinition * reg_def, uint64_t * value) { uint8_t buf[8]; if (reg_def == NULL) { set_errno(ERR_INV_CONTEXT, "Invalid register"); return -1; } if (frame == NULL) { set_errno(ERR_INV_CONTEXT, "Invalid stack frame"); return -1; } if (reg_def->size > sizeof(buf)) { errno = ERR_INV_DATA_SIZE; return -1; } if (read_reg_bytes(frame, reg_def, 0, reg_def->size, buf) < 0) return -1; if (value != NULL) { size_t i; uint64_t n = 0; for (i = 0; i < reg_def->size; i++) { n = n << 8; n |= buf[reg_def->big_endian ? i : reg_def->size - i - 1]; } *value = n; } return 0; } int write_reg_value(StackFrame * frame, RegisterDefinition * reg_def, uint64_t value) { size_t i; uint8_t buf[8]; if (reg_def == NULL) { set_errno(ERR_INV_CONTEXT, "Invalid register"); return -1; } if (frame == NULL) { set_errno(ERR_INV_CONTEXT, "Invalid stack frame"); return -1; } if (reg_def->size > sizeof(buf)) { errno = ERR_INV_DATA_SIZE; return -1; } for (i = 0; i < reg_def->size; i++) { buf[reg_def->big_endian ? reg_def->size - i - 1 : i] = (uint8_t)value; value = value >> 8; } if (write_reg_bytes(frame, reg_def, 0, reg_def->size, buf) < 0) return -1; if (!frame->is_top_frame) frame->has_reg_data = 1; return 0; } ContextAddress get_regs_PC(Context * ctx) { size_t i; uint8_t buf[8]; ContextAddress pc = 0; RegisterDefinition * def = get_PC_definition(ctx); if (def == NULL) return 0; assert(def->size <= sizeof(buf)); if (context_read_reg(ctx, def, 0, def->size, buf) < 0) return 0; for (i = 0; i < def->size; i++) { pc = pc << 8; pc |= buf[def->big_endian ? i : def->size - i - 1]; } return pc; } void set_regs_PC(Context * ctx, ContextAddress pc) { size_t i; uint8_t buf[8]; RegisterDefinition * def = get_PC_definition(ctx); if (def == NULL) return; assert(def->size <= sizeof(buf)); for (i = 0; i < def->size; i++) { buf[def->big_endian ? def->size - i - 1 : i] = (uint8_t)pc; pc = pc >> 8; } context_write_reg(ctx, def, 0, def->size, buf); } int id2frame(const char * id, Context ** ctx, int * frame) { int f = 0; Context * c = NULL; if (*id++ != 'F') { errno = ERR_INV_CONTEXT; return -1; } if (*id++ != 'P') { errno = ERR_INV_CONTEXT; return -1; } while (*id != '.') { if (*id < '0' || *id > '9') { errno = ERR_INV_CONTEXT; return -1; } f = f * 10 + (*id++ - '0'); } id++; c = id2ctx(id); if (c == NULL) { errno = ERR_INV_CONTEXT; return -1; } *ctx = c; *frame = f; return 0; } const char * frame2id(Context * ctx, int frame) { static char id[256]; assert(frame >= 0); if (!context_has_state(ctx)) { errno = ERR_INV_CONTEXT; return NULL; } snprintf(id, sizeof(id), "FP%d.%s", frame, ctx->id); return id; } const char * register2id(Context * ctx, int frame, RegisterDefinition * reg) { static char id[256]; RegisterDefinition * defs = get_reg_definitions(ctx); if (frame < 0) { snprintf(id, sizeof(id), "R%d.%s", (int)(reg - defs), ctx->id); } else { snprintf(id, sizeof(id), "R%d@%d.%s", (int)(reg - defs), frame, ctx->id); } return id; } int id2register(const char * id, Context ** ctx, int * frame, RegisterDefinition ** reg_def) { int r = 0; *ctx = NULL; *frame = STACK_TOP_FRAME; *reg_def = NULL; if (*id++ != 'R') { errno = ERR_INV_CONTEXT; return -1; } while (*id != '.' && *id != '@') { if (*id >= '0' && *id <= '9') { r = r * 10 + (*id++ - '0'); } else { errno = ERR_INV_CONTEXT; return -1; } } if (*id == '@') { int n = 0; id++; while (*id != '.') { if (*id >= '0' && *id <= '9') { n = n * 10 + (*id++ - '0'); } else { errno = ERR_INV_CONTEXT; return -1; } } *frame = n; } id++; *ctx = id2ctx(id); if (*ctx == NULL) { errno = ERR_INV_CONTEXT; return -1; } if ((*ctx)->exited) { errno = ERR_ALREADY_EXITED; return -1; } *reg_def = get_reg_definitions(*ctx) + r; return 0; } static void stack_trace_error(void) { str_exception(ERR_OTHER, "Invalid stack trace program"); } uint64_t evaluate_stack_trace_commands(Context * ctx, StackFrame * frame, StackTracingCommandSequence * cmds) { static uint64_t * stk = NULL; static int stk_size = 0; int i; int stk_pos = 0; for (i = 0; i < cmds->cmds_cnt; i++) { StackTracingCommand * cmd = cmds->cmds + i; if (stk_pos >= stk_size) { stk_size += 4; stk = (uint64_t *)loc_realloc(stk, sizeof(uint64_t) * stk_size); } switch (cmd->cmd) { case SFT_CMD_NUMBER: stk[stk_pos++] = cmd->num; break; case SFT_CMD_REGISTER: if (read_reg_value(frame, cmd->reg, stk + stk_pos) < 0) exception(errno); stk_pos++; break; case SFT_CMD_FP: stk[stk_pos++] = frame->fp; break; case SFT_CMD_DEREF: if (stk_pos < 1) stack_trace_error(); { size_t j; size_t size = cmd->size; uint64_t n = 0; uint8_t buf[8]; if (context_read_mem(ctx, (ContextAddress)stk[stk_pos - 1], buf, size) < 0) exception(errno); for (j = 0; j < size; j++) { n = (n << 8) | buf[cmd->big_endian ? j : size - j - 1]; } stk[stk_pos - 1] = n; } break; case SFT_CMD_ADD: if (stk_pos < 2) stack_trace_error(); stk[stk_pos - 2] = stk[stk_pos - 2] + stk[stk_pos - 1]; stk_pos--; break; case SFT_CMD_SUB: if (stk_pos < 2) stack_trace_error(); stk[stk_pos - 2] = stk[stk_pos - 2] - stk[stk_pos - 1]; stk_pos--; break; case SFT_CMD_AND: if (stk_pos < 2) stack_trace_error(); stk[stk_pos - 2] = stk[stk_pos - 2] & stk[stk_pos - 1]; stk_pos--; break; case SFT_CMD_OR: if (stk_pos < 2) stack_trace_error(); stk[stk_pos - 2] = stk[stk_pos - 2] | stk[stk_pos - 1]; stk_pos--; break; default: stack_trace_error(); break; } } if (stk_pos == 0) stack_trace_error(); return stk[stk_pos - 1]; } #endif /* ENABLE_DebugContext */