Added support for architecture specific debug variables, e.g. for
referencing iframe registers. Their prefix is "$". E.g. "$eax" refers to the eax register of the current iframe. The features cooperates with the "in_context" command, i.e. "in_context 92 $eip = 0" will set the eip register of thread 92 to 0 (thus sealing its fate ;-)). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27192 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -28,6 +28,10 @@ bool arch_debug_contains_call(struct thread *thread, const char *symbol,
|
|||||||
addr_t start, addr_t end);
|
addr_t start, addr_t end);
|
||||||
void arch_debug_save_registers(int *);
|
void arch_debug_save_registers(int *);
|
||||||
|
|
||||||
|
bool arch_is_debug_variable_defined(const char* variableName);
|
||||||
|
status_t arch_set_debug_variable(const char* variableName, uint64 value);
|
||||||
|
status_t arch_get_debug_variable(const char* variableName, uint64* value);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -347,6 +347,30 @@ arch_debug_get_interrupt_pc()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
arch_is_debug_variable_defined(const char* variableName)
|
||||||
|
{
|
||||||
|
// TODO: Implement!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
arch_set_debug_variable(const char* variableName, uint64 value)
|
||||||
|
{
|
||||||
|
// TODO: Implement!
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
arch_get_debug_variable(const char* variableName, uint64* value)
|
||||||
|
{
|
||||||
|
// TODO: Implement!
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arch_debug_init(kernel_args *args)
|
arch_debug_init(kernel_args *args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -294,6 +294,30 @@ arch_debug_get_interrupt_pc()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
arch_is_debug_variable_defined(const char* variableName)
|
||||||
|
{
|
||||||
|
// TODO: Implement!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
arch_set_debug_variable(const char* variableName, uint64 value)
|
||||||
|
{
|
||||||
|
// TODO: Implement!
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
arch_get_debug_variable(const char* variableName, uint64* value)
|
||||||
|
{
|
||||||
|
// TODO: Implement!
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arch_debug_init(kernel_args *args)
|
arch_debug_init(kernel_args *args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -271,6 +271,88 @@ get_previous_iframe(struct thread* thread, struct iframe* frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct iframe*
|
||||||
|
get_current_iframe(struct thread* thread)
|
||||||
|
{
|
||||||
|
if (thread == thread_get_current_thread())
|
||||||
|
return i386_get_current_iframe();
|
||||||
|
|
||||||
|
addr_t ebp = thread->arch_info.current_stack.esp[2];
|
||||||
|
// NOTE: This doesn't work, if the thread is running (on another CPU).
|
||||||
|
return find_previous_iframe(thread, ebp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32*
|
||||||
|
find_debug_variable(const char* variableName, bool& settable)
|
||||||
|
{
|
||||||
|
struct iframe* frame = get_current_iframe(debug_get_debugged_thread());
|
||||||
|
if (frame == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
settable = false;
|
||||||
|
|
||||||
|
if (strcmp(variableName, "gs") == 0) {
|
||||||
|
return &frame->gs;
|
||||||
|
} else if (strcmp(variableName, "fs") == 0) {
|
||||||
|
return &frame->fs;
|
||||||
|
} else if (strcmp(variableName, "es") == 0) {
|
||||||
|
return &frame->es;
|
||||||
|
} else if (strcmp(variableName, "ds") == 0) {
|
||||||
|
return &frame->ds;
|
||||||
|
} else if (strcmp(variableName, "cs") == 0) {
|
||||||
|
return &frame->cs;
|
||||||
|
} else if (strcmp(variableName, "edi") == 0) {
|
||||||
|
settable = true;
|
||||||
|
return &frame->edi;
|
||||||
|
} else if (strcmp(variableName, "esi") == 0) {
|
||||||
|
settable = true;
|
||||||
|
return &frame->esi;
|
||||||
|
} else if (strcmp(variableName, "ebp") == 0) {
|
||||||
|
settable = true;
|
||||||
|
return &frame->ebp;
|
||||||
|
} else if (strcmp(variableName, "esp") == 0) {
|
||||||
|
settable = true;
|
||||||
|
return &frame->esp;
|
||||||
|
} else if (strcmp(variableName, "ebx") == 0) {
|
||||||
|
settable = true;
|
||||||
|
return &frame->ebx;
|
||||||
|
} else if (strcmp(variableName, "edx") == 0) {
|
||||||
|
settable = true;
|
||||||
|
return &frame->edx;
|
||||||
|
} else if (strcmp(variableName, "ecx") == 0) {
|
||||||
|
settable = true;
|
||||||
|
return &frame->ecx;
|
||||||
|
} else if (strcmp(variableName, "eax") == 0) {
|
||||||
|
settable = true;
|
||||||
|
return &frame->eax;
|
||||||
|
} else if (strcmp(variableName, "orig_eax") == 0) {
|
||||||
|
settable = true;
|
||||||
|
return &frame->orig_eax;
|
||||||
|
} else if (strcmp(variableName, "orig_edx") == 0) {
|
||||||
|
settable = true;
|
||||||
|
return &frame->orig_edx;
|
||||||
|
} else if (strcmp(variableName, "eip") == 0) {
|
||||||
|
settable = true;
|
||||||
|
return &frame->eip;
|
||||||
|
} else if (strcmp(variableName, "eflags") == 0) {
|
||||||
|
settable = true;
|
||||||
|
return &frame->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IFRAME_IS_USER(frame)) {
|
||||||
|
if (strcmp(variableName, "user_esp") == 0) {
|
||||||
|
settable = true;
|
||||||
|
return &frame->user_esp;
|
||||||
|
} else if (strcmp(variableName, "user_ss") == 0) {
|
||||||
|
return &frame->user_ss;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
stack_trace(int argc, char **argv)
|
stack_trace(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -703,30 +785,59 @@ arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Returns the program counter of this thread where the innermost interrupts
|
|
||||||
happened. Returns \c NULL, if there's none or a problem occurred retrieving
|
/*! Returns the program counter of the currently debugged (respectively this)
|
||||||
it.
|
thread where the innermost interrupts happened. Returns \c NULL, if there's
|
||||||
|
none or a problem occurred retrieving it.
|
||||||
*/
|
*/
|
||||||
void*
|
void*
|
||||||
arch_debug_get_interrupt_pc()
|
arch_debug_get_interrupt_pc()
|
||||||
{
|
{
|
||||||
struct thread* thread = debug_get_debugged_thread();
|
struct iframe* frame = get_current_iframe(debug_get_debugged_thread());
|
||||||
|
if (frame == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (thread == thread_get_current_thread()) {
|
|
||||||
struct iframe* frame = i386_get_current_iframe();
|
|
||||||
if (frame == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return (void*)(addr_t)frame->eip;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr_t ebp = thread->arch_info.current_stack.esp[2];
|
|
||||||
// NOTE: This doesn't work, if the thread is running (on another CPU).
|
|
||||||
struct iframe* frame = find_previous_iframe(thread, ebp);
|
|
||||||
return (void*)(addr_t)frame->eip;
|
return (void*)(addr_t)frame->eip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
arch_is_debug_variable_defined(const char* variableName)
|
||||||
|
{
|
||||||
|
bool settable;
|
||||||
|
return find_debug_variable(variableName, settable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
arch_set_debug_variable(const char* variableName, uint64 value)
|
||||||
|
{
|
||||||
|
bool settable;
|
||||||
|
uint32* variable = find_debug_variable(variableName, settable);
|
||||||
|
if (variable == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
if (!settable)
|
||||||
|
return B_NOT_ALLOWED;
|
||||||
|
|
||||||
|
*variable = (uint32)value;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
arch_get_debug_variable(const char* variableName, uint64* value)
|
||||||
|
{
|
||||||
|
bool settable;
|
||||||
|
uint32* variable = find_debug_variable(variableName, settable);
|
||||||
|
if (variable == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
*value = *variable;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arch_debug_init(kernel_args *args)
|
arch_debug_init(kernel_args *args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -278,9 +278,11 @@ public:
|
|||||||
TOKEN_CONSTANT);
|
TOKEN_CONSTANT);
|
||||||
fCurrentToken.value = strtoull(fCurrentToken.string, NULL, 0);
|
fCurrentToken.value = strtoull(fCurrentToken.string, NULL, 0);
|
||||||
|
|
||||||
} else if (isalpha(*fCurrentChar) || *fCurrentChar == '_') {
|
} else if (isalpha(*fCurrentChar) || *fCurrentChar == '_'
|
||||||
|
|| *fCurrentChar == '$') {
|
||||||
// identifier
|
// identifier
|
||||||
const char* begin = fCurrentChar;
|
const char* begin = fCurrentChar;
|
||||||
|
fCurrentChar++;
|
||||||
while (*fCurrentChar != 0
|
while (*fCurrentChar != 0
|
||||||
&& (isalpha(*fCurrentChar) || *fCurrentChar == '_'
|
&& (isalpha(*fCurrentChar) || *fCurrentChar == '_'
|
||||||
|| isdigit(*fCurrentChar))) {
|
|| isdigit(*fCurrentChar))) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
|
||||||
|
#include <arch/debug.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <util/DoublyLinkedList.h>
|
#include <util/DoublyLinkedList.h>
|
||||||
|
|
||||||
@@ -16,7 +17,9 @@
|
|||||||
static const int kVariableCount = 64;
|
static const int kVariableCount = 64;
|
||||||
static const int kTemporaryVariableCount = 32;
|
static const int kTemporaryVariableCount = 32;
|
||||||
static const char kTemporaryVariablePrefix = '_';
|
static const char kTemporaryVariablePrefix = '_';
|
||||||
static const char* const kCommandReturnValueVariable = "_";
|
static const char kArchSpecificVariablePrefix = '$';
|
||||||
|
static const char* const kCommandReturnValueVariable = "_";
|
||||||
|
|
||||||
|
|
||||||
struct Variable {
|
struct Variable {
|
||||||
char name[MAX_DEBUG_VARIABLE_NAME_LEN];
|
char name[MAX_DEBUG_VARIABLE_NAME_LEN];
|
||||||
@@ -60,6 +63,13 @@ is_temporary_variable(const char* variableName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
is_arch_specific_variable(const char* variableName)
|
||||||
|
{
|
||||||
|
return variableName[0] == kArchSpecificVariablePrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dequeue_temporary_variable(TemporaryVariable* variable)
|
dequeue_temporary_variable(TemporaryVariable* variable)
|
||||||
{
|
{
|
||||||
@@ -117,7 +127,7 @@ get_variable(const char* variableName, bool create)
|
|||||||
// temporary variable
|
// temporary variable
|
||||||
for (int i = 0; i < kTemporaryVariableCount; i++) {
|
for (int i = 0; i < kTemporaryVariableCount; i++) {
|
||||||
TemporaryVariable* variable = sTemporaryVariables + i;
|
TemporaryVariable* variable = sTemporaryVariables + i;
|
||||||
|
|
||||||
if (!variable->IsUsed()) {
|
if (!variable->IsUsed()) {
|
||||||
if (freeSlot == NULL)
|
if (freeSlot == NULL)
|
||||||
freeSlot = variable;
|
freeSlot = variable;
|
||||||
@@ -131,7 +141,7 @@ get_variable(const char* variableName, bool create)
|
|||||||
// persistent variable
|
// persistent variable
|
||||||
for (int i = 0; i < kVariableCount; i++) {
|
for (int i = 0; i < kVariableCount; i++) {
|
||||||
Variable* variable = sVariables + i;
|
Variable* variable = sVariables + i;
|
||||||
|
|
||||||
if (!variable->IsUsed()) {
|
if (!variable->IsUsed()) {
|
||||||
if (freeSlot == NULL)
|
if (freeSlot == NULL)
|
||||||
freeSlot = variable;
|
freeSlot = variable;
|
||||||
@@ -226,13 +236,20 @@ cmd_variables(int argc, char **argv)
|
|||||||
bool
|
bool
|
||||||
is_debug_variable_defined(const char* variableName)
|
is_debug_variable_defined(const char* variableName)
|
||||||
{
|
{
|
||||||
return get_variable(variableName, false) != NULL;
|
if (get_variable(variableName, false) != NULL)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return is_arch_specific_variable(variableName)
|
||||||
|
&& arch_is_debug_variable_defined(variableName + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
set_debug_variable(const char* variableName, uint64 value)
|
set_debug_variable(const char* variableName, uint64 value)
|
||||||
{
|
{
|
||||||
|
if (is_arch_specific_variable(variableName))
|
||||||
|
return arch_set_debug_variable(variableName + 1, value) == B_OK;
|
||||||
|
|
||||||
if (Variable* variable = get_variable(variableName, true)) {
|
if (Variable* variable = get_variable(variableName, true)) {
|
||||||
variable->value = value;
|
variable->value = value;
|
||||||
touch_variable(variable);
|
touch_variable(variable);
|
||||||
@@ -251,6 +268,12 @@ get_debug_variable(const char* variableName, uint64 defaultValue)
|
|||||||
return variable->value;
|
return variable->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64 value;
|
||||||
|
if (is_arch_specific_variable(variableName)
|
||||||
|
&& arch_get_debug_variable(variableName + 1, &value) == B_OK) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user