d053f670567ec1734cb6ae0fc5242e90bad41f80
[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 unsigned char *PaddedStringTable;
905 PIMAGE_DOS_HEADER OutDosHeader;
906 PIMAGE_FILE_HEADER OutFileHeader;
907 PIMAGE_OPTIONAL_HEADER OutOptHeader;
908 PIMAGE_SECTION_HEADER OutSectionHeaders, CurrentSectionHeader;
909 DWORD CheckSum;
910 ULONG Length, i;
911 ULONG ProcessedRelocsLength;
912 ULONG RosSymOffset, RosSymFileLength;
913 ULONG PaddedStringTableLength;
914 int InRelocSectionIndex;
915 PIMAGE_SECTION_HEADER OutRelocSection;
916 /* Each coff symbol is 18 bytes and the string table follows */
917 char *StringTable = (char *)InData +
918 InFileHeader->PointerToSymbolTable + 18 * InFileHeader->NumberOfSymbols;
919 ULONG StringTableLength = 0;
920 ULONG StringTableLocation;
921
922 StartOfRawData = 0;
923 for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
924 {
925 const BYTE *SectionName = GetSectionName(StringTable,
926 InSectionHeaders[Section].Name);
927 if (InSectionHeaders[Section].Name[0] == '/')
928 {
929 StringTableLength = atoi(InSectionHeaders[Section].Name+1) + strlen(SectionName) + 1;
930 }
931 if ((StartOfRawData == 0 || InSectionHeaders[Section].PointerToRawData < StartOfRawData)
932 && InSectionHeaders[Section].PointerToRawData != 0
933 && (strncmp((char *) SectionName, ".stab", 5)) != 0
934 && (strncmp((char *) SectionName, ".debug_", 7)) != 0)
935 {
936 StartOfRawData = InSectionHeaders[Section].PointerToRawData;
937 }
938 }
939 OutHeader = malloc(StartOfRawData);
940 if (OutHeader == NULL)
941 {
942 fprintf(stderr,
943 "Failed to allocate %u bytes for output file header\n",
944 (unsigned int)StartOfRawData);
945 return 1;
946 }
947 memset(OutHeader, '\0', StartOfRawData);
948
949 OutDosHeader = (PIMAGE_DOS_HEADER) OutHeader;
950 memcpy(OutDosHeader, InDosHeader, InDosHeader->e_lfanew + sizeof(ULONG));
951
952 OutFileHeader = (PIMAGE_FILE_HEADER)((char *) OutHeader + OutDosHeader->e_lfanew + sizeof(ULONG));
953 memcpy(OutFileHeader, InFileHeader, sizeof(IMAGE_FILE_HEADER));
954 OutFileHeader->PointerToSymbolTable = 0;
955 OutFileHeader->NumberOfSymbols = 0;
956 OutFileHeader->Characteristics &= ~(IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_LOCAL_SYMS_STRIPPED |
957 IMAGE_FILE_DEBUG_STRIPPED);
958
959 OutOptHeader = (PIMAGE_OPTIONAL_HEADER)(OutFileHeader + 1);
960 memcpy(OutOptHeader, InOptHeader, sizeof(IMAGE_OPTIONAL_HEADER));
961 OutOptHeader->CheckSum = 0;
962
963 OutSectionHeaders = (PIMAGE_SECTION_HEADER)((char *) OutOptHeader + OutFileHeader->SizeOfOptionalHeader);
964
965 if (ProcessRelocations(&ProcessedRelocsLength,
966 &ProcessedRelocs,
967 InData,
968 InOptHeader,
969 InFileHeader->NumberOfSections,
970 InSectionHeaders))
971 {
972 return 1;
973 }
974 if (InOptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC ||
975 InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress == 0)
976 {
977 InRelocSectionIndex = -1;
978 }
979 else
980 {
981 InRelocSectionIndex = FindSectionForRVA(InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
982 InFileHeader->NumberOfSections, InSectionHeaders) - InSectionHeaders;
983 }
984
985 OutFileHeader->NumberOfSections = 0;
986 CurrentSectionHeader = OutSectionHeaders;
987 OutOptHeader->SizeOfImage = 0;
988 RosSymOffset = 0;
989 OutRelocSection = NULL;
990
991 StringTableLocation = StartOfRawData;
992
993 for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
994 {
995 const BYTE *SectionName = GetSectionName(StringTable,
996 InSectionHeaders[Section].Name);
997 if ((strncmp((char *) SectionName, ".stab", 5) != 0) &&
998 (strncmp((char *) SectionName, ".debug_", 7)) != 0)
999 {
1000 *CurrentSectionHeader = InSectionHeaders[Section];
1001 CurrentSectionHeader->PointerToLinenumbers = 0;
1002 CurrentSectionHeader->NumberOfLinenumbers = 0;
1003 if (OutOptHeader->SizeOfImage < CurrentSectionHeader->VirtualAddress +
1004 CurrentSectionHeader->Misc.VirtualSize)
1005 {
1006 OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress +
1007 CurrentSectionHeader->Misc.VirtualSize,
1008 OutOptHeader->SectionAlignment);
1009 }
1010 if (RosSymOffset < CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData)
1011 {
1012 RosSymOffset = CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData;
1013 }
1014 if (Section == (ULONG)InRelocSectionIndex)
1015 {
1016 OutRelocSection = CurrentSectionHeader;
1017 }
1018 StringTableLocation = CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData;
1019 OutFileHeader->NumberOfSections++;
1020 CurrentSectionHeader++;
1021 }
1022 }
1023
1024 if (OutRelocSection == CurrentSectionHeader - 1)
1025 {
1026 OutOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = ProcessedRelocsLength;
1027 if (OutOptHeader->SizeOfImage == OutRelocSection->VirtualAddress +
1028 ROUND_UP(OutRelocSection->Misc.VirtualSize,
1029 OutOptHeader->SectionAlignment))
1030 {
1031 OutOptHeader->SizeOfImage = OutRelocSection->VirtualAddress +
1032 ROUND_UP(ProcessedRelocsLength,
1033 OutOptHeader->SectionAlignment);
1034 }
1035 OutRelocSection->Misc.VirtualSize = ProcessedRelocsLength;
1036 if (RosSymOffset == OutRelocSection->PointerToRawData +
1037 OutRelocSection->SizeOfRawData)
1038 {
1039 RosSymOffset = OutRelocSection->PointerToRawData +
1040 ROUND_UP(ProcessedRelocsLength,
1041 OutOptHeader->FileAlignment);
1042 }
1043 OutRelocSection->SizeOfRawData = ROUND_UP(ProcessedRelocsLength,
1044 OutOptHeader->FileAlignment);
1045 }
1046
1047 if (RosSymLength > 0)
1048 {
1049 RosSymFileLength = ROUND_UP(RosSymLength, OutOptHeader->FileAlignment);
1050 memcpy(CurrentSectionHeader->Name, ".rossym", 8); /* We're lucky: string is exactly 8 bytes long */
1051 CurrentSectionHeader->Misc.VirtualSize = RosSymLength;
1052 CurrentSectionHeader->VirtualAddress = OutOptHeader->SizeOfImage;
1053 CurrentSectionHeader->SizeOfRawData = RosSymFileLength;
1054 CurrentSectionHeader->PointerToRawData = RosSymOffset;
1055 CurrentSectionHeader->PointerToRelocations = 0;
1056 CurrentSectionHeader->PointerToLinenumbers = 0;
1057 CurrentSectionHeader->NumberOfRelocations = 0;
1058 CurrentSectionHeader->NumberOfLinenumbers = 0;
1059 CurrentSectionHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
1060 | IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_TYPE_NOLOAD;
1061 OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress + CurrentSectionHeader->Misc.VirtualSize,
1062 OutOptHeader->SectionAlignment);
1063 OutFileHeader->NumberOfSections++;
1064
1065 PaddedRosSym = malloc(RosSymFileLength);
1066 if (PaddedRosSym == NULL)
1067 {
1068 fprintf(stderr,
1069 "Failed to allocate %u bytes for padded .rossym\n",
1070 (unsigned int)RosSymFileLength);
1071 return 1;
1072 }
1073 memcpy(PaddedRosSym, RosSymSection, RosSymLength);
1074 memset((char *) PaddedRosSym + RosSymLength,
1075 '\0',
1076 RosSymFileLength - RosSymLength);
1077
1078 /* Position the string table after our new section */
1079 StringTableLocation = RosSymOffset + RosSymFileLength;
1080 }
1081 else
1082 {
1083 PaddedRosSym = NULL;
1084 }
1085
1086 /* Set the string table area in the header if we need it */
1087 if (StringTableLength)
1088 {
1089 OutFileHeader->PointerToSymbolTable = StringTableLocation;
1090 OutFileHeader->NumberOfSymbols = 0;
1091 }
1092
1093 CheckSum = 0;
1094 for (i = 0; i < StartOfRawData / 2; i++)
1095 {
1096 CheckSum += ((unsigned short*) OutHeader)[i];
1097 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
1098 }
1099 Length = StartOfRawData;
1100 for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++)
1101 {
1102 DWORD SizeOfRawData;
1103 if (OutRelocSection == OutSectionHeaders + Section)
1104 {
1105 Data = (void *) ProcessedRelocs;
1106 SizeOfRawData = ProcessedRelocsLength;
1107 }
1108 else if (RosSymLength > 0 && Section + 1 == OutFileHeader->NumberOfSections)
1109 {
1110 Data = (void *) PaddedRosSym;
1111 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
1112 }
1113 else
1114 {
1115 Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
1116 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
1117 }
1118 for (i = 0; i < SizeOfRawData / 2; i++)
1119 {
1120 CheckSum += ((unsigned short*) Data)[i];
1121 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
1122 }
1123 Length += OutSectionHeaders[Section].SizeOfRawData;
1124 }
1125
1126 if (OutFileHeader->PointerToSymbolTable)
1127 {
1128 int PaddingFrom = (OutFileHeader->PointerToSymbolTable + StringTableLength) %
1129 OutOptHeader->FileAlignment;
1130 int PaddingSize = PaddingFrom ? OutOptHeader->FileAlignment - PaddingFrom : 0;
1131
1132 PaddedStringTableLength = StringTableLength + PaddingSize;
1133 PaddedStringTable = malloc(PaddedStringTableLength);
1134 /* COFF string section is preceeded by a length */
1135 assert(sizeof(StringTableLength) == 4);
1136 memcpy(PaddedStringTable, &StringTableLength, sizeof(StringTableLength));
1137 /* We just copy enough of the string table to contain the strings we want
1138 The string table length technically counts as part of the string table
1139 space itself. */
1140 memcpy(PaddedStringTable + 4, StringTable + 4, StringTableLength - 4);
1141 memset(PaddedStringTable + StringTableLength, 0, PaddingSize);
1142
1143 assert(OutFileHeader->PointerToSymbolTable % 2 == 0);
1144 for (i = 0; i < PaddedStringTableLength / 2; i++)
1145 {
1146 CheckSum += ((unsigned short*)PaddedStringTable)[i];
1147 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
1148 }
1149 Length += PaddedStringTableLength;
1150 }
1151 else
1152 {
1153 PaddedStringTable = NULL;
1154 }
1155
1156 CheckSum += Length;
1157 OutOptHeader->CheckSum = CheckSum;
1158
1159 if (fwrite(OutHeader, 1, StartOfRawData, OutFile) != StartOfRawData)
1160 {
1161 perror("Error writing output header\n");
1162 free(OutHeader);
1163 return 1;
1164 }
1165
1166 for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++)
1167 {
1168 if (OutSectionHeaders[Section].SizeOfRawData != 0)
1169 {
1170 DWORD SizeOfRawData;
1171 fseek(OutFile, OutSectionHeaders[Section].PointerToRawData, SEEK_SET);
1172 if (OutRelocSection == OutSectionHeaders + Section)
1173 {
1174 Data = (void *) ProcessedRelocs;
1175 SizeOfRawData = ProcessedRelocsLength;
1176 }
1177 else if (RosSymLength > 0 && Section + 1 == OutFileHeader->NumberOfSections)
1178 {
1179 Data = (void *) PaddedRosSym;
1180 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
1181 }
1182 else
1183 {
1184 Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
1185 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
1186 }
1187 if (fwrite(Data, 1, SizeOfRawData, OutFile) != SizeOfRawData)
1188 {
1189 perror("Error writing section data\n");
1190 free(PaddedRosSym);
1191 free(OutHeader);
1192 return 1;
1193 }
1194 }
1195 }
1196
1197 if (PaddedStringTable)
1198 {
1199 fseek(OutFile, OutFileHeader->PointerToSymbolTable, SEEK_SET);
1200 fwrite(PaddedStringTable, 1, PaddedStringTableLength, OutFile);
1201 free(PaddedStringTable);
1202 }
1203
1204 if (PaddedRosSym)
1205 {
1206 free(PaddedRosSym);
1207 }
1208 free(OutHeader);
1209
1210 return 0;
1211 }
1212
1213 int main(int argc, char* argv[])
1214 {
1215 PSYMBOLFILE_HEADER SymbolFileHeader;
1216 PIMAGE_DOS_HEADER PEDosHeader;
1217 PIMAGE_FILE_HEADER PEFileHeader;
1218 PIMAGE_OPTIONAL_HEADER PEOptHeader;
1219 PIMAGE_SECTION_HEADER PESectionHeaders;
1220 ULONG ImageBase;
1221 void *StabBase;
1222 ULONG StabsLength;
1223 void *StabStringBase;
1224 ULONG StabStringsLength;
1225 void *CoffBase = NULL;
1226 ULONG CoffsLength;
1227 void *CoffStringBase = NULL;
1228 ULONG CoffStringsLength;
1229 char* path1;
1230 char* path2;
1231 FILE* out;
1232 void *StringBase = NULL;
1233 ULONG StringsLength = 0;
1234 ULONG StabSymbolsCount = 0;
1235 PROSSYM_ENTRY StabSymbols = NULL;
1236 ULONG CoffSymbolsCount = 0;
1237 PROSSYM_ENTRY CoffSymbols = NULL;
1238 ULONG MergedSymbolsCount = 0;
1239 PROSSYM_ENTRY MergedSymbols = NULL;
1240 size_t FileSize;
1241 void *FileData;
1242 ULONG RosSymLength;
1243 void *RosSymSection;
1244 DWORD module_base;
1245 void *file;
1246 char elfhdr[4] = { '\177', 'E', 'L', 'F' };
1247 BOOLEAN UseDbgHelp = FALSE;
1248 int arg, argstate = 0;
1249 char *SourcePath = NULL;
1250
1251 for (arg = 1; arg < argc; arg++)
1252 {
1253 switch (argstate)
1254 {
1255 default:
1256 argstate = -1;
1257 break;
1258
1259 case 0:
1260 if (!strcmp(argv[arg], "-s"))
1261 {
1262 argstate = 1;
1263 }
1264 else
1265 {
1266 argstate = 2;
1267 path1 = convert_path(argv[arg]);
1268 }
1269 break;
1270
1271 case 1:
1272 free(SourcePath);
1273 SourcePath = strdup(argv[arg]);
1274 argstate = 0;
1275 break;
1276
1277 case 2:
1278 path2 = convert_path(argv[arg]);
1279 argstate = 3;
1280 break;
1281 }
1282 }
1283
1284 if (argstate != 3)
1285 {
1286 fprintf(stderr, "Usage: rsym [-s <sources>] <input> <output>\n");
1287 exit(1);
1288 }
1289
1290 FileData = load_file(path1, &FileSize);
1291 if (!FileData)
1292 {
1293 fprintf(stderr, "An error occured loading '%s'\n", path1);
1294 exit(1);
1295 }
1296
1297 file = fopen(path1, "rb");
1298
1299 /* Check if MZ header exists */
1300 PEDosHeader = (PIMAGE_DOS_HEADER) FileData;
1301 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC ||
1302 PEDosHeader->e_lfanew == 0L)
1303 {
1304 /* Ignore elf */
1305 if (!memcmp(PEDosHeader, elfhdr, sizeof(elfhdr)))
1306 exit(0);
1307 perror("Input file is not a PE image.\n");
1308 free(FileData);
1309 exit(1);
1310 }
1311
1312 /* Locate PE file header */
1313 /* sizeof(ULONG) = sizeof(MAGIC) */
1314 PEFileHeader = (PIMAGE_FILE_HEADER)((char *) FileData + PEDosHeader->e_lfanew + sizeof(ULONG));
1315
1316 /* Locate optional header */
1317 assert(sizeof(ULONG) == 4);
1318 PEOptHeader = (PIMAGE_OPTIONAL_HEADER)(PEFileHeader + 1);
1319 ImageBase = PEOptHeader->ImageBase;
1320
1321 /* Locate PE section headers */
1322 PESectionHeaders = (PIMAGE_SECTION_HEADER)((char *) PEOptHeader + PEFileHeader->SizeOfOptionalHeader);
1323
1324 if (GetStabInfo(FileData,
1325 PEFileHeader,
1326 PESectionHeaders,
1327 &StabsLength,
1328 &StabBase,
1329 &StabStringsLength,
1330 &StabStringBase))
1331 {
1332 free(FileData);
1333 exit(1);
1334 }
1335
1336 if (StabsLength == 0)
1337 {
1338 // SYMOPT_AUTO_PUBLICS
1339 // SYMOPT_FAVOR_COMPRESSED
1340 // SYMOPT_LOAD_ANYTHING
1341 // SYMOPT_LOAD_LINES
1342 SymSetOptions(0x10000 | 0x800000 | 0x40 | 0x10);
1343 SymInitialize(FileData, ".", 0);
1344
1345 module_base = SymLoadModule(FileData, file, path1, path1, 0, FileSize) & 0xffffffff;
1346
1347 if (ConvertDbgHelp(FileData,
1348 module_base,
1349 SourcePath,
1350 &StabSymbolsCount,
1351 &StabSymbols,
1352 &StringsLength,
1353 &StringBase))
1354 {
1355 free(FileData);
1356 exit(1);
1357 }
1358
1359 UseDbgHelp = TRUE;
1360 SymUnloadModule(FileData, module_base);
1361 SymCleanup(FileData);
1362 }
1363
1364 if (GetCoffInfo(FileData,
1365 PEFileHeader,
1366 PESectionHeaders,
1367 &CoffsLength,
1368 &CoffBase,
1369 &CoffStringsLength,
1370 &CoffStringBase))
1371 {
1372 free(FileData);
1373 exit(1);
1374 }
1375
1376 if (!UseDbgHelp)
1377 {
1378 StringBase = malloc(1 + StringsLength + CoffStringsLength +
1379 (CoffsLength / sizeof(ROSSYM_ENTRY)) * (E_SYMNMLEN + 1));
1380 if (StringBase == NULL)
1381 {
1382 free(FileData);
1383 fprintf(stderr, "Failed to allocate memory for strings table\n");
1384 exit(1);
1385 }
1386 /* Make offset 0 into an empty string */
1387 *((char *) StringBase) = '\0';
1388 StringsLength = 1;
1389
1390 if (ConvertStabs(&StabSymbolsCount,
1391 &StabSymbols,
1392 &StringsLength,
1393 StringBase,
1394 StabsLength,
1395 StabBase,
1396 StabStringsLength,
1397 StabStringBase,
1398 ImageBase,
1399 PEFileHeader,
1400 PESectionHeaders))
1401 {
1402 free(StringBase);
1403 free(FileData);
1404 fprintf(stderr, "Failed to allocate memory for strings table\n");
1405 exit(1);
1406 }
1407 }
1408 else
1409 {
1410 StringBase = realloc(StringBase, StringsLength + CoffStringsLength);
1411 if (!StringBase)
1412 {
1413 free(FileData);
1414 fprintf(stderr, "Failed to allocate memory for strings table\n");
1415 exit(1);
1416 }
1417 }
1418
1419 if (ConvertCoffs(&CoffSymbolsCount,
1420 &CoffSymbols,
1421 &StringsLength,
1422 StringBase,
1423 CoffsLength,
1424 CoffBase,
1425 CoffStringsLength,
1426 CoffStringBase,
1427 ImageBase,
1428 PEFileHeader,
1429 PESectionHeaders))
1430 {
1431 if (StabSymbols)
1432 {
1433 free(StabSymbols);
1434 }
1435 free(StringBase);
1436 free(FileData);
1437 exit(1);
1438 }
1439
1440 if (MergeStabsAndCoffs(&MergedSymbolsCount,
1441 &MergedSymbols,
1442 StabSymbolsCount,
1443 StabSymbols,
1444 CoffSymbolsCount,
1445 CoffSymbols))
1446 {
1447 if (CoffSymbols)
1448 {
1449 free(CoffSymbols);
1450 }
1451 if (StabSymbols)
1452 {
1453 free(StabSymbols);
1454 }
1455 free(StringBase);
1456 free(FileData);
1457 exit(1);
1458 }
1459
1460 if (CoffSymbols)
1461 {
1462 free(CoffSymbols);
1463 }
1464 if (StabSymbols)
1465 {
1466 free(StabSymbols);
1467 }
1468 if (MergedSymbolsCount == 0)
1469 {
1470 RosSymLength = 0;
1471 RosSymSection = NULL;
1472 }
1473 else
1474 {
1475 RosSymLength = sizeof(SYMBOLFILE_HEADER) +
1476 MergedSymbolsCount * sizeof(ROSSYM_ENTRY) +
1477 StringsLength;
1478
1479 RosSymSection = malloc(RosSymLength);
1480 if (RosSymSection == NULL)
1481 {
1482 free(MergedSymbols);
1483 free(StringBase);
1484 free(FileData);
1485 fprintf(stderr, "Unable to allocate memory for .rossym section\n");
1486 exit(1);
1487 }
1488 memset(RosSymSection, '\0', RosSymLength);
1489
1490 SymbolFileHeader = (PSYMBOLFILE_HEADER)RosSymSection;
1491 SymbolFileHeader->SymbolsOffset = sizeof(SYMBOLFILE_HEADER);
1492 SymbolFileHeader->SymbolsLength = MergedSymbolsCount * sizeof(ROSSYM_ENTRY);
1493 SymbolFileHeader->StringsOffset = SymbolFileHeader->SymbolsOffset +
1494 SymbolFileHeader->SymbolsLength;
1495 SymbolFileHeader->StringsLength = StringsLength;
1496
1497 memcpy((char *) RosSymSection + SymbolFileHeader->SymbolsOffset,
1498 MergedSymbols,
1499 SymbolFileHeader->SymbolsLength);
1500
1501 memcpy((char *) RosSymSection + SymbolFileHeader->StringsOffset,
1502 StringBase,
1503 SymbolFileHeader->StringsLength);
1504
1505 free(MergedSymbols);
1506 }
1507
1508 free(StringBase);
1509 out = fopen(path2, "wb");
1510 if (out == NULL)
1511 {
1512 perror("Cannot open output file");
1513 free(RosSymSection);
1514 free(FileData);
1515 exit(1);
1516 }
1517
1518 if (CreateOutputFile(out,
1519 FileData,
1520 PEDosHeader,
1521 PEFileHeader,
1522 PEOptHeader,
1523 PESectionHeaders,
1524 RosSymLength,
1525 RosSymSection))
1526 {
1527 fclose(out);
1528 if (RosSymSection)
1529 {
1530 free(RosSymSection);
1531 }
1532 free(FileData);
1533 exit(1);
1534 }
1535
1536 fclose(out);
1537 if (RosSymSection)
1538 {
1539 free(RosSymSection);
1540 }
1541 free(FileData);
1542
1543 return 0;
1544 }
1545
1546 /* EOF */