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