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