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