-
Notifications
You must be signed in to change notification settings - Fork 0
Debugging Guide
Comprehensive guide to debugging ModuOS.
Primary method for debugging kernel code.
Setup: Automatically enabled in run.bat
Viewing Logs:
# View in real-time
tail -f com1.log
tail -f com2.log
# Or use Log Viewer (Windows)
vendor/NTSoftware/Log Viewer.exe com1.logAdding Debug Output:
#include "moduos/kernel/COM/com.h"
COM_LOG_INFO(COM1_PORT, "Starting initialization");
COM_LOG_DEBUG(COM1_PORT, "Variable value: %d", value);
COM_LOG_ERROR(COM1_PORT, "Failed to initialize");Log Levels:
-
COM_LOG_INFO: General information -
COM_LOG_DEBUG: Detailed debug info -
COM_LOG_WARN: Warnings -
COM_LOG_ERROR: Errors
For early boot before COM is initialized:
#include "moduos/drivers/graphics/VGA.h"
VGA_print("Debug message\n");
VGA_print_hex(value);Access: Press Ctrl+Alt+2 in QEMU window
Useful Commands:
info registers # Show all CPU registers
info mem # Memory mappings
info pic # PIC status
info tlb # TLB entries
x/10i $rip # Disassemble 10 instructions
x/16x 0xaddress # Dump memory
Switch back to console: Ctrl+Alt+1
Start QEMU with GDB server:
qemu-system-x86_64 -cdrom dist/AMD64/kernel.iso -s -SOptions:
-
-s: Enable GDB server on port 1234 -
-S: Pause CPU at startup
Connect GDB:
gdb dist/AMD64/mdsys.sqr
(gdb) target remote localhost:1234
(gdb) break kernel_main
(gdb) continue# Breakpoints
break kernel_main # Set breakpoint at function
break *0x100000 # Set breakpoint at address
info breakpoints # List breakpoints
delete 1 # Delete breakpoint 1
# Execution
continue (c) # Continue execution
step (s) # Step into
next (n) # Step over
finish # Step out
# Inspection
print variable # Print variable value
print /x variable # Print in hex
x/10i $rip # Disassemble
x/16x address # Dump memory
backtrace (bt) # Stack trace
info registers # Show registers
# Memory
x/10gx $rsp # Show stack (10 qwords)
watch variable # Watchpoint on write
Compile with debug symbols:
CFLAGS += -gThis allows GDB to show source code and variable names.
Symptom: System halts with panic message
Debug:
- Check VGA output for panic message
- Review
com1.logfor stack trace - Note the faulting address and registers
Example Panic:
KERNEL PANIC: Page Fault
Faulting address: 0x0000000000000000
Error code: 0x0002 (Write to non-present page)
RIP: 0xFFFFFFFF80100123
Investigation:
# Find function at RIP
objdump -d dist/AMD64/mdsys.sqr | grep 80100123Symptom: QEMU resets immediately
Causes:
- Invalid IDT entry
- Stack overflow
- Page fault in fault handler
- Invalid page tables
Debug:
- Add
-d int,cpu_resetto QEMU - Check
qemu.logfor fault details - Use GDB to step through early boot
Symptom: System stops responding
Debug:
- Check if interrupts are enabled:
sticalled? - Look for infinite loops
- Check if waiting for hardware that never responds
GDB Method:
# Attach GDB to running instance
gdb dist/AMD64/mdsys.sqr
(gdb) target remote localhost:1234
(gdb) interrupt
(gdb) backtraceSymptom: Random crashes, data corruption
Debug:
- Check for buffer overflows
- Verify malloc/free pairs
- Check stack alignment
- Use memory debugging
Add Memory Guards:
#define GUARD_VALUE 0xDEADBEEF
void *kmalloc_debug(size_t size) {
void *ptr = kmalloc(size + 8);
*(uint32_t*)ptr = GUARD_VALUE;
*(uint32_t*)(ptr + 4 + size) = GUARD_VALUE;
return ptr + 4;
}
void kfree_debug(void *ptr) {
ptr -= 4;
assert(*(uint32_t*)ptr == GUARD_VALUE);
kfree(ptr);
}Error Code Bits:
- Bit 0: Page present (0=not present, 1=protection)
- Bit 1: Write access (0=read, 1=write)
- Bit 2: User mode (0=kernel, 1=user)
- Bit 3: Reserved bit violation
- Bit 4: Instruction fetch
Handler:
void page_fault_handler(registers_t *regs) {
uint64_t cr2;
__asm__ volatile("mov %%cr2, %0" : "=r"(cr2));
uint32_t err = regs->err_code;
COM_LOG_ERROR(COM1_PORT, "Page Fault at 0x%llx", cr2);
COM_LOG_ERROR(COM1_PORT, "Present: %d", err & 1);
COM_LOG_ERROR(COM1_PORT, "Write: %d", (err >> 1) & 1);
COM_LOG_ERROR(COM1_PORT, "User: %d", (err >> 2) & 1);
}Simple but effective:
COM_LOG_DEBUG(COM1_PORT, "Reached checkpoint 1");
COM_LOG_DEBUG(COM1_PORT, "Variable x = %d", x);For isolating bugs:
- Add debug print at middle of suspicious code
- If bug occurs before print, search first half
- If bug occurs after print, search second half
- Repeat until bug location found
Catch invalid states early:
#define assert(expr) \
if (!(expr)) panic("Assertion failed: " #expr)
assert(ptr != NULL);
assert(size > 0);
assert(index < array_length);Inspect memory contents:
void hexdump(void *addr, size_t len) {
uint8_t *ptr = (uint8_t*)addr;
for (size_t i = 0; i < len; i += 16) {
COM_LOG_DEBUG(COM1_PORT, "%p: ", ptr + i);
for (size_t j = 0; j < 16 && i + j < len; j++) {
COM_LOG_DEBUG(COM1_PORT, "%02x ", ptr[i + j]);
}
COM_LOG_DEBUG(COM1_PORT, "\n");
}
}qemu-system-x86_64 \
-cdrom kernel.iso \
-d int,cpu_reset,guest_errors \
-D qemu.logOptions:
-
-d int: Log all interrupts -
-d cpu_reset: Log CPU resets (triple faults) -
-d guest_errors: Log guest errors -
-D qemu.log: Output to file
qemu-system-x86_64 -cdrom kernel.iso -no-rebootPrevents automatic restart on triple fault, shows error state.
void print_stack_trace(void) {
uint64_t *rbp;
__asm__ volatile("mov %%rbp, %0" : "=r"(rbp));
for (int i = 0; i < 10 && rbp; i++) {
uint64_t rip = *(rbp + 1);
COM_LOG_DEBUG(COM1_PORT, " [%d] RIP: 0x%llx", i, rip);
rbp = (uint64_t*)*rbp;
}
}# Find function containing address
objdump -d dist/AMD64/mdsys.sqr | grep -B5 address
# Disassemble specific function
objdump -d dist/AMD64/mdsys.sqr | grep -A20 "kernel_main:"uint64_t rdtsc(void) {
uint32_t lo, hi;
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
return ((uint64_t)hi << 32) | lo;
}
uint64_t start = rdtsc();
// ... code to measure ...
uint64_t end = rdtsc();
COM_LOG_DEBUG(COM1_PORT, "Cycles: %llu", end - start);- Add logging early: Easier to remove than to add later
- Use descriptive messages: Include context and values
- Check return values: Don't ignore errors
- Validate inputs: Assert preconditions
- Use version control: Git bisect to find regressions
- Test incrementally: Small changes are easier to debug
- Keep backups: Known-good versions to compare against
- Building ModuOS - Build with debug symbols
- Running and Testing - Testing strategies
- Contributing - Submitting bug fixes