[MKHIVE] Remove key name in our custom registry tree; use cell index instead
[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 void *process;
465 DWORD module_base;
466 char *PathChop;
467 char *SourcePath;
468 struct DbgHelpLineEntry *lastLineEntry;
469 };
470
471 static struct DbgHelpLineEntry*
472 DbgHelpAddLineEntry(struct DbgHelpStringTab *tab)
473 {
474 if (tab->CurLineEntries == tab->LineEntries)
475 {
476 struct DbgHelpLineEntry *newEntries = realloc(tab->LineEntryData,
477 tab->LineEntries * 2 * sizeof(struct DbgHelpLineEntry));
478
479 if (!newEntries)
480 return 0;
481
482 tab->LineEntryData = newEntries;
483
484 memset(tab->LineEntryData + tab->LineEntries, 0, sizeof(struct DbgHelpLineEntry) * tab->LineEntries);
485 tab->LineEntries *= 2;
486 }
487
488 return &tab->LineEntryData[tab->CurLineEntries++];
489 }
490
491 static int
492 DbgHelpAddStringToTable(struct DbgHelpStringTab *tab, char *name)
493 {
494 unsigned int bucket = ComputeDJBHash(name) % tab->Length;
495 char **tabEnt = tab->Table[bucket];
496 int i;
497 char **newBucket;
498
499 if (tabEnt)
500 {
501 for (i = 0; tabEnt[i] && strcmp(tabEnt[i], name); i++);
502 if (tabEnt[i])
503 {
504 free(name);
505 return (i << 10) | bucket;
506 }
507 }
508 else
509 i = 0;
510
511 /* At this point, we need to insert */
512 tab->Bytes += strlen(name) + 1;
513
514 newBucket = realloc(tab->Table[bucket], (i+2) * sizeof(char *));
515
516 if (!newBucket)
517 {
518 fprintf(stderr, "realloc failed!\n");
519 return -1;
520 }
521
522 tab->Table[bucket] = newBucket;
523 tab->Table[bucket][i+1] = 0;
524 tab->Table[bucket][i] = name;
525 return (i << 10) | bucket;
526 }
527
528 const char*
529 DbgHelpGetString(struct DbgHelpStringTab *tab, int id)
530 {
531 int i = id >> 10;
532 int bucket = id & 0x3ff;
533 return tab->Table[bucket][i];
534 }
535
536 /* Remove a prefix of PathChop if it exists and return a copy of the tail. */
537 static char *
538 StrDupShortenPath(char *PathChop, char *FilePath)
539 {
540 int pclen = strlen(PathChop);
541 if (!strncmp(FilePath, PathChop, pclen))
542 {
543 return strdup(FilePath+pclen);
544 }
545 else
546 {
547 return strdup(FilePath);
548 }
549 }
550
551 static BOOL
552 DbgHelpAddLineNumber(PSRCCODEINFO LineInfo, void *UserContext)
553 {
554 struct DbgHelpStringTab *tab = (struct DbgHelpStringTab *)UserContext;
555 DWORD64 disp;
556 int fileId, functionId;
557 PSYMBOL_INFO pSymbol = malloc(FIELD_OFFSET(SYMBOL_INFO, Name[MAX_SYM_NAME]));
558 if (!pSymbol) return FALSE;
559 memset(pSymbol, 0, FIELD_OFFSET(SYMBOL_INFO, Name[MAX_SYM_NAME]));
560
561 /* If any file can be opened by relative path up to a certain level, then
562 record that path. */
563 if (!tab->PathChop)
564 {
565 int i, endLen;
566 char *end = strrchr(LineInfo->FileName, '/');
567
568 if (!end)
569 end = strrchr(LineInfo->FileName, '\\');
570
571 if (end)
572 {
573 for (i = (end - LineInfo->FileName) - 1; i >= 0; i--)
574 {
575 if (LineInfo->FileName[i] == '/' || LineInfo->FileName[i] == '\\')
576 {
577 char *synthname = malloc(strlen(tab->SourcePath) +
578 strlen(LineInfo->FileName + i + 1)
579 + 2);
580 strcpy(synthname, tab->SourcePath);
581 strcat(synthname, "/");
582 strcat(synthname, LineInfo->FileName + i + 1);
583 FILE *f = fopen(synthname, "r");
584 free(synthname);
585 if (f)
586 {
587 fclose(f);
588 break;
589 }
590 }
591 }
592
593 i++; /* Be in the string or past the next slash */
594 tab->PathChop = malloc(i + 1);
595 memcpy(tab->PathChop, LineInfo->FileName, i);
596 tab->PathChop[i] = 0;
597 }
598 }
599
600 fileId = DbgHelpAddStringToTable(tab,
601 StrDupShortenPath(tab->PathChop,
602 LineInfo->FileName));
603
604 pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
605 pSymbol->MaxNameLen = MAX_SYM_NAME;
606
607 if (!SymFromAddr(tab->process, LineInfo->Address, &disp, pSymbol))
608 {
609 //fprintf(stderr, "SymFromAddr failed.\n");
610 free(pSymbol);
611 return FALSE;
612 }
613
614 functionId = DbgHelpAddStringToTable(tab, strdup(pSymbol->Name));
615
616 if (LineInfo->Address == 0)
617 fprintf(stderr, "Address is 0.\n");
618
619 tab->lastLineEntry = DbgHelpAddLineEntry(tab);
620 tab->lastLineEntry->vma = LineInfo->Address - LineInfo->ModBase;
621 tab->lastLineEntry->functionId = functionId;
622 tab->lastLineEntry->fileId = fileId;
623 tab->lastLineEntry->line = LineInfo->LineNumber;
624
625 free(pSymbol);
626 return TRUE;
627 }
628
629 static int
630 ConvertDbgHelp(void *process, DWORD module_base, char *SourcePath,
631 ULONG *SymbolsCount, PROSSYM_ENTRY *SymbolsBase,
632 ULONG *StringsLength, void **StringsBase)
633 {
634 char *strings, *strings_copy;
635 int i, j, bucket, entry;
636 PROSSYM_ENTRY rossym;
637 struct DbgHelpStringTab strtab = { 0 };
638
639 strtab.process = process;
640 strtab.module_base = module_base;
641 strtab.Bytes = 1;
642 strtab.Length = 1024;
643 strtab.Table = calloc(1024, sizeof(const char **));
644 strtab.Table[0] = calloc(2, sizeof(const char *));
645 strtab.Table[0][0] = strdup(""); // The zero string
646 strtab.CurLineEntries = 0;
647 strtab.LineEntries = 16384;
648 strtab.LineEntryData = calloc(strtab.LineEntries, sizeof(struct DbgHelpLineEntry));
649 strtab.PathChop = NULL;
650 strtab.SourcePath = SourcePath ? SourcePath : "";
651
652 SymEnumLines(process, module_base, NULL, NULL, DbgHelpAddLineNumber, &strtab);
653
654 /* Transcribe necessary strings */
655 *StringsLength = strtab.Bytes;
656 strings = strings_copy = ((char *)(*StringsBase = malloc(strtab.Bytes)));
657
658 /* Copy in strings */
659 for (i = 0; i < strtab.Length; i++)
660 {
661 for (j = 0; strtab.Table[i] && strtab.Table[i][j]; j++)
662 {
663 /* Each entry is replaced by its corresponding entry in our string
664 section. We can substract the strings origin to get an offset. */
665 char *toFree = strtab.Table[i][j];
666 strtab.Table[i][j] = strcpy(strings_copy, strtab.Table[i][j]);
667 free(toFree);
668 strings_copy += strlen(strings_copy) + 1;
669 }
670 }
671
672 assert(strings_copy == strings + strtab.Bytes);
673
674 *SymbolsBase = calloc(strtab.CurLineEntries, sizeof(ROSSYM_ENTRY));
675 *SymbolsCount = strtab.CurLineEntries;
676
677 /* Copy symbols into rossym entries */
678 for (i = 0; i < strtab.CurLineEntries; i++)
679 {
680 rossym = &(*SymbolsBase)[i];
681 rossym->Address = strtab.LineEntryData[i].vma;
682 bucket = strtab.LineEntryData[i].fileId & 0x3ff;
683 entry = strtab.LineEntryData[i].fileId >> 10;
684 rossym->FileOffset = strtab.Table[bucket][entry] - strings;
685 bucket = strtab.LineEntryData[i].functionId & 0x3ff;
686 entry = strtab.LineEntryData[i].functionId >> 10;
687 rossym->FunctionOffset = strtab.Table[bucket][entry] - strings;
688 rossym->SourceLine = strtab.LineEntryData[i].line;
689 }
690
691 /* Free stringtab */
692 for (i = 0; i < strtab.Length; i++)
693 {
694 free(strtab.Table[i]);
695 }
696
697 free(strtab.LineEntryData);
698 free(strtab.PathChop);
699
700 qsort(*SymbolsBase, *SymbolsCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *))CompareSymEntry);
701
702 return 0;
703 }
704
705 static int
706 MergeStabsAndCoffs(ULONG *MergedSymbolCount, PROSSYM_ENTRY *MergedSymbols,
707 ULONG StabSymbolsCount, PROSSYM_ENTRY StabSymbols,
708 ULONG CoffSymbolsCount, PROSSYM_ENTRY CoffSymbols)
709 {
710 ULONG StabIndex, j;
711 ULONG CoffIndex;
712 ULONG_PTR StabFunctionStartAddress;
713 ULONG StabFunctionStringOffset, NewStabFunctionStringOffset;
714
715 *MergedSymbolCount = 0;
716 if (StabSymbolsCount == 0)
717 {
718 *MergedSymbols = NULL;
719 return 0;
720 }
721 *MergedSymbols = malloc((StabSymbolsCount + CoffSymbolsCount) * sizeof(ROSSYM_ENTRY));
722 if (*MergedSymbols == NULL)
723 {
724 fprintf(stderr, "Unable to allocate memory for merged symbols\n");
725 return 1;
726 }
727
728 StabFunctionStartAddress = 0;
729 StabFunctionStringOffset = 0;
730 CoffIndex = 0;
731 for (StabIndex = 0; StabIndex < StabSymbolsCount; StabIndex++)
732 {
733 (*MergedSymbols)[*MergedSymbolCount] = StabSymbols[StabIndex];
734 for (j = StabIndex + 1;
735 j < StabSymbolsCount && StabSymbols[j].Address == StabSymbols[StabIndex].Address;
736 j++)
737 {
738 if (StabSymbols[j].FileOffset != 0 && (*MergedSymbols)[*MergedSymbolCount].FileOffset == 0)
739 {
740 (*MergedSymbols)[*MergedSymbolCount].FileOffset = StabSymbols[j].FileOffset;
741 }
742 if (StabSymbols[j].FunctionOffset != 0 && (*MergedSymbols)[*MergedSymbolCount].FunctionOffset == 0)
743 {
744 (*MergedSymbols)[*MergedSymbolCount].FunctionOffset = StabSymbols[j].FunctionOffset;
745 }
746 if (StabSymbols[j].SourceLine != 0 && (*MergedSymbols)[*MergedSymbolCount].SourceLine == 0)
747 {
748 (*MergedSymbols)[*MergedSymbolCount].SourceLine = StabSymbols[j].SourceLine;
749 }
750 }
751 StabIndex = j - 1;
752
753 while (CoffIndex < CoffSymbolsCount &&
754 CoffSymbols[CoffIndex + 1].Address <= (*MergedSymbols)[*MergedSymbolCount].Address)
755 {
756 CoffIndex++;
757 }
758 NewStabFunctionStringOffset = (*MergedSymbols)[*MergedSymbolCount].FunctionOffset;
759 if (CoffSymbolsCount > 0 &&
760 CoffSymbols[CoffIndex].Address < (*MergedSymbols)[*MergedSymbolCount].Address &&
761 StabFunctionStartAddress < CoffSymbols[CoffIndex].Address &&
762 CoffSymbols[CoffIndex].FunctionOffset != 0)
763 {
764 (*MergedSymbols)[*MergedSymbolCount].FunctionOffset = CoffSymbols[CoffIndex].FunctionOffset;
765 CoffSymbols[CoffIndex].FileOffset = CoffSymbols[CoffIndex].FunctionOffset = 0;
766 }
767 if (StabFunctionStringOffset != NewStabFunctionStringOffset)
768 {
769 StabFunctionStartAddress = (*MergedSymbols)[*MergedSymbolCount].Address;
770 }
771 StabFunctionStringOffset = NewStabFunctionStringOffset;
772 (*MergedSymbolCount)++;
773 }
774 /* Handle functions that have no analog in the upstream data */
775 for (CoffIndex = 0; CoffIndex < CoffSymbolsCount; CoffIndex++)
776 {
777 if (CoffSymbols[CoffIndex].Address &&
778 CoffSymbols[CoffIndex].FunctionOffset)
779 {
780 (*MergedSymbols)[*MergedSymbolCount] = CoffSymbols[CoffIndex];
781 (*MergedSymbolCount)++;
782 }
783 }
784
785 qsort(*MergedSymbols, *MergedSymbolCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry);
786
787 return 0;
788 }
789
790 static PIMAGE_SECTION_HEADER
791 FindSectionForRVA(DWORD RVA, unsigned NumberOfSections, PIMAGE_SECTION_HEADER SectionHeaders)
792 {
793 unsigned Section;
794
795 for (Section = 0; Section < NumberOfSections; Section++)
796 {
797 if (SectionHeaders[Section].VirtualAddress <= RVA &&
798 RVA < SectionHeaders[Section].VirtualAddress + SectionHeaders[Section].Misc.VirtualSize)
799 {
800 return SectionHeaders + Section;
801 }
802 }
803
804 return NULL;
805 }
806
807 static int
808 ProcessRelocations(ULONG *ProcessedRelocsLength, void **ProcessedRelocs,
809 void *RawData, PIMAGE_OPTIONAL_HEADER OptHeader,
810 unsigned NumberOfSections, PIMAGE_SECTION_HEADER SectionHeaders)
811 {
812 PIMAGE_SECTION_HEADER RelocSectionHeader, TargetSectionHeader;
813 PIMAGE_BASE_RELOCATION BaseReloc, End, AcceptedRelocs;
814 int Found;
815
816 if (OptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC ||
817 OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress == 0)
818 {
819 /* No relocation entries */
820 *ProcessedRelocsLength = 0;
821 *ProcessedRelocs = NULL;
822 return 0;
823 }
824
825 RelocSectionHeader = FindSectionForRVA(OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
826 NumberOfSections, SectionHeaders);
827 if (RelocSectionHeader == NULL)
828 {
829 fprintf(stderr, "Can't find section header for relocation data\n");
830 return 1;
831 }
832
833 *ProcessedRelocs = malloc(RelocSectionHeader->SizeOfRawData);
834 if (*ProcessedRelocs == NULL)
835 {
836 fprintf(stderr,
837 "Failed to allocate %u bytes for relocations\n",
838 (unsigned int)RelocSectionHeader->SizeOfRawData);
839 return 1;
840 }
841 *ProcessedRelocsLength = 0;
842
843 BaseReloc = (PIMAGE_BASE_RELOCATION) ((char *) RawData +
844 RelocSectionHeader->PointerToRawData +
845 (OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress -
846 RelocSectionHeader->VirtualAddress));
847 End = (PIMAGE_BASE_RELOCATION) ((char *) BaseReloc +
848 OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
849
850 while (BaseReloc < End && BaseReloc->SizeOfBlock > 0)
851 {
852 TargetSectionHeader = FindSectionForRVA(BaseReloc->VirtualAddress,
853 NumberOfSections,
854 SectionHeaders);
855 if (TargetSectionHeader != NULL)
856 {
857 AcceptedRelocs = *ProcessedRelocs;
858 Found = 0;
859 while (AcceptedRelocs < (PIMAGE_BASE_RELOCATION) ((char *) *ProcessedRelocs +
860 *ProcessedRelocsLength)
861 && !Found)
862 {
863 Found = BaseReloc->SizeOfBlock == AcceptedRelocs->SizeOfBlock &&
864 memcmp(BaseReloc, AcceptedRelocs, AcceptedRelocs->SizeOfBlock) == 0;
865 AcceptedRelocs = (PIMAGE_BASE_RELOCATION) ((char *) AcceptedRelocs +
866 AcceptedRelocs->SizeOfBlock);
867 }
868 if (!Found)
869 {
870 memcpy((char *) *ProcessedRelocs + *ProcessedRelocsLength,
871 BaseReloc,
872 BaseReloc->SizeOfBlock);
873 *ProcessedRelocsLength += BaseReloc->SizeOfBlock;
874 }
875 }
876 BaseReloc = (PIMAGE_BASE_RELOCATION)((char *) BaseReloc + BaseReloc->SizeOfBlock);
877 }
878
879 return 0;
880 }
881
882 static const BYTE*
883 GetSectionName(void *StringsBase, const BYTE *SectionTitle)
884 {
885 if (SectionTitle[0] == '/')
886 {
887 int offset = atoi((char*)SectionTitle+1);
888 return ((BYTE *)StringsBase) + offset;
889 }
890 else
891 return SectionTitle;
892 }
893
894 static int
895 CreateOutputFile(FILE *OutFile, void *InData,
896 PIMAGE_DOS_HEADER InDosHeader, PIMAGE_FILE_HEADER InFileHeader,
897 PIMAGE_OPTIONAL_HEADER InOptHeader, PIMAGE_SECTION_HEADER InSectionHeaders,
898 ULONG RosSymLength, void *RosSymSection)
899 {
900 ULONG StartOfRawData;
901 unsigned Section;
902 void *OutHeader, *ProcessedRelocs, *PaddedRosSym, *Data;
903 unsigned char *PaddedStringTable;
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 ULONG PaddedStringTableLength;
913 int InRelocSectionIndex;
914 PIMAGE_SECTION_HEADER OutRelocSection;
915 /* Each coff symbol is 18 bytes and the string table follows */
916 char *StringTable = (char *)InData +
917 InFileHeader->PointerToSymbolTable + 18 * InFileHeader->NumberOfSymbols;
918 ULONG StringTableLength = 0;
919 ULONG StringTableLocation;
920
921 StartOfRawData = 0;
922 for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
923 {
924 const BYTE *SectionName = GetSectionName(StringTable,
925 InSectionHeaders[Section].Name);
926 if (InSectionHeaders[Section].Name[0] == '/')
927 {
928 StringTableLength = atoi(InSectionHeaders[Section].Name+1) + strlen(SectionName) + 1;
929 }
930 if ((StartOfRawData == 0 || InSectionHeaders[Section].PointerToRawData < StartOfRawData)
931 && InSectionHeaders[Section].PointerToRawData != 0
932 && (strncmp((char *) SectionName, ".stab", 5)) != 0
933 && (strncmp((char *) SectionName, ".debug_", 7)) != 0)
934 {
935 StartOfRawData = InSectionHeaders[Section].PointerToRawData;
936 }
937 }
938 OutHeader = malloc(StartOfRawData);
939 if (OutHeader == NULL)
940 {
941 fprintf(stderr,
942 "Failed to allocate %u bytes for output file header\n",
943 (unsigned int)StartOfRawData);
944 return 1;
945 }
946 memset(OutHeader, '\0', StartOfRawData);
947
948 OutDosHeader = (PIMAGE_DOS_HEADER) OutHeader;
949 memcpy(OutDosHeader, InDosHeader, InDosHeader->e_lfanew + sizeof(ULONG));
950
951 OutFileHeader = (PIMAGE_FILE_HEADER)((char *) OutHeader + OutDosHeader->e_lfanew + sizeof(ULONG));
952 memcpy(OutFileHeader, InFileHeader, sizeof(IMAGE_FILE_HEADER));
953 OutFileHeader->PointerToSymbolTable = 0;
954 OutFileHeader->NumberOfSymbols = 0;
955 OutFileHeader->Characteristics &= ~(IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_LOCAL_SYMS_STRIPPED |
956 IMAGE_FILE_DEBUG_STRIPPED);
957
958 OutOptHeader = (PIMAGE_OPTIONAL_HEADER)(OutFileHeader + 1);
959 memcpy(OutOptHeader, InOptHeader, sizeof(IMAGE_OPTIONAL_HEADER));
960 OutOptHeader->CheckSum = 0;
961
962 OutSectionHeaders = (PIMAGE_SECTION_HEADER)((char *) OutOptHeader + OutFileHeader->SizeOfOptionalHeader);
963
964 if (ProcessRelocations(&ProcessedRelocsLength,
965 &ProcessedRelocs,
966 InData,
967 InOptHeader,
968 InFileHeader->NumberOfSections,
969 InSectionHeaders))
970 {
971 return 1;
972 }
973 if (InOptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC ||
974 InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress == 0)
975 {
976 InRelocSectionIndex = -1;
977 }
978 else
979 {
980 InRelocSectionIndex = FindSectionForRVA(InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
981 InFileHeader->NumberOfSections, InSectionHeaders) - InSectionHeaders;
982 }
983
984 OutFileHeader->NumberOfSections = 0;
985 CurrentSectionHeader = OutSectionHeaders;
986 OutOptHeader->SizeOfImage = 0;
987 RosSymOffset = 0;
988 OutRelocSection = NULL;
989
990 StringTableLocation = StartOfRawData;
991
992 for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
993 {
994 const BYTE *SectionName = GetSectionName(StringTable,
995 InSectionHeaders[Section].Name);
996 if ((strncmp((char *) SectionName, ".stab", 5) != 0) &&
997 (strncmp((char *) SectionName, ".debug_", 7)) != 0)
998 {
999 *CurrentSectionHeader = InSectionHeaders[Section];
1000 CurrentSectionHeader->PointerToLinenumbers = 0;
1001 CurrentSectionHeader->NumberOfLinenumbers = 0;
1002 if (OutOptHeader->SizeOfImage < CurrentSectionHeader->VirtualAddress +
1003 CurrentSectionHeader->Misc.VirtualSize)
1004 {
1005 OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress +
1006 CurrentSectionHeader->Misc.VirtualSize,
1007 OutOptHeader->SectionAlignment);
1008 }
1009 if (RosSymOffset < CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData)
1010 {
1011 RosSymOffset = CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData;
1012 }
1013 if (Section == (ULONG)InRelocSectionIndex)
1014 {
1015 OutRelocSection = CurrentSectionHeader;
1016 }
1017 StringTableLocation = CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData;
1018 OutFileHeader->NumberOfSections++;
1019 CurrentSectionHeader++;
1020 }
1021 }
1022
1023 if (OutRelocSection == CurrentSectionHeader - 1)
1024 {
1025 OutOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = ProcessedRelocsLength;
1026 if (OutOptHeader->SizeOfImage == OutRelocSection->VirtualAddress +
1027 ROUND_UP(OutRelocSection->Misc.VirtualSize,
1028 OutOptHeader->SectionAlignment))
1029 {
1030 OutOptHeader->SizeOfImage = OutRelocSection->VirtualAddress +
1031 ROUND_UP(ProcessedRelocsLength,
1032 OutOptHeader->SectionAlignment);
1033 }
1034 OutRelocSection->Misc.VirtualSize = ProcessedRelocsLength;
1035 if (RosSymOffset == OutRelocSection->PointerToRawData +
1036 OutRelocSection->SizeOfRawData)
1037 {
1038 RosSymOffset = OutRelocSection->PointerToRawData +
1039 ROUND_UP(ProcessedRelocsLength,
1040 OutOptHeader->FileAlignment);
1041 }
1042 OutRelocSection->SizeOfRawData = ROUND_UP(ProcessedRelocsLength,
1043 OutOptHeader->FileAlignment);
1044 }
1045
1046 if (RosSymLength > 0)
1047 {
1048 RosSymFileLength = ROUND_UP(RosSymLength, OutOptHeader->FileAlignment);
1049 memcpy(CurrentSectionHeader->Name, ".rossym", 8); /* We're lucky: string is exactly 8 bytes long */
1050 CurrentSectionHeader->Misc.VirtualSize = RosSymLength;
1051 CurrentSectionHeader->VirtualAddress = OutOptHeader->SizeOfImage;
1052 CurrentSectionHeader->SizeOfRawData = RosSymFileLength;
1053 CurrentSectionHeader->PointerToRawData = RosSymOffset;
1054 CurrentSectionHeader->PointerToRelocations = 0;
1055 CurrentSectionHeader->PointerToLinenumbers = 0;
1056 CurrentSectionHeader->NumberOfRelocations = 0;
1057 CurrentSectionHeader->NumberOfLinenumbers = 0;
1058 CurrentSectionHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
1059 | IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_TYPE_NOLOAD;
1060 OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress + CurrentSectionHeader->Misc.VirtualSize,
1061 OutOptHeader->SectionAlignment);
1062 OutFileHeader->NumberOfSections++;
1063
1064 PaddedRosSym = malloc(RosSymFileLength);
1065 if (PaddedRosSym == NULL)
1066 {
1067 fprintf(stderr,
1068 "Failed to allocate %u bytes for padded .rossym\n",
1069 (unsigned int)RosSymFileLength);
1070 return 1;
1071 }
1072 memcpy(PaddedRosSym, RosSymSection, RosSymLength);
1073 memset((char *) PaddedRosSym + RosSymLength,
1074 '\0',
1075 RosSymFileLength - RosSymLength);
1076
1077 /* Position the string table after our new section */
1078 StringTableLocation = RosSymOffset + RosSymFileLength;
1079 }
1080 else
1081 {
1082 PaddedRosSym = NULL;
1083 }
1084
1085 /* Set the string table area in the header if we need it */
1086 if (StringTableLength)
1087 {
1088 OutFileHeader->PointerToSymbolTable = StringTableLocation;
1089 OutFileHeader->NumberOfSymbols = 0;
1090 }
1091
1092 CheckSum = 0;
1093 for (i = 0; i < StartOfRawData / 2; i++)
1094 {
1095 CheckSum += ((unsigned short*) OutHeader)[i];
1096 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
1097 }
1098 Length = StartOfRawData;
1099 for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++)
1100 {
1101 DWORD SizeOfRawData;
1102 if (OutRelocSection == OutSectionHeaders + Section)
1103 {
1104 Data = (void *) ProcessedRelocs;
1105 SizeOfRawData = ProcessedRelocsLength;
1106 }
1107 else if (RosSymLength > 0 && Section + 1 == OutFileHeader->NumberOfSections)
1108 {
1109 Data = (void *) PaddedRosSym;
1110 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
1111 }
1112 else
1113 {
1114 Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
1115 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
1116 }
1117 for (i = 0; i < SizeOfRawData / 2; i++)
1118 {
1119 CheckSum += ((unsigned short*) Data)[i];
1120 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
1121 }
1122 Length += OutSectionHeaders[Section].SizeOfRawData;
1123 }
1124
1125 if (OutFileHeader->PointerToSymbolTable)
1126 {
1127 int PaddingFrom = (OutFileHeader->PointerToSymbolTable + StringTableLength) %
1128 OutOptHeader->FileAlignment;
1129 int PaddingSize = PaddingFrom ? OutOptHeader->FileAlignment - PaddingFrom : 0;
1130
1131 PaddedStringTableLength = StringTableLength + PaddingSize;
1132 PaddedStringTable = malloc(PaddedStringTableLength);
1133 /* COFF string section is preceeded by a length */
1134 assert(sizeof(StringTableLength) == 4);
1135 memcpy(PaddedStringTable, &StringTableLength, sizeof(StringTableLength));
1136 /* We just copy enough of the string table to contain the strings we want
1137 The string table length technically counts as part of the string table
1138 space itself. */
1139 memcpy(PaddedStringTable + 4, StringTable + 4, StringTableLength - 4);
1140 memset(PaddedStringTable + StringTableLength, 0, PaddingSize);
1141
1142 assert(OutFileHeader->PointerToSymbolTable % 2 == 0);
1143 for (i = 0; i < PaddedStringTableLength / 2; i++)
1144 {
1145 CheckSum += ((unsigned short*)PaddedStringTable)[i];
1146 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
1147 }
1148 Length += PaddedStringTableLength;
1149 }
1150 else
1151 {
1152 PaddedStringTable = NULL;
1153 }
1154
1155 CheckSum += Length;
1156 OutOptHeader->CheckSum = CheckSum;
1157
1158 if (fwrite(OutHeader, 1, StartOfRawData, OutFile) != StartOfRawData)
1159 {
1160 perror("Error writing output header\n");
1161 free(OutHeader);
1162 return 1;
1163 }
1164
1165 for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++)
1166 {
1167 if (OutSectionHeaders[Section].SizeOfRawData != 0)
1168 {
1169 DWORD SizeOfRawData;
1170 fseek(OutFile, OutSectionHeaders[Section].PointerToRawData, SEEK_SET);
1171 if (OutRelocSection == OutSectionHeaders + Section)
1172 {
1173 Data = (void *) ProcessedRelocs;
1174 SizeOfRawData = ProcessedRelocsLength;
1175 }
1176 else if (RosSymLength > 0 && Section + 1 == OutFileHeader->NumberOfSections)
1177 {
1178 Data = (void *) PaddedRosSym;
1179 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
1180 }
1181 else
1182 {
1183 Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
1184 SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
1185 }
1186 if (fwrite(Data, 1, SizeOfRawData, OutFile) != SizeOfRawData)
1187 {
1188 perror("Error writing section data\n");
1189 free(PaddedRosSym);
1190 free(OutHeader);
1191 return 1;
1192 }
1193 }
1194 }
1195
1196 if (PaddedStringTable)
1197 {
1198 fseek(OutFile, OutFileHeader->PointerToSymbolTable, SEEK_SET);
1199 fwrite(PaddedStringTable, 1, PaddedStringTableLength, OutFile);
1200 free(PaddedStringTable);
1201 }
1202
1203 if (PaddedRosSym)
1204 {
1205 free(PaddedRosSym);
1206 }
1207 free(OutHeader);
1208
1209 return 0;
1210 }
1211
1212 int main(int argc, char* argv[])
1213 {
1214 PSYMBOLFILE_HEADER SymbolFileHeader;
1215 PIMAGE_DOS_HEADER PEDosHeader;
1216 PIMAGE_FILE_HEADER PEFileHeader;
1217 PIMAGE_OPTIONAL_HEADER PEOptHeader;
1218 PIMAGE_SECTION_HEADER PESectionHeaders;
1219 ULONG ImageBase;
1220 void *StabBase;
1221 ULONG StabsLength;
1222 void *StabStringBase;
1223 ULONG StabStringsLength;
1224 void *CoffBase = NULL;
1225 ULONG CoffsLength;
1226 void *CoffStringBase = NULL;
1227 ULONG CoffStringsLength;
1228 char* path1;
1229 char* path2;
1230 FILE* out;
1231 void *StringBase = NULL;
1232 ULONG StringsLength = 0;
1233 ULONG StabSymbolsCount = 0;
1234 PROSSYM_ENTRY StabSymbols = NULL;
1235 ULONG CoffSymbolsCount = 0;
1236 PROSSYM_ENTRY CoffSymbols = NULL;
1237 ULONG MergedSymbolsCount = 0;
1238 PROSSYM_ENTRY MergedSymbols = NULL;
1239 size_t FileSize;
1240 void *FileData;
1241 ULONG RosSymLength;
1242 void *RosSymSection;
1243 DWORD module_base;
1244 void *file;
1245 char elfhdr[4] = { '\177', 'E', 'L', 'F' };
1246 BOOLEAN UseDbgHelp = FALSE;
1247 int arg, argstate = 0;
1248 char *SourcePath = NULL;
1249
1250 for (arg = 1; arg < argc; arg++)
1251 {
1252 switch (argstate)
1253 {
1254 default:
1255 argstate = -1;
1256 break;
1257
1258 case 0:
1259 if (!strcmp(argv[arg], "-s"))
1260 {
1261 argstate = 1;
1262 }
1263 else
1264 {
1265 argstate = 2;
1266 path1 = convert_path(argv[arg]);
1267 }
1268 break;
1269
1270 case 1:
1271 free(SourcePath);
1272 SourcePath = strdup(argv[arg]);
1273 argstate = 0;
1274 break;
1275
1276 case 2:
1277 path2 = convert_path(argv[arg]);
1278 argstate = 3;
1279 break;
1280 }
1281 }
1282
1283 if (argstate != 3)
1284 {
1285 fprintf(stderr, "Usage: rsym [-s <sources>] <input> <output>\n");
1286 exit(1);
1287 }
1288
1289 FileData = load_file(path1, &FileSize);
1290 if (!FileData)
1291 {
1292 fprintf(stderr, "An error occured loading '%s'\n", path1);
1293 exit(1);
1294 }
1295
1296 file = fopen(path1, "rb");
1297
1298 /* Check if MZ header exists */
1299 PEDosHeader = (PIMAGE_DOS_HEADER) FileData;
1300 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC ||
1301 PEDosHeader->e_lfanew == 0L)
1302 {
1303 /* Ignore elf */
1304 if (!memcmp(PEDosHeader, elfhdr, sizeof(elfhdr)))
1305 exit(0);
1306 perror("Input file is not a PE image.\n");
1307 free(FileData);
1308 exit(1);
1309 }
1310
1311 /* Locate PE file header */
1312 /* sizeof(ULONG) = sizeof(MAGIC) */
1313 PEFileHeader = (PIMAGE_FILE_HEADER)((char *) FileData + PEDosHeader->e_lfanew + sizeof(ULONG));
1314
1315 /* Locate optional header */
1316 assert(sizeof(ULONG) == 4);
1317 PEOptHeader = (PIMAGE_OPTIONAL_HEADER)(PEFileHeader + 1);
1318 ImageBase = PEOptHeader->ImageBase;
1319
1320 /* Locate PE section headers */
1321 PESectionHeaders = (PIMAGE_SECTION_HEADER)((char *) PEOptHeader + PEFileHeader->SizeOfOptionalHeader);
1322
1323 if (GetStabInfo(FileData,
1324 PEFileHeader,
1325 PESectionHeaders,
1326 &StabsLength,
1327 &StabBase,
1328 &StabStringsLength,
1329 &StabStringBase))
1330 {
1331 free(FileData);
1332 exit(1);
1333 }
1334
1335 if (StabsLength == 0)
1336 {
1337 // SYMOPT_AUTO_PUBLICS
1338 // SYMOPT_FAVOR_COMPRESSED
1339 // SYMOPT_LOAD_ANYTHING
1340 // SYMOPT_LOAD_LINES
1341 SymSetOptions(0x10000 | 0x800000 | 0x40 | 0x10);
1342 SymInitialize(FileData, ".", 0);
1343
1344 module_base = SymLoadModule(FileData, file, path1, path1, 0, FileSize) & 0xffffffff;
1345
1346 if (ConvertDbgHelp(FileData,
1347 module_base,
1348 SourcePath,
1349 &StabSymbolsCount,
1350 &StabSymbols,
1351 &StringsLength,
1352 &StringBase))
1353 {
1354 free(FileData);
1355 exit(1);
1356 }
1357
1358 UseDbgHelp = TRUE;
1359 SymUnloadModule(FileData, module_base);
1360 SymCleanup(FileData);
1361 }
1362
1363 if (GetCoffInfo(FileData,
1364 PEFileHeader,
1365 PESectionHeaders,
1366 &CoffsLength,
1367 &CoffBase,
1368 &CoffStringsLength,
1369 &CoffStringBase))
1370 {
1371 free(FileData);
1372 exit(1);
1373 }
1374
1375 if (!UseDbgHelp)
1376 {
1377 StringBase = malloc(1 + StringsLength + CoffStringsLength +
1378 (CoffsLength / sizeof(ROSSYM_ENTRY)) * (E_SYMNMLEN + 1));
1379 if (StringBase == NULL)
1380 {
1381 free(FileData);
1382 fprintf(stderr, "Failed to allocate memory for strings table\n");
1383 exit(1);
1384 }
1385 /* Make offset 0 into an empty string */
1386 *((char *) StringBase) = '\0';
1387 StringsLength = 1;
1388
1389 if (ConvertStabs(&StabSymbolsCount,
1390 &StabSymbols,
1391 &StringsLength,
1392 StringBase,
1393 StabsLength,
1394 StabBase,
1395 StabStringsLength,
1396 StabStringBase,
1397 ImageBase,
1398 PEFileHeader,
1399 PESectionHeaders))
1400 {
1401 free(StringBase);
1402 free(FileData);
1403 fprintf(stderr, "Failed to allocate memory for strings table\n");
1404 exit(1);
1405 }
1406 }
1407 else
1408 {
1409 StringBase = realloc(StringBase, StringsLength + CoffStringsLength);
1410 if (!StringBase)
1411 {
1412 free(FileData);
1413 fprintf(stderr, "Failed to allocate memory for strings table\n");
1414 exit(1);
1415 }
1416 }
1417
1418 if (ConvertCoffs(&CoffSymbolsCount,
1419 &CoffSymbols,
1420 &StringsLength,
1421 StringBase,
1422 CoffsLength,
1423 CoffBase,
1424 CoffStringsLength,
1425 CoffStringBase,
1426 ImageBase,
1427 PEFileHeader,
1428 PESectionHeaders))
1429 {
1430 if (StabSymbols)
1431 {
1432 free(StabSymbols);
1433 }
1434 free(StringBase);
1435 free(FileData);
1436 exit(1);
1437 }
1438
1439 if (MergeStabsAndCoffs(&MergedSymbolsCount,
1440 &MergedSymbols,
1441 StabSymbolsCount,
1442 StabSymbols,
1443 CoffSymbolsCount,
1444 CoffSymbols))
1445 {
1446 if (CoffSymbols)
1447 {
1448 free(CoffSymbols);
1449 }
1450 if (StabSymbols)
1451 {
1452 free(StabSymbols);
1453 }
1454 free(StringBase);
1455 free(FileData);
1456 exit(1);
1457 }
1458
1459 if (CoffSymbols)
1460 {
1461 free(CoffSymbols);
1462 }
1463 if (StabSymbols)
1464 {
1465 free(StabSymbols);
1466 }
1467 if (MergedSymbolsCount == 0)
1468 {
1469 RosSymLength = 0;
1470 RosSymSection = NULL;
1471 }
1472 else
1473 {
1474 RosSymLength = sizeof(SYMBOLFILE_HEADER) +
1475 MergedSymbolsCount * sizeof(ROSSYM_ENTRY) +
1476 StringsLength;
1477
1478 RosSymSection = malloc(RosSymLength);
1479 if (RosSymSection == NULL)
1480 {
1481 free(MergedSymbols);
1482 free(StringBase);
1483 free(FileData);
1484 fprintf(stderr, "Unable to allocate memory for .rossym section\n");
1485 exit(1);
1486 }
1487 memset(RosSymSection, '\0', RosSymLength);
1488
1489 SymbolFileHeader = (PSYMBOLFILE_HEADER)RosSymSection;
1490 SymbolFileHeader->SymbolsOffset = sizeof(SYMBOLFILE_HEADER);
1491 SymbolFileHeader->SymbolsLength = MergedSymbolsCount * sizeof(ROSSYM_ENTRY);
1492 SymbolFileHeader->StringsOffset = SymbolFileHeader->SymbolsOffset +
1493 SymbolFileHeader->SymbolsLength;
1494 SymbolFileHeader->StringsLength = StringsLength;
1495
1496 memcpy((char *) RosSymSection + SymbolFileHeader->SymbolsOffset,
1497 MergedSymbols,
1498 SymbolFileHeader->SymbolsLength);
1499
1500 memcpy((char *) RosSymSection + SymbolFileHeader->StringsOffset,
1501 StringBase,
1502 SymbolFileHeader->StringsLength);
1503
1504 free(MergedSymbols);
1505 }
1506
1507 free(StringBase);
1508 out = fopen(path2, "wb");
1509 if (out == NULL)
1510 {
1511 perror("Cannot open output file");
1512 free(RosSymSection);
1513 free(FileData);
1514 exit(1);
1515 }
1516
1517 if (CreateOutputFile(out,
1518 FileData,
1519 PEDosHeader,
1520 PEFileHeader,
1521 PEOptHeader,
1522 PESectionHeaders,
1523 RosSymLength,
1524 RosSymSection))
1525 {
1526 fclose(out);
1527 if (RosSymSection)
1528 {
1529 free(RosSymSection);
1530 }
1531 free(FileData);
1532 exit(1);
1533 }
1534
1535 fclose(out);
1536 if (RosSymSection)
1537 {
1538 free(RosSymSection);
1539 }
1540 free(FileData);
1541
1542 return 0;
1543 }
1544
1545 /* EOF */