mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[KDGDB] Adapt to amd64
This commit is contained in:
parent
97858f3c87
commit
0eea78648c
4 changed files with 284 additions and 14 deletions
|
@ -10,9 +10,11 @@ list(APPEND SOURCE
|
|||
utils.c
|
||||
kdgdb.h)
|
||||
|
||||
# TODO: AMD64, ARM...
|
||||
# TODO: ARM...
|
||||
if(ARCH STREQUAL "i386")
|
||||
list(APPEND SOURCE i386_sup.c)
|
||||
elseif(ARCH STREQUAL "amd64")
|
||||
list(APPEND SOURCE amd64_sup.c)
|
||||
endif()
|
||||
|
||||
add_library(kdcom MODULE
|
||||
|
|
263
drivers/base/kdgdb/amd64_sup.c
Normal file
263
drivers/base/kdgdb/amd64_sup.c
Normal file
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* PROJECT: ReactOS KD dll - GDB stub
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Base functions for the kernel debugger
|
||||
* COPYRIGHT: Copyright 2021 Jérôme Gardou
|
||||
*/
|
||||
|
||||
#include "kdgdb.h"
|
||||
|
||||
enum reg_name
|
||||
{
|
||||
RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP,
|
||||
R8, R9, R10, R11, R12, R13, R14, R15,
|
||||
RIP,
|
||||
EFLAGS,
|
||||
CS, SS, DS, ES, FS, GS,
|
||||
ST0, ST1, ST2, ST3, ST4, ST5, ST6, ST7,
|
||||
FCTRL, FSTAT, FTAG, FISEG, FIOFF, FOSEG, FOOFF, FOP
|
||||
};
|
||||
|
||||
static const unsigned char reg_size[] =
|
||||
{
|
||||
8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8,
|
||||
4,
|
||||
4, 4, 4, 4, 4, 4,
|
||||
10, 10, 10, 10, 10, 10, 10, 10,
|
||||
8, 8, 8, 8, 8, 8, 8, 8
|
||||
};
|
||||
|
||||
static
|
||||
void*
|
||||
ctx_to_reg(CONTEXT* ctx, enum reg_name name)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case RAX: return &ctx->Rax;
|
||||
case RBX: return &ctx->Rbx;
|
||||
case RCX: return &ctx->Rcx;
|
||||
case RDX: return &ctx->Rdx;
|
||||
case RSP: return &ctx->Rsp;
|
||||
case RBP: return &ctx->Rbp;
|
||||
case RSI: return &ctx->Rsi;
|
||||
case RDI: return &ctx->Rdi;
|
||||
case RIP: return &ctx->Rip;
|
||||
case R8: return &ctx->R8;
|
||||
case R9: return &ctx->R9;
|
||||
case R10: return &ctx->R10;
|
||||
case R11: return &ctx->R11;
|
||||
case R12: return &ctx->R12;
|
||||
case R13: return &ctx->R13;
|
||||
case R14: return &ctx->R14;
|
||||
case R15: return &ctx->R15;
|
||||
case EFLAGS: return &ctx->EFlags;
|
||||
case CS: return &ctx->SegCs;
|
||||
case DS: return &ctx->SegSs;
|
||||
case ES: return &ctx->SegEs;
|
||||
case FS: return &ctx->SegFs;
|
||||
case GS: return &ctx->SegGs;
|
||||
case SS: return &ctx->SegSs;
|
||||
}
|
||||
#undef return_reg
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void*
|
||||
thread_to_reg(PETHREAD Thread, enum reg_name reg_name)
|
||||
{
|
||||
static const void* NullValue = NULL;
|
||||
|
||||
#if 0
|
||||
if (Thread->Tcb.TrapFrame)
|
||||
{
|
||||
PKTRAP_FRAME TrapFrame = Thread->Tcb.TrapFrame;
|
||||
|
||||
switch (reg_name)
|
||||
{
|
||||
case RAX: return &TrapFrame->Rax;
|
||||
case RBX: return &TrapFrame->Rbx;
|
||||
case RCX: return &TrapFrame->Rcx;
|
||||
case RDX: return &TrapFrame->Rdx;
|
||||
case RSP: return &TrapFrame->Rsp;
|
||||
case RBP: return &TrapFrame->Rbp;
|
||||
case RSI: return &TrapFrame->Rsi;
|
||||
case RDI: return &TrapFrame->Rdi;
|
||||
case RIP: return &TrapFrame->Rip;
|
||||
case R8: return &TrapFrame->R8;
|
||||
case R9: return &TrapFrame->R9;
|
||||
case R10: return &TrapFrame->R10;
|
||||
case R11: return &TrapFrame->R11;
|
||||
case EFLAGS: return &TrapFrame->EFlags;
|
||||
case CS: return &TrapFrame->SegCs;
|
||||
case DS: return &TrapFrame->SegSs;
|
||||
case ES: return &TrapFrame->SegEs;
|
||||
case FS: return &TrapFrame->SegFs;
|
||||
case GS: return &TrapFrame->SegGs;
|
||||
case SS: return &TrapFrame->SegSs;
|
||||
default:
|
||||
KDDBGPRINT("Unhandled regname: %d.\n", reg_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (!Thread->Tcb.InitialStack)
|
||||
{
|
||||
/* Terminated thread ? */
|
||||
switch (reg_name)
|
||||
{
|
||||
case RSP:
|
||||
case RBP:
|
||||
case RIP:
|
||||
KDDBGPRINT("Returning NULL for register %d.\n", reg_name);
|
||||
return &NullValue;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(reg_name)
|
||||
{
|
||||
case RSP: return &Thread->Tcb.KernelStack;
|
||||
case RIP:
|
||||
{
|
||||
PULONG_PTR Rsp = Thread->Tcb.KernelStack;
|
||||
return &Rsp[3];
|
||||
}
|
||||
case RBP:
|
||||
{
|
||||
PULONG_PTR Rsp = Thread->Tcb.KernelStack;
|
||||
return &Rsp[4];
|
||||
}
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
KDSTATUS
|
||||
gdb_send_registers(void)
|
||||
{
|
||||
CHAR RegisterStr[17];
|
||||
UCHAR* RegisterPtr;
|
||||
unsigned short i;
|
||||
unsigned short size;
|
||||
|
||||
start_gdb_packet();
|
||||
|
||||
KDDBGPRINT("Sending registers of thread %" PRIxPTR ".\n", gdb_dbg_tid);
|
||||
KDDBGPRINT("Current thread_id: %p.\n", PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
|
||||
if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) ||
|
||||
gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
|
||||
{
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
RegisterPtr = ctx_to_reg(&CurrentContext, i);
|
||||
size = reg_size[i] * 2;
|
||||
RegisterStr[size] = 0;
|
||||
while (size)
|
||||
{
|
||||
size--;
|
||||
RegisterStr[size] = hex_chars[RegisterPtr[size/2] & 0xF];
|
||||
size--;
|
||||
RegisterStr[size] = hex_chars[RegisterPtr[size/2] >> 4];
|
||||
}
|
||||
|
||||
send_gdb_partial_packet(RegisterStr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PETHREAD DbgThread;
|
||||
|
||||
DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid);
|
||||
|
||||
if (DbgThread == NULL)
|
||||
{
|
||||
/* Thread is dead */
|
||||
send_gdb_partial_packet("E03");
|
||||
return finish_gdb_packet();
|
||||
}
|
||||
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
RegisterPtr = thread_to_reg(DbgThread, i);
|
||||
size = reg_size[i] * 2;
|
||||
RegisterStr[size] = 0;
|
||||
|
||||
while (size)
|
||||
{
|
||||
if (RegisterPtr)
|
||||
{
|
||||
size--;
|
||||
RegisterStr[size] = hex_chars[RegisterPtr[size/2] & 0xF];
|
||||
size--;
|
||||
RegisterStr[size] = hex_chars[RegisterPtr[size/2] >> 4];
|
||||
}
|
||||
else
|
||||
{
|
||||
size--;
|
||||
RegisterStr[size] = 'x';
|
||||
size--;
|
||||
RegisterStr[size] = 'x';
|
||||
}
|
||||
}
|
||||
|
||||
send_gdb_partial_packet(RegisterStr);
|
||||
}
|
||||
}
|
||||
|
||||
return finish_gdb_packet();
|
||||
}
|
||||
|
||||
KDSTATUS
|
||||
gdb_send_register(void)
|
||||
{
|
||||
enum reg_name reg_name;
|
||||
void *ptr;
|
||||
|
||||
/* Get the GDB register name (gdb_input = "pXX") */
|
||||
reg_name = (hex_value(gdb_input[1]) << 4) | hex_value(gdb_input[2]);
|
||||
|
||||
if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) ||
|
||||
gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
|
||||
{
|
||||
/* We can get it from the context of the current exception */
|
||||
ptr = ctx_to_reg(&CurrentContext, reg_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
PETHREAD DbgThread;
|
||||
|
||||
DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid);
|
||||
|
||||
if (DbgThread == NULL)
|
||||
{
|
||||
/* Thread is dead */
|
||||
return send_gdb_packet("E03");
|
||||
}
|
||||
|
||||
ptr = thread_to_reg(DbgThread, reg_name);
|
||||
}
|
||||
|
||||
if (!ptr)
|
||||
{
|
||||
unsigned char size = reg_size[reg_name];
|
||||
start_gdb_packet();
|
||||
while (size--)
|
||||
send_gdb_partial_packet("xx");
|
||||
return finish_gdb_packet();
|
||||
}
|
||||
else
|
||||
{
|
||||
KDDBGPRINT("KDDBG : Sending registers as memory.\n");
|
||||
return send_gdb_memory(ptr, reg_size[reg_name]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -301,12 +301,6 @@ handle_gdb_query(void)
|
|||
return gdb_send_debug_io(&String, FALSE);
|
||||
}
|
||||
|
||||
if (strncmp(gdb_input, "qOffsets", 8) == 0)
|
||||
{
|
||||
/* We load ntoskrnl at 0x80800000 while compiling it at 0x00800000 base address */
|
||||
return send_gdb_packet("TextSeg=80000000");
|
||||
}
|
||||
|
||||
if (strcmp(gdb_input, "qTStatus") == 0)
|
||||
{
|
||||
/* No tracepoint support */
|
||||
|
@ -323,7 +317,7 @@ handle_gdb_query(void)
|
|||
{
|
||||
static LIST_ENTRY* CurrentEntry = NULL;
|
||||
char str_helper[256];
|
||||
char name_helper[64];
|
||||
char name_helper[64];
|
||||
ULONG_PTR Offset = hex_to_address(&gdb_input[22]);
|
||||
ULONG_PTR ToSend = hex_to_address(strstr(&gdb_input[22], ",") + 1);
|
||||
ULONG Sent = 0;
|
||||
|
@ -381,7 +375,7 @@ handle_gdb_query(void)
|
|||
|
||||
/* GDB doesn't load the file if you don't prefix it with a drive letter... */
|
||||
mem_length = _snprintf(str_helper, 256, "<library name=\"C:\\%s\"><segment address=\"0x%p\"/></library>", &name_helper, DllBase);
|
||||
|
||||
|
||||
/* DLL name must be too long. */
|
||||
if (mem_length < 0)
|
||||
{
|
||||
|
@ -639,7 +633,7 @@ handle_gdb_write_mem(
|
|||
/* Nothing to do */
|
||||
return LOOP_IF_SUCCESS(send_gdb_packet("OK"));
|
||||
}
|
||||
|
||||
|
||||
State->u.WriteMemory.TransferCount = BufferLength;
|
||||
MessageData->Length = BufferLength;
|
||||
MessageData->Buffer = (CHAR*)OutBuffer;
|
||||
|
@ -794,7 +788,7 @@ RestoreBreakPointSendHandler(
|
|||
KDDBGPRINT("Wrong API number (%lu) after DbgKdRestoreBreakPointApi request.\n", State->ApiNumber);
|
||||
}
|
||||
|
||||
/* We ignore failure here. If DbgKdRestoreBreakPointApi fails,
|
||||
/* We ignore failure here. If DbgKdRestoreBreakPointApi fails,
|
||||
* this means that the breakpoint was already invalid for KD. So clean it up on our side. */
|
||||
for (i = 0; i < (sizeof(BreakPointHandles) / sizeof(BreakPointHandles[0])); i++)
|
||||
{
|
||||
|
@ -879,7 +873,7 @@ handle_gdb_c(
|
|||
Status = send_gdb_packet("OK");
|
||||
if (Status != KdPacketReceived)
|
||||
return Status;
|
||||
|
||||
|
||||
|
||||
if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
|
||||
{
|
||||
|
@ -967,7 +961,7 @@ handle_gdb_v(
|
|||
|
||||
if (strncmp(gdb_input, "vCont;s", 7) == 0)
|
||||
{
|
||||
|
||||
|
||||
return handle_gdb_s(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include <pstypes.h>
|
||||
|
||||
// #define KDDEBUG /* uncomment to enable debugging this dll */
|
||||
#define KDDEBUG /* uncomment to enable debugging this dll */
|
||||
|
||||
/* To undefine once https://sourceware.org/bugzilla/show_bug.cgi?id=17397 is resolved */
|
||||
#define MONOPROCESS 1
|
||||
|
@ -132,6 +132,17 @@ extern KDSTATUS gdb_send_registers(void);
|
|||
# define KD_BREAKPOINT_SIZE sizeof(UCHAR)
|
||||
# define KD_BREAKPOINT_VALUE 0xCC
|
||||
/* Single step mode */
|
||||
# define KdpSetSingleStep(Context) \
|
||||
((Context)->EFlags |= EFLAGS_TF)
|
||||
#elif defined(_M_AMD64)
|
||||
# define KdpGetContextPc(Context) \
|
||||
((Context)->Rip)
|
||||
# define KdpSetContextPc(Context, ProgramCounter) \
|
||||
((Context)->Rip = (ProgramCounter))
|
||||
# define KD_BREAKPOINT_TYPE UCHAR
|
||||
# define KD_BREAKPOINT_SIZE sizeof(UCHAR)
|
||||
# define KD_BREAKPOINT_VALUE 0xCC
|
||||
/* Single step mode */
|
||||
# define KdpSetSingleStep(Context) \
|
||||
((Context)->EFlags |= EFLAGS_TF)
|
||||
#else
|
||||
|
|
Loading…
Reference in a new issue