1 /* 2 * Usage: rsym input-file output-file 3 * 4 * There are two sources of information: the .stab/.stabstr 5 * sections of the executable and the COFF symbol table. Most 6 * of the information is in the .stab/.stabstr sections. 7 * However, most of our asm files don't contain .stab directives, 8 * so routines implemented in assembler won't show up in the 9 * .stab section. They are present in the COFF symbol table. 10 * So, we mostly use the .stab/.stabstr sections, but we augment 11 * the info there with info from the COFF symbol table when 12 * possible. 13 * 14 * This is a tool and is compiled using the host compiler, 15 * i.e. on Linux gcc and not mingw-gcc (cross-compiler). 16 * Therefore we can't include SDK headers and we have to 17 * duplicate some definitions here. 18 * Also note that the internal functions are "old C-style", 19 * returning an int, where a return of 0 means success and 20 * non-zero is failure. 21 */ 22 23 #include "../../dll/win32/dbghelp/compat.h" 24 25 #include <stdio.h> 26 #include <string.h> 27 #include <stdlib.h> 28 #include <assert.h> 29 #include <wchar.h> 30 31 #include "rsym.h" 32 33 #define MAX_PATH 260 34 #define MAX_SYM_NAME 2000 35 36 struct StringEntry 37 { 38 struct StringEntry *Next; 39 ULONG Offset; 40 char *String; 41 }; 42 43 struct StringHashTable 44 { 45 ULONG TableSize; 46 struct StringEntry **Table; 47 }; 48 49 /* This is the famous DJB hash */ 50 static unsigned int 51 ComputeDJBHash(const char *name) 52 { 53 unsigned int val = 5381; 54 int i = 0; 55 56 for (i = 0; name[i]; i++) 57 { 58 val = (33 * val) + name[i]; 59 } 60 61 return val; 62 } 63 64 static void 65 AddStringToHash(struct StringHashTable *StringTable, 66 unsigned int hash, 67 ULONG Offset, 68 char *StringPtr) 69 { 70 struct StringEntry *entry = calloc(1, sizeof(struct StringEntry)); 71 entry->Offset = Offset; 72 entry->String = StringPtr; 73 entry->Next = StringTable->Table[hash]; 74 StringTable->Table[hash] = entry; 75 } 76 77 static void 78 StringHashTableInit(struct StringHashTable *StringTable, 79 ULONG StringsLength, 80 char *StringsBase) 81 { 82 char *Start = StringsBase; 83 char *End = StringsBase + StringsLength; 84 StringTable->TableSize = 1024; 85 StringTable->Table = calloc(1024, sizeof(struct StringEntry *)); 86 while (Start < End) 87 { 88 AddStringToHash(StringTable, 89 ComputeDJBHash(Start) % StringTable->TableSize, 90 Start - StringsBase, 91 Start); 92 Start += strlen(Start) + 1; 93 } 94 } 95 96 static void 97 StringHashTableFree(struct StringHashTable *StringTable) 98 { 99 int i; 100 struct StringEntry *entry; 101 for (i = 0; i < StringTable->TableSize; i++) 102 { 103 while ((entry = StringTable->Table[i])) 104 { 105 entry = entry->Next; 106 free(StringTable->Table[i]); 107 StringTable->Table[i] = entry; 108 } 109 } 110 free(StringTable->Table); 111 } 112 113 static int 114 CompareSymEntry(const PROSSYM_ENTRY SymEntry1, const PROSSYM_ENTRY SymEntry2) 115 { 116 if (SymEntry1->Address < SymEntry2->Address) 117 { 118 return -1; 119 } 120 121 if (SymEntry2->Address < SymEntry1->Address) 122 { 123 return +1; 124 } 125 126 if (SymEntry2->SourceLine == 0) 127 { 128 return -1; 129 } 130 131 if (SymEntry1->SourceLine == 0) 132 { 133 return +1; 134 } 135 136 return 0; 137 } 138 139 static int 140 GetStabInfo(void *FileData, PIMAGE_FILE_HEADER PEFileHeader, 141 PIMAGE_SECTION_HEADER PESectionHeaders, 142 ULONG *StabSymbolsLength, void **StabSymbolsBase, 143 ULONG *StabStringsLength, void **StabStringsBase) 144 { 145 ULONG Idx; 146 147 /* Load .stab and .stabstr sections if available */ 148 *StabSymbolsBase = NULL; 149 *StabSymbolsLength = 0; 150 *StabStringsBase = NULL; 151 *StabStringsLength = 0; 152 153 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++) 154 { 155 /* printf("section: '%.08s'\n", PESectionHeaders[Idx].Name); */ 156 if ((strncmp((char *) PESectionHeaders[Idx].Name, ".stab", 5) == 0) 157 && (PESectionHeaders[Idx].Name[5] == 0)) 158 { 159 /* printf(".stab section found. Size %d\n", PESectionHeaders[Idx].SizeOfRawData); */ 160 161 *StabSymbolsLength = PESectionHeaders[Idx].SizeOfRawData; 162 *StabSymbolsBase = (void *)((char *) FileData + PESectionHeaders[Idx].PointerToRawData); 163 } 164 165 if (strncmp((char *) PESectionHeaders[Idx].Name, ".stabstr", 8) == 0) 166 { 167 /* printf(".stabstr section found. Size %d\n", PESectionHeaders[Idx].SizeOfRawData); */ 168 169 *StabStringsLength = PESectionHeaders[Idx].SizeOfRawData; 170 *StabStringsBase = (void *)((char *) FileData + PESectionHeaders[Idx].PointerToRawData); 171 } 172 } 173 174 return 0; 175 } 176 177 static int 178 GetCoffInfo(void *FileData, PIMAGE_FILE_HEADER PEFileHeader, 179 PIMAGE_SECTION_HEADER PESectionHeaders, 180 ULONG *CoffSymbolsLength, void **CoffSymbolsBase, 181 ULONG *CoffStringsLength, void **CoffStringsBase) 182 { 183 184 if (PEFileHeader->PointerToSymbolTable == 0 || PEFileHeader->NumberOfSymbols == 0) 185 { 186 /* No COFF symbol table */ 187 *CoffSymbolsLength = 0; 188 *CoffStringsLength = 0; 189 } 190 else 191 { 192 *CoffSymbolsLength = PEFileHeader->NumberOfSymbols * sizeof(COFF_SYMENT); 193 *CoffSymbolsBase = (void *)((char *) FileData + PEFileHeader->PointerToSymbolTable); 194 *CoffStringsLength = *((ULONG *) ((char *) *CoffSymbolsBase + *CoffSymbolsLength)); 195 *CoffStringsBase = (void *)((char *) *CoffSymbolsBase + *CoffSymbolsLength); 196 } 197 198 return 0; 199 } 200 201 static ULONG 202 FindOrAddString(struct StringHashTable *StringTable, 203 char *StringToFind, 204 ULONG *StringsLength, 205 void *StringsBase) 206 { 207 unsigned int hash = ComputeDJBHash(StringToFind) % StringTable->TableSize; 208 struct StringEntry *entry = StringTable->Table[hash]; 209 210 while (entry && strcmp(entry->String, StringToFind)) 211 entry = entry->Next; 212 213 if (entry) 214 { 215 return entry->Offset; 216 } 217 else 218 { 219 char *End = (char *)StringsBase + *StringsLength; 220 221 strcpy(End, StringToFind); 222 *StringsLength += strlen(StringToFind) + 1; 223 224 AddStringToHash(StringTable, hash, End - (char *)StringsBase, End); 225 226 return End - (char *)StringsBase; 227 } 228 } 229 230 static int 231 ConvertStabs(ULONG *SymbolsCount, PROSSYM_ENTRY *SymbolsBase, 232 ULONG *StringsLength, void *StringsBase, 233 ULONG StabSymbolsLength, void *StabSymbolsBase, 234 ULONG StabStringsLength, void *StabStringsBase, 235 ULONG_PTR ImageBase, PIMAGE_FILE_HEADER PEFileHeader, 236 PIMAGE_SECTION_HEADER PESectionHeaders) 237 { 238 PSTAB_ENTRY StabEntry; 239 ULONG Count, i; 240 ULONG_PTR Address, LastFunctionAddress; 241 int First = 1; 242 char *Name; 243 ULONG NameLen; 244 char FuncName[256]; 245 PROSSYM_ENTRY Current; 246 struct StringHashTable StringHash; 247 248 StabEntry = StabSymbolsBase; 249 Count = StabSymbolsLength / sizeof(STAB_ENTRY); 250 *SymbolsCount = 0; 251 252 if (Count == 0) 253 { 254 /* No symbol info */ 255 *SymbolsBase = NULL; 256 return 0; 257 } 258 259 *SymbolsBase = malloc(Count * sizeof(ROSSYM_ENTRY)); 260 if (*SymbolsBase == NULL) 261 { 262 fprintf(stderr, "Failed to allocate memory for converted .stab symbols\n"); 263 return 1; 264 } 265 Current = *SymbolsBase; 266 memset(Current, 0, sizeof(*Current)); 267 268 StringHashTableInit(&StringHash, *StringsLength, (char *)StringsBase); 269 270 LastFunctionAddress = 0; 271 for (i = 0; i < Count; i++) 272 { 273 if (LastFunctionAddress == 0) 274 { 275 Address = StabEntry[i].n_value - ImageBase; 276 } 277 else 278 { 279 Address = LastFunctionAddress + StabEntry[i].n_value; 280 } 281 switch (StabEntry[i].n_type) 282 { 283 case N_SO: 284 case N_SOL: 285 case N_BINCL: 286 Name = (char *) StabStringsBase + StabEntry[i].n_strx; 287 if (StabStringsLength < StabEntry[i].n_strx 288 || *Name == '\0' || Name[strlen(Name) - 1] == '/' 289 || Name[strlen(Name) - 1] == '\\' 290 || StabEntry[i].n_value < ImageBase) 291 { 292 continue; 293 } 294 if (First || Address != Current->Address) 295 { 296 if (!First) 297 { 298 memset(++Current, 0, sizeof(*Current)); 299 Current->FunctionOffset = Current[-1].FunctionOffset; 300 } 301 else 302 First = 0; 303 Current->Address = Address; 304 } 305 Current->FileOffset = FindOrAddString(&StringHash, 306 (char *)StabStringsBase + StabEntry[i].n_strx, 307 StringsLength, 308 StringsBase); 309 break; 310 case N_FUN: 311 if (StabEntry[i].n_desc == 0 || StabEntry[i].n_value < ImageBase) 312 { 313 LastFunctionAddress = 0; /* line # 0 = end of function */ 314 continue; 315 } 316 if (First || Address != Current->Address) 317 { 318 if (!First) 319 memset(++Current, 0, sizeof(*Current)); 320 else 321 First = 0; 322 Current->Address = Address; 323 Current->FileOffset = Current[-1].FileOffset; 324 } 325 Name = (char *)StabStringsBase + StabEntry[i].n_strx; 326 NameLen = strcspn(Name, ":"); 327 if (sizeof(FuncName) <= NameLen) 328 { 329 free(*SymbolsBase); 330 fprintf(stderr, "Function name too long\n"); 331 return 1; 332 } 333 memcpy(FuncName, Name, NameLen); 334 FuncName[NameLen] = '\0'; 335 Current->FunctionOffset = FindOrAddString(&StringHash, 336 FuncName, 337 StringsLength, 338 StringsBase); 339 Current->SourceLine = 0; 340 LastFunctionAddress = Address; 341 break; 342 case N_SLINE: 343 if (First || Address != Current->Address) 344 { 345 if (!First) 346 { 347 memset(++Current, 0, sizeof(*Current)); 348 Current->FileOffset = Current[-1].FileOffset; 349 Current->FunctionOffset = Current[-1].FunctionOffset; 350 } 351 else 352 First = 0; 353 Current->Address = Address; 354 } 355 Current->SourceLine = StabEntry[i].n_desc; 356 break; 357 default: 358 continue; 359 } 360 } 361 *SymbolsCount = (Current - *SymbolsBase + 1); 362 363 qsort(*SymbolsBase, *SymbolsCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry); 364 365 StringHashTableFree(&StringHash); 366 367 return 0; 368 } 369 370 static int 371 ConvertCoffs(ULONG *SymbolsCount, PROSSYM_ENTRY *SymbolsBase, 372 ULONG *StringsLength, void *StringsBase, 373 ULONG CoffSymbolsLength, void *CoffSymbolsBase, 374 ULONG CoffStringsLength, void *CoffStringsBase, 375 ULONG_PTR ImageBase, PIMAGE_FILE_HEADER PEFileHeader, 376 PIMAGE_SECTION_HEADER PESectionHeaders) 377 { 378 ULONG Count, i; 379 PCOFF_SYMENT CoffEntry; 380 char FuncName[256], FileName[1024]; 381 char *p; 382 PROSSYM_ENTRY Current; 383 struct StringHashTable StringHash; 384 385 CoffEntry = (PCOFF_SYMENT) CoffSymbolsBase; 386 Count = CoffSymbolsLength / sizeof(COFF_SYMENT); 387 388 *SymbolsBase = malloc(Count * sizeof(ROSSYM_ENTRY)); 389 if (*SymbolsBase == NULL) 390 { 391 fprintf(stderr, "Unable to allocate memory for converted COFF symbols\n"); 392 return 1; 393 } 394 *SymbolsCount = 0; 395 Current = *SymbolsBase; 396 397 StringHashTableInit(&StringHash, *StringsLength, (char*)StringsBase); 398 399 for (i = 0; i < Count; i++) 400 { 401 if (ISFCN(CoffEntry[i].e_type) || C_EXT == CoffEntry[i].e_sclass) 402 { 403 Current->Address = CoffEntry[i].e_value; 404 if (CoffEntry[i].e_scnum > 0) 405 { 406 if (PEFileHeader->NumberOfSections < CoffEntry[i].e_scnum) 407 { 408 free(*SymbolsBase); 409 fprintf(stderr, 410 "Invalid section number %d in COFF symbols (only %d sections present)\n", 411 CoffEntry[i].e_scnum, 412 PEFileHeader->NumberOfSections); 413 return 1; 414 } 415 Current->Address += PESectionHeaders[CoffEntry[i].e_scnum - 1].VirtualAddress; 416 } 417 Current->FileOffset = 0; 418 if (CoffEntry[i].e.e.e_zeroes == 0) 419 { 420 if (sizeof(FuncName) <= strlen((char *) CoffStringsBase + CoffEntry[i].e.e.e_offset)) 421 { 422 free(*SymbolsBase); 423 fprintf(stderr, "Function name too long\n"); 424 StringHashTableFree(&StringHash); 425 return 1; 426 } 427 strcpy(FuncName, (char *) CoffStringsBase + CoffEntry[i].e.e.e_offset); 428 } 429 else 430 { 431 memcpy(FuncName, CoffEntry[i].e.e_name, E_SYMNMLEN); 432 FuncName[E_SYMNMLEN] = '\0'; 433 } 434 435 /* Name demangling: stdcall */ 436 p = strrchr(FuncName, '@'); 437 if (p != NULL) 438 { 439 *p = '\0'; 440 } 441 p = ('_' == FuncName[0] || '@' == FuncName[0] ? FuncName + 1 : FuncName); 442 Current->FunctionOffset = FindOrAddString(&StringHash, 443 p, 444 StringsLength, 445 StringsBase); 446 Current->SourceLine = 0; 447 memset(++Current, 0, sizeof(*Current)); 448 } 449 450 i += CoffEntry[i].e_numaux; 451 } 452 453 *SymbolsCount = (Current - *SymbolsBase + 1); 454 qsort(*SymbolsBase, *SymbolsCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry); 455 456 StringHashTableFree(&StringHash); 457 458 return 0; 459 } 460 461 struct DbgHelpLineEntry { 462 ULONG vma; 463 ULONG fileId; 464 ULONG functionId; 465 ULONG line; 466 }; 467 468 struct DbgHelpStringTab { 469 ULONG Length; 470 ULONG Bytes; 471 char ***Table; 472 ULONG LineEntries, CurLineEntries; 473 struct DbgHelpLineEntry *LineEntryData; 474 void *process; 475 DWORD module_base; 476 char *PathChop; 477 char *SourcePath; 478 struct DbgHelpLineEntry *lastLineEntry; 479 }; 480 481 static struct DbgHelpLineEntry* 482 DbgHelpAddLineEntry(struct DbgHelpStringTab *tab) 483 { 484 if (tab->CurLineEntries == tab->LineEntries) 485 { 486 struct DbgHelpLineEntry *newEntries = realloc(tab->LineEntryData, 487 tab->LineEntries * 2 * sizeof(struct DbgHelpLineEntry)); 488 489 if (!newEntries) 490 return 0; 491 492 tab->LineEntryData = newEntries; 493 494 memset(tab->LineEntryData + tab->LineEntries, 0, sizeof(struct DbgHelpLineEntry) * tab->LineEntries); 495 tab->LineEntries *= 2; 496 } 497 498 return &tab->LineEntryData[tab->CurLineEntries++]; 499 } 500 501 static int 502 DbgHelpAddStringToTable(struct DbgHelpStringTab *tab, char *name) 503 { 504 unsigned int bucket = ComputeDJBHash(name) % tab->Length; 505 char **tabEnt = tab->Table[bucket]; 506 int i; 507 char **newBucket; 508 509 if (tabEnt) 510 { 511 for (i = 0; tabEnt[i] && strcmp(tabEnt[i], name); i++); 512 if (tabEnt[i]) 513 { 514 free(name); 515 return (i << 10) | bucket; 516 } 517 } 518 else 519 i = 0; 520 521 /* At this point, we need to insert */ 522 tab->Bytes += strlen(name) + 1; 523 524 newBucket = realloc(tab->Table[bucket], (i+2) * sizeof(char *)); 525 526 if (!newBucket) 527 { 528 fprintf(stderr, "realloc failed!\n"); 529 return -1; 530 } 531 532 tab->Table[bucket] = newBucket; 533 tab->Table[bucket][i+1] = 0; 534 tab->Table[bucket][i] = name; 535 return (i << 10) | bucket; 536 } 537 538 const char* 539 DbgHelpGetString(struct DbgHelpStringTab *tab, int id) 540 { 541 int i = id >> 10; 542 int bucket = id & 0x3ff; 543 return tab->Table[bucket][i]; 544 } 545 546 /* Remove a prefix of PathChop if it exists and return a copy of the tail. */ 547 static char * 548 StrDupShortenPath(char *PathChop, char *FilePath) 549 { 550 int pclen = strlen(PathChop); 551 if (!strncmp(FilePath, PathChop, pclen)) 552 { 553 return strdup(FilePath+pclen); 554 } 555 else 556 { 557 return strdup(FilePath); 558 } 559 } 560 561 static BOOL 562 DbgHelpAddLineNumber(PSRCCODEINFO LineInfo, void *UserContext) 563 { 564 struct DbgHelpStringTab *tab = (struct DbgHelpStringTab *)UserContext; 565 DWORD64 disp; 566 int fileId, functionId; 567 PSYMBOL_INFO pSymbol = malloc(FIELD_OFFSET(SYMBOL_INFO, Name[MAX_SYM_NAME])); 568 if (!pSymbol) return FALSE; 569 memset(pSymbol, 0, FIELD_OFFSET(SYMBOL_INFO, Name[MAX_SYM_NAME])); 570 571 /* If any file can be opened by relative path up to a certain level, then 572 record that path. */ 573 if (!tab->PathChop) 574 { 575 int i, endLen; 576 char *end = strrchr(LineInfo->FileName, '/'); 577 578 if (!end) 579 end = strrchr(LineInfo->FileName, '\\'); 580 581 if (end) 582 { 583 for (i = (end - LineInfo->FileName) - 1; i >= 0; i--) 584 { 585 if (LineInfo->FileName[i] == '/' || LineInfo->FileName[i] == '\\') 586 { 587 char *synthname = malloc(strlen(tab->SourcePath) + 588 strlen(LineInfo->FileName + i + 1) 589 + 2); 590 strcpy(synthname, tab->SourcePath); 591 strcat(synthname, "/"); 592 strcat(synthname, LineInfo->FileName + i + 1); 593 FILE *f = fopen(synthname, "r"); 594 free(synthname); 595 if (f) 596 { 597 fclose(f); 598 break; 599 } 600 } 601 } 602 603 i++; /* Be in the string or past the next slash */ 604 tab->PathChop = malloc(i + 1); 605 memcpy(tab->PathChop, LineInfo->FileName, i); 606 tab->PathChop[i] = 0; 607 } 608 } 609 610 fileId = DbgHelpAddStringToTable(tab, 611 StrDupShortenPath(tab->PathChop, 612 LineInfo->FileName)); 613 614 pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); 615 pSymbol->MaxNameLen = MAX_SYM_NAME; 616 617 if (!SymFromAddr(tab->process, LineInfo->Address, &disp, pSymbol)) 618 { 619 //fprintf(stderr, "SymFromAddr failed.\n"); 620 free(pSymbol); 621 return FALSE; 622 } 623 624 functionId = DbgHelpAddStringToTable(tab, strdup(pSymbol->Name)); 625 626 if (LineInfo->Address == 0) 627 fprintf(stderr, "Address is 0.\n"); 628 629 tab->lastLineEntry = DbgHelpAddLineEntry(tab); 630 tab->lastLineEntry->vma = LineInfo->Address - LineInfo->ModBase; 631 tab->lastLineEntry->functionId = functionId; 632 tab->lastLineEntry->fileId = fileId; 633 tab->lastLineEntry->line = LineInfo->LineNumber; 634 635 free(pSymbol); 636 return TRUE; 637 } 638 639 static int 640 ConvertDbgHelp(void *process, DWORD module_base, char *SourcePath, 641 ULONG *SymbolsCount, PROSSYM_ENTRY *SymbolsBase, 642 ULONG *StringsLength, void **StringsBase) 643 { 644 char *strings, *strings_copy; 645 int i, j, bucket, entry; 646 PROSSYM_ENTRY rossym; 647 struct DbgHelpStringTab strtab = { 0 }; 648 649 strtab.process = process; 650 strtab.module_base = module_base; 651 strtab.Bytes = 1; 652 strtab.Length = 1024; 653 strtab.Table = calloc(1024, sizeof(const char **)); 654 strtab.Table[0] = calloc(2, sizeof(const char *)); 655 strtab.Table[0][0] = strdup(""); // The zero string 656 strtab.CurLineEntries = 0; 657 strtab.LineEntries = 16384; 658 strtab.LineEntryData = calloc(strtab.LineEntries, sizeof(struct DbgHelpLineEntry)); 659 strtab.PathChop = NULL; 660 strtab.SourcePath = SourcePath ? SourcePath : ""; 661 662 SymEnumLines(process, module_base, NULL, NULL, DbgHelpAddLineNumber, &strtab); 663 664 /* Transcribe necessary strings */ 665 *StringsLength = strtab.Bytes; 666 strings = strings_copy = ((char *)(*StringsBase = malloc(strtab.Bytes))); 667 668 /* Copy in strings */ 669 for (i = 0; i < strtab.Length; i++) 670 { 671 for (j = 0; strtab.Table[i] && strtab.Table[i][j]; j++) 672 { 673 /* Each entry is replaced by its corresponding entry in our string 674 section. We can substract the strings origin to get an offset. */ 675 char *toFree = strtab.Table[i][j]; 676 strtab.Table[i][j] = strcpy(strings_copy, strtab.Table[i][j]); 677 free(toFree); 678 strings_copy += strlen(strings_copy) + 1; 679 } 680 } 681 682 assert(strings_copy == strings + strtab.Bytes); 683 684 *SymbolsBase = calloc(strtab.CurLineEntries, sizeof(ROSSYM_ENTRY)); 685 *SymbolsCount = strtab.CurLineEntries; 686 687 /* Copy symbols into rossym entries */ 688 for (i = 0; i < strtab.CurLineEntries; i++) 689 { 690 rossym = &(*SymbolsBase)[i]; 691 rossym->Address = strtab.LineEntryData[i].vma; 692 bucket = strtab.LineEntryData[i].fileId & 0x3ff; 693 entry = strtab.LineEntryData[i].fileId >> 10; 694 rossym->FileOffset = strtab.Table[bucket][entry] - strings; 695 bucket = strtab.LineEntryData[i].functionId & 0x3ff; 696 entry = strtab.LineEntryData[i].functionId >> 10; 697 rossym->FunctionOffset = strtab.Table[bucket][entry] - strings; 698 rossym->SourceLine = strtab.LineEntryData[i].line; 699 } 700 701 /* Free stringtab */ 702 for (i = 0; i < strtab.Length; i++) 703 { 704 free(strtab.Table[i]); 705 } 706 707 free(strtab.LineEntryData); 708 free(strtab.PathChop); 709 710 qsort(*SymbolsBase, *SymbolsCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *))CompareSymEntry); 711 712 return 0; 713 } 714 715 static int 716 MergeStabsAndCoffs(ULONG *MergedSymbolCount, PROSSYM_ENTRY *MergedSymbols, 717 ULONG StabSymbolsCount, PROSSYM_ENTRY StabSymbols, 718 ULONG CoffSymbolsCount, PROSSYM_ENTRY CoffSymbols) 719 { 720 ULONG StabIndex, j; 721 ULONG CoffIndex; 722 ULONG_PTR StabFunctionStartAddress; 723 ULONG StabFunctionStringOffset, NewStabFunctionStringOffset, CoffFunctionStringOffset; 724 PROSSYM_ENTRY CoffFunctionSymbol; 725 726 *MergedSymbolCount = 0; 727 if (StabSymbolsCount == 0) 728 { 729 *MergedSymbols = NULL; 730 return 0; 731 } 732 *MergedSymbols = malloc((StabSymbolsCount + CoffSymbolsCount) * sizeof(ROSSYM_ENTRY)); 733 if (*MergedSymbols == NULL) 734 { 735 fprintf(stderr, "Unable to allocate memory for merged symbols\n"); 736 return 1; 737 } 738 739 StabFunctionStartAddress = 0; 740 StabFunctionStringOffset = 0; 741 CoffFunctionStringOffset = 0; 742 CoffFunctionSymbol = NULL; 743 CoffIndex = 0; 744 for (StabIndex = 0; StabIndex < StabSymbolsCount; StabIndex++) 745 { 746 (*MergedSymbols)[*MergedSymbolCount] = StabSymbols[StabIndex]; 747 for (j = StabIndex + 1; 748 j < StabSymbolsCount && StabSymbols[j].Address == StabSymbols[StabIndex].Address; 749 j++) 750 { 751 if (StabSymbols[j].FileOffset != 0 && (*MergedSymbols)[*MergedSymbolCount].FileOffset == 0) 752 { 753 (*MergedSymbols)[*MergedSymbolCount].FileOffset = StabSymbols[j].FileOffset; 754 } 755 if (StabSymbols[j].FunctionOffset != 0 && (*MergedSymbols)[*MergedSymbolCount].FunctionOffset == 0) 756 { 757 (*MergedSymbols)[*MergedSymbolCount].FunctionOffset = StabSymbols[j].FunctionOffset; 758 } 759 if (StabSymbols[j].SourceLine != 0 && (*MergedSymbols)[*MergedSymbolCount].SourceLine == 0) 760 { 761 (*MergedSymbols)[*MergedSymbolCount].SourceLine = StabSymbols[j].SourceLine; 762 } 763 } 764 StabIndex = j - 1; 765 766 while (CoffIndex < CoffSymbolsCount && 767 CoffSymbols[CoffIndex].Address <= (*MergedSymbols)[*MergedSymbolCount].Address) 768 { 769 if (CoffSymbols[CoffIndex].FunctionOffset != 0) 770 { 771 CoffFunctionSymbol = &CoffSymbols[CoffIndex]; 772 CoffFunctionStringOffset = CoffFunctionSymbol->FunctionOffset; 773 } 774 CoffIndex++; 775 } 776 NewStabFunctionStringOffset = (*MergedSymbols)[*MergedSymbolCount].FunctionOffset; 777 if (CoffFunctionSymbol && 778 CoffFunctionSymbol->Address <= (*MergedSymbols)[*MergedSymbolCount].Address && 779 StabFunctionStartAddress < CoffFunctionSymbol->Address) 780 { 781 (*MergedSymbols)[*MergedSymbolCount].FunctionOffset = CoffFunctionStringOffset; 782 CoffFunctionSymbol->FunctionOffset = 0; 783 } 784 if (StabFunctionStringOffset != NewStabFunctionStringOffset) 785 { 786 StabFunctionStartAddress = (*MergedSymbols)[*MergedSymbolCount].Address; 787 } 788 StabFunctionStringOffset = NewStabFunctionStringOffset; 789 (*MergedSymbolCount)++; 790 } 791 /* Handle functions that have no analog in the upstream data */ 792 for (CoffIndex = 0; CoffIndex < CoffSymbolsCount; CoffIndex++) 793 { 794 if (CoffSymbols[CoffIndex].Address && 795 CoffSymbols[CoffIndex].FunctionOffset) 796 { 797 (*MergedSymbols)[*MergedSymbolCount] = CoffSymbols[CoffIndex]; 798 (*MergedSymbolCount)++; 799 } 800 } 801 802 qsort(*MergedSymbols, *MergedSymbolCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry); 803 804 return 0; 805 } 806 807 static PIMAGE_SECTION_HEADER 808 FindSectionForRVA(DWORD RVA, unsigned NumberOfSections, PIMAGE_SECTION_HEADER SectionHeaders) 809 { 810 unsigned Section; 811 812 for (Section = 0; Section < NumberOfSections; Section++) 813 { 814 if (SectionHeaders[Section].VirtualAddress <= RVA && 815 RVA < SectionHeaders[Section].VirtualAddress + SectionHeaders[Section].Misc.VirtualSize) 816 { 817 return SectionHeaders + Section; 818 } 819 } 820 821 return NULL; 822 } 823 824 static int 825 ProcessRelocations(ULONG *ProcessedRelocsLength, void **ProcessedRelocs, 826 void *RawData, PIMAGE_OPTIONAL_HEADER OptHeader, 827 unsigned NumberOfSections, PIMAGE_SECTION_HEADER SectionHeaders) 828 { 829 PIMAGE_SECTION_HEADER RelocSectionHeader, TargetSectionHeader; 830 PIMAGE_BASE_RELOCATION BaseReloc, End, AcceptedRelocs; 831 int Found; 832 833 if (OptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC || 834 OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress == 0) 835 { 836 /* No relocation entries */ 837 *ProcessedRelocsLength = 0; 838 *ProcessedRelocs = NULL; 839 return 0; 840 } 841 842 RelocSectionHeader = FindSectionForRVA(OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, 843 NumberOfSections, SectionHeaders); 844 if (RelocSectionHeader == NULL) 845 { 846 fprintf(stderr, "Can't find section header for relocation data\n"); 847 return 1; 848 } 849 850 *ProcessedRelocs = malloc(RelocSectionHeader->SizeOfRawData); 851 if (*ProcessedRelocs == NULL) 852 { 853 fprintf(stderr, 854 "Failed to allocate %u bytes for relocations\n", 855 (unsigned int)RelocSectionHeader->SizeOfRawData); 856 return 1; 857 } 858 *ProcessedRelocsLength = 0; 859 860 BaseReloc = (PIMAGE_BASE_RELOCATION) ((char *) RawData + 861 RelocSectionHeader->PointerToRawData + 862 (OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress - 863 RelocSectionHeader->VirtualAddress)); 864 End = (PIMAGE_BASE_RELOCATION) ((char *) BaseReloc + 865 OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size); 866 867 while (BaseReloc < End && BaseReloc->SizeOfBlock > 0) 868 { 869 TargetSectionHeader = FindSectionForRVA(BaseReloc->VirtualAddress, 870 NumberOfSections, 871 SectionHeaders); 872 if (TargetSectionHeader != NULL) 873 { 874 AcceptedRelocs = *ProcessedRelocs; 875 Found = 0; 876 while (AcceptedRelocs < (PIMAGE_BASE_RELOCATION) ((char *) *ProcessedRelocs + 877 *ProcessedRelocsLength) 878 && !Found) 879 { 880 Found = BaseReloc->SizeOfBlock == AcceptedRelocs->SizeOfBlock && 881 memcmp(BaseReloc, AcceptedRelocs, AcceptedRelocs->SizeOfBlock) == 0; 882 AcceptedRelocs = (PIMAGE_BASE_RELOCATION) ((char *) AcceptedRelocs + 883 AcceptedRelocs->SizeOfBlock); 884 } 885 if (!Found) 886 { 887 memcpy((char *) *ProcessedRelocs + *ProcessedRelocsLength, 888 BaseReloc, 889 BaseReloc->SizeOfBlock); 890 *ProcessedRelocsLength += BaseReloc->SizeOfBlock; 891 } 892 } 893 BaseReloc = (PIMAGE_BASE_RELOCATION)((char *) BaseReloc + BaseReloc->SizeOfBlock); 894 } 895 896 return 0; 897 } 898 899 static const BYTE* 900 GetSectionName(void *StringsBase, const BYTE *SectionTitle) 901 { 902 if (SectionTitle[0] == '/') 903 { 904 int offset = atoi((char*)SectionTitle+1); 905 return ((BYTE *)StringsBase) + offset; 906 } 907 else 908 return SectionTitle; 909 } 910 911 static int 912 CreateOutputFile(FILE *OutFile, void *InData, 913 PIMAGE_DOS_HEADER InDosHeader, PIMAGE_FILE_HEADER InFileHeader, 914 PIMAGE_OPTIONAL_HEADER InOptHeader, PIMAGE_SECTION_HEADER InSectionHeaders, 915 ULONG RosSymLength, void *RosSymSection) 916 { 917 ULONG StartOfRawData; 918 unsigned Section; 919 void *OutHeader, *ProcessedRelocs, *PaddedRosSym, *Data; 920 unsigned char *PaddedStringTable; 921 PIMAGE_DOS_HEADER OutDosHeader; 922 PIMAGE_FILE_HEADER OutFileHeader; 923 PIMAGE_OPTIONAL_HEADER OutOptHeader; 924 PIMAGE_SECTION_HEADER OutSectionHeaders, CurrentSectionHeader; 925 DWORD CheckSum; 926 ULONG Length, i; 927 ULONG ProcessedRelocsLength; 928 ULONG RosSymOffset, RosSymFileLength; 929 ULONG PaddedStringTableLength; 930 int InRelocSectionIndex; 931 PIMAGE_SECTION_HEADER OutRelocSection; 932 /* Each coff symbol is 18 bytes and the string table follows */ 933 char *StringTable = (char *)InData + 934 InFileHeader->PointerToSymbolTable + 18 * InFileHeader->NumberOfSymbols; 935 ULONG StringTableLength = 0; 936 ULONG StringTableLocation; 937 938 StartOfRawData = 0; 939 for (Section = 0; Section < InFileHeader->NumberOfSections; Section++) 940 { 941 const BYTE *SectionName = GetSectionName(StringTable, 942 InSectionHeaders[Section].Name); 943 if (InSectionHeaders[Section].Name[0] == '/') 944 { 945 StringTableLength = atoi((const char *)InSectionHeaders[Section].Name + 1) + 946 strlen((const char *)SectionName) + 1; 947 } 948 if ((StartOfRawData == 0 || InSectionHeaders[Section].PointerToRawData < StartOfRawData) 949 && InSectionHeaders[Section].PointerToRawData != 0 950 && (strncmp((char *) SectionName, ".stab", 5)) != 0 951 && (strncmp((char *) SectionName, ".debug_", 7)) != 0) 952 { 953 StartOfRawData = InSectionHeaders[Section].PointerToRawData; 954 } 955 } 956 OutHeader = malloc(StartOfRawData); 957 if (OutHeader == NULL) 958 { 959 fprintf(stderr, 960 "Failed to allocate %u bytes for output file header\n", 961 (unsigned int)StartOfRawData); 962 return 1; 963 } 964 memset(OutHeader, '\0', StartOfRawData); 965 966 OutDosHeader = (PIMAGE_DOS_HEADER) OutHeader; 967 memcpy(OutDosHeader, InDosHeader, InDosHeader->e_lfanew + sizeof(ULONG)); 968 969 OutFileHeader = (PIMAGE_FILE_HEADER)((char *) OutHeader + OutDosHeader->e_lfanew + sizeof(ULONG)); 970 memcpy(OutFileHeader, InFileHeader, sizeof(IMAGE_FILE_HEADER)); 971 OutFileHeader->PointerToSymbolTable = 0; 972 OutFileHeader->NumberOfSymbols = 0; 973 OutFileHeader->Characteristics &= ~(IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_LOCAL_SYMS_STRIPPED | 974 IMAGE_FILE_DEBUG_STRIPPED); 975 976 OutOptHeader = (PIMAGE_OPTIONAL_HEADER)(OutFileHeader + 1); 977 memcpy(OutOptHeader, InOptHeader, sizeof(IMAGE_OPTIONAL_HEADER)); 978 OutOptHeader->CheckSum = 0; 979 980 OutSectionHeaders = (PIMAGE_SECTION_HEADER)((char *) OutOptHeader + OutFileHeader->SizeOfOptionalHeader); 981 982 if (ProcessRelocations(&ProcessedRelocsLength, 983 &ProcessedRelocs, 984 InData, 985 InOptHeader, 986 InFileHeader->NumberOfSections, 987 InSectionHeaders)) 988 { 989 return 1; 990 } 991 if (InOptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC || 992 InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress == 0) 993 { 994 InRelocSectionIndex = -1; 995 } 996 else 997 { 998 InRelocSectionIndex = FindSectionForRVA(InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, 999 InFileHeader->NumberOfSections, InSectionHeaders) - InSectionHeaders; 1000 } 1001 1002 OutFileHeader->NumberOfSections = 0; 1003 CurrentSectionHeader = OutSectionHeaders; 1004 OutOptHeader->SizeOfImage = 0; 1005 RosSymOffset = 0; 1006 OutRelocSection = NULL; 1007 1008 StringTableLocation = StartOfRawData; 1009 1010 for (Section = 0; Section < InFileHeader->NumberOfSections; Section++) 1011 { 1012 const BYTE *SectionName = GetSectionName(StringTable, 1013 InSectionHeaders[Section].Name); 1014 if ((strncmp((char *) SectionName, ".stab", 5) != 0) && 1015 (strncmp((char *) SectionName, ".debug_", 7)) != 0) 1016 { 1017 *CurrentSectionHeader = InSectionHeaders[Section]; 1018 CurrentSectionHeader->PointerToLinenumbers = 0; 1019 CurrentSectionHeader->NumberOfLinenumbers = 0; 1020 if (OutOptHeader->SizeOfImage < CurrentSectionHeader->VirtualAddress + 1021 CurrentSectionHeader->Misc.VirtualSize) 1022 { 1023 OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress + 1024 CurrentSectionHeader->Misc.VirtualSize, 1025 OutOptHeader->SectionAlignment); 1026 } 1027 if (RosSymOffset < CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData) 1028 { 1029 RosSymOffset = CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData; 1030 } 1031 if (Section == (ULONG)InRelocSectionIndex) 1032 { 1033 OutRelocSection = CurrentSectionHeader; 1034 } 1035 StringTableLocation = CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData; 1036 OutFileHeader->NumberOfSections++; 1037 CurrentSectionHeader++; 1038 } 1039 } 1040 1041 if (OutRelocSection == CurrentSectionHeader - 1) 1042 { 1043 OutOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = ProcessedRelocsLength; 1044 if (OutOptHeader->SizeOfImage == OutRelocSection->VirtualAddress + 1045 ROUND_UP(OutRelocSection->Misc.VirtualSize, 1046 OutOptHeader->SectionAlignment)) 1047 { 1048 OutOptHeader->SizeOfImage = OutRelocSection->VirtualAddress + 1049 ROUND_UP(ProcessedRelocsLength, 1050 OutOptHeader->SectionAlignment); 1051 } 1052 OutRelocSection->Misc.VirtualSize = ProcessedRelocsLength; 1053 if (RosSymOffset == OutRelocSection->PointerToRawData + 1054 OutRelocSection->SizeOfRawData) 1055 { 1056 RosSymOffset = OutRelocSection->PointerToRawData + 1057 ROUND_UP(ProcessedRelocsLength, 1058 OutOptHeader->FileAlignment); 1059 } 1060 OutRelocSection->SizeOfRawData = ROUND_UP(ProcessedRelocsLength, 1061 OutOptHeader->FileAlignment); 1062 } 1063 1064 if (RosSymLength > 0) 1065 { 1066 RosSymFileLength = ROUND_UP(RosSymLength, OutOptHeader->FileAlignment); 1067 memcpy(CurrentSectionHeader->Name, ".rossym", 8); /* We're lucky: string is exactly 8 bytes long */ 1068 CurrentSectionHeader->Misc.VirtualSize = RosSymLength; 1069 CurrentSectionHeader->VirtualAddress = OutOptHeader->SizeOfImage; 1070 CurrentSectionHeader->SizeOfRawData = RosSymFileLength; 1071 CurrentSectionHeader->PointerToRawData = RosSymOffset; 1072 CurrentSectionHeader->PointerToRelocations = 0; 1073 CurrentSectionHeader->PointerToLinenumbers = 0; 1074 CurrentSectionHeader->NumberOfRelocations = 0; 1075 CurrentSectionHeader->NumberOfLinenumbers = 0; 1076 CurrentSectionHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 1077 | IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_TYPE_NOLOAD; 1078 OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress + CurrentSectionHeader->Misc.VirtualSize, 1079 OutOptHeader->SectionAlignment); 1080 OutFileHeader->NumberOfSections++; 1081 1082 PaddedRosSym = malloc(RosSymFileLength); 1083 if (PaddedRosSym == NULL) 1084 { 1085 fprintf(stderr, 1086 "Failed to allocate %u bytes for padded .rossym\n", 1087 (unsigned int)RosSymFileLength); 1088 return 1; 1089 } 1090 memcpy(PaddedRosSym, RosSymSection, RosSymLength); 1091 memset((char *) PaddedRosSym + RosSymLength, 1092 '\0', 1093 RosSymFileLength - RosSymLength); 1094 1095 /* Position the string table after our new section */ 1096 StringTableLocation = RosSymOffset + RosSymFileLength; 1097 } 1098 else 1099 { 1100 PaddedRosSym = NULL; 1101 } 1102 1103 /* Set the string table area in the header if we need it */ 1104 if (StringTableLength) 1105 { 1106 OutFileHeader->PointerToSymbolTable = StringTableLocation; 1107 OutFileHeader->NumberOfSymbols = 0; 1108 } 1109 1110 CheckSum = 0; 1111 for (i = 0; i < StartOfRawData / 2; i++) 1112 { 1113 CheckSum += ((unsigned short*) OutHeader)[i]; 1114 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16)); 1115 } 1116 Length = StartOfRawData; 1117 for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++) 1118 { 1119 DWORD SizeOfRawData; 1120 if (OutRelocSection == OutSectionHeaders + Section) 1121 { 1122 Data = (void *) ProcessedRelocs; 1123 SizeOfRawData = ProcessedRelocsLength; 1124 } 1125 else if (RosSymLength > 0 && Section + 1 == OutFileHeader->NumberOfSections) 1126 { 1127 Data = (void *) PaddedRosSym; 1128 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData; 1129 } 1130 else 1131 { 1132 Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData); 1133 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData; 1134 } 1135 for (i = 0; i < SizeOfRawData / 2; i++) 1136 { 1137 CheckSum += ((unsigned short*) Data)[i]; 1138 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16)); 1139 } 1140 Length += OutSectionHeaders[Section].SizeOfRawData; 1141 } 1142 1143 if (OutFileHeader->PointerToSymbolTable) 1144 { 1145 int PaddingFrom = (OutFileHeader->PointerToSymbolTable + StringTableLength) % 1146 OutOptHeader->FileAlignment; 1147 int PaddingSize = PaddingFrom ? OutOptHeader->FileAlignment - PaddingFrom : 0; 1148 1149 PaddedStringTableLength = StringTableLength + PaddingSize; 1150 PaddedStringTable = malloc(PaddedStringTableLength); 1151 /* COFF string section is preceeded by a length */ 1152 assert(sizeof(StringTableLength) == 4); 1153 memcpy(PaddedStringTable, &StringTableLength, sizeof(StringTableLength)); 1154 /* We just copy enough of the string table to contain the strings we want 1155 The string table length technically counts as part of the string table 1156 space itself. */ 1157 memcpy(PaddedStringTable + 4, StringTable + 4, StringTableLength - 4); 1158 memset(PaddedStringTable + StringTableLength, 0, PaddingSize); 1159 1160 assert(OutFileHeader->PointerToSymbolTable % 2 == 0); 1161 for (i = 0; i < PaddedStringTableLength / 2; i++) 1162 { 1163 CheckSum += ((unsigned short*)PaddedStringTable)[i]; 1164 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16)); 1165 } 1166 Length += PaddedStringTableLength; 1167 } 1168 else 1169 { 1170 PaddedStringTable = NULL; 1171 } 1172 1173 CheckSum += Length; 1174 OutOptHeader->CheckSum = CheckSum; 1175 1176 if (fwrite(OutHeader, 1, StartOfRawData, OutFile) != StartOfRawData) 1177 { 1178 perror("Error writing output header\n"); 1179 free(OutHeader); 1180 return 1; 1181 } 1182 1183 for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++) 1184 { 1185 if (OutSectionHeaders[Section].SizeOfRawData != 0) 1186 { 1187 DWORD SizeOfRawData; 1188 fseek(OutFile, OutSectionHeaders[Section].PointerToRawData, SEEK_SET); 1189 if (OutRelocSection == OutSectionHeaders + Section) 1190 { 1191 Data = (void *) ProcessedRelocs; 1192 SizeOfRawData = ProcessedRelocsLength; 1193 } 1194 else if (RosSymLength > 0 && Section + 1 == OutFileHeader->NumberOfSections) 1195 { 1196 Data = (void *) PaddedRosSym; 1197 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData; 1198 } 1199 else 1200 { 1201 Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData); 1202 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData; 1203 } 1204 if (fwrite(Data, 1, SizeOfRawData, OutFile) != SizeOfRawData) 1205 { 1206 perror("Error writing section data\n"); 1207 free(PaddedRosSym); 1208 free(OutHeader); 1209 return 1; 1210 } 1211 } 1212 } 1213 1214 if (PaddedStringTable) 1215 { 1216 fseek(OutFile, OutFileHeader->PointerToSymbolTable, SEEK_SET); 1217 fwrite(PaddedStringTable, 1, PaddedStringTableLength, OutFile); 1218 free(PaddedStringTable); 1219 } 1220 1221 if (PaddedRosSym) 1222 { 1223 free(PaddedRosSym); 1224 } 1225 free(OutHeader); 1226 1227 return 0; 1228 } 1229 1230 int main(int argc, char* argv[]) 1231 { 1232 PSYMBOLFILE_HEADER SymbolFileHeader; 1233 PIMAGE_DOS_HEADER PEDosHeader; 1234 PIMAGE_FILE_HEADER PEFileHeader; 1235 PIMAGE_OPTIONAL_HEADER PEOptHeader; 1236 PIMAGE_SECTION_HEADER PESectionHeaders; 1237 ULONG ImageBase; 1238 void *StabBase; 1239 ULONG StabsLength; 1240 void *StabStringBase; 1241 ULONG StabStringsLength; 1242 void *CoffBase = NULL; 1243 ULONG CoffsLength; 1244 void *CoffStringBase = NULL; 1245 ULONG CoffStringsLength; 1246 char* path1; 1247 char* path2; 1248 FILE* out; 1249 void *StringBase = NULL; 1250 ULONG StringsLength = 0; 1251 ULONG StabSymbolsCount = 0; 1252 PROSSYM_ENTRY StabSymbols = NULL; 1253 ULONG CoffSymbolsCount = 0; 1254 PROSSYM_ENTRY CoffSymbols = NULL; 1255 ULONG MergedSymbolsCount = 0; 1256 PROSSYM_ENTRY MergedSymbols = NULL; 1257 size_t FileSize; 1258 void *FileData; 1259 ULONG RosSymLength; 1260 void *RosSymSection; 1261 DWORD module_base; 1262 void *file; 1263 char elfhdr[4] = { '\177', 'E', 'L', 'F' }; 1264 BOOLEAN UseDbgHelp = FALSE; 1265 int arg, argstate = 0; 1266 char *SourcePath = NULL; 1267 1268 for (arg = 1; arg < argc; arg++) 1269 { 1270 switch (argstate) 1271 { 1272 default: 1273 argstate = -1; 1274 break; 1275 1276 case 0: 1277 if (!strcmp(argv[arg], "-s")) 1278 { 1279 argstate = 1; 1280 } 1281 else 1282 { 1283 argstate = 2; 1284 path1 = convert_path(argv[arg]); 1285 } 1286 break; 1287 1288 case 1: 1289 free(SourcePath); 1290 SourcePath = strdup(argv[arg]); 1291 argstate = 0; 1292 break; 1293 1294 case 2: 1295 path2 = convert_path(argv[arg]); 1296 argstate = 3; 1297 break; 1298 } 1299 } 1300 1301 if (argstate != 3) 1302 { 1303 fprintf(stderr, "Usage: rsym [-s <sources>] <input> <output>\n"); 1304 exit(1); 1305 } 1306 1307 FileData = load_file(path1, &FileSize); 1308 if (!FileData) 1309 { 1310 fprintf(stderr, "An error occured loading '%s'\n", path1); 1311 exit(1); 1312 } 1313 1314 file = fopen(path1, "rb"); 1315 1316 /* Check if MZ header exists */ 1317 PEDosHeader = (PIMAGE_DOS_HEADER) FileData; 1318 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC || 1319 PEDosHeader->e_lfanew == 0L) 1320 { 1321 /* Ignore elf */ 1322 if (!memcmp(PEDosHeader, elfhdr, sizeof(elfhdr))) 1323 exit(0); 1324 perror("Input file is not a PE image.\n"); 1325 free(FileData); 1326 exit(1); 1327 } 1328 1329 /* Locate PE file header */ 1330 /* sizeof(ULONG) = sizeof(MAGIC) */ 1331 PEFileHeader = (PIMAGE_FILE_HEADER)((char *) FileData + PEDosHeader->e_lfanew + sizeof(ULONG)); 1332 1333 /* Locate optional header */ 1334 assert(sizeof(ULONG) == 4); 1335 PEOptHeader = (PIMAGE_OPTIONAL_HEADER)(PEFileHeader + 1); 1336 ImageBase = PEOptHeader->ImageBase; 1337 1338 /* Locate PE section headers */ 1339 PESectionHeaders = (PIMAGE_SECTION_HEADER)((char *) PEOptHeader + PEFileHeader->SizeOfOptionalHeader); 1340 1341 if (GetStabInfo(FileData, 1342 PEFileHeader, 1343 PESectionHeaders, 1344 &StabsLength, 1345 &StabBase, 1346 &StabStringsLength, 1347 &StabStringBase)) 1348 { 1349 free(FileData); 1350 exit(1); 1351 } 1352 1353 if (StabsLength == 0) 1354 { 1355 // SYMOPT_AUTO_PUBLICS 1356 // SYMOPT_FAVOR_COMPRESSED 1357 // SYMOPT_LOAD_ANYTHING 1358 // SYMOPT_LOAD_LINES 1359 SymSetOptions(0x10000 | 0x800000 | 0x40 | 0x10); 1360 SymSetExtendedOption(SYMOPT_EX_WINE_NATIVE_MODULES, TRUE); 1361 SymInitialize(FileData, ".", 0); 1362 1363 module_base = SymLoadModule(FileData, file, path1, path1, 0, FileSize) & 0xffffffff; 1364 1365 if (ConvertDbgHelp(FileData, 1366 module_base, 1367 SourcePath, 1368 &StabSymbolsCount, 1369 &StabSymbols, 1370 &StringsLength, 1371 &StringBase)) 1372 { 1373 free(FileData); 1374 exit(1); 1375 } 1376 1377 UseDbgHelp = TRUE; 1378 SymUnloadModule(FileData, module_base); 1379 SymCleanup(FileData); 1380 } 1381 1382 if (GetCoffInfo(FileData, 1383 PEFileHeader, 1384 PESectionHeaders, 1385 &CoffsLength, 1386 &CoffBase, 1387 &CoffStringsLength, 1388 &CoffStringBase)) 1389 { 1390 free(FileData); 1391 exit(1); 1392 } 1393 1394 if (!UseDbgHelp) 1395 { 1396 StringBase = malloc(1 + StringsLength + CoffStringsLength + 1397 (CoffsLength / sizeof(ROSSYM_ENTRY)) * (E_SYMNMLEN + 1)); 1398 if (StringBase == NULL) 1399 { 1400 free(FileData); 1401 fprintf(stderr, "Failed to allocate memory for strings table\n"); 1402 exit(1); 1403 } 1404 /* Make offset 0 into an empty string */ 1405 *((char *) StringBase) = '\0'; 1406 StringsLength = 1; 1407 1408 if (ConvertStabs(&StabSymbolsCount, 1409 &StabSymbols, 1410 &StringsLength, 1411 StringBase, 1412 StabsLength, 1413 StabBase, 1414 StabStringsLength, 1415 StabStringBase, 1416 ImageBase, 1417 PEFileHeader, 1418 PESectionHeaders)) 1419 { 1420 free(StringBase); 1421 free(FileData); 1422 fprintf(stderr, "Failed to allocate memory for strings table\n"); 1423 exit(1); 1424 } 1425 } 1426 else 1427 { 1428 StringBase = realloc(StringBase, StringsLength + CoffStringsLength); 1429 if (!StringBase) 1430 { 1431 free(FileData); 1432 fprintf(stderr, "Failed to allocate memory for strings table\n"); 1433 exit(1); 1434 } 1435 } 1436 1437 if (ConvertCoffs(&CoffSymbolsCount, 1438 &CoffSymbols, 1439 &StringsLength, 1440 StringBase, 1441 CoffsLength, 1442 CoffBase, 1443 CoffStringsLength, 1444 CoffStringBase, 1445 ImageBase, 1446 PEFileHeader, 1447 PESectionHeaders)) 1448 { 1449 if (StabSymbols) 1450 { 1451 free(StabSymbols); 1452 } 1453 free(StringBase); 1454 free(FileData); 1455 exit(1); 1456 } 1457 1458 if (MergeStabsAndCoffs(&MergedSymbolsCount, 1459 &MergedSymbols, 1460 StabSymbolsCount, 1461 StabSymbols, 1462 CoffSymbolsCount, 1463 CoffSymbols)) 1464 { 1465 if (CoffSymbols) 1466 { 1467 free(CoffSymbols); 1468 } 1469 if (StabSymbols) 1470 { 1471 free(StabSymbols); 1472 } 1473 free(StringBase); 1474 free(FileData); 1475 exit(1); 1476 } 1477 1478 if (CoffSymbols) 1479 { 1480 free(CoffSymbols); 1481 } 1482 if (StabSymbols) 1483 { 1484 free(StabSymbols); 1485 } 1486 if (MergedSymbolsCount == 0) 1487 { 1488 RosSymLength = 0; 1489 RosSymSection = NULL; 1490 } 1491 else 1492 { 1493 RosSymLength = sizeof(SYMBOLFILE_HEADER) + 1494 MergedSymbolsCount * sizeof(ROSSYM_ENTRY) + 1495 StringsLength; 1496 1497 RosSymSection = malloc(RosSymLength); 1498 if (RosSymSection == NULL) 1499 { 1500 free(MergedSymbols); 1501 free(StringBase); 1502 free(FileData); 1503 fprintf(stderr, "Unable to allocate memory for .rossym section\n"); 1504 exit(1); 1505 } 1506 memset(RosSymSection, '\0', RosSymLength); 1507 1508 SymbolFileHeader = (PSYMBOLFILE_HEADER)RosSymSection; 1509 SymbolFileHeader->SymbolsOffset = sizeof(SYMBOLFILE_HEADER); 1510 SymbolFileHeader->SymbolsLength = MergedSymbolsCount * sizeof(ROSSYM_ENTRY); 1511 SymbolFileHeader->StringsOffset = SymbolFileHeader->SymbolsOffset + 1512 SymbolFileHeader->SymbolsLength; 1513 SymbolFileHeader->StringsLength = StringsLength; 1514 1515 memcpy((char *) RosSymSection + SymbolFileHeader->SymbolsOffset, 1516 MergedSymbols, 1517 SymbolFileHeader->SymbolsLength); 1518 1519 memcpy((char *) RosSymSection + SymbolFileHeader->StringsOffset, 1520 StringBase, 1521 SymbolFileHeader->StringsLength); 1522 1523 free(MergedSymbols); 1524 } 1525 1526 free(StringBase); 1527 out = fopen(path2, "wb"); 1528 if (out == NULL) 1529 { 1530 perror("Cannot open output file"); 1531 free(RosSymSection); 1532 free(FileData); 1533 exit(1); 1534 } 1535 1536 if (CreateOutputFile(out, 1537 FileData, 1538 PEDosHeader, 1539 PEFileHeader, 1540 PEOptHeader, 1541 PESectionHeaders, 1542 RosSymLength, 1543 RosSymSection)) 1544 { 1545 fclose(out); 1546 if (RosSymSection) 1547 { 1548 free(RosSymSection); 1549 } 1550 free(FileData); 1551 exit(1); 1552 } 1553 1554 fclose(out); 1555 if (RosSymSection) 1556 { 1557 free(RosSymSection); 1558 } 1559 free(FileData); 1560 1561 return 0; 1562 } 1563 1564 /* EOF */ 1565