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