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