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