/*********************************************************************** * pe_load_export_debug_info */ static BOOL pe_load_export_debug_info(const struct process* pcs, struct module* module) { struct image_file_map* fmap = &module->format_info[DFI_PE]->u.pe_info->fmap; unsigned int i; const IMAGE_EXPORT_DIRECTORY* exports; DWORD base = module->module.BaseOfImage; DWORD size; IMAGE_NT_HEADERS* nth; void* mapping; if (dbghelp_options & SYMOPT_NO_PUBLICS) return TRUE; if (!(mapping = pe_map_full(fmap, &nth))) return FALSE; #if 0 /* Add start of DLL (better use the (yet unimplemented) Exe SymTag for this) */ /* FIXME: module.ModuleName isn't correctly set yet if it's passed in SymLoadModule */ symt_new_public(module, NULL, module->module.ModuleName, FALSE, base, 1); #endif /* Add entry point */ symt_new_public(module, NULL, "EntryPoint", FALSE, base + nth->OptionalHeader.AddressOfEntryPoint, 1); #if 0 /* FIXME: we'd better store addresses linked to sections rather than absolute values */ IMAGE_SECTION_HEADER* section; /* Add start of sections */ section = (IMAGE_SECTION_HEADER*) ((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader); for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++) { symt_new_public(module, NULL, section->Name, FALSE, RtlImageRvaToVa(nth, mapping, section->VirtualAddress, NULL), 1); } #endif /* Add exported functions */ if ((exports = RtlImageDirectoryEntryToData(mapping, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size))) { const WORD* ordinals = NULL; const DWORD_PTR* functions = NULL; const DWORD* names = NULL; unsigned int j; char buffer[16]; functions = RtlImageRvaToVa(nth, mapping, exports->AddressOfFunctions, NULL); ordinals = RtlImageRvaToVa(nth, mapping, exports->AddressOfNameOrdinals, NULL); names = RtlImageRvaToVa(nth, mapping, exports->AddressOfNames, NULL); if (functions && ordinals && names) { for (i = 0; i < exports->NumberOfNames; i++) { if (!names[i]) continue; symt_new_public(module, NULL, RtlImageRvaToVa(nth, mapping, names[i], NULL), FALSE, base + functions[ordinals[i]], 1); } for (i = 0; i < exports->NumberOfFunctions; i++) { if (!functions[i]) continue; /* Check if we already added it with a name */ for (j = 0; j < exports->NumberOfNames; j++) if ((ordinals[j] == i) && names[j]) break; if (j < exports->NumberOfNames) continue; snprintf(buffer, sizeof(buffer), "%d", i + exports->Base); symt_new_public(module, NULL, buffer, FALSE, base + (DWORD)functions[i], 1); } } } /* no real debug info, only entry points */ if (module->module.SymType == SymDeferred) module->module.SymType = SymExport; pe_unmap_full(fmap); return TRUE; }
/****************************************************************** * macho_finish_stabs * * Integrate the non-debugging symbols we've gathered into the * symbols that were generated during stabs parsing. */ static void macho_finish_stabs(struct module* module, struct hash_table* ht_symtab) { struct hash_table_iter hti_ours; struct symtab_elt* ste; BOOL adjusted = FALSE; TRACE("(%p, %p)\n", module, ht_symtab); /* For each of our non-debugging symbols, see if it can provide some * missing details to one of the module's known symbols. */ hash_table_iter_init(ht_symtab, &hti_ours, NULL); while ((ste = hash_table_iter_up(&hti_ours))) { struct hash_table_iter hti_modules; void* ptr; struct symt_ht* sym; struct symt_function* func; struct symt_data* data; hash_table_iter_init(&module->ht_symbols, &hti_modules, ste->ht_elt.name); while ((ptr = hash_table_iter_up(&hti_modules))) { sym = GET_ENTRY(ptr, struct symt_ht, hash_elt); if (strcmp(sym->hash_elt.name, ste->ht_elt.name)) continue; switch (sym->symt.tag) { case SymTagFunction: func = (struct symt_function*)sym; if (func->address == module->format_info[DFI_MACHO]->u.macho_info->load_addr) { TRACE("Adjusting function %p/%s!%s from 0x%08lx to 0x%08lx\n", func, debugstr_w(module->module.ModuleName), sym->hash_elt.name, func->address, ste->addr); func->address = ste->addr; adjusted = TRUE; } if (func->address == ste->addr) ste->used = 1; break; case SymTagData: data = (struct symt_data*)sym; switch (data->kind) { case DataIsGlobal: case DataIsFileStatic: if (data->u.var.offset == module->format_info[DFI_MACHO]->u.macho_info->load_addr) { TRACE("Adjusting data symbol %p/%s!%s from 0x%08lx to 0x%08lx\n", data, debugstr_w(module->module.ModuleName), sym->hash_elt.name, data->u.var.offset, ste->addr); data->u.var.offset = ste->addr; adjusted = TRUE; } if (data->u.var.offset == ste->addr) { enum DataKind new_kind; new_kind = ste->is_global ? DataIsGlobal : DataIsFileStatic; if (data->kind != new_kind) { WARN("Changing kind for %p/%s!%s from %d to %d\n", sym, debugstr_w(module->module.ModuleName), sym->hash_elt.name, (int)data->kind, (int)new_kind); data->kind = new_kind; adjusted = TRUE; } ste->used = 1; } break; default:; } break; default: TRACE("Ignoring tag %u\n", sym->symt.tag); break; } } } if (adjusted) { /* since we may have changed some addresses, mark the module to be resorted */ module->sortlist_valid = FALSE; } /* Mark any of our non-debugging symbols which fall on an already-used * address as "used". This allows us to skip them in the next loop, * below. We do this in separate loops because symt_new_* marks the * list as needing sorting and symt_find_nearest sorts if needed, * causing thrashing. */ if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY)) { hash_table_iter_init(ht_symtab, &hti_ours, NULL); while ((ste = hash_table_iter_up(&hti_ours))) { struct symt_ht* sym; ULONG64 addr; if (ste->used) continue; sym = symt_find_nearest(module, ste->addr); if (sym) symt_get_address(&sym->symt, &addr); if (sym && ste->addr == addr) { ULONG64 size = 0; DWORD kind = -1; ste->used = 1; /* If neither symbol has a correct size (ours never does), we * consider them both to be markers. No warning is needed in * that case. * Also, we check that we don't have two symbols, one local, the other * global, which is legal. */ symt_get_info(module, &sym->symt, TI_GET_LENGTH, &size); symt_get_info(module, &sym->symt, TI_GET_DATAKIND, &kind); if (size && kind == (ste->is_global ? DataIsGlobal : DataIsFileStatic)) FIXME("Duplicate in %s: %s<%08lx> %s<%s-%s>\n", debugstr_w(module->module.ModuleName), ste->ht_elt.name, ste->addr, sym->hash_elt.name, wine_dbgstr_longlong(addr), wine_dbgstr_longlong(size)); } } } /* For any of our remaining non-debugging symbols which have no match * among the module's known symbols, add them as new symbols. */ hash_table_iter_init(ht_symtab, &hti_ours, NULL); while ((ste = hash_table_iter_up(&hti_ours))) { if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY) && !ste->used) { if (ste->is_code) { symt_new_function(module, ste->compiland, ste->ht_elt.name, ste->addr, 0, NULL); } else { struct location loc; loc.kind = loc_absolute; loc.reg = 0; loc.offset = ste->addr; symt_new_global_variable(module, ste->compiland, ste->ht_elt.name, !ste->is_global, loc, 0, NULL); } ste->used = 1; } if (ste->is_public && !(dbghelp_options & SYMOPT_NO_PUBLICS)) { symt_new_public(module, ste->compiland, ste->ht_elt.name, ste->addr, 0); } } }
/****************************************************************** * pe_load_coff_symbol_table * * Load public symbols out of the COFF symbol table (if any). */ static BOOL pe_load_coff_symbol_table(struct module* module) { struct image_file_map* fmap = &module->format_info[DFI_PE]->u.pe_info->fmap; const IMAGE_SYMBOL* isym; int i, numsym, naux; const char* strtable; char tmp[9]; const char* name; const char* lastfilename = NULL; struct symt_compiland* compiland = NULL; const IMAGE_SECTION_HEADER* sect; const char* mapping; numsym = fmap->u.pe.ntheader.FileHeader.NumberOfSymbols; if (!fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable || !numsym) return TRUE; if (!(mapping = pe_map_full(fmap, NULL))) return FALSE; isym = (const IMAGE_SYMBOL*)((const char*)mapping + fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable); /* FIXME: no way to get strtable size */ strtable = (const char*)&isym[numsym]; sect = IMAGE_FIRST_SECTION(RtlImageNtHeader((HMODULE)mapping)); for (i = 0; i < numsym; i+= naux, isym += naux) { if (isym->StorageClass == IMAGE_SYM_CLASS_FILE) { lastfilename = (const char*)(isym + 1); compiland = NULL; } if (isym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && isym->SectionNumber > 0 && isym->SectionNumber <= fmap->u.pe.ntheader.FileHeader.NumberOfSections) { if (isym->N.Name.Short) { name = memcpy(tmp, isym->N.ShortName, 8); tmp[8] = '\0'; } else name = strtable + isym->N.Name.Long; if (name[0] == '_') name++; if (!compiland && lastfilename) compiland = symt_new_compiland(module, 0, source_new(module, NULL, lastfilename)); if (!(dbghelp_options & SYMOPT_NO_PUBLICS)) symt_new_public(module, compiland, name, FALSE, module->module.BaseOfImage + sect[isym->SectionNumber - 1].VirtualAddress + isym->Value, 1); } naux = isym->NumberOfAuxSymbols + 1; } module->module.SymType = SymCoff; module->module.LineNumbers = FALSE; module->module.GlobalSymbols = FALSE; module->module.TypeInfo = FALSE; module->module.SourceIndexed = FALSE; module->module.Publics = TRUE; pe_unmap_full(fmap); return TRUE; }