[FATTEN][KBDTOOL][RSYM]
[reactos.git] / reactos / sdk / 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 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;
724
725 *MergedSymbolCount = 0;
726 if (StabSymbolsCount == 0)
727 {
728 *MergedSymbols = NULL;
729 return 0;
730 }
731 *MergedSymbols = malloc((StabSymbolsCount + CoffSymbolsCount) * sizeof(ROSSYM_ENTRY));
732 if (*MergedSymbols == NULL)
733 {
734 fprintf(stderr, "Unable to allocate memory for merged symbols\n");
735 return 1;
736 }
737
738 StabFunctionStartAddress = 0;
739 StabFunctionStringOffset = 0;
740 CoffIndex = 0;
741 for (StabIndex = 0; StabIndex < StabSymbolsCount; StabIndex++)
742 {
743 (*MergedSymbols)[*MergedSymbolCount] = StabSymbols[StabIndex];
744 for (j = StabIndex + 1;
745 j < StabSymbolsCount && StabSymbols[j].Address == StabSymbols[StabIndex].Address;
746 j++)
747 {
748 if (StabSymbols[j].FileOffset != 0 && (*MergedSymbols)[*MergedSymbolCount].FileOffset == 0)
749 {
750 (*MergedSymbols)[*MergedSymbolCount].FileOffset = StabSymbols[j].FileOffset;
751 }
752 if (StabSymbols[j].FunctionOffset != 0 && (*MergedSymbols)[*MergedSymbolCount].FunctionOffset == 0)
753 {
754 (*MergedSymbols)[*MergedSymbolCount].FunctionOffset = StabSymbols[j].FunctionOffset;
755 }
756 if (StabSymbols[j].SourceLine != 0 && (*MergedSymbols)[*MergedSymbolCount].SourceLine == 0)
757 {
758 (*MergedSymbols)[*MergedSymbolCount].SourceLine = StabSymbols[j].SourceLine;
759 }
760 }
761 StabIndex = j - 1;
762
763 while (CoffIndex < CoffSymbolsCount &&
764 CoffSymbols[CoffIndex + 1].Address <= (*MergedSymbols)[*MergedSymbolCount].Address)
765 {
766 CoffIndex++;
767 }
768 NewStabFunctionStringOffset = (*MergedSymbols)[*MergedSymbolCount].FunctionOffset;
769 if (CoffSymbolsCount > 0 &&
770 CoffSymbols[CoffIndex].Address < (*MergedSymbols)[*MergedSymbolCount].Address &&
771 StabFunctionStartAddress < CoffSymbols[CoffIndex].Address &&
772 CoffSymbols[CoffIndex].FunctionOffset != 0)
773 {
774 (*MergedSymbols)[*MergedSymbolCount].FunctionOffset = CoffSymbols[CoffIndex].FunctionOffset;
775 CoffSymbols[CoffIndex].FileOffset = CoffSymbols[CoffIndex].FunctionOffset = 0;
776 }
777 if (StabFunctionStringOffset != NewStabFunctionStringOffset)
778 {
779 StabFunctionStartAddress = (*MergedSymbols)[*MergedSymbolCount].Address;
780 }
781 StabFunctionStringOffset = NewStabFunctionStringOffset;
782 (*MergedSymbolCount)++;
783 }
784 /* Handle functions that have no analog in the upstream data */
785 for (CoffIndex = 0; CoffIndex < CoffSymbolsCount; CoffIndex++)
786 {
787 if (CoffSymbols[CoffIndex].Address &&
788 CoffSymbols[CoffIndex].FunctionOffset)
789 {
790 (*MergedSymbols)[*MergedSymbolCount] = CoffSymbols[CoffIndex];
791 (*MergedSymbolCount)++;
792 }
793 }
794
795 qsort(*MergedSymbols, *MergedSymbolCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry);
796
797 return 0;
798 }
799
800 static PIMAGE_SECTION_HEADER
801 FindSectionForRVA(DWORD RVA, unsigned NumberOfSections, PIMAGE_SECTION_HEADER SectionHeaders)
802 {
803 unsigned Section;
804
805 for (Section = 0; Section < NumberOfSections; Section++)
806 {
807 if (SectionHeaders[Section].VirtualAddress <= RVA &&
808 RVA < SectionHeaders[Section].VirtualAddress + SectionHeaders[Section].Misc.VirtualSize)
809 {
810 return SectionHeaders + Section;
811 }
812 }
813
814 return NULL;
815 }
816
817 static int
818 ProcessRelocations(ULONG *ProcessedRelocsLength, void **ProcessedRelocs,
819 void *RawData, PIMAGE_OPTIONAL_HEADER OptHeader,
820 unsigned NumberOfSections, PIMAGE_SECTION_HEADER SectionHeaders)
821 {
822 PIMAGE_SECTION_HEADER RelocSectionHeader, TargetSectionHeader;
823 PIMAGE_BASE_RELOCATION BaseReloc, End, AcceptedRelocs;
824 int Found;
825
826 if (OptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC ||
827 OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress == 0)
828 {
829 /* No relocation entries */
830 *ProcessedRelocsLength = 0;
831 *ProcessedRelocs = NULL;
832 return 0;
833 }
834
835 RelocSectionHeader = FindSectionForRVA(OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
836 NumberOfSections, SectionHeaders);
837 if (RelocSectionHeader == NULL)
838 {
839 fprintf(stderr, "Can't find section header for relocation data\n");
840 return 1;
841 }
842
843 *ProcessedRelocs = malloc(RelocSectionHeader->SizeOfRawData);
844 if (*ProcessedRelocs == NULL)
845 {
846 fprintf(stderr,
847 "Failed to allocate %u bytes for relocations\n",
848 (unsigned int)RelocSectionHeader->SizeOfRawData);
849 return 1;
850 }
851 *ProcessedRelocsLength = 0;
852
853 BaseReloc = (PIMAGE_BASE_RELOCATION) ((char *) RawData +
854 RelocSectionHeader->PointerToRawData +
855 (OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress -
856 RelocSectionHeader->VirtualAddress));
857 End = (PIMAGE_BASE_RELOCATION) ((char *) BaseReloc +
858 OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
859
860 while (BaseReloc < End && BaseReloc->SizeOfBlock > 0)
861 {
862 TargetSectionHeader = FindSectionForRVA(BaseReloc->VirtualAddress,
863 NumberOfSections,
864 SectionHeaders);
865 if (TargetSectionHeader != NULL)
866 {
867 AcceptedRelocs = *ProcessedRelocs;
868 Found = 0;
869 while (AcceptedRelocs < (PIMAGE_BASE_RELOCATION) ((char *) *ProcessedRelocs +
870 *ProcessedRelocsLength)
871 && !Found)
872 {
873 Found = BaseReloc->SizeOfBlock == AcceptedRelocs->SizeOfBlock &&
874 memcmp(BaseReloc, AcceptedRelocs, AcceptedRelocs->SizeOfBlock) == 0;
875 AcceptedRelocs = (PIMAGE_BASE_RELOCATION) ((char *) AcceptedRelocs +
876 AcceptedRelocs->SizeOfBlock);
877 }
878 if (!Found)
879 {
880 memcpy((char *) *ProcessedRelocs + *ProcessedRelocsLength,
881 BaseReloc,
882 BaseReloc->SizeOfBlock);
883 *ProcessedRelocsLength += BaseReloc->SizeOfBlock;
884 }
885 }
886 BaseReloc = (PIMAGE_BASE_RELOCATION)((char *) BaseReloc + BaseReloc->SizeOfBlock);
887 }
888
889 return 0;
890 }
891
892 static const BYTE*
893 GetSectionName(void *StringsBase, const BYTE *SectionTitle)
894 {
895 if (SectionTitle[0] == '/')
896 {
897 int offset = atoi((char*)SectionTitle+1);
898 return ((BYTE *)StringsBase) + offset;
899 }
900 else
901 return SectionTitle;
902 }
903
904 static int
905 CreateOutputFile(FILE *OutFile, void *InData,
906 PIMAGE_DOS_HEADER InDosHeader, PIMAGE_FILE_HEADER InFileHeader,
907 PIMAGE_OPTIONAL_HEADER InOptHeader, PIMAGE_SECTION_HEADER InSectionHeaders,
908 ULONG RosSymLength, void *RosSymSection)
909 {
910 ULONG StartOfRawData;
911 unsigned Section;
912 void *OutHeader, *ProcessedRelocs, *PaddedRosSym, *Data;
913 unsigned char *PaddedStringTable;
914 PIMAGE_DOS_HEADER OutDosHeader;
915 PIMAGE_FILE_HEADER OutFileHeader;
916 PIMAGE_OPTIONAL_HEADER OutOptHeader;
917 PIMAGE_SECTION_HEADER OutSectionHeaders, CurrentSectionHeader;
918 DWORD CheckSum;
919 ULONG Length, i;
920 ULONG ProcessedRelocsLength;
921 ULONG RosSymOffset, RosSymFileLength;
922 ULONG PaddedStringTableLength;
923 int InRelocSectionIndex;
924 PIMAGE_SECTION_HEADER OutRelocSection;
925 /* Each coff symbol is 18 bytes and the string table follows */
926 char *StringTable = (char *)InData +
927 InFileHeader->PointerToSymbolTable + 18 * InFileHeader->NumberOfSymbols;
928 ULONG StringTableLength = 0;
929 ULONG StringTableLocation;
930
931 StartOfRawData = 0;
932 for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
933 {
934 const BYTE *SectionName = GetSectionName(StringTable,
935 InSectionHeaders[Section].Name);
936 if (InSectionHeaders[Section].Name[0] == '/')
937 {
938 StringTableLength = atoi((const char *)InSectionHeaders[Section].Name + 1) +
939 strlen((const char *)SectionName) + 1;
940 }
941 if ((StartOfRawData == 0 || InSectionHeaders[Section].PointerToRawData < StartOfRawData)
942 && InSectionHeaders[Section].PointerToRawData != 0
943 && (strncmp((char *) SectionName, ".stab", 5)) != 0
944 && (strncmp((char *) SectionName, ".debug_", 7)) != 0)
945 {
946 StartOfRawData = InSectionHeaders[Section].PointerToRawData;
947 }
948 }
949 OutHeader = malloc(StartOfRawData);
950 if (OutHeader == NULL)
951 {
952 fprintf(stderr,
953 "Failed to allocate %u bytes for output file header\n",
954 (unsigned int)StartOfRawData);
955 return 1;
956 }
957 memset(OutHeader, '\0', StartOfRawData);
958
959 OutDosHeader = (PIMAGE_DOS_HEADER) OutHeader;
960 memcpy(OutDosHeader, InDosHeader, InDosHeader->e_lfanew + sizeof(ULONG));
961
962 OutFileHeader = (PIMAGE_FILE_HEADER)((char *) OutHeader + OutDosHeader->e_lfanew + sizeof(ULONG));
963 memcpy(OutFileHeader, InFileHeader, sizeof(IMAGE_FILE_HEADER));
964 OutFileHeader->PointerToSymbolTable = 0;
965 OutFileHeader->NumberOfSymbols = 0;
966 OutFileHeader->Characteristics &= ~(IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_LOCAL_SYMS_STRIPPED |
967 IMAGE_FILE_DEBUG_STRIPPED);
968
969 OutOptHeader = (PIMAGE_OPTIONAL_HEADER)(OutFileHeader + 1);
970 memcpy(OutOptHeader, InOptHeader, sizeof(IMAGE_OPTIONAL_HEADER));
971 OutOptHeader->CheckSum = 0;
972
973 OutSectionHeaders = (PIMAGE_SECTION_HEADER)((char *) OutOptHeader + OutFileHeader->SizeOfOptionalHeader);
974
975 if (ProcessRelocations(&ProcessedRelocsLength,
976 &ProcessedRelocs,
977 InData,
978 InOptHeader,
979 InFileHeader->NumberOfSections,
980 InSectionHeaders))
981 {
982 return 1;
983 }
984 if (InOptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC ||
985 InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress == 0)
986 {
987 InRelocSectionIndex = -1;
988 }
989 else
990 {
991 InRelocSectionIndex = FindSectionForRVA(InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
992 InFileHeader->NumberOfSections, InSectionHeaders) - InSectionHeaders;
993 }
994
995 OutFileHeader->NumberOfSections = 0;
996 CurrentSectionHeader = OutSectionHeaders;
997 OutOptHeader->SizeOfImage = 0;
998 RosSymOffset = 0;
999 OutRelocSection = NULL;
1000
1001 StringTableLocation = StartOfRawData;
1002
1003 for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
1004 {
1005 const BYTE *SectionName = GetSectionName(StringTable,
1006 InSectionHeaders[Section].Name);
1007 if ((strncmp((char *) SectionName, ".stab", 5) != 0) &&
1008 (strncmp((char *) SectionName, ".debug_", 7)) != 0)
1009 {
1010 *CurrentSectionHeader = InSectionHeaders[Section];
1011 CurrentSectionHeader->PointerToLinenumbers = 0;
1012 CurrentSectionHeader->NumberOfLinenumbers = 0;
1013 if (OutOptHeader->SizeOfImage < CurrentSectionHeader->VirtualAddress +
1014 CurrentSectionHeader->Misc.VirtualSize)
1015 {
1016 OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress +
1017 CurrentSectionHeader->Misc.VirtualSize,
1018 OutOptHeader->SectionAlignment);
1019 }
1020 if (RosSymOffset < CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData)
1021 {
1022 RosSymOffset = CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData;
1023 }
1024 if (Section == (ULONG)InRelocSectionIndex)
1025 {
1026 OutRelocSection = CurrentSectionHeader;
1027 }
1028 StringTableLocation = CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData;
1029 OutFileHeader->NumberOfSections++;
1030 CurrentSectionHeader++;
1031 }
1032 }
1033
1034 if (OutRelocSection == CurrentSectionHeader - 1)
1035 {
1036 OutOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = ProcessedRelocsLength;
1037 if (OutOptHeader->SizeOfImage == OutRelocSection->VirtualAddress +
1038 ROUND_UP(OutRelocSection->Misc.VirtualSize,
1039 OutOptHeader->SectionAlignment))
1040 {
1041 OutOptHeader->SizeOfImage = OutRelocSection->VirtualAddress +
1042 ROUND_UP(ProcessedRelocsLength,
1043 OutOptHeader->SectionAlignment);
1044 }
1045 OutRelocSection->Misc.VirtualSize = ProcessedRelocsLength;
1046 if (RosSymOffset == OutRelocSection->PointerToRawData +
1047 OutRelocSection->SizeOfRawData)
1048 {
1049 RosSymOffset = OutRelocSection->PointerToRawData +
1050 ROUND_UP(ProcessedRelocsLength,
1051 OutOptHeader->FileAlignment);
1052 }
1053 OutRelocSection->SizeOfRawData = ROUND_UP(ProcessedRelocsLength,
1054 OutOptHeader->FileAlignment);
1055 }
1056
1057 if (RosSymLength > 0)
1058 {
1059 RosSymFileLength = ROUND_UP(RosSymLength, OutOptHeader->FileAlignment);
1060 memcpy(CurrentSectionHeader->Name, ".rossym", 8); /* We're lucky: string is exactly 8 bytes long */
1061 CurrentSectionHeader->Misc.VirtualSize = RosSymLength;
1062 CurrentSectionHeader->VirtualAddress = OutOptHeader->SizeOfImage;
1063 CurrentSectionHeader->SizeOfRawData = RosSymFileLength;
1064 CurrentSectionHeader->PointerToRawData = RosSymOffset;
1065 CurrentSectionHeader->PointerToRelocations = 0;
1066 CurrentSectionHeader->PointerToLinenumbers = 0;
1067 CurrentSectionHeader->NumberOfRelocations = 0;
1068 CurrentSectionHeader->NumberOfLinenumbers = 0;
1069 CurrentSectionHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
1070 | IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_TYPE_NOLOAD;
1071 OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress + CurrentSectionHeader->Misc.VirtualSize,
1072 OutOptHeader->SectionAlignment);
1073 OutFileHeader->NumberOfSections++;
1074
1075 PaddedRosSym = malloc(RosSymFileLength);
1076 if (PaddedRosSym == NULL)
1077 {
1078 fprintf(stderr,
1079 "Failed to allocate %u bytes for padded .rossym\n",
1080 (unsigned int)RosSymFileLength);
1081 return 1;
1082 }
1083 memcpy(PaddedRosSym, RosSymSection, RosSymLength);
1084 memset((char *) PaddedRosSym + RosSymLength,
1085 '\0',
1086 RosSymFileLength - RosSymLength);
1087
1088 /* Position the string table after our new section */
1089 StringTableLocation = RosSymOffset + RosSymFileLength;
1090 }
1091 else
1092 {
1093 PaddedRosSym = NULL;
1094 }
1095
1096 /* Set the string table area in the header if we need it */
1097 if (StringTableLength)
1098 {
1099 OutFileHeader->PointerToSymbolTable = StringTableLocation;
1100 OutFileHeader->NumberOfSymbols = 0;
1101 }
1102
1103 CheckSum = 0;
1104 for (i = 0; i < StartOfRawData / 2; i++)
1105 {
1106 CheckSum += ((unsigned short*) OutHeader)[i];
1107 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
1108 }
1109 Length = StartOfRawData;
1110 for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++)
1111 {
1112 DWORD SizeOfRawData;
1113 if (OutRelocSection == OutSectionHeaders + Section)
1114 {
1115 Data = (void *) ProcessedRelocs;
1116 SizeOfRawData = ProcessedRelocsLength;
1117 }
1118 else if (RosSymLength > 0 && Section + 1 == OutFileHeader->NumberOfSections)
1119 {
1120 Data = (void *) PaddedRosSym;
1121 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
1122 }
1123 else
1124 {
1125 Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
1126 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
1127 }
1128 for (i = 0; i < SizeOfRawData / 2; i++)
1129 {
1130 CheckSum += ((unsigned short*) Data)[i];
1131 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
1132 }
1133 Length += OutSectionHeaders[Section].SizeOfRawData;
1134 }
1135
1136 if (OutFileHeader->PointerToSymbolTable)
1137 {
1138 int PaddingFrom = (OutFileHeader->PointerToSymbolTable + StringTableLength) %
1139 OutOptHeader->FileAlignment;
1140 int PaddingSize = PaddingFrom ? OutOptHeader->FileAlignment - PaddingFrom : 0;
1141
1142 PaddedStringTableLength = StringTableLength + PaddingSize;
1143 PaddedStringTable = malloc(PaddedStringTableLength);
1144 /* COFF string section is preceeded by a length */
1145 assert(sizeof(StringTableLength) == 4);
1146 memcpy(PaddedStringTable, &StringTableLength, sizeof(StringTableLength));
1147 /* We just copy enough of the string table to contain the strings we want
1148 The string table length technically counts as part of the string table
1149 space itself. */
1150 memcpy(PaddedStringTable + 4, StringTable + 4, StringTableLength - 4);
1151 memset(PaddedStringTable + StringTableLength, 0, PaddingSize);
1152
1153 assert(OutFileHeader->PointerToSymbolTable % 2 == 0);
1154 for (i = 0; i < PaddedStringTableLength / 2; i++)
1155 {
1156 CheckSum += ((unsigned short*)PaddedStringTable)[i];
1157 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
1158 }
1159 Length += PaddedStringTableLength;
1160 }
1161 else
1162 {
1163 PaddedStringTable = NULL;
1164 }
1165
1166 CheckSum += Length;
1167 OutOptHeader->CheckSum = CheckSum;
1168
1169 if (fwrite(OutHeader, 1, StartOfRawData, OutFile) != StartOfRawData)
1170 {
1171 perror("Error writing output header\n");
1172 free(OutHeader);
1173 return 1;
1174 }
1175
1176 for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++)
1177 {
1178 if (OutSectionHeaders[Section].SizeOfRawData != 0)
1179 {
1180 DWORD SizeOfRawData;
1181 fseek(OutFile, OutSectionHeaders[Section].PointerToRawData, SEEK_SET);
1182 if (OutRelocSection == OutSectionHeaders + Section)
1183 {
1184 Data = (void *) ProcessedRelocs;
1185 SizeOfRawData = ProcessedRelocsLength;
1186 }
1187 else if (RosSymLength > 0 && Section + 1 == OutFileHeader->NumberOfSections)
1188 {
1189 Data = (void *) PaddedRosSym;
1190 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
1191 }
1192 else
1193 {
1194 Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
1195 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
1196 }
1197 if (fwrite(Data, 1, SizeOfRawData, OutFile) != SizeOfRawData)
1198 {
1199 perror("Error writing section data\n");
1200 free(PaddedRosSym);
1201 free(OutHeader);
1202 return 1;
1203 }
1204 }
1205 }
1206
1207 if (PaddedStringTable)
1208 {
1209 fseek(OutFile, OutFileHeader->PointerToSymbolTable, SEEK_SET);
1210 fwrite(PaddedStringTable, 1, PaddedStringTableLength, OutFile);
1211 free(PaddedStringTable);
1212 }
1213
1214 if (PaddedRosSym)
1215 {
1216 free(PaddedRosSym);
1217 }
1218 free(OutHeader);
1219
1220 return 0;
1221 }
1222
1223 int main(int argc, char* argv[])
1224 {
1225 PSYMBOLFILE_HEADER SymbolFileHeader;
1226 PIMAGE_DOS_HEADER PEDosHeader;
1227 PIMAGE_FILE_HEADER PEFileHeader;
1228 PIMAGE_OPTIONAL_HEADER PEOptHeader;
1229 PIMAGE_SECTION_HEADER PESectionHeaders;
1230 ULONG ImageBase;
1231 void *StabBase;
1232 ULONG StabsLength;
1233 void *StabStringBase;
1234 ULONG StabStringsLength;
1235 void *CoffBase = NULL;
1236 ULONG CoffsLength;
1237 void *CoffStringBase = NULL;
1238 ULONG CoffStringsLength;
1239 char* path1;
1240 char* path2;
1241 FILE* out;
1242 void *StringBase = NULL;
1243 ULONG StringsLength = 0;
1244 ULONG StabSymbolsCount = 0;
1245 PROSSYM_ENTRY StabSymbols = NULL;
1246 ULONG CoffSymbolsCount = 0;
1247 PROSSYM_ENTRY CoffSymbols = NULL;
1248 ULONG MergedSymbolsCount = 0;
1249 PROSSYM_ENTRY MergedSymbols = NULL;
1250 size_t FileSize;
1251 void *FileData;
1252 ULONG RosSymLength;
1253 void *RosSymSection;
1254 DWORD module_base;
1255 void *file;
1256 char elfhdr[4] = { '\177', 'E', 'L', 'F' };
1257 BOOLEAN UseDbgHelp = FALSE;
1258 int arg, argstate = 0;
1259 char *SourcePath = NULL;
1260
1261 for (arg = 1; arg < argc; arg++)
1262 {
1263 switch (argstate)
1264 {
1265 default:
1266 argstate = -1;
1267 break;
1268
1269 case 0:
1270 if (!strcmp(argv[arg], "-s"))
1271 {
1272 argstate = 1;
1273 }
1274 else
1275 {
1276 argstate = 2;
1277 path1 = convert_path(argv[arg]);
1278 }
1279 break;
1280
1281 case 1:
1282 free(SourcePath);
1283 SourcePath = strdup(argv[arg]);
1284 argstate = 0;
1285 break;
1286
1287 case 2:
1288 path2 = convert_path(argv[arg]);
1289 argstate = 3;
1290 break;
1291 }
1292 }
1293
1294 if (argstate != 3)
1295 {
1296 fprintf(stderr, "Usage: rsym [-s <sources>] <input> <output>\n");
1297 exit(1);
1298 }
1299
1300 FileData = load_file(path1, &FileSize);
1301 if (!FileData)
1302 {
1303 fprintf(stderr, "An error occured loading '%s'\n", path1);
1304 exit(1);
1305 }
1306
1307 file = fopen(path1, "rb");
1308
1309 /* Check if MZ header exists */
1310 PEDosHeader = (PIMAGE_DOS_HEADER) FileData;
1311 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC ||
1312 PEDosHeader->e_lfanew == 0L)
1313 {
1314 /* Ignore elf */
1315 if (!memcmp(PEDosHeader, elfhdr, sizeof(elfhdr)))
1316 exit(0);
1317 perror("Input file is not a PE image.\n");
1318 free(FileData);
1319 exit(1);
1320 }
1321
1322 /* Locate PE file header */
1323 /* sizeof(ULONG) = sizeof(MAGIC) */
1324 PEFileHeader = (PIMAGE_FILE_HEADER)((char *) FileData + PEDosHeader->e_lfanew + sizeof(ULONG));
1325
1326 /* Locate optional header */
1327 assert(sizeof(ULONG) == 4);
1328 PEOptHeader = (PIMAGE_OPTIONAL_HEADER)(PEFileHeader + 1);
1329 ImageBase = PEOptHeader->ImageBase;
1330
1331 /* Locate PE section headers */
1332 PESectionHeaders = (PIMAGE_SECTION_HEADER)((char *) PEOptHeader + PEFileHeader->SizeOfOptionalHeader);
1333
1334 if (GetStabInfo(FileData,
1335 PEFileHeader,
1336 PESectionHeaders,
1337 &StabsLength,
1338 &StabBase,
1339 &StabStringsLength,
1340 &StabStringBase))
1341 {
1342 free(FileData);
1343 exit(1);
1344 }
1345
1346 if (StabsLength == 0)
1347 {
1348 // SYMOPT_AUTO_PUBLICS
1349 // SYMOPT_FAVOR_COMPRESSED
1350 // SYMOPT_LOAD_ANYTHING
1351 // SYMOPT_LOAD_LINES
1352 SymSetOptions(0x10000 | 0x800000 | 0x40 | 0x10);
1353 SymInitialize(FileData, ".", 0);
1354
1355 module_base = SymLoadModule(FileData, file, path1, path1, 0, FileSize) & 0xffffffff;
1356
1357 if (ConvertDbgHelp(FileData,
1358 module_base,
1359 SourcePath,
1360 &StabSymbolsCount,
1361 &StabSymbols,
1362 &StringsLength,
1363 &StringBase))
1364 {
1365 free(FileData);
1366 exit(1);
1367 }
1368
1369 UseDbgHelp = TRUE;
1370 SymUnloadModule(FileData, module_base);
1371 SymCleanup(FileData);
1372 }
1373
1374 if (GetCoffInfo(FileData,
1375 PEFileHeader,
1376 PESectionHeaders,
1377 &CoffsLength,
1378 &CoffBase,
1379 &CoffStringsLength,
1380 &CoffStringBase))
1381 {
1382 free(FileData);
1383 exit(1);
1384 }
1385
1386 if (!UseDbgHelp)
1387 {
1388 StringBase = malloc(1 + StringsLength + CoffStringsLength +
1389 (CoffsLength / sizeof(ROSSYM_ENTRY)) * (E_SYMNMLEN + 1));
1390 if (StringBase == NULL)
1391 {
1392 free(FileData);
1393 fprintf(stderr, "Failed to allocate memory for strings table\n");
1394 exit(1);
1395 }
1396 /* Make offset 0 into an empty string */
1397 *((char *) StringBase) = '\0';
1398 StringsLength = 1;
1399
1400 if (ConvertStabs(&StabSymbolsCount,
1401 &StabSymbols,
1402 &StringsLength,
1403 StringBase,
1404 StabsLength,
1405 StabBase,
1406 StabStringsLength,
1407 StabStringBase,
1408 ImageBase,
1409 PEFileHeader,
1410 PESectionHeaders))
1411 {
1412 free(StringBase);
1413 free(FileData);
1414 fprintf(stderr, "Failed to allocate memory for strings table\n");
1415 exit(1);
1416 }
1417 }
1418 else
1419 {
1420 StringBase = realloc(StringBase, StringsLength + CoffStringsLength);
1421 if (!StringBase)
1422 {
1423 free(FileData);
1424 fprintf(stderr, "Failed to allocate memory for strings table\n");
1425 exit(1);
1426 }
1427 }
1428
1429 if (ConvertCoffs(&CoffSymbolsCount,
1430 &CoffSymbols,
1431 &StringsLength,
1432 StringBase,
1433 CoffsLength,
1434 CoffBase,
1435 CoffStringsLength,
1436 CoffStringBase,
1437 ImageBase,
1438 PEFileHeader,
1439 PESectionHeaders))
1440 {
1441 if (StabSymbols)
1442 {
1443 free(StabSymbols);
1444 }
1445 free(StringBase);
1446 free(FileData);
1447 exit(1);
1448 }
1449
1450 if (MergeStabsAndCoffs(&MergedSymbolsCount,
1451 &MergedSymbols,
1452 StabSymbolsCount,
1453 StabSymbols,
1454 CoffSymbolsCount,
1455 CoffSymbols))
1456 {
1457 if (CoffSymbols)
1458 {
1459 free(CoffSymbols);
1460 }
1461 if (StabSymbols)
1462 {
1463 free(StabSymbols);
1464 }
1465 free(StringBase);
1466 free(FileData);
1467 exit(1);
1468 }
1469
1470 if (CoffSymbols)
1471 {
1472 free(CoffSymbols);
1473 }
1474 if (StabSymbols)
1475 {
1476 free(StabSymbols);
1477 }
1478 if (MergedSymbolsCount == 0)
1479 {
1480 RosSymLength = 0;
1481 RosSymSection = NULL;
1482 }
1483 else
1484 {
1485 RosSymLength = sizeof(SYMBOLFILE_HEADER) +
1486 MergedSymbolsCount * sizeof(ROSSYM_ENTRY) +
1487 StringsLength;
1488
1489 RosSymSection = malloc(RosSymLength);
1490 if (RosSymSection == NULL)
1491 {
1492 free(MergedSymbols);
1493 free(StringBase);
1494 free(FileData);
1495 fprintf(stderr, "Unable to allocate memory for .rossym section\n");
1496 exit(1);
1497 }
1498 memset(RosSymSection, '\0', RosSymLength);
1499
1500 SymbolFileHeader = (PSYMBOLFILE_HEADER)RosSymSection;
1501 SymbolFileHeader->SymbolsOffset = sizeof(SYMBOLFILE_HEADER);
1502 SymbolFileHeader->SymbolsLength = MergedSymbolsCount * sizeof(ROSSYM_ENTRY);
1503 SymbolFileHeader->StringsOffset = SymbolFileHeader->SymbolsOffset +
1504 SymbolFileHeader->SymbolsLength;
1505 SymbolFileHeader->StringsLength = StringsLength;
1506
1507 memcpy((char *) RosSymSection + SymbolFileHeader->SymbolsOffset,
1508 MergedSymbols,
1509 SymbolFileHeader->SymbolsLength);
1510
1511 memcpy((char *) RosSymSection + SymbolFileHeader->StringsOffset,
1512 StringBase,
1513 SymbolFileHeader->StringsLength);
1514
1515 free(MergedSymbols);
1516 }
1517
1518 free(StringBase);
1519 out = fopen(path2, "wb");
1520 if (out == NULL)
1521 {
1522 perror("Cannot open output file");
1523 free(RosSymSection);
1524 free(FileData);
1525 exit(1);
1526 }
1527
1528 if (CreateOutputFile(out,
1529 FileData,
1530 PEDosHeader,
1531 PEFileHeader,
1532 PEOptHeader,
1533 PESectionHeaders,
1534 RosSymLength,
1535 RosSymSection))
1536 {
1537 fclose(out);
1538 if (RosSymSection)
1539 {
1540 free(RosSymSection);
1541 }
1542 free(FileData);
1543 exit(1);
1544 }
1545
1546 fclose(out);
1547 if (RosSymSection)
1548 {
1549 free(RosSymSection);
1550 }
1551 free(FileData);
1552
1553 return 0;
1554 }
1555
1556 /* EOF */