/****************************************************************** * macho_parse_symtab * * Callback for macho_enum_load_commands. Processes the LC_SYMTAB * load commands from the Mach-O file. */ static int macho_parse_symtab(struct macho_file_map* fmap, const struct load_command* lc, void* user) { const struct symtab_command* sc = (const struct symtab_command*)lc; struct macho_debug_info* mdi = user; const struct nlist* stab; const char* stabstr; int ret = 0; TRACE("(%p/%d, %p, %p) %u syms at 0x%08x, strings 0x%08x - 0x%08x\n", fmap, fmap->fd, lc, user, sc->nsyms, sc->symoff, sc->stroff, sc->stroff + sc->strsize); if (!macho_map_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist), sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr)) return 0; if (!stabs_parse(mdi->module, mdi->module->format_info[DFI_MACHO]->u.macho_info->load_addr - fmap->segs_start, stab, sc->nsyms * sizeof(struct nlist), stabstr, sc->strsize, macho_stabs_def_cb, mdi)) ret = -1; macho_unmap_ranges(fmap, sc->symoff, sc->nsyms * sizeof(struct nlist), sc->stroff, sc->strsize, (const void**)&stab, (const void**)&stabstr); return ret; }
/****************************************************************** * pe_load_stabs * * look for stabs information in PE header (it's how the mingw compiler provides * its debugging information) */ static BOOL pe_load_stabs(const struct process* pcs, struct module* module) { struct image_file_map* fmap = &module->format_info[DFI_PE]->u.pe_info->fmap; struct image_section_map sect_stabs, sect_stabstr; BOOL ret = FALSE; if (pe_find_section(fmap, ".stab", §_stabs) && pe_find_section(fmap, ".stabstr", §_stabstr)) { const char* stab; const char* stabstr; stab = image_map_section(§_stabs); stabstr = image_map_section(§_stabstr); if (stab != IMAGE_NO_MAP && stabstr != IMAGE_NO_MAP) { ret = stabs_parse(module, module->module.BaseOfImage - fmap->u.pe.ntheader.OptionalHeader.ImageBase, stab, image_get_map_size(§_stabs), stabstr, image_get_map_size(§_stabstr), NULL, NULL); } image_unmap_section(§_stabs); image_unmap_section(§_stabstr); if (ret) pe_locate_with_coff_symbol_table(module); } TRACE("%s the STABS debug info\n", ret ? "successfully loaded" : "failed to load"); return ret; }
/****************************************************************** * pe_load_stabs * * look for stabs information in PE header (it's how the mingw compiler provides * its debugging information) */ static BOOL pe_load_stabs(const struct process* pcs, struct module* module, void* mapping, IMAGE_NT_HEADERS* nth) { IMAGE_SECTION_HEADER* section; int i, stabsize = 0, stabstrsize = 0; unsigned int stabs = 0, stabstr = 0; BOOL ret = FALSE; section = (IMAGE_SECTION_HEADER*) ((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader); for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++) { if (!strcasecmp((const char*)section->Name, ".stab")) { stabs = section->VirtualAddress; stabsize = section->SizeOfRawData; } else if (!strncasecmp((const char*)section->Name, ".stabstr", 8)) { stabstr = section->VirtualAddress; stabstrsize = section->SizeOfRawData; } } if (stabstrsize && stabsize) { ret = stabs_parse(module, module->module.BaseOfImage - nth->OptionalHeader.ImageBase, RtlImageRvaToVa(nth, mapping, stabs, NULL), stabsize, RtlImageRvaToVa(nth, mapping, stabstr, NULL), stabstrsize); } TRACE("%s the STABS debug info\n", ret ? "successfully loaded" : "failed to load"); return ret; }
/* machLoadDebugInfo(): attempts to load the debug information for the module identified by <module>. If <map> is NULL, the dylib name is generated from the image name stored in <module> and the file's header and debug information is read into <map> if found. If <map> is non-NULL, it is assumed that the debug information has already been read into it, and parses from that instead. Returns TRUE if the file was found, successfully opened, and had its debug information parsed. Returns FALSE on failure. */ BOOL machLoadDebugInfo(struct process *pcs, struct module *module, MachMap *map){ MachMap _map; BOOL opened = FALSE; BOOL ret = FALSE; int i; DWORD64 loadOffset = 0; TRACE("loading the debug information for %s {module = %p, map = %p}\n", debugstr_w(module->module.LoadedImageName), module, map); /* the file has not been mapped yet => map it now */ if (map == NULL){ /* this isn't a mach file or it couldn't be loaded => fail */ if (!machIsMachFile(module->module.LoadedImageName, NULL, &_map)){ ERR("could not map the image file %s into memory\n", debugstr_w(module->module.LoadedImageName)); return FALSE; } map = &_map; opened = TRUE; } /* try to retrieve the load offset from the NT header. The module base address that is passed into machLoadModule() and that is stored in 'module->module.BaseOfImage' is not entirely the correct address. The symbol addresses stored in the debug information are relative to the start of the mach module itself, and that always seems to load at an address 0x2000 bytes below the module's base address. Unfortunately, all the addresses that get passed to the SymFromAddr() function are relative to the address stored in 'module->module.BaseOfImage. Happily, the offset between these two addresses is stored in the module's header for the text section (IMAGE_SECTION_HEADER). We'll attempt to grab the offset from there instead of hardcoding it. The load offset will be applied to all the symbol addresses as they are parsed. */ if (module->module.BaseOfImage){ IMAGE_NT_HEADERS nt; /* read the NT header => attempt to grab a section header and extract the load offset */ if (pe_load_nt_header(pcs->handle, module->module.BaseOfImage, &nt)){ IMAGE_SECTION_HEADER sec; int i; for (i = 0; i < nt.FileHeader.NumberOfSections; i++){ if (pe_load_nt_sect_header(pcs->handle, module->module.BaseOfImage, i, &nt, &sec)){ if (!strcmp((char *)sec.Name, ".text")){ loadOffset = (DWORD64)(signed)sec.VirtualAddress; break; } } } if (loadOffset == 0) WARN("could not find a valid text section header. Assuming a load offset of 0. Symbol lookups will fail in this module\n"); } else{ /* HACK!!! This value seems to be the correct offset for our modules, but we couldn't calculate it because this module isn't currently loaded. Setting this offset here allows symbols from non-resident modules to still be looked up by address (assuming the base address was correctly specified as well). */ loadOffset = -0x2000ll; FIXME("module could not be read from. Assuming a load offset of 0x%08llx\n", loadOffset); } } else ERR("no module base specified or found. Symbol lookups in this module will fail!\n"); for (i = 0; i < map->numLoadCmds; i++){ switch (map->loadCmds[i].header->cmd){ case LC_SYMTAB: TRACE("parsing the STABS debug information {BaseOfImage = 0x%08llx, loadOffset = 0x%08llx}\n", module->module.BaseOfImage, loadOffset); ret = stabs_parse( module, module->module.BaseOfImage + loadOffset, map->loadCmds[i].data.stabs.stab, map->loadCmds[i].data.stabs.stabSize, (const char *)map->loadCmds[i].data.stabs.strings, map->loadCmds[i].data.stabs.stringsSize); TRACE("%s the STABS debug information\n", ret ? "SUCCESSFULLY loaded" : "FAILED to load"); break; case LC_DYSYMTAB: /* FIXME!! figure out if we need to load or fixup anything from this table */ FIXME("figure out if we need to load or fixup anything from the dynamic symbol table\n"); break; default: continue; } } TRACE("done loading debug information for %s\n", debugstr_w(module->module.LoadedImageName)); if (opened) machUnmapFile(map); return ret; }