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