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