1 /* 2 * Read VC++ debug information from COFF and eventually 3 * from PDB files. 4 * 5 * Copyright (C) 1996, Eric Youngdale. 6 * Copyright (C) 1999-2000, Ulrich Weigand. 7 * Copyright (C) 2004, Eric Pouech. 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 22 */ 23 24 /* 25 * Note - this handles reading debug information for 32 bit applications 26 * that run under Windows-NT for example. I doubt that this would work well 27 * for 16 bit applications, but I don't think it really matters since the 28 * file format is different, and we should never get in here in such cases. 29 * 30 * TODO: 31 * Get 16 bit CV stuff working. 32 * Add symbol size to internal symbol table. 33 */ 34 35 #include "dbghelp_private.h" 36 37 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_coff); 38 39 /*======================================================================== 40 * Process COFF debug information. 41 */ 42 43 struct CoffFile 44 { 45 unsigned int startaddr; 46 unsigned int endaddr; 47 struct symt_compiland* compiland; 48 int linetab_offset; 49 int linecnt; 50 struct symt** entries; 51 int neps; 52 int neps_alloc; 53 }; 54 55 struct CoffFileSet 56 { 57 struct CoffFile* files; 58 int nfiles; 59 int nfiles_alloc; 60 }; 61 62 static const char* coff_get_name(const IMAGE_SYMBOL* coff_sym, 63 const char* coff_strtab) 64 { 65 static char namebuff[9]; 66 const char* nampnt; 67 68 if (coff_sym->N.Name.Short) 69 { 70 memcpy(namebuff, coff_sym->N.ShortName, 8); 71 namebuff[8] = '\0'; 72 nampnt = &namebuff[0]; 73 } 74 else 75 { 76 nampnt = coff_strtab + coff_sym->N.Name.Long; 77 } 78 79 if (nampnt[0] == '_') nampnt++; 80 return nampnt; 81 } 82 83 static int coff_add_file(struct CoffFileSet* coff_files, struct module* module, 84 const char* filename) 85 { 86 struct CoffFile* file; 87 88 if (coff_files->nfiles + 1 >= coff_files->nfiles_alloc) 89 { 90 if (coff_files->files) 91 { 92 coff_files->nfiles_alloc *= 2; 93 coff_files->files = HeapReAlloc(GetProcessHeap(), 0, coff_files->files, 94 coff_files->nfiles_alloc * sizeof(struct CoffFile)); 95 } 96 else 97 { 98 coff_files->nfiles_alloc = 16; 99 coff_files->files = HeapAlloc(GetProcessHeap(), 0, 100 coff_files->nfiles_alloc * sizeof(struct CoffFile)); 101 } 102 } 103 file = coff_files->files + coff_files->nfiles; 104 file->startaddr = 0xffffffff; 105 file->endaddr = 0; 106 file->compiland = symt_new_compiland(module, 0, 107 source_new(module, NULL, filename)); 108 file->linetab_offset = -1; 109 file->linecnt = 0; 110 file->entries = NULL; 111 file->neps = file->neps_alloc = 0; 112 113 return coff_files->nfiles++; 114 } 115 116 static void coff_add_symbol(struct CoffFile* coff_file, struct symt* sym) 117 { 118 if (coff_file->neps + 1 >= coff_file->neps_alloc) 119 { 120 if (coff_file->entries) 121 { 122 coff_file->neps_alloc *= 2; 123 coff_file->entries = HeapReAlloc(GetProcessHeap(), 0, coff_file->entries, 124 coff_file->neps_alloc * sizeof(struct symt*)); 125 } 126 else 127 { 128 coff_file->neps_alloc = 32; 129 coff_file->entries = HeapAlloc(GetProcessHeap(), 0, 130 coff_file->neps_alloc * sizeof(struct symt*)); 131 } 132 } 133 coff_file->entries[coff_file->neps++] = sym; 134 } 135 136 DECLSPEC_HIDDEN BOOL coff_process_info(const struct msc_debug_info* msc_dbg) 137 { 138 const IMAGE_AUX_SYMBOL* aux; 139 const IMAGE_COFF_SYMBOLS_HEADER* coff; 140 const IMAGE_LINENUMBER* coff_linetab; 141 const IMAGE_LINENUMBER* linepnt; 142 const char* coff_strtab; 143 const IMAGE_SYMBOL* coff_sym; 144 const IMAGE_SYMBOL* coff_symbols; 145 struct CoffFileSet coff_files; 146 int curr_file_idx = -1; 147 unsigned int i; 148 int j; 149 int k; 150 int l; 151 int linetab_indx; 152 const char* nampnt; 153 int naux; 154 BOOL ret = FALSE; 155 ULONG64 addr; 156 157 TRACE("Processing COFF symbols...\n"); 158 159 assert(sizeof(IMAGE_SYMBOL) == IMAGE_SIZEOF_SYMBOL); 160 assert(sizeof(IMAGE_LINENUMBER) == IMAGE_SIZEOF_LINENUMBER); 161 162 coff_files.files = NULL; 163 coff_files.nfiles = coff_files.nfiles_alloc = 0; 164 165 coff = (const IMAGE_COFF_SYMBOLS_HEADER*)msc_dbg->root; 166 167 coff_symbols = (const IMAGE_SYMBOL*)((const char *)coff + coff->LvaToFirstSymbol); 168 coff_linetab = (const IMAGE_LINENUMBER*)((const char *)coff + coff->LvaToFirstLinenumber); 169 coff_strtab = (const char*)(coff_symbols + coff->NumberOfSymbols); 170 171 linetab_indx = 0; 172 173 for (i = 0; i < coff->NumberOfSymbols; i++) 174 { 175 coff_sym = coff_symbols + i; 176 naux = coff_sym->NumberOfAuxSymbols; 177 178 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE) 179 { 180 curr_file_idx = coff_add_file(&coff_files, msc_dbg->module, 181 (const char*)(coff_sym + 1)); 182 TRACE("New file %s\n", (const char*)(coff_sym + 1)); 183 i += naux; 184 continue; 185 } 186 187 if (curr_file_idx < 0) 188 { 189 assert(coff_files.nfiles == 0 && coff_files.nfiles_alloc == 0); 190 curr_file_idx = coff_add_file(&coff_files, msc_dbg->module, "<none>"); 191 TRACE("New file <none>\n"); 192 } 193 194 /* 195 * This guy marks the size and location of the text section 196 * for the current file. We need to keep track of this so 197 * we can figure out what file the different global functions 198 * go with. 199 */ 200 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && 201 naux != 0 && coff_sym->Type == 0 && coff_sym->SectionNumber == 1) 202 { 203 aux = (const IMAGE_AUX_SYMBOL*) (coff_sym + 1); 204 205 if (coff_files.files[curr_file_idx].linetab_offset != -1) 206 { 207 /* 208 * Save this so we can still get the old name. 209 */ 210 const char* fn; 211 212 fn = source_get(msc_dbg->module, 213 coff_files.files[curr_file_idx].compiland->source); 214 215 TRACE("Duplicating sect from %s: %x %x %x %d %d\n", 216 fn, aux->Section.Length, 217 aux->Section.NumberOfRelocations, 218 aux->Section.NumberOfLinenumbers, 219 aux->Section.Number, aux->Section.Selection); 220 TRACE("More sect %d %s %08x %d %d %d\n", 221 coff_sym->SectionNumber, 222 coff_get_name(coff_sym, coff_strtab), 223 coff_sym->Value, coff_sym->Type, 224 coff_sym->StorageClass, coff_sym->NumberOfAuxSymbols); 225 226 /* 227 * Duplicate the file entry. We have no way to describe 228 * multiple text sections in our current way of handling things. 229 */ 230 coff_add_file(&coff_files, msc_dbg->module, fn); 231 } 232 else 233 { 234 TRACE("New text sect from %s: %x %x %x %d %d\n", 235 source_get(msc_dbg->module, coff_files.files[curr_file_idx].compiland->source), 236 aux->Section.Length, 237 aux->Section.NumberOfRelocations, 238 aux->Section.NumberOfLinenumbers, 239 aux->Section.Number, aux->Section.Selection); 240 } 241 242 if (coff_files.files[curr_file_idx].startaddr > coff_sym->Value) 243 { 244 coff_files.files[curr_file_idx].startaddr = coff_sym->Value; 245 } 246 247 if (coff_files.files[curr_file_idx].endaddr < coff_sym->Value + aux->Section.Length) 248 { 249 coff_files.files[curr_file_idx].endaddr = coff_sym->Value + aux->Section.Length; 250 } 251 252 coff_files.files[curr_file_idx].linetab_offset = linetab_indx; 253 coff_files.files[curr_file_idx].linecnt = aux->Section.NumberOfLinenumbers; 254 linetab_indx += aux->Section.NumberOfLinenumbers; 255 i += naux; 256 continue; 257 } 258 259 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0 && 260 coff_sym->SectionNumber == 1) 261 { 262 DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress; 263 /* 264 * This is a normal static function when naux == 0. 265 * Just register it. The current file is the correct 266 * one in this instance. 267 */ 268 nampnt = coff_get_name(coff_sym, coff_strtab); 269 270 TRACE("\tAdding static symbol %s\n", nampnt); 271 272 /* FIXME: was adding symbol to this_file ??? */ 273 coff_add_symbol(&coff_files.files[curr_file_idx], 274 &symt_new_function(msc_dbg->module, 275 coff_files.files[curr_file_idx].compiland, 276 nampnt, 277 msc_dbg->module->module.BaseOfImage + base + coff_sym->Value, 278 0 /* FIXME */, 279 NULL /* FIXME */)->symt); 280 continue; 281 } 282 283 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && 284 ISFCN(coff_sym->Type) && coff_sym->SectionNumber > 0) 285 { 286 struct symt_compiland* compiland = NULL; 287 DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress; 288 nampnt = coff_get_name(coff_sym, coff_strtab); 289 290 TRACE("%d: %s %s\n", 291 i, wine_dbgstr_longlong(msc_dbg->module->module.BaseOfImage + base + coff_sym->Value), 292 nampnt); 293 TRACE("\tAdding global symbol %s (sect=%s)\n", 294 nampnt, msc_dbg->sectp[coff_sym->SectionNumber - 1].Name); 295 296 /* 297 * Now we need to figure out which file this guy belongs to. 298 */ 299 for (j = 0; j < coff_files.nfiles; j++) 300 { 301 if (coff_files.files[j].startaddr <= base + coff_sym->Value 302 && coff_files.files[j].endaddr > base + coff_sym->Value) 303 { 304 compiland = coff_files.files[j].compiland; 305 break; 306 } 307 } 308 if (j < coff_files.nfiles) 309 { 310 coff_add_symbol(&coff_files.files[j], 311 &symt_new_function(msc_dbg->module, compiland, nampnt, 312 msc_dbg->module->module.BaseOfImage + base + coff_sym->Value, 313 0 /* FIXME */, NULL /* FIXME */)->symt); 314 } 315 else 316 { 317 symt_new_function(msc_dbg->module, NULL, nampnt, 318 msc_dbg->module->module.BaseOfImage + base + coff_sym->Value, 319 0 /* FIXME */, NULL /* FIXME */); 320 } 321 i += naux; 322 continue; 323 } 324 325 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && 326 coff_sym->SectionNumber > 0) 327 { 328 DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress; 329 struct location loc; 330 331 /* 332 * Similar to above, but for the case of data symbols. 333 * These aren't treated as entrypoints. 334 */ 335 nampnt = coff_get_name(coff_sym, coff_strtab); 336 337 TRACE("%d: %s %s\n", 338 i, wine_dbgstr_longlong(msc_dbg->module->module.BaseOfImage + base + coff_sym->Value), 339 nampnt); 340 TRACE("\tAdding global data symbol %s\n", nampnt); 341 342 /* 343 * Now we need to figure out which file this guy belongs to. 344 */ 345 loc.kind = loc_absolute; 346 loc.reg = 0; 347 loc.offset = msc_dbg->module->module.BaseOfImage + base + coff_sym->Value; 348 symt_new_global_variable(msc_dbg->module, NULL, nampnt, TRUE /* FIXME */, 349 loc, 0 /* FIXME */, NULL /* FIXME */); 350 i += naux; 351 continue; 352 } 353 354 if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0) 355 { 356 /* 357 * Ignore these. They don't have anything to do with 358 * reality. 359 */ 360 continue; 361 } 362 363 TRACE("Skipping unknown entry '%s' %d %d %d\n", 364 coff_get_name(coff_sym, coff_strtab), 365 coff_sym->StorageClass, coff_sym->SectionNumber, naux); 366 367 /* 368 * For now, skip past the aux entries. 369 */ 370 i += naux; 371 } 372 373 if (coff_files.files != NULL) 374 { 375 /* 376 * OK, we now should have a list of files, and we should have a list 377 * of entrypoints. We need to sort the entrypoints so that we are 378 * able to tie the line numbers with the given functions within the 379 * file. 380 */ 381 for (j = 0; j < coff_files.nfiles; j++) 382 { 383 if (coff_files.files[j].entries != NULL) 384 { 385 qsort(coff_files.files[j].entries, coff_files.files[j].neps, 386 sizeof(struct symt*), symt_cmp_addr); 387 } 388 } 389 390 /* 391 * Now pick apart the line number tables, and attach the entries 392 * to the given functions. 393 */ 394 for (j = 0; j < coff_files.nfiles; j++) 395 { 396 l = 0; 397 if (coff_files.files[j].neps != 0) 398 { 399 for (k = 0; k < coff_files.files[j].linecnt; k++) 400 { 401 linepnt = coff_linetab + coff_files.files[j].linetab_offset + k; 402 /* 403 * If we have spilled onto the next entrypoint, then 404 * bump the counter.. 405 */ 406 for (; l+1 < coff_files.files[j].neps; l++) 407 { 408 if (symt_get_address(coff_files.files[j].entries[l+1], &addr) && 409 msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress < addr) 410 { 411 if (coff_files.files[j].entries[l+1]->tag == SymTagFunction) 412 { 413 /* 414 * Add the line number. This is always relative to the 415 * start of the function, so we need to subtract that offset 416 * first. 417 */ 418 symt_add_func_line(msc_dbg->module, 419 (struct symt_function*)coff_files.files[j].entries[l+1], 420 coff_files.files[j].compiland->source, 421 linepnt->Linenumber, 422 msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress - addr); 423 } 424 break; 425 } 426 } 427 } 428 } 429 } 430 431 for (j = 0; j < coff_files.nfiles; j++) 432 { 433 HeapFree(GetProcessHeap(), 0, coff_files.files[j].entries); 434 } 435 HeapFree(GetProcessHeap(), 0, coff_files.files); 436 msc_dbg->module->module.SymType = SymCoff; 437 /* FIXME: we could have a finer grain here */ 438 msc_dbg->module->module.LineNumbers = TRUE; 439 msc_dbg->module->module.GlobalSymbols = TRUE; 440 msc_dbg->module->module.TypeInfo = FALSE; 441 msc_dbg->module->module.SourceIndexed = TRUE; 442 msc_dbg->module->module.Publics = TRUE; 443 ret = TRUE; 444 } 445 446 return ret; 447 } 448