blob: fbdfa28ad5fba083bba3d21c8902061d59f2e2de [file] [log] [blame]
/*******************************************************************************
* 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 <config.h>
#if ENABLE_DebugContext
#include <stddef.h>
#include <stdio.h>
#include <assert.h>
#include <framework/cpudefs.h>
#include <framework/errors.h>
#include <framework/context.h>
#include <framework/myalloc.h>
#include <framework/exceptions.h>
#include <services/symbols.h>
#include <machine/cpudefs-ext.h>
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 */