/****************************************************************** * pe_locate_with_coff_symbol_table * * Use the COFF symbol table (if any) from the IMAGE_FILE_HEADER to set the absolute address * of global symbols. * Mingw32 requires this for stabs debug information as address for global variables isn't filled in * (this is similar to what is done in elf_module.c when using the .symtab ELF section) */ static BOOL pe_locate_with_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; char tmp[9]; const char* name; struct hash_table_iter hti; void* ptr; struct symt_data* sym; 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*)(mapping + fmap->u.pe.ntheader.FileHeader.PointerToSymbolTable); for (i = 0; i < numsym; i+= naux, isym += naux) { 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 = fmap->u.pe.strtable + isym->N.Name.Long; if (name[0] == '_') name++; hash_table_iter_init(&module->ht_symbols, &hti, name); while ((ptr = hash_table_iter_up(&hti))) { sym = CONTAINING_RECORD(ptr, struct symt_data, hash_elt); if (sym->symt.tag == SymTagData && (sym->kind == DataIsGlobal || sym->kind == DataIsFileStatic) && sym->u.var.kind == loc_absolute && !strcmp(sym->hash_elt.name, name)) { TRACE("Changing absolute address for %d.%s: %lx -> %s\n", isym->SectionNumber, name, sym->u.var.offset, wine_dbgstr_longlong(module->module.BaseOfImage + fmap->u.pe.sect[isym->SectionNumber - 1].shdr.VirtualAddress + isym->Value)); sym->u.var.offset = module->module.BaseOfImage + fmap->u.pe.sect[isym->SectionNumber - 1].shdr.VirtualAddress + isym->Value; break; } } } naux = isym->NumberOfAuxSymbols + 1; } pe_unmap_full(fmap); return TRUE; }
int module_compute_num_syms(struct module* module) { struct hash_table_iter hti; void* ptr; module->module.NumSyms = 0; hash_table_iter_init(&module->ht_symbols, &hti, NULL); while ((ptr = hash_table_iter_up(&hti))) module->module.NumSyms++; return module->module.NumSyms; }
/****************************************************************** * 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); } } }