BOOL symt_get_address(const struct symt* type, ULONG64* addr) { switch (type->tag) { case SymTagData: switch (((const struct symt_data*)type)->kind) { case DataIsGlobal: case DataIsFileStatic: *addr = ((const struct symt_data*)type)->u.var.offset; break; default: return FALSE; } break; case SymTagFunction: *addr = ((const struct symt_function*)type)->address; break; case SymTagPublicSymbol: *addr = ((const struct symt_public*)type)->address; break; case SymTagFuncDebugStart: case SymTagFuncDebugEnd: case SymTagLabel: if (!((const struct symt_hierarchy_point*)type)->parent || !symt_get_address(((const struct symt_hierarchy_point*)type)->parent, addr)) return FALSE; *addr += ((const struct symt_hierarchy_point*)type)->loc.offset; break; case SymTagThunk: *addr = ((const struct symt_thunk*)type)->address; break; case SymTagCompiland: *addr = ((const struct symt_compiland*)type)->address; break; default: FIXME("Unsupported sym-tag %s for get-address\n", symt_get_tag_str(type->tag)); return FALSE; } 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); } } }
DECLSPEC_HIDDEN BOOL coff_process_info(const struct msc_debug_info* msc_dbg) { const IMAGE_AUX_SYMBOL* aux; const IMAGE_COFF_SYMBOLS_HEADER* coff; const IMAGE_LINENUMBER* coff_linetab; const IMAGE_LINENUMBER* linepnt; const char* coff_strtab; const IMAGE_SYMBOL* coff_sym; const IMAGE_SYMBOL* coff_symbols; struct CoffFileSet coff_files; int curr_file_idx = -1; unsigned int i; int j; int k; int l; int linetab_indx; const char* nampnt; int naux; BOOL ret = FALSE; ULONG64 addr; TRACE("Processing COFF symbols...\n"); assert(sizeof(IMAGE_SYMBOL) == IMAGE_SIZEOF_SYMBOL); assert(sizeof(IMAGE_LINENUMBER) == IMAGE_SIZEOF_LINENUMBER); coff_files.files = NULL; coff_files.nfiles = coff_files.nfiles_alloc = 0; coff = (const IMAGE_COFF_SYMBOLS_HEADER*)msc_dbg->root; coff_symbols = (const IMAGE_SYMBOL*)((const char *)coff + coff->LvaToFirstSymbol); coff_linetab = (const IMAGE_LINENUMBER*)((const char *)coff + coff->LvaToFirstLinenumber); coff_strtab = (const char*)(coff_symbols + coff->NumberOfSymbols); linetab_indx = 0; for (i = 0; i < coff->NumberOfSymbols; i++) { coff_sym = coff_symbols + i; naux = coff_sym->NumberOfAuxSymbols; if (coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE) { curr_file_idx = coff_add_file(&coff_files, msc_dbg->module, (const char*)(coff_sym + 1)); TRACE("New file %s\n", (const char*)(coff_sym + 1)); i += naux; continue; } if (curr_file_idx < 0) { assert(coff_files.nfiles == 0 && coff_files.nfiles_alloc == 0); curr_file_idx = coff_add_file(&coff_files, msc_dbg->module, "<none>"); TRACE("New file <none>\n"); } /* * This guy marks the size and location of the text section * for the current file. We need to keep track of this so * we can figure out what file the different global functions * go with. */ if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux != 0 && coff_sym->Type == 0 && coff_sym->SectionNumber == 1) { aux = (const IMAGE_AUX_SYMBOL*) (coff_sym + 1); if (coff_files.files[curr_file_idx].linetab_offset != -1) { /* * Save this so we can still get the old name. */ const char* fn; fn = source_get(msc_dbg->module, coff_files.files[curr_file_idx].compiland->source); TRACE("Duplicating sect from %s: %x %x %x %d %d\n", fn, aux->Section.Length, aux->Section.NumberOfRelocations, aux->Section.NumberOfLinenumbers, aux->Section.Number, aux->Section.Selection); TRACE("More sect %d %s %08x %d %d %d\n", coff_sym->SectionNumber, coff_get_name(coff_sym, coff_strtab), coff_sym->Value, coff_sym->Type, coff_sym->StorageClass, coff_sym->NumberOfAuxSymbols); /* * Duplicate the file entry. We have no way to describe * multiple text sections in our current way of handling things. */ coff_add_file(&coff_files, msc_dbg->module, fn); } else { TRACE("New text sect from %s: %x %x %x %d %d\n", source_get(msc_dbg->module, coff_files.files[curr_file_idx].compiland->source), aux->Section.Length, aux->Section.NumberOfRelocations, aux->Section.NumberOfLinenumbers, aux->Section.Number, aux->Section.Selection); } if (coff_files.files[curr_file_idx].startaddr > coff_sym->Value) { coff_files.files[curr_file_idx].startaddr = coff_sym->Value; } if (coff_files.files[curr_file_idx].endaddr < coff_sym->Value + aux->Section.Length) { coff_files.files[curr_file_idx].endaddr = coff_sym->Value + aux->Section.Length; } coff_files.files[curr_file_idx].linetab_offset = linetab_indx; coff_files.files[curr_file_idx].linecnt = aux->Section.NumberOfLinenumbers; linetab_indx += aux->Section.NumberOfLinenumbers; i += naux; continue; } if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0 && coff_sym->SectionNumber == 1) { DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress; /* * This is a normal static function when naux == 0. * Just register it. The current file is the correct * one in this instance. */ nampnt = coff_get_name(coff_sym, coff_strtab); TRACE("\tAdding static symbol %s\n", nampnt); /* FIXME: was adding symbol to this_file ??? */ coff_add_symbol(&coff_files.files[curr_file_idx], &symt_new_function(msc_dbg->module, coff_files.files[curr_file_idx].compiland, nampnt, msc_dbg->module->module.BaseOfImage + base + coff_sym->Value, 0 /* FIXME */, NULL /* FIXME */)->symt); i += naux; continue; } if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && ISFCN(coff_sym->Type) && coff_sym->SectionNumber > 0) { struct symt_compiland* compiland = NULL; DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress; nampnt = coff_get_name(coff_sym, coff_strtab); TRACE("%d: %s %s\n", i, wine_dbgstr_longlong(msc_dbg->module->module.BaseOfImage + base + coff_sym->Value), nampnt); TRACE("\tAdding global symbol %s (sect=%s)\n", nampnt, msc_dbg->sectp[coff_sym->SectionNumber - 1].Name); /* * Now we need to figure out which file this guy belongs to. */ for (j = 0; j < coff_files.nfiles; j++) { if (coff_files.files[j].startaddr <= base + coff_sym->Value && coff_files.files[j].endaddr > base + coff_sym->Value) { compiland = coff_files.files[j].compiland; break; } } if (j < coff_files.nfiles) { coff_add_symbol(&coff_files.files[j], &symt_new_function(msc_dbg->module, compiland, nampnt, msc_dbg->module->module.BaseOfImage + base + coff_sym->Value, 0 /* FIXME */, NULL /* FIXME */)->symt); } else { symt_new_function(msc_dbg->module, NULL, nampnt, msc_dbg->module->module.BaseOfImage + base + coff_sym->Value, 0 /* FIXME */, NULL /* FIXME */); } i += naux; continue; } if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && coff_sym->SectionNumber > 0) { DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress; struct location loc; /* * Similar to above, but for the case of data symbols. * These aren't treated as entrypoints. */ nampnt = coff_get_name(coff_sym, coff_strtab); TRACE("%d: %s %s\n", i, wine_dbgstr_longlong(msc_dbg->module->module.BaseOfImage + base + coff_sym->Value), nampnt); TRACE("\tAdding global data symbol %s\n", nampnt); /* * Now we need to figure out which file this guy belongs to. */ loc.kind = loc_absolute; loc.reg = 0; loc.offset = msc_dbg->module->module.BaseOfImage + base + coff_sym->Value; symt_new_global_variable(msc_dbg->module, NULL, nampnt, TRUE /* FIXME */, loc, 0 /* FIXME */, NULL /* FIXME */); i += naux; continue; } if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0) { /* * Ignore these. They don't have anything to do with * reality. */ i += naux; continue; } TRACE("Skipping unknown entry '%s' %d %d %d\n", coff_get_name(coff_sym, coff_strtab), coff_sym->StorageClass, coff_sym->SectionNumber, naux); /* * For now, skip past the aux entries. */ i += naux; } if (coff_files.files != NULL) { /* * OK, we now should have a list of files, and we should have a list * of entrypoints. We need to sort the entrypoints so that we are * able to tie the line numbers with the given functions within the * file. */ for (j = 0; j < coff_files.nfiles; j++) { if (coff_files.files[j].entries != NULL) { qsort(coff_files.files[j].entries, coff_files.files[j].neps, sizeof(struct symt*), symt_cmp_addr); } } /* * Now pick apart the line number tables, and attach the entries * to the given functions. */ for (j = 0; j < coff_files.nfiles; j++) { l = 0; if (coff_files.files[j].neps != 0) { for (k = 0; k < coff_files.files[j].linecnt; k++) { linepnt = coff_linetab + coff_files.files[j].linetab_offset + k; /* * If we have spilled onto the next entrypoint, then * bump the counter.. */ for (;;) { if (l+1 >= coff_files.files[j].neps) break; symt_get_address(coff_files.files[j].entries[l+1], &addr); if (((msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress) < addr)) break; l++; } if (coff_files.files[j].entries[l+1]->tag == SymTagFunction) { /* * Add the line number. This is always relative to the * start of the function, so we need to subtract that offset * first. */ symt_get_address(coff_files.files[j].entries[l+1], &addr); symt_add_func_line(msc_dbg->module, (struct symt_function*)coff_files.files[j].entries[l+1], coff_files.files[j].compiland->source, linepnt->Linenumber, msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress - addr); } } } } for (j = 0; j < coff_files.nfiles; j++) { HeapFree(GetProcessHeap(), 0, coff_files.files[j].entries); } HeapFree(GetProcessHeap(), 0, coff_files.files); msc_dbg->module->module.SymType = SymCoff; /* FIXME: we could have a finer grain here */ msc_dbg->module->module.LineNumbers = TRUE; msc_dbg->module->module.GlobalSymbols = TRUE; msc_dbg->module->module.TypeInfo = FALSE; msc_dbg->module->module.SourceIndexed = TRUE; msc_dbg->module->module.Publics = TRUE; ret = TRUE; } return ret; }