[lcrash/gdb] ADD: Automatically load debug symbols when lcrashkern is ready
This commit is contained in:
parent
76de467bdc
commit
cd237386e3
13
.gdbinit
Normal file
13
.gdbinit
Normal file
@ -0,0 +1,13 @@
|
||||
# INNNNNNNNNNNTRODUCING: the gdb unfucker 9000
|
||||
printf "Setting up Lindows debug tools\n"
|
||||
|
||||
# We operate in MODES, modes are guessed by what we're connecting to
|
||||
set $XU_LWDBG_MODE = "INACTIVE"
|
||||
|
||||
# Load guile code
|
||||
source common/gdb/guile/core.scm
|
||||
|
||||
# Create guile hooks
|
||||
define target hookpost-remote
|
||||
lwdbg internal handle-target-remote-post
|
||||
end
|
@ -435,6 +435,8 @@ add_custom_command(OUTPUT lindows.img
|
||||
BYPRODUCTS disk.sfdisk
|
||||
)
|
||||
|
||||
configure_file(config.h.in config.h)
|
||||
|
||||
add_custom_target(lindows ALL DEPENDS lindows.img)
|
||||
|
||||
add_subdirectory(executive)
|
||||
|
5
README
5
README
@ -1,3 +1,8 @@
|
||||
== STYLE ==
|
||||
|
||||
=== GUILE ===
|
||||
- Avoid direct use of (execute)
|
||||
|
||||
== NAMING ==
|
||||
|
||||
Mph: Metaprogramming helpers
|
||||
|
150
common/gdb/guile/core.scm
Normal file
150
common/gdb/guile/core.scm
Normal file
@ -0,0 +1,150 @@
|
||||
(use-modules (gdb)) ; import gdb libraries
|
||||
|
||||
; == Misc libraries ==
|
||||
(use-modules (srfi srfi-9)) ; provides define-record-type
|
||||
(use-modules (ice-9 string-fun)) ; provides string-replace-substring
|
||||
|
||||
; Types
|
||||
(define btp-u8 (lookup-type "unsigned char"))
|
||||
(define btp-u16 (lookup-type "unsigned short"))
|
||||
(define btp-u32 (lookup-type "unsigned int"))
|
||||
(define btp-u64 (lookup-type "unsigned long long"))
|
||||
(define btp-i8 (lookup-type "char"))
|
||||
(define btp-i16 (lookup-type "short"))
|
||||
(define btp-i32 (lookup-type "int"))
|
||||
(define btp-i64 (lookup-type "long long"))
|
||||
(define btp-c8 (lookup-type "char"))
|
||||
(define btp-bool btp-u8)
|
||||
(define btp-uptr btp-u64)
|
||||
|
||||
; == Execute wrappers ==
|
||||
; Be careful modifying this, other commands depend on it for multiline commands
|
||||
(define gdbw-python (lambda (code) (execute (format #f "python ~a" code) #:to-string #t)))
|
||||
|
||||
(define gdbw-remove-symbol-file (lambda (file) (execute (format #f "remove-symbol-file ~s" file))))
|
||||
|
||||
(define gdbw-add-symbol-file (lambda* (file #:key (offset '()))
|
||||
(define cmd (format #f "add-symbol-file ~s" file))
|
||||
(when (number? offset) (set! cmd (string-append cmd (format #f " -o ~a" offset))))
|
||||
(execute cmd)))
|
||||
|
||||
; HACK: gdb doesn't support multiline execute for guile, so we use execute to call python's execute
|
||||
(define gdbw-commands (lambda (breakpoints cmds)
|
||||
(for-each (lambda (breakpoint)
|
||||
(define gdb-breakpoint breakpoint)
|
||||
(when (breakpoint? gdb-breakpoint) (set! gdb-breakpoint (breakpoint-number gdb-breakpoint)))
|
||||
; HACK: This is a silly hack that abuses an unchecked cast from unsigned numbers to signed ones in the gdb shell, allowing us to bypass the "no negative numbers!" thing
|
||||
(when (< gdb-breakpoint 0) (set! gdb-breakpoint (+ 4294967295 (+ 1 gdb-breakpoint))))
|
||||
(gdbw-python (format #f "gdb.execute(~s)" (format #f "commands ~a\n~a\nend" gdb-breakpoint (string-join cmds "\n")))))
|
||||
breakpoints)))
|
||||
|
||||
; HACK: gdb doesn't support connection data for guile, so we have to implement it ourself with this incredible hack
|
||||
(define-record-type <gdbw-info-connections-result>
|
||||
(make-gdbw-info-connections-result current number what description)
|
||||
gdbw-info-connections-result?
|
||||
(current gdbw-info-connections-result-current)
|
||||
(number gdbw-info-connections-result-number)
|
||||
(what gdbw-info-connections-result-what)
|
||||
(description gdbw-info-connections-result-description))
|
||||
(define gdbw-info-connections (lambda () ; TODO: this looks awful, i'm positive there's a better way to do a lot of this, come back when i understand scheme
|
||||
(define compact-gdb-table-row (lambda (raw)
|
||||
(define crunch (lambda (pos chunks remain)
|
||||
(if (< pos (string-length remain))
|
||||
(let ((nidx (string-index remain #\space pos)))
|
||||
(if (< (+ nidx 1) (string-length remain))
|
||||
(if (char=? (string-ref remain (+ nidx 1)) #\space)
|
||||
(let ((fidx (string-skip remain #\space nidx)))
|
||||
(crunch 0 (append chunks (list (substring remain 0 nidx))) (substring remain fidx)))
|
||||
(crunch (+ nidx 1) chunks remain))
|
||||
(append chunks (list (substring remain 0 (- (string-length remain) 1))))))
|
||||
(append chunks (list (substring remain 0 (- (string-length remain) 1)))))))
|
||||
(crunch 0 '() raw)))
|
||||
(map (lambda (l) (let ((crow (compact-gdb-table-row l)))
|
||||
(make-gdbw-info-connections-result
|
||||
(char=? (string-ref (car crow) 0) #\*)
|
||||
(string->number (substring (car crow) 2))
|
||||
(car (cdr crow))
|
||||
(car (cdr (cdr crow))))))
|
||||
(list-head (list-tail (string-split (execute "info connections" #:to-string #t) #\newline) 1) 1))))
|
||||
|
||||
; == Debugging mode stuff ==
|
||||
(define DEBUG_MODE_KERNEL 'KERNEL)
|
||||
(define DEBUG_MODE_INVALID 'INVALID)
|
||||
(define DEBUG_MODE_NONE 'NONE)
|
||||
|
||||
(define debug-mode DEBUG_MODE_NONE)
|
||||
|
||||
(define debug-mode-transition (lambda (mode) ; Reconfigure internal state to debug a new target
|
||||
; Check for major fuckups
|
||||
(when (equal? mode DEBUG_MODE_INVALID) (error "Transitioned into an invalid debug mode, this should never happen!"))
|
||||
|
||||
; Deinitialize the previous target's debug code
|
||||
(cond
|
||||
((equal? debug-mode DEBUG_MODE_KERNEL)
|
||||
(delete-breakpoint! kernel-debug-table-update-watcher)))
|
||||
|
||||
; Set the new debug mode
|
||||
(set! debug-mode mode)
|
||||
|
||||
; Initialize the current target's debug code
|
||||
(cond
|
||||
((equal? debug-mode DEBUG_MODE_KERNEL)
|
||||
(register-breakpoint! kernel-debug-table-update-watcher)
|
||||
(gdbw-commands (list kernel-debug-table-update-watcher) '("silent" "lwdbg kernel refresh-debug-tables" "continue"))
|
||||
(process-kernel-debug-tables)))))
|
||||
|
||||
; == Code for processing data in kernel debug tables ==
|
||||
(define cckernel-binary-location '())
|
||||
(define cckernel-binary-offset '())
|
||||
(define kernel-binary-location '())
|
||||
(define kernel-binary-offset '())
|
||||
(define kernel-debug-table-update-watcher (make-breakpoint "*(0x100000)"
|
||||
#:type BP_WATCHPOINT
|
||||
#:wp-class WP_WRITE
|
||||
#:internal #t))
|
||||
(define process-kernel-debug-tables (lambda ()
|
||||
(define build-dir (value-dereference (value-cast (make-value #x100008) (type-pointer (type-pointer btp-c8)))))
|
||||
(when (not (value=? build-dir (make-value 0)))
|
||||
(set! build-dir (value->string build-dir))
|
||||
(if (value=? (value-dereference (value-cast (make-value #x100010) (type-pointer btp-bool))) 1)
|
||||
((lambda () (define new-cckernel-binary-offset (value->integer (value-dereference (value-cast (make-value #x100018) (type-pointer btp-uptr)))))
|
||||
(define new-cckernel-binary-location (string-append build-dir "/lcrash/cckernel"))
|
||||
(when (not (null? cckernel-binary-location))
|
||||
(gdbw-remove-symbol-file cckernel-binary-location)
|
||||
(set! cckernel-binary-location '())
|
||||
(set! cckernel-binary-offset '()))
|
||||
(gdbw-add-symbol-file new-cckernel-binary-location #:offset new-cckernel-binary-offset)
|
||||
(set! cckernel-binary-location new-cckernel-binary-location)
|
||||
(set! cckernel-binary-offset new-cckernel-binary-offset)))
|
||||
(display "TODO: CCKERNEL UNLOADED\n"))
|
||||
(if (value=? (value-dereference (value-cast (make-value #x100020) (type-pointer btp-bool))) 1)
|
||||
((lambda () (define new-kernel-binary-offset (value->integer (value-dereference (value-cast (make-value #x100028) (type-pointer btp-uptr)))))
|
||||
(define new-kernel-binary-location (string-append build-dir "/lcrash/lcrashkern"))
|
||||
(when (not (null? kernel-binary-location))
|
||||
(gdbw-remove-symbol-file kernel-binary-location)
|
||||
(set! kernel-binary-location '())
|
||||
(set! kernel-binary-offset '()))
|
||||
(gdbw-add-symbol-file new-kernel-binary-location #:offset new-kernel-binary-offset)
|
||||
(set! kernel-binary-location new-kernel-binary-location)
|
||||
(set! kernel-binary-offset new-kernel-binary-offset)))
|
||||
(display "TODO: KERNEL UNLOADED\n")))))
|
||||
|
||||
; == Command prefixes ==
|
||||
(register-command! (make-command "lwdbg" #:prefix? #t))
|
||||
(register-command! (make-command "lwdbg internal" #:prefix? #t))
|
||||
(register-command! (make-command "lwdbg kernel" #:prefix? #t))
|
||||
|
||||
; Called by gdb hookpost for target remote
|
||||
(register-command! (make-command "lwdbg internal handle-target-remote-post"
|
||||
#:invoke (lambda (self arg from-tty)
|
||||
(debug-mode-transition
|
||||
(let ((target (string-split (gdbw-info-connections-result-what (car (filter gdbw-info-connections-result-current (gdbw-info-connections)))) #\space)))
|
||||
(if (string=? (car target) "remote")
|
||||
DEBUG_MODE_KERNEL
|
||||
DEBUG_MODE_INVALID))))))
|
||||
|
||||
; Command to forcefully refresh the thing
|
||||
(register-command! (make-command "lwdbg kernel refresh-debug-tables"
|
||||
#:command-class COMMAND_USER
|
||||
#:doc "Refresh the kernel debug tables"
|
||||
#:invoke (lambda (self arg from-tty) (process-kernel-debug-tables))))
|
3
config.h.in
Normal file
3
config.h.in
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define LW_CONFIG_PROJECT_OUTPUT_DIR "@CMAKE_BINARY_DIR@"
|
@ -19,6 +19,7 @@ set_property(TARGET lcrashkern PROPERTY LINK_DEPENDS
|
||||
set_property(TARGET lcrashkern PROPERTY LINK_OPTIONS -nostdlib -Wl,-T,${CMAKE_CURRENT_SOURCE_DIR}/lcrash.ld )
|
||||
target_compile_options(lcrashkern PRIVATE -ggdb -fpic -pie -Wall -fanalyzer)
|
||||
target_link_options(lcrashkern PRIVATE -fpic -pie)
|
||||
target_include_directories(lcrashkern PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lcrashkern.gz
|
||||
@ -54,6 +55,7 @@ set_property(TARGET cckernel PROPERTY LINK_DEPENDS
|
||||
)
|
||||
set(COMPRESSED_KERNEL_PATH ${CMAKE_CURRENT_BINARY_DIR}/lcrashkern.gz)
|
||||
configure_file(setup/compressed/cckernel.S.in setup/compressed/cckernel.S)
|
||||
target_include_directories(cckernel PRIVATE ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR})
|
||||
|
||||
# This is the actual bzImage used by linux/grub
|
||||
lw_add_executable(lcrash
|
||||
|
@ -10,7 +10,9 @@
|
||||
|
||||
bool AcpiIsPresent = false;
|
||||
|
||||
struct AcpiRSDP* AcpiTheRSDP = 0;
|
||||
struct AcpiRSDP* AcpiTheRSDP = 0;
|
||||
struct AcpiXSDT* AcpiTheXSDT = 0;
|
||||
u32 AcpiXSDTLength = 0;
|
||||
|
||||
void AcpiInitialize() {
|
||||
// Check boot params
|
||||
@ -42,6 +44,15 @@ found: // Is this a valid ACPI table?
|
||||
for (int i = 0; i < sizeof(struct AcpiRSDP); i++) Sum += ((u8*)AcpiTheRSDP)[i];
|
||||
if (Sum != 0) goto fail;
|
||||
|
||||
// Grab the XSDT
|
||||
AcpiTheXSDT = AcpiTheRSDP->XSDTAddress;
|
||||
|
||||
// Is this a valid XSDT?
|
||||
if (!CompareMemory(AcpiTheXSDT->Header.Signature, "XSDT", 4)) goto fail;
|
||||
|
||||
// Get the XSDT length
|
||||
AcpiXSDTLength = (AcpiTheXSDT->Header.Length - sizeof(struct AcpiXSDT)) / 8;
|
||||
|
||||
AcpiIsPresent = true;
|
||||
return;
|
||||
|
||||
@ -51,3 +62,15 @@ fail: AcpiIsPresent = false;
|
||||
|
||||
bool AcpiPresent() { return AcpiIsPresent; }
|
||||
struct AcpiRSDP* AcpiGetRSDP() { return AcpiTheRSDP; }
|
||||
struct AcpiXSDT* AcpiGetXSDT() { return AcpiTheXSDT; }
|
||||
u32 AcpiGetXSDTLength() { return AcpiXSDTLength; }
|
||||
|
||||
void* AcpiGetTable(const char TableName[4]) {
|
||||
// Let's not fuck this up this early
|
||||
if (!AcpiPresent()) return NULL;
|
||||
|
||||
// Alright let's see here...
|
||||
for (int i = 0; i < AcpiXSDTLength; i++) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -56,3 +56,23 @@ void AcpiInitialize();
|
||||
* Check if ACPI is present
|
||||
*/
|
||||
bool AcpiPresent();
|
||||
|
||||
/**
|
||||
* Get the ACPI RSDP, only call if ACPI is present
|
||||
*/
|
||||
struct AcpiRSDP* AcpiGetRSDP();
|
||||
|
||||
/**
|
||||
* Get the ACPI XSDT, only call if ACPI is present
|
||||
*/
|
||||
struct AcpiXSDT* AcpiGetXSDT();
|
||||
|
||||
/**
|
||||
* Get the ACPI XSDT entry count, only call if ACPI is present
|
||||
*/
|
||||
u32 AcpiGetXSDTLength();
|
||||
|
||||
/**
|
||||
* Get the ACPI table with the specified name, returns NULL if not found
|
||||
*/
|
||||
void* AcpiGetTable(const char TableName[4]);
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
#define DEFINE_GDB_PY_SCRIPT(name) \
|
||||
asm("\
|
||||
.pushsection \".debug_gdb_scripts\", \"MS\", @progbits, 1\n\
|
||||
@ -7,3 +9,26 @@
|
||||
.asciz \""name"\"\n\
|
||||
.popsection \n\
|
||||
");
|
||||
|
||||
/// Fixed data block placed at the address 0x100000
|
||||
/// Please update the initialization code in /lcrash/setup/compressed/main.c when this is changed
|
||||
struct GdbDataBlock {
|
||||
/// Update tick thing stored at the beginning of the fixed data block for debuggers
|
||||
/// TODO: Optimization may break this, should this be volatile?
|
||||
u64 Update;
|
||||
|
||||
/// Base of the cmake build directory. This is needed for lwdbg to configure itself
|
||||
c8* BuildDirectory;
|
||||
|
||||
/// cckernel is present
|
||||
bool CCKernelLoaded;
|
||||
|
||||
/// Base address of the cckernel
|
||||
void* CCKernelBase;
|
||||
|
||||
/// Full kernel is present
|
||||
bool KernelLoaded;
|
||||
|
||||
/// Base address of the kernel
|
||||
void* KernelBase;
|
||||
};
|
||||
|
@ -1,6 +1,8 @@
|
||||
/// lcrash entry point
|
||||
/// super awesome...
|
||||
|
||||
#include <lcrash/gdb/gdb.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "lnxboot.h"
|
||||
|
||||
@ -11,6 +13,12 @@ void entry64(struct boot_params* BootParams) {
|
||||
BootBootParams = BootParams;
|
||||
BootSetupInfo = (void*)BootParams + 0x1f1;
|
||||
|
||||
// Notify the debugger that we're ready
|
||||
struct GdbDataBlock* GdbDataBlock = (struct GdbDataBlock*)0x100000;
|
||||
GdbDataBlock->KernelLoaded = true;
|
||||
GdbDataBlock->KernelBase = BootSetupInfo->code32_start;
|
||||
GdbDataBlock->Update++;
|
||||
|
||||
// Initialize EFI code if we had EFI
|
||||
EfiInitialize();
|
||||
|
||||
|
@ -7,6 +7,10 @@ SECTIONS {
|
||||
*(.text)
|
||||
}
|
||||
|
||||
.rodata : {
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
.cckernel : {
|
||||
*(.cckernel)
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
#include "../../lnxboot.h"
|
||||
#include "../../gdb/gdb.h"
|
||||
#include <config.h>
|
||||
|
||||
#include "gzip.h"
|
||||
#include "elf.h"
|
||||
@ -11,8 +13,18 @@ extern void* _CC_ecckernel;
|
||||
void ccmain(void* imgbase, struct boot_params* boot_params) {
|
||||
struct setup_info* setup_info = (struct setup_info*)((void*)boot_params + 0x1f1);
|
||||
|
||||
// Fill the lcrash debug data block
|
||||
struct GdbDataBlock* GdbDataBlock = (struct GdbDataBlock*)0x100000;
|
||||
GdbDataBlock->BuildDirectory = LW_CONFIG_PROJECT_OUTPUT_DIR + (uptr)imgbase;
|
||||
GdbDataBlock->CCKernelLoaded = true;
|
||||
GdbDataBlock->CCKernelBase = imgbase;
|
||||
GdbDataBlock->KernelLoaded = false;
|
||||
GdbDataBlock->KernelBase = NULL;
|
||||
GdbDataBlock->Update++;
|
||||
|
||||
// Determine the kernel load address
|
||||
char* kernel_load_addr = (char*)setup_info->code32_start;
|
||||
if (kernel_load_addr == 0) kernel_load_addr = (char*)0x100000;
|
||||
if (kernel_load_addr == 0) kernel_load_addr = (char*)0x101000;
|
||||
|
||||
char* cckernel = imgbase + (uptr)&_CC_cckernel;
|
||||
//for (long i = 0; i < setup_info->payload_length; i++) {
|
||||
|
@ -27,3 +27,6 @@ typedef u8 bool;
|
||||
#else
|
||||
#error What the fuck? [pointers are not 4 or 8 bytes long]
|
||||
#endif
|
||||
|
||||
/// Null may become part of the nullptr type, so it's defined here
|
||||
#define NULL 0
|
||||
|
Loading…
x
Reference in New Issue
Block a user