WadObjectFile * wad_object_load(const char *path) { WadObjectFile *wo; WadFile *wf; WadObjectFile *wad_arobject_load(const char *path, const char *name); if (wad_debug_mode & DEBUG_OBJECT) { wad_printf("wad: Loading object '%s'", path); } for (wo = wad_objects; wo; wo=wo->next) { if (strcmp(wo->path,path) == 0) { if (wad_debug_mode & DEBUG_OBJECT) { wad_printf(" (cached)\n"); } return wo; } } if (wad_debug_mode & DEBUG_OBJECT) { wad_printf("\n"); } /* Didn't find it. Now we need to go load some files */ /* If this is an archive reference like /path/libfoo.a(blah.o), we need to split up the name a little bit */ { char realfile[MAX_PATH]; char *objfile; char *c; c = strchr(path,'('); if (c) { wad_strcpy(realfile,path); c = strchr(realfile,'('); *c = 0; objfile = c+1; c = strchr(objfile,')'); *c = 0; /* Okay, I'm going to attempt to map this as a library file */ wo = wad_arobject_load(realfile,objfile); if (wo) { /* Reset the path */ wo->path = wad_strdup(path); wo->next = wad_objects; wad_objects = wo; return wo; } } } wf = load_file(path); if (!wf) return 0; wo = (WadObjectFile *) wad_malloc(sizeof(WadObjectFile)); wo->path = wad_strdup(path); wo->ptr = wf->addr; wo->len = wf->size; wo->next = wad_objects; wad_objects = wo; return wo; }
void wad_signal_init() { struct sigaction newvec; static stack_t sigstk; static int initstack = 0; if (wad_debug_mode & DEBUG_INIT) { wad_printf("WAD: Initializing signal handler.\n"); } /* This is buggy in Linux and threads. disabled by default */ #ifndef WAD_LINUX if (!initstack) { /* Set up an alternative stack */ sigstk.ss_sp = (char *) wad_sig_stack; sigstk.ss_size = STACK_SIZE; sigstk.ss_flags = 0; if (!(wad_debug_mode & DEBUG_NOSTACK)) { if (sigaltstack(&sigstk, (stack_t*)0) < 0) { perror("sigaltstack"); } } initstack=1; } #endif sigemptyset(&newvec.sa_mask); sigaddset(&newvec.sa_mask, SIGSEGV); sigaddset(&newvec.sa_mask, SIGBUS); sigaddset(&newvec.sa_mask, SIGABRT); sigaddset(&newvec.sa_mask, SIGILL); sigaddset(&newvec.sa_mask, SIGFPE); newvec.sa_flags = SA_SIGINFO; if (wad_debug_mode & DEBUG_ONESHOT) { newvec.sa_flags |= SA_RESETHAND; } #ifndef WAD_LINUX if (!(wad_debug_mode & DEBUG_NOSTACK)) { newvec.sa_flags |= SA_ONSTACK; } #endif newvec.sa_sigaction = ((void (*)(int,siginfo_t *, void *)) wad_signalhandler); if (sigaction(SIGSEGV, &newvec, NULL) < 0) goto werror; if (sigaction(SIGBUS, &newvec, NULL) < 0) goto werror; if (sigaction(SIGABRT, &newvec, NULL) < 0) goto werror; if (sigaction(SIGFPE, &newvec, NULL) < 0) goto werror; if (sigaction(SIGILL, &newvec, NULL) < 0) goto werror; return; werror: wad_printf("WAD: Couldn't install signal handler!\n"); }
int wad_segment_read() { int fs; int n; WadSegment *s, *lasts; segments = 0; lasts = 0; fs = segment_open(); while (1) { s = (WadSegment *) wad_malloc(sizeof(WadSegment)); skip: n = segment_read(fs,s); if (n <= 0) break; if (wad_file_check(s->vaddr)) goto skip; /* Skip files we already loaded */ s->next = 0; if (!lasts) { segments = s; lasts = s; } else { lasts->next = s; lasts = s; } if (wad_debug_mode & DEBUG_SEGMENT) { wad_printf("wad_segment: read : %08x-%08x, base=%x in %s\n", s->vaddr, ((char *) s->vaddr) + s->size, s->base, s->mappath); } } close(fs); return 0; }
void wad_find_symbol(WadFrame *f) { if (wad_debug_mode & DEBUG_SYMBOL) { wad_printf("wad: Searching for 0x%08x --> ", f->pc); } if (f->object) wad_elf_find_symbol(f); if (wad_debug_mode & DEBUG_SYMBOL) { if (f->sym_name) { wad_printf("%s", f->sym_name); if (f->sym_file) wad_printf(" in '%s'\n", f->sym_file); else wad_printf("\n"); } else { wad_printf("?\n"); } } }
static int elf_search_section_sym(WadFrame *f, char *secname, char *strname) { int nsymtab; int nstrtab; int symtab_size; Elf32_Sym *sym; int nsym; char *str; int i; unsigned long vaddr, base; char *name; char *localfile = 0; vaddr = (unsigned long) f->pc; base = (unsigned long) f->segment->base; nsymtab = wad_elf_section_byname(f->object,secname); if (nsymtab < 0) return 0; nstrtab = wad_elf_section_byname(f->object,strname); if (nstrtab < 0) return 0; symtab_size = wad_elf_section_size(f->object,nsymtab); sym = (Elf32_Sym *) wad_elf_section_data(f->object,nsymtab); str = (char *) wad_elf_section_data(f->object,nstrtab); nsym = (symtab_size/sizeof(Elf32_Sym)); for (i = 0; i < nsym; i++) { name = str + sym[i].st_name; /* Look for filename in case the symbol maps to a local symbol */ if (ELF32_ST_TYPE(sym[i].st_info) == STT_FILE) { localfile = name; } if (wad_debug_mode & DEBUG_SYMBOL_SEARCH) { wad_printf("%x(%x): %s %x + %x, %x, %x\n", base, vaddr, name, sym[i].st_value, sym[i].st_size, sym[i].st_info, sym[i].st_shndx); } if (((base + sym[i].st_value) <= vaddr) && (vaddr <= (base+sym[i].st_value + sym[i].st_size))) { #ifdef WAD_LINUX /* If the section index is 0, the symbol is undefined */ if (sym[i].st_shndx == 0) continue; #endif f->sym_name = name; f->sym_nlen = strlen(name); f->sym_base = base + sym[i].st_value; f->sym_size = sym[i].st_size; if (ELF32_ST_BIND(sym[i].st_info) == STB_LOCAL) { f->sym_file = localfile; f->sym_bind = SYM_LOCAL; } else { f->sym_bind = SYM_GLOBAL; } return 1; } } return 0; }
static void types_print() { stabtype *s; int i; for (i = 0; i < HASH_SIZE; i++) { s = lnames[i]; while (s) { wad_printf("%20s %s\n", s->name, s->value); s = s->next; } } }
/* private function to manage the loading of raw files into memory */ static WadFile * load_file(const char *path) { int fd; WadFile *wf = wad_files; if (wad_debug_mode & DEBUG_FILE) { wad_printf("wad: Loading file '%s' ... ", path); } while (wf) { if (strcmp(wf->path,path) == 0) { if (wad_debug_mode & DEBUG_FILE) wad_printf("cached.\n"); return wf; } wf = wf->next; } fd = open(path, O_RDONLY); if (fd < 0) { if (wad_debug_mode & DEBUG_FILE) wad_printf("not found!\n"); return 0; /* Doesn't exist. Oh well */ } if (wad_debug_mode & DEBUG_FILE) wad_printf("loaded.\n"); wf = (WadFile *) wad_malloc(sizeof(WadFile)); wf->path = wad_strdup(path); /* Get file length */ wf->size = lseek(fd,0,SEEK_END); lseek(fd,0,SEEK_SET); /* Try to mmap the file */ wf->addr = mmap(NULL,wf->size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0); close(fd); if (wf->addr == MAP_FAILED) { if (wad_debug_mode & DEBUG_FILE) wad_printf("wad: Couldn't mmap '%s'\n", path); return 0; } wf->next = wad_files; wad_files = wf; return wf; }
void wad_object_reset() { WadFile *f = wad_files; if (wad_debug_mode & DEBUG_OBJECT) { wad_printf("wad: Releasing all files.\n"); } /* Unmap all of the loaded files */ while (f) { if (f->addr) { munmap(f->addr, f->size); } f = f->next; } /* Reset the linked lists */ wad_files = 0; wad_objects = 0; }
void wad_elf_debug(WadObjectFile *wo) { int i; wad_printf("ELF Debug : obj = %x (%s)\n", wo, wo->path); wad_printf(" phdrcnt = %d\n", wad_elf_phdrcnt(wo)); wad_printf(" phdrpos = %x\n", wad_elf_phdrpos(wo)); wad_printf(" shdrcnt = %d\n", wad_elf_shdrcnt(wo)); wad_printf(" shdrpos = %x\n", wad_elf_shdrpos(wo)); for (i = 0; i < wad_elf_shdrcnt(wo); i++) { wad_printf(" section '%s': data = 0x%x, size = %d\n", wad_elf_section_name(wo,i), wad_elf_section_data(wo,i), wad_elf_section_size(wo,i)); } }
WadSegment * wad_segment_find(void *vaddr) { WadSegment *ls; WadSegment *s; char *addr = (char *)vaddr; s = segments; ls = segments; while (s) { if (strcmp(s->mapname,ls->mapname) || (!strlen(ls->mapname))) { ls = s; /* First segment for a given name */ } if ((addr >= s->vaddr) && (addr < (s->vaddr + s->size))) { if (wad_debug_mode & DEBUG_SEGMENT) { wad_printf("wad_segment: %08x --> %08x-%08x in %s\n", vaddr, s->vaddr, ((char *) s->vaddr) + s->size, s->mappath); } return ls; } s = s->next; } return 0; }
/* Initialize wad */ void wad_init() { static int init = 0; wad_memory_init(); if (getenv("WAD_DEBUG_SEGMENT")) { wad_debug_mode |= DEBUG_SEGMENT; } if (getenv("WAD_DEBUG_SYMBOL")) { wad_debug_mode |= DEBUG_SYMBOL; } if (getenv("WAD_DEBUG_OBJECT")) { wad_debug_mode |= DEBUG_OBJECT; } if (getenv("WAD_DEBUG_FILE")) { wad_debug_mode |= DEBUG_FILE; } if (getenv("WAD_DEBUG_HOLD")) { wad_debug_mode |= DEBUG_HOLD; } if (getenv("WAD_DEBUG_STABS")) { wad_debug_mode |= DEBUG_STABS; } if (getenv("WAD_DEBUG_RETURN")) { wad_debug_mode |= DEBUG_RETURN; } if (getenv("WAD_DEBUG_SYMBOL_SEARCH")) { wad_debug_mode |= DEBUG_SYMBOL_SEARCH; } if (getenv("WAD_DEBUG_INIT")) { wad_debug_mode |= DEBUG_INIT; } if (getenv("WAD_DEBUG_STACK")) { wad_debug_mode |= DEBUG_STACK; } if (getenv("WAD_DEBUG_UNWIND")) { wad_debug_mode |= DEBUG_UNWIND; } if (getenv("WAD_DEBUG_SIGNAL")) { wad_debug_mode |= DEBUG_SIGNAL; } if (getenv("WAD_NOSTACK")) { wad_debug_mode |= DEBUG_NOSTACK; } if (getenv("WAD_ONESHOT")) { wad_debug_mode |= DEBUG_ONESHOT; } if (getenv("WAD_DEBUG_STRING")) { wad_debug_mode |= DEBUG_STRING; } if (getenv("WAD_DEBUG_MEMORY")) { wad_debug_mode |= DEBUG_MEMORY; } if (wad_debug_mode & DEBUG_INIT) { wad_printf("WAD: initializing\n"); } if (!init) { wad_signal_init(); wad_object_reset(); } init = 1; }
static int scan_function(Stab *s, char *stabstr, int ns, WadFrame *f) { int i; unsigned long offset; int get_parms = 1; int nbrace = 0; offset = f->pc - f->sym_base; if (wad_debug_mode & DEBUG_STABS) { wad_printf("---[ %s ] --------------\n", f->sym_name); } for (i = 0; i < ns; i++,s++) { if (wad_debug_mode & DEBUG_STABS) { wad_printf(" %10d %10x %10d %10d %10d: '%s'\n", s->n_strx, s->n_type, s->n_other, s->n_desc, s->n_value, stabstr+s->n_strx); } if ((s->n_type == N_UNDF) || (s->n_type == N_SO) || /* (s->n_type == N_FUN) || */ (s->n_type == N_OBJ)) return i; if ((s->n_type == N_FUN) && !(strlen(stabstr+s->n_strx))) return 1; if (s->n_type == N_LBRAC) { nbrace++; get_parms = 0; } if (s->n_type == N_RBRAC) { nbrace--; if (nbrace <= 0) return i; } /* Local variable declaration */ if (s->n_type == N_LSYM) { /* This might be a local variable definition */ /* wad_printf("local: n_value = %d, offset = %d\n", s->n_value, offset);*/ if (s->n_desc <= f->loc_line) { /* Okay. We can pay attention to it */ char *pname; char *c; int len; WadLocal *arg, *a; pname = stabstr+s->n_strx; c = strchr(pname,':'); if (*(c+1) != '(') continue; if (c) { len = (c-pname); } else { len = strlen(pname); } /* printf("local\n"); */ stab_symbol(s,stabstr); a = f->debug_locals; while (a) { if ((strncmp(a->name,pname,len) == 0) && (strlen(a->name) == len)) { /* We already saw this argument. Given a choice between a register and a stack argument. We will choose the stack version */ a->loc = PARM_STACK; a->stack = s->n_value; break; } a = a->next; } if (a) continue; /* We got an argument match. Just skip to the next stab */ arg = (WadLocal *) wad_malloc(sizeof(WadLocal)); { char t = pname[len]; pname[len] = 0; arg->name = wad_string_lookup(pname); pname[len] = t; } arg->loc = PARM_STACK; arg->line = s->n_desc; arg->stack = s->n_value; arg->type = 0; arg->next = 0; { char tname[128]; char *t = tname; c+=1; while ((*c) && (*c != '=')) { *t++ = *c++; } *t = 0; t = type_resolve(tname); arg->type = type_typecode(t); if (wad_debug_mode & DEBUG_STABS) { wad_printf("type_resolve '%s' -> '%s' (%d)\n", tname, t, arg->type); } } if (f->debug_locals) { f->debug_lastlocal->next = arg; f->debug_lastlocal = arg; } else { f->debug_locals = arg; f->debug_lastlocal = arg; f->debug_nlocals= 0; } f->debug_nlocals++; } } if (s->n_type == N_SLINE) { get_parms = 0; if (s->n_value <= offset) { f->loc_line = s->n_desc; } } else if (((s->n_type == N_PSYM) || (s->n_type == N_RSYM)) && get_parms) { /* Parameter counting */ char *pname; char *c; int len; WadLocal *arg; pname = stabstr+s->n_strx; c = strchr(pname,':'); if (c) { len = (c-pname); } else { len = strlen(pname); } /* Get type information */ stab_symbol(s,stabstr); /* Check if the argument was already used */ /* In this case, the first stab simply identifies an argument. The second one identifies its location for the debugger */ { /* Need to do some fix up for linux here */ WadLocal *a = f->debug_args; while (a) { if ((strncmp(a->name,pname,len) == 0) && (strlen(a->name) == len)) { /* We already saw this argument. Given a choice between a register and a stack argument. We will choose the stack version */ if (a->loc == PARM_STACK) { break; } /* Go ahead and use the new argument */ if (s->n_type == N_RSYM) { a->loc = PARM_REGISTER; a->reg = s->n_value; } else { a->loc = PARM_STACK; a->stack = s->n_value; } break; } a = a->next; } if (a) continue; /* We got an argument match. Just skip to the next stab */ } arg = (WadLocal *) wad_malloc(sizeof(WadLocal)); { char t = pname[len]; pname[len] = 0; arg->name = wad_string_lookup(pname); pname[len] = t; } if (s->n_type == N_RSYM) { arg->loc = PARM_REGISTER; arg->reg = s->n_value; arg->stack = 0; } else { arg->loc = PARM_STACK; arg->line = s->n_desc; arg->stack = s->n_value; } arg->type = 0; arg->next = 0; { char tname[128]; char *t = tname; c+=2; while ((*c) && (*c != '=')) { *t++ = *c++; } *t = 0; t = type_resolve(tname); arg->type = type_typecode(t); if (wad_debug_mode & DEBUG_STABS) { wad_printf("type_resolve '%s' -> '%s' (%d)\n", tname, t, arg->type); } } if (f->debug_args) { f->debug_lastarg->next = arg; f->debug_lastarg = arg; } else { f->debug_args = arg; f->debug_lastarg = arg; f->debug_nargs= 0; } f->debug_nargs++; } } return i; }
int wad_elf_debug_info(WadFrame *f) { int nstab, nstabstr, nstabindex, nstabindexstr, nstabexcl, nstabexclstr; int ret; void *stab; char *stabstr; int stabsize; nstab = wad_elf_section_byname(f->object,".stab"); nstabstr = wad_elf_section_byname(f->object,".stabstr"); nstabindex = wad_elf_section_byname(f->object,".stab.index"); nstabindexstr = wad_elf_section_byname(f->object,".stab.indexstr"); nstabexcl = wad_elf_section_byname(f->object,".stab.excl"); nstabexclstr = wad_elf_section_byname(f->object,".stab.exclstr"); #ifdef DEBUG_DEBUG wad_printf("nstab = %d\n", nstab); wad_printf("nstabstr = %d\n", nstabstr); wad_printf("nstabindex = %d\n", nstabindex); wad_printf("nstabindexstr = %d\n", nstabindexstr); wad_printf("nstabexcl = %d\n", nstabexcl); wad_printf("nstabexclstr = %d\n", nstabexclstr); #endif /* Now start searching stabs */ /* Look in the .stab section */ if (nstab > 0) { stab = wad_elf_section_data(f->object,nstab); stabsize = wad_elf_section_size(f->object,nstab); stabstr = (char *) wad_elf_section_data(f->object,nstabstr); if (wad_search_stab(stab,stabsize,stabstr, f)) return 1; } /* Look in the .stab.excl section. A solaris oddity? */ if (nstabexcl > 0) { stab = wad_elf_section_data(f->object,nstabexcl); stabsize = wad_elf_section_size(f->object, nstabexcl); stabstr = (char *) wad_elf_section_data(f->object, nstabexclstr); if (wad_search_stab(stab,stabsize,stabstr, f)) return 1; } /* Look in the .stab.index section. A Solaris oddity? */ if (nstabindex > 0) { stab = wad_elf_section_data(f->object,nstabindex); stabsize = wad_elf_section_size(f->object, nstabindex); stabstr = (char *) wad_elf_section_data(f->object, nstabindexstr); if (wad_search_stab(stab,stabsize,stabstr, f)) { /* Hmmm. Might be in a different file */ WadObjectFile *wo1, *wold; char objfile[MAX_PATH]; /* printf("DEBUG %s\n", f->sym_name); */ wad_strcpy(objfile, f->loc_objfile); wo1 = wad_object_load(objfile); if (wo1) { wold = f->object; f->object = wo1; wad_find_debug(f); f->object = wold; return ret; } else { /* wad_printf("couldn't load %s\n", objfile); */ } /* if (!ret) return wad_search_stab(stab,stabsize,stabstr,f);*/ return ret; } } return 0; }
void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) { greg_t *pc; greg_t *npc; greg_t *sp; greg_t *fp; #ifdef WAD_LINUX greg_t *esi; greg_t *edi; greg_t *ebx; #endif unsigned long addr; ucontext_t *context; unsigned long p_sp; /* process stack pointer */ unsigned long p_pc; /* Process program counter */ unsigned long p_fp; /* Process frame pointer */ int nlevels = 0; int found = 0; void _returnsignal(); WadFrame *frame, *origframe; char *framedata; char *retname = 0; unsigned long current_brk; /* Reset all of the signals while running WAD */ wad_signal_clear(); wad_nlr_func = 0; context = (ucontext_t *) vcontext; wad_printf("WAD: Collecting debugging information...\n"); /* Read the segments */ if (wad_segment_read() < 0) { wad_printf("WAD: Unable to read segment map\n"); return; } if (wad_debug_mode & DEBUG_SIGNAL) { wad_printf("WAD: siginfo = %x, context = %x\n", si, vcontext); } current_brk = (long) sbrk(0); /* Get some information about the current context */ #ifdef WAD_SOLARIS pc = &((context->uc_mcontext).gregs[REG_PC]); npc = &((context->uc_mcontext).gregs[REG_nPC]); sp = &((context->uc_mcontext).gregs[REG_SP]); #endif #ifdef WAD_LINUX sp = &((context->uc_mcontext).gregs[ESP]); /* Top of stack */ fp = &((context->uc_mcontext).gregs[EBP]); /* Stack base - frame pointer */ pc = &((context->uc_mcontext).gregs[EIP]); /* Current instruction */ esi = &((context->uc_mcontext).gregs[ESI]); edi = &((context->uc_mcontext).gregs[EDI]); ebx = &((context->uc_mcontext).gregs[EBX]); wad_saved_esi = (unsigned long) (*esi); wad_saved_edi = (unsigned long) (*edi); wad_saved_ebx = (unsigned long) (*ebx); /* printf("esi = %x, edi = %x, ebx = %x\n", wad_saved_esi, wad_saved_edi, wad_saved_ebx); */ /* printf("&sp = %x, &pc = %x\n", sp, pc); */ #endif /* Get some information out of the signal handler stack */ addr = (unsigned long) si->si_addr; /* See if this might be a stack overflow */ p_pc = (unsigned long) (*pc); p_sp = (unsigned long) (*sp); #ifdef WAD_LINUX p_fp = (unsigned long) (*fp); #endif #ifdef WAD_SOLARIS p_fp = (unsigned long) *(((long *) p_sp) + 14); #endif if (wad_debug_mode & DEBUG_SIGNAL) { wad_printf("fault at address %x, pc = %x, sp = %x, fp = %x\n", addr, p_pc, p_sp, p_fp); } frame = wad_stack_trace(p_pc, p_sp, p_fp); if (!frame) { /* We're really hosed. Not possible to generate a stack trace */ wad_printf("WAD: Unable to generate stack trace.\n"); wad_printf("WAD: Maybe the call stack has been corrupted by buffer overflow.\n"); wad_signal_clear(); return; } { WadFrame *f = frame; while (f) { wad_find_object(f); wad_find_symbol(f); f = f->next; } f = frame; while (f) { wad_find_debug(f); wad_build_vars(f); f = f->next; } } wad_heap_overflow = 0; if (sig == SIGSEGV) { if (addr >= current_brk) wad_heap_overflow = 1; } wad_stack_debug(frame); /* Generate debugging strings */ wad_debug_make_strings(frame); wad_stab_debug(); /* Walk the exception frames and try to find a return point */ origframe = frame; while (frame) { WadReturnFunc *wr = wad_check_return(frame->sym_name); if (wr) { found = 1; wad_nlr_value = wr->value; retname = wr->name; } if (found) { frame->last = 1; /* Cut off top of the stack trace */ break; } frame = frame->next; nlevels++; } if (found) { wad_nlr_levels = nlevels - 1; #ifdef WAD_LINUX wad_restore_i386_registers(origframe, wad_nlr_levels); #endif } else { wad_nlr_levels = -1; } wad_string_debug(); wad_memory_debug(); /* Before we do anything with callbacks, we are going to attempt to dump a wad-core */ { int fd; static int already = 0; fd = open("wadtrace",O_WRONLY | O_CREAT | (already*O_APPEND) | ((already==0)*O_TRUNC),0666); if (fd > 0) { wad_dump_trace(fd,sig,origframe,retname); close(fd); already=1; } } if (sig_callback) { (*sig_callback)(sig,origframe,retname); } else { /* No signal handler defined. Go invoke the default */ wad_default_callback(sig, origframe,retname); } if (wad_debug_mode & DEBUG_HOLD) while(1); /* If we found a function to which we should return, we jump to an alternative piece of code that unwinds the stack and initiates a non-local return. */ if (wad_nlr_levels >= 0) { *(pc) = (greg_t) _returnsignal; #ifdef WAD_SOLARIS *(npc) = *(pc) + 4; #endif if (!(wad_debug_mode & DEBUG_ONESHOT)) { wad_signal_init(); } return; } exit(1); }