Reimplemented the gdb stub support for the 'g' command (read registers):
* Added an arch_debug_gdb_get_registers() interface that is supposed to provide the register values in the format expected by gdb and implemented it for x86. * Reimplemented gdb_regreply() to use that. Also made it buffer overflow safe. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41880 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -50,6 +50,8 @@ bool arch_is_debug_variable_defined(const char* variableName);
|
|||||||
status_t arch_set_debug_variable(const char* variableName, uint64 value);
|
status_t arch_set_debug_variable(const char* variableName, uint64 value);
|
||||||
status_t arch_get_debug_variable(const char* variableName, uint64* value);
|
status_t arch_get_debug_variable(const char* variableName, uint64* value);
|
||||||
|
|
||||||
|
ssize_t arch_debug_gdb_get_registers(char* buffer, size_t bufferSize);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -334,3 +334,9 @@ arch_debug_unset_current_thread(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
arch_debug_gdb_get_registers(char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
// TODO: Implement!
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|||||||
@@ -398,6 +398,14 @@ arch_get_debug_variable(const char* variableName, uint64* value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
arch_debug_gdb_get_registers(char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
// TODO: Implement!
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arch_debug_init(kernel_args *args)
|
arch_debug_init(kernel_args *args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -99,6 +99,14 @@ arch_get_debug_variable(const char* variableName, uint64* value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
arch_debug_gdb_get_registers(char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
// TODO: Implement!
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arch_debug_init(kernel_args* args)
|
arch_debug_init(kernel_args* args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -336,6 +336,14 @@ arch_get_debug_variable(const char* variableName, uint64* value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
arch_debug_gdb_get_registers(char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
// TODO: Implement!
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arch_debug_init(kernel_args *args)
|
arch_debug_init(kernel_args *args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <ByteOrder.h>
|
||||||
#include <TypeConstants.h>
|
#include <TypeConstants.h>
|
||||||
|
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
@@ -1168,6 +1169,58 @@ arch_get_debug_variable(const char* variableName, uint64* value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Writes the contents of the CPU registers at some fixed outer stack frame or
|
||||||
|
iframe into the given buffer in the format expected by gdb.
|
||||||
|
|
||||||
|
This function is called in response to gdb's 'g' command.
|
||||||
|
|
||||||
|
\param buffer The buffer to write the registers to.
|
||||||
|
\param bufferSize The size of \a buffer in bytes.
|
||||||
|
\return When successful, the number of bytes written to \a buffer, or a
|
||||||
|
negative error code on error.
|
||||||
|
*/
|
||||||
|
ssize_t
|
||||||
|
arch_debug_gdb_get_registers(char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
struct iframe* frame = get_current_iframe(debug_get_debugged_thread());
|
||||||
|
if (frame == NULL)
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
// For x86 the register order is:
|
||||||
|
//
|
||||||
|
// eax, ebx, ecx, edx,
|
||||||
|
// esp, ebp, esi, edi,
|
||||||
|
// eip, eflags,
|
||||||
|
// cs, ss, ds, es
|
||||||
|
//
|
||||||
|
// Note that even though the segment descriptors are actually 16 bits wide,
|
||||||
|
// gdb requires them as 32 bit integers. Note also that for some reason
|
||||||
|
// gdb wants the register dump in *big endian* format.
|
||||||
|
static const int32 kRegisterCount = 14;
|
||||||
|
uint32 registers[kRegisterCount] = {
|
||||||
|
frame->eax, frame->ebx, frame->ecx, frame->edx,
|
||||||
|
frame->esp, frame->ebp, frame->esi, frame->edi,
|
||||||
|
frame->eip, frame->flags,
|
||||||
|
frame->cs, frame->ds, frame->ds, frame->es
|
||||||
|
// assume ss == ds
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* const bufferStart = buffer;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < kRegisterCount; i++) {
|
||||||
|
int result = snprintf(buffer, bufferSize, "%08" B_PRIx32,
|
||||||
|
B_HOST_TO_BENDIAN_INT32(registers[i]));
|
||||||
|
if (result >= (int)bufferSize)
|
||||||
|
return B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
|
buffer += result;
|
||||||
|
bufferSize -= result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer - bufferStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arch_debug_init(kernel_args *args)
|
arch_debug_init(kernel_args *args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include <ByteOrder.h>
|
#include <ByteOrder.h>
|
||||||
|
|
||||||
|
#include <arch/debug.h>
|
||||||
#include <arch/debug_console.h>
|
#include <arch/debug_console.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
@@ -107,23 +108,34 @@ gdb_reply(char const* format, ...)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gdb_regreply(int const* regs, int numregs)
|
gdb_regreply()
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
int len;
|
|
||||||
int sum;
|
|
||||||
|
|
||||||
sReply[0] = '$';
|
sReply[0] = '$';
|
||||||
for (i = 0; i < numregs; i++)
|
|
||||||
sprintf(sReply + 1 + 8 * i, "%08lx", B_HOST_TO_BENDIAN_INT32(regs[i]));
|
|
||||||
|
|
||||||
len = strlen(sReply);
|
// get registers (architecture specific)
|
||||||
sum = 0;
|
ssize_t bytesWritten = arch_debug_gdb_get_registers(sReply + 1,
|
||||||
for (i = 1; i < len; i++)
|
sizeof(sReply) - 1);
|
||||||
|
if (bytesWritten < 0) {
|
||||||
|
gdb_reply("E01");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add 1 for the leading '$'
|
||||||
|
bytesWritten++;
|
||||||
|
|
||||||
|
// compute check sum
|
||||||
|
int sum = 0;
|
||||||
|
for (int32 i = 1; i < bytesWritten; i++)
|
||||||
sum += sReply[i];
|
sum += sReply[i];
|
||||||
sum %= 256;
|
sum %= 256;
|
||||||
|
|
||||||
sprintf(sReply + len, "#%02x", sum);
|
// print check sum
|
||||||
|
int result = snprintf(sReply + bytesWritten, sizeof(sReply) - bytesWritten,
|
||||||
|
"#%02x", sum);
|
||||||
|
if (result >= (ssize_t)sizeof(sReply) - bytesWritten) {
|
||||||
|
gdb_reply("E01");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
gdb_resend_reply();
|
gdb_resend_reply();
|
||||||
}
|
}
|
||||||
@@ -227,34 +239,8 @@ gdb_parse_command(void)
|
|||||||
return QUIT;
|
return QUIT;
|
||||||
|
|
||||||
case 'g':
|
case 'g':
|
||||||
{
|
gdb_regreply();
|
||||||
#if 0
|
|
||||||
int cpu;
|
|
||||||
|
|
||||||
// command 'g' is used for reading the register
|
|
||||||
// file. Faked by now.
|
|
||||||
//
|
|
||||||
// For x86 the register order is:
|
|
||||||
//
|
|
||||||
// eax, ebx, ecx, edx,
|
|
||||||
// esp, ebp, esi, edi,
|
|
||||||
// eip, eflags,
|
|
||||||
// cs, ss, ds, es
|
|
||||||
//
|
|
||||||
// Note that even thought the segment descriptors
|
|
||||||
// are actually 16 bits wide, gdb requires them
|
|
||||||
// as 32 bit integers. Note also that for some
|
|
||||||
// reason (unknown to me) gdb wants the register
|
|
||||||
// dump in *big endian* format.
|
|
||||||
cpu = smp_get_current_cpu();
|
|
||||||
gdb_regreply(dbg_register_file[cpu], 14);
|
|
||||||
#else
|
|
||||||
(void)gdb_regreply;
|
|
||||||
gdb_reply("E01");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case 'G':
|
case 'G':
|
||||||
// write registers
|
// write registers
|
||||||
|
|||||||
Reference in New Issue
Block a user