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:
parent
bb2420a474
commit
9536ec0297
|
@ -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_get_debug_variable(const char* variableName, uint64* value);
|
||||
|
||||
ssize_t arch_debug_gdb_get_registers(char* buffer, size_t bufferSize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#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
|
||||
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
|
||||
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
|
||||
arch_debug_init(kernel_args *args)
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <ByteOrder.h>
|
||||
#include <TypeConstants.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
|
||||
arch_debug_init(kernel_args *args)
|
||||
{
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <ByteOrder.h>
|
||||
|
||||
#include <arch/debug.h>
|
||||
#include <arch/debug_console.h>
|
||||
#include <debug.h>
|
||||
#include <elf.h>
|
||||
|
@ -107,23 +108,34 @@ gdb_reply(char const* format, ...)
|
|||
|
||||
|
||||
static void
|
||||
gdb_regreply(int const* regs, int numregs)
|
||||
gdb_regreply()
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
int sum;
|
||||
|
||||
sReply[0] = '$';
|
||||
for (i = 0; i < numregs; i++)
|
||||
sprintf(sReply + 1 + 8 * i, "%08lx", B_HOST_TO_BENDIAN_INT32(regs[i]));
|
||||
|
||||
len = strlen(sReply);
|
||||
sum = 0;
|
||||
for (i = 1; i < len; i++)
|
||||
// get registers (architecture specific)
|
||||
ssize_t bytesWritten = arch_debug_gdb_get_registers(sReply + 1,
|
||||
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 %= 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();
|
||||
}
|
||||
|
@ -227,34 +239,8 @@ gdb_parse_command(void)
|
|||
return QUIT;
|
||||
|
||||
case 'g':
|
||||
{
|
||||
#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
|
||||
|
||||
gdb_regreply();
|
||||
break;
|
||||
}
|
||||
|
||||
case 'G':
|
||||
// write registers
|
||||
|
|
Loading…
Reference in New Issue