diff --git a/headers/private/kernel/arch/debug.h b/headers/private/kernel/arch/debug.h index b3abd64286..14c43bd8f6 100644 --- a/headers/private/kernel/arch/debug.h +++ b/headers/private/kernel/arch/debug.h @@ -1,9 +1,10 @@ -/* +/* ** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ -#ifndef _NEWOS_KERNEL_ARCH_DEBUG -#define _NEWOS_KERNEL_ARCH_DEBUG +#ifndef _KERNEL_ARCH_DEBUG_H +#define _KERNEL_ARCH_DEBUG_H -#endif +int arch_dbg_init(kernel_args *ka); +#endif /* _KERNEL_ARCH_DEBUG_H */ diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index 737b2c7f86..e379a17144 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -82,6 +82,28 @@ typedef struct pdentry { unsigned int addr:20; } pdentry; +struct iframe { + unsigned int gs; + unsigned int fs; + unsigned int es; + unsigned int ds; + unsigned int edi; + unsigned int esi; + unsigned int ebp; + unsigned int esp; + unsigned int ebx; + unsigned int edx; + unsigned int ecx; + unsigned int eax; + unsigned int vector; + unsigned int error_code; + unsigned int eip; + unsigned int cs; + unsigned int flags; + unsigned int user_esp; + unsigned int user_ss; +}; + #define nop() __asm__ ("nop"::) void setup_system_time(unsigned int cv_factor); @@ -93,6 +115,9 @@ void i386_swap_pgdir(addr new_pgdir); void i386_fsave_swap(void *old_fpu_state, void *new_fpu_state); void i386_fxsave_swap(void *old_fpu_state, void *new_fpu_state); +#define read_ebp(value) \ + __asm__("movl %%ebp,%0" : "=r" (value)) + #define read_dr3(value) \ __asm__("movl %%dr3,%0" : "=r" (value)) diff --git a/headers/private/kernel/arch/x86/arch_thread.h b/headers/private/kernel/arch/x86/arch_thread.h index 3911ae4ab0..14fa30a446 100644 --- a/headers/private/kernel/arch/x86/arch_thread.h +++ b/headers/private/kernel/arch/x86/arch_thread.h @@ -11,6 +11,11 @@ extern "C" { #include + +void i386_push_iframe(struct thread *t, struct iframe *frame); +void i386_pop_iframe(struct thread *t); + + extern inline struct thread *arch_thread_get_current_thread(void) { struct thread *t; read_dr3(t); diff --git a/headers/private/kernel/arch/x86/thread_struct.h b/headers/private/kernel/arch/x86/thread_struct.h index 57d394a9e5..96f181856a 100755 --- a/headers/private/kernel/arch/x86/thread_struct.h +++ b/headers/private/kernel/arch/x86/thread_struct.h @@ -10,10 +10,17 @@ struct farcall { unsigned int *ss; }; +#define IFRAME_TRACE_DEPTH 4 + // architecture specific thread info struct arch_thread { struct farcall current_stack; struct farcall interrupt_stack; + + // used to track interrupts on this thread + struct iframe *iframes[IFRAME_TRACE_DEPTH]; + int iframe_ptr; + // 512 byte floating point save point uint8 fpu_state[512]; }; @@ -22,5 +29,4 @@ struct arch_team { // nothing here }; -#endif - +#endif /* _KERNEL_ARCH_x86_THREAD_STRUCT_H */ diff --git a/headers/private/kernel/elf.h b/headers/private/kernel/elf.h index 98b57b070f..533e9e86cf 100755 --- a/headers/private/kernel/elf.h +++ b/headers/private/kernel/elf.h @@ -11,7 +11,7 @@ int elf_load_uspace(const char *path, struct team *t, int flags, addr *entry); image_id elf_load_kspace(const char *path, const char *sym_prepend); int elf_unload_kspace( const char *path); addr elf_lookup_symbol(image_id id, const char *symbol); +int elf_lookup_symbol_address(addr address, addr *baseAddress, char *text, size_t length); int elf_init(kernel_args *ka); -#endif - +#endif /* _KERNEL_ELF_H */ diff --git a/src/kernel/core/arch/x86/arch_debug.c b/src/kernel/core/arch/x86/arch_debug.c index 218995e243..11bfd88499 100755 --- a/src/kernel/core/arch/x86/arch_debug.c +++ b/src/kernel/core/arch/x86/arch_debug.c @@ -2,8 +2,95 @@ ** Copyright 2001, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ + #include #include #include +#include + +#include +#include +#include +#include +#include +#include + + +static int +dbg_stack_trace(int argc, char **argv) +{ + struct thread *t; + uint32 ebp; + int i; + + if (argc < 2) + t = thread_get_current_thread(); + else { + dprintf("not supported\n"); + return 0; + } + + for (i = 0; i < t->arch_info.iframe_ptr; i++) { + char *temp = (char *)t->arch_info.iframes[i]; + dprintf("iframe %p %p %p\n", temp, temp + sizeof(struct iframe), temp + sizeof(struct iframe) - 8); + } + + dprintf("stack trace for thread 0x%x '%s'\n", t->id, t->name); + dprintf("frame \tcaller:\n"); + dprintf("-------------------------------\n"); + + read_ebp(ebp); + for (;;) { + bool is_iframe = false; + // see if the ebp matches the iframe + for (i = 0; i < t->arch_info.iframe_ptr; i++) { + if (ebp == ((uint32) t->arch_info.iframes[i] - 8)) { + // it's an iframe + is_iframe = true; + } + } + + if (is_iframe) { + struct iframe *frame = (struct iframe *)(ebp + 8); + + dprintf("iframe at %p\n", frame); + dprintf(" eax\t0x%x\tebx\t0x%x\tecx\t0x%x\tedx\t0x%x\n", frame->eax, frame->ebx, frame->ecx, frame->edx); + dprintf(" esi\t0x%x\tedi\t0x%x\tebp\t0x%x\tesp\t0x%x\n", frame->esi, frame->edi, frame->ebp, frame->esp); + dprintf(" eip\t0x%x\teflags\t0x%x", frame->eip, frame->flags); + if ((frame->error_code & 0x4) != 0) { + // from user space + dprintf("\tuser esp\t0x%x", frame->user_esp); + } + dprintf("\n"); + dprintf(" vector\t0x%x\terror code\t0x%x\n", frame->vector, frame->error_code); + ebp = frame->ebp; + } else { + uint32 eip = *((uint32 *)ebp + 1); + char symname[256]; + addr base_address; + + if (eip == 0 || ebp == 0) + break; + + if (elf_lookup_symbol_address(eip, &base_address, symname, sizeof(symname)) >= 0) + dprintf("%p\t%p:<%p+%p>\t'%s'\n", (void *)ebp, (void *)eip, (void *)base_address, (void *)(eip - base_address), symname); + else + dprintf("%p\t%p\n", (void *)ebp, (void *)eip); + + ebp = *(uint32 *)ebp; + } + } + return 0; +} + + +int +arch_dbg_init(kernel_args *ka) +{ + // at this stage, the debugger command system is alive + + add_debugger_command("sc", &dbg_stack_trace, "Stack crawl for current thread"); + + return B_NO_ERROR; +} -// XXX will put stack trace and disassembly routines here diff --git a/src/kernel/core/arch/x86/arch_int.c b/src/kernel/core/arch/x86/arch_int.c index 76a14c817f..02824876bb 100755 --- a/src/kernel/core/arch/x86/arch_int.c +++ b/src/kernel/core/arch/x86/arch_int.c @@ -2,6 +2,7 @@ ** Copyright 2001, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ + #include #include #include @@ -30,31 +31,11 @@ #define MAX_ARGS 16 -struct int_frame { - unsigned int gs; - unsigned int fs; - unsigned int es; - unsigned int ds; - unsigned int edi; - unsigned int esi; - unsigned int ebp; - unsigned int esp; - unsigned int ebx; - unsigned int edx; - unsigned int ecx; - unsigned int eax; - unsigned int vector; - unsigned int error_code; - unsigned int eip; - unsigned int cs; - unsigned int flags; - unsigned int user_esp; - unsigned int user_ss; -}; - static desc_table *idt = NULL; -static void interrupt_ack(int n) + +static void +interrupt_ack(int n) { if(n >= 0x20 && n < 0x30) { // 8239 controlled interrupt @@ -64,7 +45,9 @@ static void interrupt_ack(int n) } } -static void _set_gate(desc_table *gate_addr, unsigned int addr, int type, int dpl) + +static void +_set_gate(desc_table *gate_addr, unsigned int addr, int type, int dpl) { unsigned int gate1; // first byte of gate desc unsigned int gate2; // second byte of gate desc @@ -76,11 +59,14 @@ static void _set_gate(desc_table *gate_addr, unsigned int addr, int type, int dp gate_addr->b = gate2; } -void arch_int_enable_io_interrupt(int irq) + +void +arch_int_enable_io_interrupt(int irq) { if (irq < 0 || irq >= 0x10) return; -dprintf("arch_int_enable_io_interrupt: irq %d\n", irq); + + dprintf("arch_int_enable_io_interrupt: irq %d\n", irq); /* if this is a external interrupt via 8239, enable it here */ if (irq < 8) out8(in8(0x21) & ~(1 << irq), 0x21); @@ -88,7 +74,9 @@ dprintf("arch_int_enable_io_interrupt: irq %d\n", irq); out8(in8(0xa1) & ~(1 << (irq - 8)), 0xa1); } -void arch_int_disable_io_interrupt(int irq) + +void +arch_int_disable_io_interrupt(int irq) { /* never disable slave pic line IRQ 2 */ if (irq < 0 || irq >= 0x10 || irq == 2) @@ -100,29 +88,39 @@ void arch_int_disable_io_interrupt(int irq) out8(in8(0xa1) | (1 << (irq - 8)), 0xa1); } -static void set_intr_gate(int n, void *addr) + +static void +set_intr_gate(int n, void *addr) { _set_gate(&idt[n], (unsigned int)addr, 14, 0); } + /* XXX - currently unused and static... -static void set_trap_gate(int n, void *addr) +static void +set_trap_gate(int n, void *addr) { _set_gate(&idt[n], (unsigned int)addr, 15, 0); } */ -static void set_system_gate(int n, void *addr) + +static void +set_system_gate(int n, void *addr) { _set_gate(&idt[n], (unsigned int)addr, 15, 3); } -void arch_int_enable_interrupts(void) + +void +arch_int_enable_interrupts(void) { asm("sti"); } -int arch_int_disable_interrupts(void) + +int +arch_int_disable_interrupts(void) { int flags; @@ -132,7 +130,9 @@ int arch_int_disable_interrupts(void) return flags & 0x200 ? 1 : 0; } -void arch_int_restore_interrupts(int oldstate) + +void +arch_int_restore_interrupts(int oldstate) { int flags = oldstate ? 0x200 : 0; @@ -146,7 +146,9 @@ void arch_int_restore_interrupts(int oldstate) : : "r" (flags), "r" (0)); } -bool arch_int_is_interrupts_enabled(void) + +bool +arch_int_is_interrupts_enabled(void) { int flags; @@ -155,10 +157,16 @@ bool arch_int_is_interrupts_enabled(void) return flags & 0x200 ? 1 : 0; } -void i386_handle_trap(struct int_frame frame); /* keep the compiler happy, this function must be called only from assembly */ -void i386_handle_trap(struct int_frame frame) + +void i386_handle_trap(struct iframe frame); /* keep the compiler happy, this function must be called only from assembly */ +void +i386_handle_trap(struct iframe frame) { int ret = B_HANDLED_INTERRUPT; + struct thread *thread = thread_get_current_thread(); + + if (thread) + i386_push_iframe(thread, &frame); // if(frame.vector != 0x20) // dprintf("i386_handle_trap: vector 0x%x, ip 0x%x, cpu %d\n", frame.vector, frame.eip, smp_get_current_cpu()); @@ -250,13 +258,18 @@ void i386_handle_trap(struct int_frame frame) restore_interrupts(state); } - if(frame.cs == USER_CODE_SEG || frame.vector == 99) { + if (frame.cs == USER_CODE_SEG || frame.vector == 99) { thread_atkernel_exit(); } // dprintf("0x%x cpu %d!\n", thread_get_current_thread_id(), smp_get_current_cpu()); + + if (thread) + i386_pop_iframe(thread); } -int arch_int_init(kernel_args *ka) + +int +arch_int_init(kernel_args *ka) { idt = (desc_table *)ka->arch_args.vir_idt; @@ -320,7 +333,9 @@ int arch_int_init(kernel_args *ka) return 0; } -int arch_int_init2(kernel_args *ka) + +int +arch_int_init2(kernel_args *ka) { idt = (desc_table *)ka->arch_args.vir_idt; vm_create_anonymous_region(vm_get_kernel_aspace_id(), "idt", (void *)&idt, diff --git a/src/kernel/core/arch/x86/arch_thread.c b/src/kernel/core/arch/x86/arch_thread.c index 7ce0e40f4e..ad4fce2373 100755 --- a/src/kernel/core/arch/x86/arch_thread.c +++ b/src/kernel/core/arch/x86/arch_thread.c @@ -2,6 +2,7 @@ ** Copyright 2001, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ + #include #include #include @@ -12,15 +13,36 @@ #include #include -int arch_team_init_team_struct(struct team *p, bool kernel) -{ - return 0; -} // from arch_interrupts.S extern void i386_stack_init( struct farcall *interrupt_stack_offset ); -int arch_thread_init_thread_struct(struct thread *t) + +void +i386_push_iframe(struct thread *thread, struct iframe *frame) +{ + ASSERT(thread->arch_info.iframe_ptr < IFRAME_TRACE_DEPTH); + thread->arch_info.iframes[thread->arch_info.iframe_ptr++] = frame; +} + + +void +i386_pop_iframe(struct thread *thread) +{ + ASSERT(thread->arch_info.iframe_ptr > 0); + thread->arch_info.iframe_ptr--; +} + + +int +arch_team_init_team_struct(struct team *p, bool kernel) +{ + return 0; +} + + +int +arch_thread_init_thread_struct(struct thread *t) { // set up an initial state (stack & fpu) memset(&t->arch_info, 0, sizeof(t->arch_info)); @@ -32,7 +54,9 @@ int arch_thread_init_thread_struct(struct thread *t) return 0; } -int arch_thread_initialize_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void)) + +int +arch_thread_initialize_kthread_stack(struct thread *t, int (*start_func)(void), void (*entry_func)(void), void (*exit_func)(void)) { unsigned int *kstack = (unsigned int *)t->kernel_stack_base; unsigned int kstack_size = KSTACK_SIZE; @@ -74,12 +98,16 @@ int arch_thread_initialize_kthread_stack(struct thread *t, int (*start_func)(voi return 0; } -void arch_thread_switch_kstack_and_call(struct thread *t, addr new_kstack, void (*func)(void *), void *arg) + +void +arch_thread_switch_kstack_and_call(struct thread *t, addr new_kstack, void (*func)(void *), void *arg) { i386_switch_stack_and_call(new_kstack, func, arg); } -void arch_thread_context_switch(struct thread *t_from, struct thread *t_to) + +void +arch_thread_context_switch(struct thread *t_from, struct thread *t_to) { addr new_pgdir; #if 0 @@ -138,7 +166,9 @@ void arch_thread_context_switch(struct thread *t_from, struct thread *t_to) i386_context_switch(&t_from->arch_info, &t_to->arch_info, new_pgdir); } -void arch_thread_dump_info(void *info) + +void +arch_thread_dump_info(void *info) { struct arch_thread *at = (struct arch_thread *)info; @@ -147,7 +177,9 @@ void arch_thread_dump_info(void *info) dprintf("\tfpu_state at %p\n", at->fpu_state); } -void arch_thread_enter_uspace(addr entry, void *args, addr ustack_top) + +void +arch_thread_enter_uspace(addr entry, void *args, addr ustack_top) { dprintf("arch_thread_entry_uspace: entry 0x%lx, args %p, ustack_top 0x%lx\n", entry, args, ustack_top); diff --git a/src/kernel/core/debug.c b/src/kernel/core/debug.c index 869b4d0df7..4c317856df 100644 --- a/src/kernel/core/debug.c +++ b/src/kernel/core/debug.c @@ -4,6 +4,7 @@ ** Copyright 2001, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ + #include #include #include @@ -52,7 +53,9 @@ static char *args[MAX_ARGS] = { NULL, }; #define distance(a, b) ((a) < (b) ? (b) - (a) : (a) - (b)) -static int debug_read_line(char *buf, int max_len) + +static int +debug_read_line(char *buf, int max_len) { char c; int ptr = 0; @@ -160,21 +163,23 @@ static int debug_read_line(char *buf, int max_len) return ptr; } -static int debug_parse_line(char *buf, char **argv, int *argc, int max_args) + +static int +debug_parse_line(char *buf, char **argv, int *argc, int max_args) { int pos = 0; strcpy(parse_line, buf); - if(!isspace(parse_line[0])) { + if (!isspace(parse_line[0])) { argv[0] = parse_line; *argc = 1; } else { *argc = 0; } - while(parse_line[pos] != '\0') { - if(isspace(parse_line[pos])) { + while (parse_line[pos] != '\0') { + if (isspace(parse_line[pos])) { parse_line[pos] = '\0'; // scan all of the whitespace out of this while(isspace(parse_line[++pos])) @@ -193,7 +198,9 @@ static int debug_parse_line(char *buf, char **argv, int *argc, int max_args) return *argc; } -static void kernel_debugger_loop() + +static void +kernel_debugger_loop() { int argc; struct debugger_command *cmd; @@ -226,7 +233,9 @@ static void kernel_debugger_loop() } } -void kernel_debugger(const char * message) + +void +kernel_debugger(const char * message) { dbg_save_registers(&(dbg_register_file[smp_get_current_cpu()][0])); @@ -239,7 +248,9 @@ void kernel_debugger(const char * message) kernel_debugger_loop(); } -int panic(const char *fmt, ...) + +int +panic(const char *fmt, ...) { int ret = 0; va_list args; @@ -270,7 +281,9 @@ int panic(const char *fmt, ...) return ret; } -int dprintf(const char *fmt, ...) + +int +dprintf(const char *fmt, ...) { va_list args; char temp[512]; @@ -286,7 +299,9 @@ int dprintf(const char *fmt, ...) return ret; } -char dbg_putch(char c) + +char +dbg_putch(char c) { char ret; int flags = disable_interrupts(); @@ -303,7 +318,9 @@ char dbg_putch(char c) return ret; } -void dbg_puts(const char *s) + +void +dbg_puts(const char *s) { int flags = disable_interrupts(); acquire_spinlock(&dbg_spinlock); @@ -315,7 +332,9 @@ void dbg_puts(const char *s) restore_interrupts(flags); } -int add_debugger_command(const char * name, int (*func)(int, char **), const char * desc) + +int +add_debugger_command(const char * name, int (*func)(int, char **), const char * desc) { int flags; struct debugger_command *cmd; @@ -340,7 +359,9 @@ int add_debugger_command(const char * name, int (*func)(int, char **), const cha return B_NO_ERROR; } -int remove_debugger_command(const char * name, int (*func)(int, char **)) + +int +remove_debugger_command(const char * name, int (*func)(int, char **)) { int flags; struct debugger_command *cmd; @@ -378,13 +399,16 @@ int remove_debugger_command(const char * name, int (*func)(int, char **)) } -static int cmd_reboot(int argc, char **argv) +static int +cmd_reboot(int argc, char **argv) { reboot(); return 0; // I'll be really suprised if this line ever run! ;-) } -static int cmd_help(int argc, char **argv) + +static int +cmd_help(int argc, char **argv) { struct debugger_command *cmd; @@ -398,30 +422,40 @@ static int cmd_help(int argc, char **argv) return 0; } -int dbg_init(kernel_args *ka) + +int +dbg_init(kernel_args *ka) { commands = NULL; return arch_dbg_con_init(ka); } -int dbg_init2(kernel_args *ka) + +int +dbg_init2(kernel_args *ka) { add_debugger_command("help", &cmd_help, "List all debugger commands"); add_debugger_command("reboot", &cmd_reboot, "Reboot"); add_debugger_command("gdb", &cmd_gdb, "Connect to remote gdb"); + dbg_init(ka); + return B_NO_ERROR; } -bool dbg_set_serial_debug(bool new_val) + +bool +dbg_set_serial_debug(bool new_val) { int temp = serial_debug_on; serial_debug_on = new_val; return temp; } -bool dbg_get_serial_debug() + +bool +dbg_get_serial_debug() { return serial_debug_on; } diff --git a/src/kernel/core/elf.c b/src/kernel/core/elf.c index 11737ef1f8..313a1abef4 100644 --- a/src/kernel/core/elf.c +++ b/src/kernel/core/elf.c @@ -84,8 +84,8 @@ static image_id next_image_id = 0; #define HASHCHAINS(image) ((unsigned int *)&(image)->symhash[2+HASHTABSIZE(image)]) -static int -get_address_symbol_info(addr address, char *text, int maxtextlen) +int +elf_lookup_symbol_address(addr address, addr *baseAddress, char *text, size_t length) { struct elf_image_info **ptr; struct elf_image_info *image; @@ -102,7 +102,8 @@ get_address_symbol_info(addr address, char *text, int maxtextlen) found_sym = 0; found_image = 0; found_delta = 0x7fffffff; - for(ptr = &kernel_images; *ptr; ptr = &(*ptr)->next) { + + for (ptr = &kernel_images; *ptr; ptr = &(*ptr)->next) { image = *ptr; PRINT((" image %p, base = %p, size = %p\n", image, (void *)image->regions[0].start, (void *)image->regions[0].size)); @@ -112,7 +113,7 @@ get_address_symbol_info(addr address, char *text, int maxtextlen) PRINT((" searching...\n")); found_image = image; for (i = 0; i < HASHTABSIZE(image); i++) { - for(j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { + for (j = HASHBUCKETS(image)[i]; j != STN_UNDEF; j = HASHCHAINS(image)[j]) { long d; sym = &image->syms[j]; @@ -131,17 +132,22 @@ get_address_symbol_info(addr address, char *text, int maxtextlen) } break; } - if (found_sym == 0) { - PRINT(("symbol not found!\n")); - strlcpy(text, "symbol not found", maxtextlen); - rv = -1; - } else { + + if (found_sym != 0) { PRINT(("symbol at %p, in image %p, name = %s\n", found_sym, found_image, found_image->name)); PRINT(("name index %d, '%s'\n", found_sym->st_name, SYMNAME(found_image, found_sym))); PRINT(("addr = %#lx, offset = %#lx\n",(found_sym->st_value + found_image->regions[0].delta),found_delta)); - // XXX should honor maxtextlen here - sprintf(text, "<%#lx:%s + %#lx> %s", (found_sym->st_value + found_image->regions[0].delta), SYMNAME(found_image, found_sym), found_delta, found_image->name); + + strlcpy(text, SYMNAME(found_image, found_sym), length); + + if (baseAddress) + *baseAddress = found_sym->st_value + found_image->regions[0].delta; + rv = 0; + } else { + PRINT(("symbol not found!\n")); + strlcpy(text, "symbol not found", length); + rv = -1; } mutex_unlock(&image_lock); @@ -161,8 +167,8 @@ print_address_info(int argc, char **argv) } address = atoul(argv[1]); - - get_address_symbol_info(address, text, sizeof(text)); + + elf_lookup_symbol_address(address, NULL, text, sizeof(text)); dprintf("%p = %s\n",(void *)address,text); return 0; }