raddr2line utility
[reactos.git] / reactos / tools / 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 <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26
27 #include "rsym.h"
28
29 static int
30 CompareSymEntry(const PROSSYM_ENTRY SymEntry1, const PROSSYM_ENTRY SymEntry2)
31 {
32 if (SymEntry1->Address < SymEntry2->Address)
33 {
34 return -1;
35 }
36
37 if (SymEntry2->Address < SymEntry1->Address)
38 {
39 return +1;
40 }
41
42 return 0;
43 }
44
45 static int
46 GetStabInfo(void *FileData, PIMAGE_FILE_HEADER PEFileHeader,
47 PIMAGE_SECTION_HEADER PESectionHeaders,
48 ULONG *StabSymbolsLength, void **StabSymbolsBase,
49 ULONG *StabStringsLength, void **StabStringsBase)
50 {
51 ULONG Idx;
52
53 /* Load .stab and .stabstr sections if available */
54 *StabSymbolsBase = NULL;
55 *StabSymbolsLength = 0;
56 *StabStringsBase = NULL;
57 *StabStringsLength = 0;
58
59 for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
60 {
61 /* printf("section: '%.08s'\n", PESectionHeaders[Idx].Name); */
62 if ((strncmp((char*)PESectionHeaders[Idx].Name, ".stab", 5) == 0)
63 && (PESectionHeaders[Idx].Name[5] == 0))
64 {
65 /* printf(".stab section found. Size %d\n",
66 PESectionHeaders[Idx].SizeOfRawData); */
67
68 *StabSymbolsLength = PESectionHeaders[Idx].SizeOfRawData;
69 *StabSymbolsBase = (void *)((char *) FileData + PESectionHeaders[Idx].PointerToRawData);
70 }
71
72 if (strncmp((char*)PESectionHeaders[Idx].Name, ".stabstr", 8) == 0)
73 {
74 /* printf(".stabstr section found. Size %d\n",
75 PESectionHeaders[Idx].SizeOfRawData); */
76
77 *StabStringsLength = PESectionHeaders[Idx].SizeOfRawData;
78 *StabStringsBase = (void *)((char *) FileData + PESectionHeaders[Idx].PointerToRawData);
79 }
80 }
81
82 return 0;
83 }
84
85 static int
86 GetCoffInfo(void *FileData, PIMAGE_FILE_HEADER PEFileHeader,
87 PIMAGE_SECTION_HEADER PESectionHeaders,
88 ULONG *CoffSymbolsLength, void **CoffSymbolsBase,
89 ULONG *CoffStringsLength, void **CoffStringsBase)
90 {
91
92 if (0 == PEFileHeader->PointerToSymbolTable || 0 == PEFileHeader->NumberOfSymbols)
93 {
94 /* No COFF symbol table */
95 *CoffSymbolsLength = 0;
96 *CoffStringsLength = 0;
97 }
98 else
99 {
100 *CoffSymbolsLength = PEFileHeader->NumberOfSymbols * sizeof(COFF_SYMENT);
101 *CoffSymbolsBase = (void *)((char *) FileData + PEFileHeader->PointerToSymbolTable);
102 *CoffStringsLength = *((ULONG *) ((char *) *CoffSymbolsBase + *CoffSymbolsLength));
103 *CoffStringsBase = (void *)((char *) *CoffSymbolsBase + *CoffSymbolsLength);
104 }
105
106 return 0;
107 }
108
109 static ULONG
110 FindOrAddString(char *StringToFind, ULONG *StringsLength, void *StringsBase)
111 {
112 char *Search, *End;
113
114 Search = (char *) StringsBase;
115 End = Search + *StringsLength;
116
117 while (Search < End)
118 {
119 if (0 == strcmp(Search, StringToFind))
120 {
121 return Search - (char *) StringsBase;
122 }
123 Search += strlen(Search) + 1;
124 }
125
126 strcpy(Search, StringToFind);
127 *StringsLength += strlen(StringToFind) + 1;
128
129 return Search - (char *) StringsBase;
130 }
131
132 static int
133 ConvertStabs(ULONG *SymbolsCount, PROSSYM_ENTRY *SymbolsBase,
134 ULONG *StringsLength, void *StringsBase,
135 ULONG StabSymbolsLength, void *StabSymbolsBase,
136 ULONG StabStringsLength, void *StabStringsBase,
137 ULONG_PTR ImageBase, PIMAGE_FILE_HEADER PEFileHeader,
138 PIMAGE_SECTION_HEADER PESectionHeaders)
139 {
140 PSTAB_ENTRY StabEntry;
141 ULONG Count, i;
142 ULONG_PTR Address, LastFunctionAddress;
143 int First;
144 char *Name;
145 char FuncName[256];
146
147 StabEntry = StabSymbolsBase;
148 Count = StabSymbolsLength / sizeof(STAB_ENTRY);
149 *SymbolsBase = malloc(Count * sizeof(ROSSYM_ENTRY));
150 if (NULL == *SymbolsBase)
151 {
152 fprintf(stderr, "Failed to allocate memory for converted .stab symbols\n");
153 return 1;
154 }
155 *SymbolsCount = 0;
156
157 LastFunctionAddress = 0;
158 First = 1;
159 for (i = 0; i < Count; i++)
160 {
161 switch (StabEntry[i].n_type)
162 {
163 case N_SO:
164 Name = (char *) StabStringsBase + StabEntry[i].n_strx;
165 if (StabStringsLength < StabEntry[i].n_strx
166 ||'\0' == *Name || '/' == Name[strlen(Name) - 1]
167 || '\\' == Name[strlen(Name) - 1]
168 || StabEntry[i].n_value < ImageBase)
169 {
170 continue;
171 }
172 Address = StabEntry[i].n_value - ImageBase;
173 if (Address != (*SymbolsBase)[*SymbolsCount].Address && ! First)
174 {
175 (*SymbolsCount)++;
176 }
177 (*SymbolsBase)[*SymbolsCount].Address = Address;
178 (*SymbolsBase)[*SymbolsCount].FileOffset = FindOrAddString((char *) StabStringsBase
179 + StabEntry[i].n_strx,
180 StringsLength,
181 StringsBase);
182 (*SymbolsBase)[*SymbolsCount].FunctionOffset = 0;
183 (*SymbolsBase)[*SymbolsCount].SourceLine = 0;
184 LastFunctionAddress = 0;
185 break;
186 case N_FUN:
187 if (0 == StabEntry[i].n_desc || StabEntry[i].n_value < ImageBase) /* line # 0 isn't valid */
188 {
189 continue;
190 }
191 Address = StabEntry[i].n_value - ImageBase;
192 if (Address != (*SymbolsBase)[*SymbolsCount].Address && ! First)
193 {
194 (*SymbolsCount)++;
195 (*SymbolsBase)[*SymbolsCount].FileOffset = (*SymbolsBase)[*SymbolsCount - 1].FileOffset;
196 }
197 (*SymbolsBase)[*SymbolsCount].Address = Address;
198 if (sizeof(FuncName) <= strlen((char *) StabStringsBase + StabEntry[i].n_strx))
199 {
200 free(*SymbolsBase);
201 fprintf(stderr, "Function name too long\n");
202 return 1;
203 }
204 strcpy(FuncName, (char *) StabStringsBase + StabEntry[i].n_strx);
205 Name = strchr(FuncName, ':');
206 if (NULL != Name)
207 {
208 *Name = '\0';
209 }
210 (*SymbolsBase)[*SymbolsCount].FunctionOffset = FindOrAddString(FuncName,
211 StringsLength,
212 StringsBase);
213 (*SymbolsBase)[*SymbolsCount].SourceLine = 0;
214 LastFunctionAddress = Address;
215 break;
216 case N_SLINE:
217 if (0 == LastFunctionAddress)
218 {
219 Address = StabEntry[i].n_value - ImageBase;
220 }
221 else
222 {
223 Address = LastFunctionAddress + StabEntry[i].n_value;
224 }
225 if (Address != (*SymbolsBase)[*SymbolsCount].Address && ! First)
226 {
227 (*SymbolsCount)++;
228 (*SymbolsBase)[*SymbolsCount].FileOffset = (*SymbolsBase)[*SymbolsCount - 1].FileOffset;
229 (*SymbolsBase)[*SymbolsCount].FunctionOffset = (*SymbolsBase)[*SymbolsCount - 1].FunctionOffset;
230 }
231 (*SymbolsBase)[*SymbolsCount].Address = Address;
232 (*SymbolsBase)[*SymbolsCount].SourceLine = StabEntry[i].n_desc;
233 break;
234 default:
235 continue;
236 }
237 First = 0;
238 }
239 (*SymbolsCount)++;
240
241 qsort(*SymbolsBase, *SymbolsCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry);
242
243 return 0;
244 }
245
246 static int
247 ConvertCoffs(ULONG *SymbolsCount, PROSSYM_ENTRY *SymbolsBase,
248 ULONG *StringsLength, void *StringsBase,
249 ULONG CoffSymbolsLength, void *CoffSymbolsBase,
250 ULONG CoffStringsLength, void *CoffStringsBase,
251 ULONG_PTR ImageBase, PIMAGE_FILE_HEADER PEFileHeader,
252 PIMAGE_SECTION_HEADER PESectionHeaders)
253 {
254 ULONG Count, i;
255 PCOFF_SYMENT CoffEntry;
256 char FuncName[256];
257 char *p;
258
259 CoffEntry = (PCOFF_SYMENT) CoffSymbolsBase;
260 Count = CoffSymbolsLength / sizeof(COFF_SYMENT);
261 *SymbolsBase = malloc(Count * sizeof(ROSSYM_ENTRY));
262 if (NULL == *SymbolsBase)
263 {
264 fprintf(stderr, "Unable to allocate memory for converted COFF symbols\n");
265 return 1;
266 }
267 *SymbolsCount = 0;
268
269 for (i = 0; i < Count; i++)
270 {
271 if (ISFCN(CoffEntry[i].e_type) || C_EXT == CoffEntry[i].e_sclass)
272 {
273 (*SymbolsBase)[*SymbolsCount].Address = CoffEntry[i].e_value;
274 if (0 < CoffEntry[i].e_scnum)
275 {
276 if (PEFileHeader->NumberOfSections < CoffEntry[i].e_scnum)
277 {
278 free(*SymbolsBase);
279 fprintf(stderr, "Invalid section number %d in COFF symbols (only %d sections present)\n",
280 CoffEntry[i].e_scnum, PEFileHeader->NumberOfSections);
281 return 1;
282 }
283 (*SymbolsBase)[*SymbolsCount].Address += PESectionHeaders[CoffEntry[i].e_scnum - 1].VirtualAddress;
284 }
285 (*SymbolsBase)[*SymbolsCount].FileOffset = 0;
286 if (0 == CoffEntry[i].e.e.e_zeroes)
287 {
288 if (sizeof(FuncName) <= strlen((char *) CoffStringsBase + CoffEntry[i].e.e.e_offset))
289 {
290 free(*SymbolsBase);
291 fprintf(stderr, "Function name too long\n");
292 return 1;
293 }
294 strcpy(FuncName, (char *) CoffStringsBase + CoffEntry[i].e.e.e_offset);
295 }
296 else
297 {
298 memcpy(FuncName, CoffEntry[i].e.e_name, E_SYMNMLEN);
299 FuncName[E_SYMNMLEN] = '\0';
300 }
301
302 /* Name demangling: stdcall */
303 p = strrchr(FuncName, '@');
304 if (NULL != p)
305 {
306 *p = '\0';
307 }
308 p = ('_' == FuncName[0] || '@' == FuncName[0] ? FuncName + 1 : FuncName);
309 (*SymbolsBase)[*SymbolsCount].FunctionOffset = FindOrAddString(p,
310 StringsLength,
311 StringsBase);
312 (*SymbolsBase)[*SymbolsCount].SourceLine = 0;
313 (*SymbolsCount)++;
314 }
315 i += CoffEntry[i].e_numaux;
316 }
317
318 qsort(*SymbolsBase, *SymbolsCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry);
319
320 return 0;
321 }
322
323 static int
324 MergeStabsAndCoffs(ULONG *MergedSymbolCount, PROSSYM_ENTRY *MergedSymbols,
325 ULONG StabSymbolsCount, PROSSYM_ENTRY StabSymbols,
326 ULONG CoffSymbolsCount, PROSSYM_ENTRY CoffSymbols)
327 {
328 ULONG StabIndex, j;
329 ULONG CoffIndex;
330 ULONG_PTR StabFunctionStartAddress;
331 ULONG StabFunctionStringOffset, NewStabFunctionStringOffset;
332
333 *MergedSymbols = malloc(StabSymbolsCount * sizeof(ROSSYM_ENTRY));
334 if (NULL == *MergedSymbols)
335 {
336 fprintf(stderr, "Unable to allocate memory for merged symbols\n");
337 return 1;
338 }
339 *MergedSymbolCount = 0;
340
341 StabFunctionStartAddress = 0;
342 StabFunctionStringOffset = 0;
343 CoffIndex = 0;
344 for (StabIndex = 0; StabIndex < StabSymbolsCount; StabIndex++)
345 {
346 (*MergedSymbols)[*MergedSymbolCount] = StabSymbols[StabIndex];
347 for (j = StabIndex + 1;
348 j < StabSymbolsCount && StabSymbols[j].Address == StabSymbols[StabIndex].Address;
349 j++)
350 {
351 if (0 != StabSymbols[j].FileOffset && 0 == (*MergedSymbols)[*MergedSymbolCount].FileOffset)
352 {
353 (*MergedSymbols)[*MergedSymbolCount].FileOffset = StabSymbols[j].FileOffset;
354 }
355 if (0 != StabSymbols[j].FunctionOffset && 0 == (*MergedSymbols)[*MergedSymbolCount].FunctionOffset)
356 {
357 (*MergedSymbols)[*MergedSymbolCount].FunctionOffset = StabSymbols[j].FunctionOffset;
358 }
359 if (0 != StabSymbols[j].SourceLine && 0 == (*MergedSymbols)[*MergedSymbolCount].SourceLine)
360 {
361 (*MergedSymbols)[*MergedSymbolCount].SourceLine = StabSymbols[j].SourceLine;
362 }
363 }
364 StabIndex = j - 1;
365 while (CoffIndex < CoffSymbolsCount
366 && CoffSymbols[CoffIndex + 1].Address <= (*MergedSymbols)[*MergedSymbolCount].Address)
367 {
368 CoffIndex++;
369 }
370 NewStabFunctionStringOffset = (*MergedSymbols)[*MergedSymbolCount].FunctionOffset;
371 if (CoffSymbols[CoffIndex].Address < (*MergedSymbols)[*MergedSymbolCount].Address
372 && StabFunctionStartAddress < CoffSymbols[CoffIndex].Address
373 && 0 != CoffSymbols[CoffIndex].FunctionOffset)
374 {
375 (*MergedSymbols)[*MergedSymbolCount].FunctionOffset = CoffSymbols[CoffIndex].FunctionOffset;
376 }
377 if (StabFunctionStringOffset != NewStabFunctionStringOffset)
378 {
379 StabFunctionStartAddress = (*MergedSymbols)[*MergedSymbolCount].Address;
380 }
381 StabFunctionStringOffset = NewStabFunctionStringOffset;
382 (*MergedSymbolCount)++;
383 }
384
385 return 0;
386 }
387
388 static PIMAGE_SECTION_HEADER
389 FindSectionForRVA(DWORD RVA, unsigned NumberOfSections, PIMAGE_SECTION_HEADER SectionHeaders)
390 {
391 unsigned Section;
392
393 for (Section = 0; Section < NumberOfSections; Section++)
394 {
395 if (SectionHeaders[Section].VirtualAddress <= RVA &&
396 RVA < SectionHeaders[Section].VirtualAddress + SectionHeaders[Section].Misc.VirtualSize)
397 {
398 return SectionHeaders + Section;
399 }
400 }
401
402 return NULL;
403 }
404
405 static int
406 IncludeRelocationsForSection(PIMAGE_SECTION_HEADER SectionHeader)
407 {
408 static char *BlacklistedSections[] =
409 {
410 ".idata",
411 ".reloc"
412 };
413 char SectionName[IMAGE_SIZEOF_SHORT_NAME];
414 unsigned i;
415
416 if (0 != (SectionHeader->Characteristics & IMAGE_SCN_LNK_REMOVE))
417 {
418 return 0;
419 }
420
421 for (i = 0; i < sizeof(BlacklistedSections) / sizeof(BlacklistedSections[0]); i++)
422 {
423 strncpy(SectionName, BlacklistedSections[i], IMAGE_SIZEOF_SHORT_NAME);
424 if (0 == memcmp(SectionName, SectionHeader->Name, IMAGE_SIZEOF_SHORT_NAME))
425 {
426 return 0;
427 }
428 }
429
430 return 1;
431 }
432
433 static int
434 ProcessRelocations(ULONG *ProcessedRelocsLength, void **ProcessedRelocs,
435 void *RawData, PIMAGE_OPTIONAL_HEADER OptHeader,
436 unsigned NumberOfSections, PIMAGE_SECTION_HEADER SectionHeaders)
437 {
438 PIMAGE_SECTION_HEADER RelocSectionHeader, TargetSectionHeader;
439 PIMAGE_BASE_RELOCATION BaseReloc, End, AcceptedRelocs;
440 int Found;
441
442 if (OptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC
443 || 0 == OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
444 {
445 /* No relocation entries */
446 *ProcessedRelocsLength = 0;
447 *ProcessedRelocs = NULL;
448 return 0;
449 }
450
451 RelocSectionHeader = FindSectionForRVA(OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
452 NumberOfSections, SectionHeaders);
453 if (NULL == RelocSectionHeader)
454 {
455 fprintf(stderr, "Can't find section header for relocation data\n");
456 return 1;
457 }
458
459 *ProcessedRelocs = malloc(RelocSectionHeader->SizeOfRawData);
460 if (NULL == *ProcessedRelocs)
461 {
462 fprintf(stderr, "Failed to allocate %lu bytes for relocations\n", RelocSectionHeader->SizeOfRawData);
463 return 1;
464 }
465 *ProcessedRelocsLength = 0;
466
467 BaseReloc = (PIMAGE_BASE_RELOCATION) ((char *) RawData
468 + RelocSectionHeader->PointerToRawData
469 + (OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress -
470 RelocSectionHeader->VirtualAddress));
471 End = (PIMAGE_BASE_RELOCATION) ((char *) BaseReloc
472 + OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
473
474 while (BaseReloc < End && 0 < BaseReloc->SizeOfBlock)
475 {
476 TargetSectionHeader = FindSectionForRVA(BaseReloc->VirtualAddress, NumberOfSections,
477 SectionHeaders);
478 if (NULL != TargetSectionHeader && IncludeRelocationsForSection(TargetSectionHeader))
479 {
480 AcceptedRelocs = *ProcessedRelocs;
481 Found = 0;
482 while (AcceptedRelocs < (PIMAGE_BASE_RELOCATION) ((char *) *ProcessedRelocs +
483 *ProcessedRelocsLength)
484 && ! Found)
485 {
486 Found = BaseReloc->SizeOfBlock == AcceptedRelocs->SizeOfBlock
487 && 0 == memcmp(BaseReloc, AcceptedRelocs, AcceptedRelocs->SizeOfBlock);
488 AcceptedRelocs= (PIMAGE_BASE_RELOCATION) ((char *) AcceptedRelocs +
489 AcceptedRelocs->SizeOfBlock);
490 }
491 if (! Found)
492 {
493 memcpy((char *) *ProcessedRelocs + *ProcessedRelocsLength,
494 BaseReloc, BaseReloc->SizeOfBlock);
495 *ProcessedRelocsLength += BaseReloc->SizeOfBlock;
496 }
497 }
498 BaseReloc = (PIMAGE_BASE_RELOCATION)((char *) BaseReloc + BaseReloc->SizeOfBlock);
499 }
500
501 return 0;
502 }
503
504 static int
505 CreateOutputFile(FILE *OutFile, void *InData,
506 PIMAGE_DOS_HEADER InDosHeader, PIMAGE_FILE_HEADER InFileHeader,
507 PIMAGE_OPTIONAL_HEADER InOptHeader, PIMAGE_SECTION_HEADER InSectionHeaders,
508 ULONG RosSymLength, void *RosSymSection)
509 {
510 ULONG StartOfRawData;
511 unsigned Section;
512 void *OutHeader, *ProcessedRelocs, *PaddedRosSym, *Data;
513 PIMAGE_DOS_HEADER OutDosHeader;
514 PIMAGE_FILE_HEADER OutFileHeader;
515 PIMAGE_OPTIONAL_HEADER OutOptHeader;
516 PIMAGE_SECTION_HEADER OutSectionHeaders, CurrentSectionHeader;
517 DWORD CheckSum;
518 ULONG Length, i;
519 ULONG ProcessedRelocsLength;
520 ULONG RosSymOffset, RosSymFileLength;
521 int InRelocSectionIndex;
522 PIMAGE_SECTION_HEADER OutRelocSection;
523
524 StartOfRawData = 0;
525 for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
526 {
527 if ((0 == StartOfRawData
528 || InSectionHeaders[Section].PointerToRawData < StartOfRawData)
529 && 0 != InSectionHeaders[Section].PointerToRawData
530 && 0 == (InSectionHeaders[Section].Characteristics & IMAGE_SCN_LNK_REMOVE))
531 {
532 StartOfRawData = InSectionHeaders[Section].PointerToRawData;
533 }
534 }
535 OutHeader = malloc(StartOfRawData);
536 if (NULL == OutHeader)
537 {
538 fprintf(stderr, "Failed to allocate %lu bytes for output file header\n", StartOfRawData);
539 return 1;
540 }
541 memset(OutHeader, '\0', StartOfRawData);
542
543 OutDosHeader = (PIMAGE_DOS_HEADER) OutHeader;
544 memcpy(OutDosHeader, InDosHeader, InDosHeader->e_lfanew + sizeof(ULONG));
545
546 OutFileHeader = (PIMAGE_FILE_HEADER)((char *) OutHeader + OutDosHeader->e_lfanew + sizeof(ULONG));
547 memcpy(OutFileHeader, InFileHeader, sizeof(IMAGE_FILE_HEADER));
548 OutFileHeader->PointerToSymbolTable = 0;
549 OutFileHeader->NumberOfSymbols = 0;
550 OutFileHeader->Characteristics &= ~(IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_LOCAL_SYMS_STRIPPED |
551 IMAGE_FILE_DEBUG_STRIPPED);
552
553 OutOptHeader = (PIMAGE_OPTIONAL_HEADER)(OutFileHeader + 1);
554 memcpy(OutOptHeader, InOptHeader, sizeof(IMAGE_OPTIONAL_HEADER));
555 OutOptHeader->CheckSum = 0;
556
557 OutSectionHeaders = (PIMAGE_SECTION_HEADER)((char *) OutOptHeader + OutFileHeader->SizeOfOptionalHeader);
558
559 if (ProcessRelocations(&ProcessedRelocsLength, &ProcessedRelocs, InData, InOptHeader,
560 InFileHeader->NumberOfSections, InSectionHeaders))
561 {
562 return 1;
563 }
564 if (InOptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC
565 || 0 == InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
566 {
567 InRelocSectionIndex = -1;
568 }
569 else
570 {
571 InRelocSectionIndex = FindSectionForRVA(InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
572 InFileHeader->NumberOfSections, InSectionHeaders) - InSectionHeaders;
573 }
574
575 OutFileHeader->NumberOfSections = 0;
576 CurrentSectionHeader = OutSectionHeaders;
577 OutOptHeader->SizeOfImage = 0;
578 RosSymOffset = 0;
579 OutRelocSection = NULL;
580 for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
581 {
582 if (0 == (InSectionHeaders[Section].Characteristics & IMAGE_SCN_LNK_REMOVE))
583 {
584 *CurrentSectionHeader = InSectionHeaders[Section];
585 CurrentSectionHeader->PointerToLinenumbers = 0;
586 CurrentSectionHeader->NumberOfLinenumbers = 0;
587 if (OutOptHeader->SizeOfImage < CurrentSectionHeader->VirtualAddress +
588 CurrentSectionHeader->Misc.VirtualSize)
589 {
590 OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress +
591 CurrentSectionHeader->Misc.VirtualSize,
592 OutOptHeader->SectionAlignment);
593 }
594 if (RosSymOffset < CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData)
595 {
596 RosSymOffset = CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData;
597 }
598 if (Section == InRelocSectionIndex)
599 {
600 OutRelocSection = CurrentSectionHeader;
601 }
602 (OutFileHeader->NumberOfSections) ++;
603 CurrentSectionHeader++;
604 }
605 }
606
607 if (OutRelocSection == CurrentSectionHeader - 1)
608 {
609 OutOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = ProcessedRelocsLength;
610 if (OutOptHeader->SizeOfImage == OutRelocSection->VirtualAddress +
611 ROUND_UP(OutRelocSection->Misc.VirtualSize,
612 OutOptHeader->SectionAlignment))
613 {
614 OutOptHeader->SizeOfImage = OutRelocSection->VirtualAddress +
615 ROUND_UP(ProcessedRelocsLength,
616 OutOptHeader->SectionAlignment);
617 }
618 OutRelocSection->Misc.VirtualSize = ProcessedRelocsLength;
619 if (RosSymOffset == OutRelocSection->PointerToRawData
620 + OutRelocSection->SizeOfRawData)
621 {
622 RosSymOffset = OutRelocSection->PointerToRawData +
623 ROUND_UP(ProcessedRelocsLength, OutOptHeader->FileAlignment);
624 }
625 OutRelocSection->SizeOfRawData = ROUND_UP(ProcessedRelocsLength,
626 OutOptHeader->FileAlignment);
627 }
628
629 RosSymFileLength = ROUND_UP(RosSymLength, OutOptHeader->FileAlignment);
630 memcpy(CurrentSectionHeader->Name, ".rossym", 8); /* We're lucky: string is exactly 8 bytes long */
631 CurrentSectionHeader->Misc.VirtualSize = RosSymLength;
632 CurrentSectionHeader->VirtualAddress = OutOptHeader->SizeOfImage;
633 CurrentSectionHeader->SizeOfRawData = RosSymFileLength;
634 CurrentSectionHeader->PointerToRawData = RosSymOffset;
635 CurrentSectionHeader->PointerToRelocations = 0;
636 CurrentSectionHeader->PointerToLinenumbers = 0;
637 CurrentSectionHeader->NumberOfRelocations = 0;
638 CurrentSectionHeader->NumberOfLinenumbers = 0;
639 CurrentSectionHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
640 | IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_TYPE_NOLOAD;
641 OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress +
642 CurrentSectionHeader->Misc.VirtualSize,
643 OutOptHeader->SectionAlignment);
644 (OutFileHeader->NumberOfSections)++;
645
646 PaddedRosSym = malloc(RosSymFileLength);
647 if (NULL == PaddedRosSym)
648 {
649 fprintf(stderr, "Failed to allocate %lu bytes for padded .rossym\n", RosSymFileLength);
650 return 1;
651 }
652 memcpy(PaddedRosSym, RosSymSection, RosSymLength);
653 memset((char *) PaddedRosSym + RosSymLength, '\0', RosSymFileLength - RosSymLength);
654
655 CheckSum = 0;
656 for (i = 0; i < StartOfRawData / 2; i++)
657 {
658 CheckSum += ((unsigned short*) OutHeader)[i];
659 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
660 }
661 Length = StartOfRawData;
662 for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++)
663 {
664 if (OutRelocSection == OutSectionHeaders + Section)
665 {
666 Data = (void *) ProcessedRelocs;
667 }
668 else if (Section + 1 == OutFileHeader->NumberOfSections)
669 {
670 Data = (void *) PaddedRosSym;
671 }
672 else
673 {
674 Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
675 }
676 for (i = 0; i < OutSectionHeaders[Section].SizeOfRawData / 2; i++)
677 {
678 CheckSum += ((unsigned short*) Data)[i];
679 CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
680 }
681 Length += OutSectionHeaders[Section].SizeOfRawData;
682 }
683 CheckSum += Length;
684 OutOptHeader->CheckSum = CheckSum;
685
686 if (fwrite(OutHeader, 1, StartOfRawData, OutFile) != StartOfRawData)
687 {
688 perror("Error writing output header\n");
689 free(OutHeader);
690 return 1;
691 }
692
693 for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++)
694 {
695 if (0 != OutSectionHeaders[Section].SizeOfRawData)
696 {
697 fseek(OutFile, OutSectionHeaders[Section].PointerToRawData, SEEK_SET);
698 if (OutRelocSection == OutSectionHeaders + Section)
699 {
700 Data = (void *) ProcessedRelocs;
701 }
702 else if (Section + 1 == OutFileHeader->NumberOfSections)
703 {
704 Data = (void *) PaddedRosSym;
705 }
706 else
707 {
708 Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
709 }
710 if (fwrite(Data, 1, OutSectionHeaders[Section].SizeOfRawData, OutFile) !=
711 OutSectionHeaders[Section].SizeOfRawData)
712 {
713 perror("Error writing section data\n");
714 free(PaddedRosSym);
715 free(OutHeader);
716 return 1;
717 }
718 }
719 }
720
721 free(PaddedRosSym);
722 free(OutHeader);
723
724 return 0;
725 }
726
727 int main(int argc, char* argv[])
728 {
729 PSYMBOLFILE_HEADER SymbolFileHeader;
730 PIMAGE_DOS_HEADER PEDosHeader;
731 PIMAGE_FILE_HEADER PEFileHeader;
732 PIMAGE_OPTIONAL_HEADER PEOptHeader;
733 PIMAGE_SECTION_HEADER PESectionHeaders;
734 ULONG ImageBase;
735 void *StabBase;
736 ULONG StabsLength;
737 void *StabStringBase;
738 ULONG StabStringsLength;
739 void *CoffBase;
740 ULONG CoffsLength;
741 void *CoffStringBase;
742 ULONG CoffStringsLength;
743 char* path1;
744 char* path2;
745 FILE* out;
746 void *StringBase;
747 ULONG StringsLength;
748 ULONG StabSymbolsCount;
749 PROSSYM_ENTRY StabSymbols;
750 ULONG CoffSymbolsCount;
751 PROSSYM_ENTRY CoffSymbols;
752 ULONG MergedSymbolsCount;
753 PROSSYM_ENTRY MergedSymbols;
754 size_t FileSize;
755 void *FileData;
756 ULONG RosSymLength;
757 void *RosSymSection;
758
759 if (3 != argc)
760 {
761 fprintf(stderr, "Usage: rsym <exefile> <symfile>\n");
762 exit(1);
763 }
764
765 path1 = convert_path(argv[1]);
766 path2 = convert_path(argv[2]);
767
768 FileData = load_file ( path1, &FileSize );
769 if ( !FileData )
770 {
771 fprintf ( stderr, "An error occured loading '%s'\n", path1 );
772 exit(1);
773 }
774
775 /* Check if MZ header exists */
776 PEDosHeader = (PIMAGE_DOS_HEADER) FileData;
777 if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC || PEDosHeader->e_lfanew == 0L)
778 {
779 perror("Input file is not a PE image.\n");
780 free(FileData);
781 exit(1);
782 }
783
784 /* Locate PE file header */
785 /* sizeof(ULONG) = sizeof(MAGIC) */
786 PEFileHeader = (PIMAGE_FILE_HEADER)((char *) FileData + PEDosHeader->e_lfanew + sizeof(ULONG));
787
788 /* Locate optional header */
789 PEOptHeader = (PIMAGE_OPTIONAL_HEADER)(PEFileHeader + 1);
790 ImageBase = PEOptHeader->ImageBase;
791
792 /* Locate PE section headers */
793 PESectionHeaders = (PIMAGE_SECTION_HEADER)((char *) PEOptHeader + PEFileHeader->SizeOfOptionalHeader);
794
795 if (GetStabInfo(FileData, PEFileHeader, PESectionHeaders, &StabsLength, &StabBase,
796 &StabStringsLength, &StabStringBase))
797 {
798 free(FileData);
799 exit(1);
800 }
801
802 if (GetCoffInfo(FileData, PEFileHeader, PESectionHeaders, &CoffsLength, &CoffBase,
803 &CoffStringsLength, &CoffStringBase))
804 {
805 free(FileData);
806 exit(1);
807 }
808
809 StringBase = malloc(1 + StabStringsLength + CoffStringsLength +
810 (CoffsLength / sizeof(ROSSYM_ENTRY)) * (E_SYMNMLEN + 1));
811 if (NULL == StringBase)
812 {
813 free(FileData);
814 fprintf(stderr, "Failed to allocate memory for strings table\n");
815 exit(1);
816 }
817 /* Make offset 0 into an empty string */
818 *((char *) StringBase) = '\0';
819 StringsLength = 1;
820
821 if (ConvertStabs(&StabSymbolsCount, &StabSymbols, &StringsLength, StringBase,
822 StabsLength, StabBase, StabStringsLength, StabStringBase,
823 ImageBase, PEFileHeader, PESectionHeaders))
824 {
825 free(StringBase);
826 free(FileData);
827 fprintf(stderr, "Failed to allocate memory for strings table\n");
828 exit(1);
829 }
830
831 if (ConvertCoffs(&CoffSymbolsCount, &CoffSymbols, &StringsLength, StringBase,
832 CoffsLength, CoffBase, CoffStringsLength, CoffStringBase,
833 ImageBase, PEFileHeader, PESectionHeaders))
834 {
835 free(StabSymbols);
836 free(StringBase);
837 free(FileData);
838 exit(1);
839 }
840
841 if (MergeStabsAndCoffs(&MergedSymbolsCount, &MergedSymbols,
842 StabSymbolsCount, StabSymbols,
843 CoffSymbolsCount, CoffSymbols))
844 {
845 free(CoffSymbols);
846 free(StabSymbols);
847 free(StringBase);
848 free(FileData);
849 exit(1);
850 }
851
852 free(CoffSymbols);
853 free(StabSymbols);
854
855 RosSymLength = sizeof(SYMBOLFILE_HEADER) + MergedSymbolsCount * sizeof(ROSSYM_ENTRY)
856 + StringsLength;
857 RosSymSection = malloc(RosSymLength);
858 if (NULL == RosSymSection)
859 {
860 free(MergedSymbols);
861 free(StringBase);
862 free(FileData);
863 fprintf(stderr, "Unable to allocate memory for .rossym section\n");
864 exit(1);
865 }
866 memset(RosSymSection, '\0', RosSymLength);
867
868 SymbolFileHeader = (PSYMBOLFILE_HEADER) RosSymSection;
869 SymbolFileHeader->SymbolsOffset = sizeof(SYMBOLFILE_HEADER);
870 SymbolFileHeader->SymbolsLength = MergedSymbolsCount * sizeof(ROSSYM_ENTRY);
871 SymbolFileHeader->StringsOffset = SymbolFileHeader->SymbolsOffset + SymbolFileHeader->SymbolsLength;
872 SymbolFileHeader->StringsLength = StringsLength;
873
874 memcpy((char *) RosSymSection + SymbolFileHeader->SymbolsOffset, MergedSymbols,
875 SymbolFileHeader->SymbolsLength);
876 memcpy((char *) RosSymSection + SymbolFileHeader->StringsOffset, StringBase,
877 SymbolFileHeader->StringsLength);
878
879 free(MergedSymbols);
880 free(StringBase);
881
882 out = fopen(path2, "wb");
883 if (out == NULL)
884 {
885 perror("Cannot open output file");
886 free(RosSymSection);
887 free(FileData);
888 exit(1);
889 }
890
891 if (CreateOutputFile(out, FileData, PEDosHeader, PEFileHeader, PEOptHeader,
892 PESectionHeaders, RosSymLength, RosSymSection))
893 {
894 fclose(out);
895 free(RosSymSection);
896 free(FileData);
897 exit(1);
898 }
899
900 fclose(out);
901 free(RosSymSection);
902 free(FileData);
903
904 return 0;
905 }
906
907 /* EOF */