2 * Usage: rsym input-file output-file
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
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.
23 #include "../../dll/win32/dbghelp/compat.h"
34 #define MAX_SYM_NAME 2000
38 struct StringEntry
*Next
;
43 struct StringHashTable
46 struct StringEntry
**Table
;
49 /* This is the famous DJB hash */
51 ComputeDJBHash(const char *name
)
53 unsigned int val
= 5381;
56 for (i
= 0; name
[i
]; i
++)
58 val
= (33 * val
) + name
[i
];
65 AddStringToHash(struct StringHashTable
*StringTable
,
70 struct StringEntry
*entry
= calloc(1, sizeof(struct StringEntry
));
71 entry
->Offset
= Offset
;
72 entry
->String
= StringPtr
;
73 entry
->Next
= StringTable
->Table
[hash
];
74 StringTable
->Table
[hash
] = entry
;
78 StringHashTableInit(struct StringHashTable
*StringTable
,
82 char *Start
= StringsBase
;
83 char *End
= StringsBase
+ StringsLength
;
84 StringTable
->TableSize
= 1024;
85 StringTable
->Table
= calloc(1024, sizeof(struct StringEntry
*));
88 AddStringToHash(StringTable
,
89 ComputeDJBHash(Start
) % StringTable
->TableSize
,
92 Start
+= strlen(Start
) + 1;
97 StringHashTableFree(struct StringHashTable
*StringTable
)
100 struct StringEntry
*entry
;
101 for (i
= 0; i
< StringTable
->TableSize
; i
++)
103 while ((entry
= StringTable
->Table
[i
]))
106 free(StringTable
->Table
[i
]);
107 StringTable
->Table
[i
] = entry
;
110 free(StringTable
->Table
);
114 CompareSymEntry(const PROSSYM_ENTRY SymEntry1
, const PROSSYM_ENTRY SymEntry2
)
116 if (SymEntry1
->Address
< SymEntry2
->Address
)
121 if (SymEntry2
->Address
< SymEntry1
->Address
)
130 GetStabInfo(void *FileData
, PIMAGE_FILE_HEADER PEFileHeader
,
131 PIMAGE_SECTION_HEADER PESectionHeaders
,
132 ULONG
*StabSymbolsLength
, void **StabSymbolsBase
,
133 ULONG
*StabStringsLength
, void **StabStringsBase
)
137 /* Load .stab and .stabstr sections if available */
138 *StabSymbolsBase
= NULL
;
139 *StabSymbolsLength
= 0;
140 *StabStringsBase
= NULL
;
141 *StabStringsLength
= 0;
143 for (Idx
= 0; Idx
< PEFileHeader
->NumberOfSections
; Idx
++)
145 /* printf("section: '%.08s'\n", PESectionHeaders[Idx].Name); */
146 if ((strncmp((char *) PESectionHeaders
[Idx
].Name
, ".stab", 5) == 0)
147 && (PESectionHeaders
[Idx
].Name
[5] == 0))
149 /* printf(".stab section found. Size %d\n", PESectionHeaders[Idx].SizeOfRawData); */
151 *StabSymbolsLength
= PESectionHeaders
[Idx
].SizeOfRawData
;
152 *StabSymbolsBase
= (void *)((char *) FileData
+ PESectionHeaders
[Idx
].PointerToRawData
);
155 if (strncmp((char *) PESectionHeaders
[Idx
].Name
, ".stabstr", 8) == 0)
157 /* printf(".stabstr section found. Size %d\n", PESectionHeaders[Idx].SizeOfRawData); */
159 *StabStringsLength
= PESectionHeaders
[Idx
].SizeOfRawData
;
160 *StabStringsBase
= (void *)((char *) FileData
+ PESectionHeaders
[Idx
].PointerToRawData
);
168 GetCoffInfo(void *FileData
, PIMAGE_FILE_HEADER PEFileHeader
,
169 PIMAGE_SECTION_HEADER PESectionHeaders
,
170 ULONG
*CoffSymbolsLength
, void **CoffSymbolsBase
,
171 ULONG
*CoffStringsLength
, void **CoffStringsBase
)
174 if (PEFileHeader
->PointerToSymbolTable
== 0 || PEFileHeader
->NumberOfSymbols
== 0)
176 /* No COFF symbol table */
177 *CoffSymbolsLength
= 0;
178 *CoffStringsLength
= 0;
182 *CoffSymbolsLength
= PEFileHeader
->NumberOfSymbols
* sizeof(COFF_SYMENT
);
183 *CoffSymbolsBase
= (void *)((char *) FileData
+ PEFileHeader
->PointerToSymbolTable
);
184 *CoffStringsLength
= *((ULONG
*) ((char *) *CoffSymbolsBase
+ *CoffSymbolsLength
));
185 *CoffStringsBase
= (void *)((char *) *CoffSymbolsBase
+ *CoffSymbolsLength
);
192 FindOrAddString(struct StringHashTable
*StringTable
,
194 ULONG
*StringsLength
,
197 unsigned int hash
= ComputeDJBHash(StringToFind
) % StringTable
->TableSize
;
198 struct StringEntry
*entry
= StringTable
->Table
[hash
];
200 while (entry
&& strcmp(entry
->String
, StringToFind
))
205 return entry
->Offset
;
209 char *End
= (char *)StringsBase
+ *StringsLength
;
211 strcpy(End
, StringToFind
);
212 *StringsLength
+= strlen(StringToFind
) + 1;
214 AddStringToHash(StringTable
, hash
, End
- (char *)StringsBase
, End
);
216 return End
- (char *)StringsBase
;
221 ConvertStabs(ULONG
*SymbolsCount
, PROSSYM_ENTRY
*SymbolsBase
,
222 ULONG
*StringsLength
, void *StringsBase
,
223 ULONG StabSymbolsLength
, void *StabSymbolsBase
,
224 ULONG StabStringsLength
, void *StabStringsBase
,
225 ULONG_PTR ImageBase
, PIMAGE_FILE_HEADER PEFileHeader
,
226 PIMAGE_SECTION_HEADER PESectionHeaders
)
228 PSTAB_ENTRY StabEntry
;
230 ULONG_PTR Address
, LastFunctionAddress
;
235 PROSSYM_ENTRY Current
;
236 struct StringHashTable StringHash
;
238 StabEntry
= StabSymbolsBase
;
239 Count
= StabSymbolsLength
/ sizeof(STAB_ENTRY
);
249 *SymbolsBase
= malloc(Count
* sizeof(ROSSYM_ENTRY
));
250 if (*SymbolsBase
== NULL
)
252 fprintf(stderr
, "Failed to allocate memory for converted .stab symbols\n");
255 Current
= *SymbolsBase
;
256 memset(Current
, 0, sizeof(*Current
));
258 StringHashTableInit(&StringHash
, *StringsLength
, (char *)StringsBase
);
260 LastFunctionAddress
= 0;
261 for (i
= 0; i
< Count
; i
++)
263 if (LastFunctionAddress
== 0)
265 Address
= StabEntry
[i
].n_value
- ImageBase
;
269 Address
= LastFunctionAddress
+ StabEntry
[i
].n_value
;
271 switch (StabEntry
[i
].n_type
)
276 Name
= (char *) StabStringsBase
+ StabEntry
[i
].n_strx
;
277 if (StabStringsLength
< StabEntry
[i
].n_strx
278 || *Name
== '\0' || Name
[strlen(Name
) - 1] == '/'
279 || Name
[strlen(Name
) - 1] == '\\'
280 || StabEntry
[i
].n_value
< ImageBase
)
284 if (First
|| Address
!= Current
->Address
)
288 memset(++Current
, 0, sizeof(*Current
));
289 Current
->FunctionOffset
= Current
[-1].FunctionOffset
;
293 Current
->Address
= Address
;
295 Current
->FileOffset
= FindOrAddString(&StringHash
,
296 (char *)StabStringsBase
+ StabEntry
[i
].n_strx
,
301 if (StabEntry
[i
].n_desc
== 0 || StabEntry
[i
].n_value
< ImageBase
)
303 LastFunctionAddress
= 0; /* line # 0 = end of function */
306 if (First
|| Address
!= Current
->Address
)
309 memset(++Current
, 0, sizeof(*Current
));
312 Current
->Address
= Address
;
313 Current
->FileOffset
= Current
[-1].FileOffset
;
315 Name
= (char *)StabStringsBase
+ StabEntry
[i
].n_strx
;
316 NameLen
= strcspn(Name
, ":");
317 if (sizeof(FuncName
) <= NameLen
)
320 fprintf(stderr
, "Function name too long\n");
323 memcpy(FuncName
, Name
, NameLen
);
324 FuncName
[NameLen
] = '\0';
325 Current
->FunctionOffset
= FindOrAddString(&StringHash
,
329 Current
->SourceLine
= 0;
330 LastFunctionAddress
= Address
;
333 if (First
|| Address
!= Current
->Address
)
337 memset(++Current
, 0, sizeof(*Current
));
338 Current
->FileOffset
= Current
[-1].FileOffset
;
339 Current
->FunctionOffset
= Current
[-1].FunctionOffset
;
343 Current
->Address
= Address
;
345 Current
->SourceLine
= StabEntry
[i
].n_desc
;
351 *SymbolsCount
= (Current
- *SymbolsBase
+ 1);
353 qsort(*SymbolsBase
, *SymbolsCount
, sizeof(ROSSYM_ENTRY
), (int (*)(const void *, const void *)) CompareSymEntry
);
355 StringHashTableFree(&StringHash
);
361 ConvertCoffs(ULONG
*SymbolsCount
, PROSSYM_ENTRY
*SymbolsBase
,
362 ULONG
*StringsLength
, void *StringsBase
,
363 ULONG CoffSymbolsLength
, void *CoffSymbolsBase
,
364 ULONG CoffStringsLength
, void *CoffStringsBase
,
365 ULONG_PTR ImageBase
, PIMAGE_FILE_HEADER PEFileHeader
,
366 PIMAGE_SECTION_HEADER PESectionHeaders
)
369 PCOFF_SYMENT CoffEntry
;
370 char FuncName
[256], FileName
[1024];
372 PROSSYM_ENTRY Current
;
373 struct StringHashTable StringHash
;
375 CoffEntry
= (PCOFF_SYMENT
) CoffSymbolsBase
;
376 Count
= CoffSymbolsLength
/ sizeof(COFF_SYMENT
);
378 *SymbolsBase
= malloc(Count
* sizeof(ROSSYM_ENTRY
));
379 if (*SymbolsBase
== NULL
)
381 fprintf(stderr
, "Unable to allocate memory for converted COFF symbols\n");
385 Current
= *SymbolsBase
;
387 StringHashTableInit(&StringHash
, *StringsLength
, (char*)StringsBase
);
389 for (i
= 0; i
< Count
; i
++)
391 if (ISFCN(CoffEntry
[i
].e_type
) || C_EXT
== CoffEntry
[i
].e_sclass
)
393 Current
->Address
= CoffEntry
[i
].e_value
;
394 if (CoffEntry
[i
].e_scnum
> 0)
396 if (PEFileHeader
->NumberOfSections
< CoffEntry
[i
].e_scnum
)
400 "Invalid section number %d in COFF symbols (only %d sections present)\n",
401 CoffEntry
[i
].e_scnum
,
402 PEFileHeader
->NumberOfSections
);
405 Current
->Address
+= PESectionHeaders
[CoffEntry
[i
].e_scnum
- 1].VirtualAddress
;
407 Current
->FileOffset
= 0;
408 if (CoffEntry
[i
].e
.e
.e_zeroes
== 0)
410 if (sizeof(FuncName
) <= strlen((char *) CoffStringsBase
+ CoffEntry
[i
].e
.e
.e_offset
))
413 fprintf(stderr
, "Function name too long\n");
414 StringHashTableFree(&StringHash
);
417 strcpy(FuncName
, (char *) CoffStringsBase
+ CoffEntry
[i
].e
.e
.e_offset
);
421 memcpy(FuncName
, CoffEntry
[i
].e
.e_name
, E_SYMNMLEN
);
422 FuncName
[E_SYMNMLEN
] = '\0';
425 /* Name demangling: stdcall */
426 p
= strrchr(FuncName
, '@');
431 p
= ('_' == FuncName
[0] || '@' == FuncName
[0] ? FuncName
+ 1 : FuncName
);
432 Current
->FunctionOffset
= FindOrAddString(&StringHash
,
436 Current
->SourceLine
= 0;
437 memset(++Current
, 0, sizeof(*Current
));
440 i
+= CoffEntry
[i
].e_numaux
;
443 *SymbolsCount
= (Current
- *SymbolsBase
+ 1);
444 qsort(*SymbolsBase
, *SymbolsCount
, sizeof(ROSSYM_ENTRY
), (int (*)(const void *, const void *)) CompareSymEntry
);
446 StringHashTableFree(&StringHash
);
451 struct DbgHelpLineEntry
{
458 struct DbgHelpStringTab
{
462 ULONG LineEntries
, CurLineEntries
;
463 struct DbgHelpLineEntry
*LineEntryData
;
468 struct DbgHelpLineEntry
*lastLineEntry
;
471 static struct DbgHelpLineEntry
*
472 DbgHelpAddLineEntry(struct DbgHelpStringTab
*tab
)
474 if (tab
->CurLineEntries
== tab
->LineEntries
)
476 struct DbgHelpLineEntry
*newEntries
= realloc(tab
->LineEntryData
,
477 tab
->LineEntries
* 2 * sizeof(struct DbgHelpLineEntry
));
482 tab
->LineEntryData
= newEntries
;
484 memset(tab
->LineEntryData
+ tab
->LineEntries
, 0, sizeof(struct DbgHelpLineEntry
) * tab
->LineEntries
);
485 tab
->LineEntries
*= 2;
488 return &tab
->LineEntryData
[tab
->CurLineEntries
++];
492 DbgHelpAddStringToTable(struct DbgHelpStringTab
*tab
, char *name
)
494 unsigned int bucket
= ComputeDJBHash(name
) % tab
->Length
;
495 char **tabEnt
= tab
->Table
[bucket
];
501 for (i
= 0; tabEnt
[i
] && strcmp(tabEnt
[i
], name
); i
++);
505 return (i
<< 10) | bucket
;
511 /* At this point, we need to insert */
512 tab
->Bytes
+= strlen(name
) + 1;
514 newBucket
= realloc(tab
->Table
[bucket
], (i
+2) * sizeof(char *));
518 fprintf(stderr
, "realloc failed!\n");
522 tab
->Table
[bucket
] = newBucket
;
523 tab
->Table
[bucket
][i
+1] = 0;
524 tab
->Table
[bucket
][i
] = name
;
525 return (i
<< 10) | bucket
;
529 DbgHelpGetString(struct DbgHelpStringTab
*tab
, int id
)
532 int bucket
= id
& 0x3ff;
533 return tab
->Table
[bucket
][i
];
536 /* Remove a prefix of PathChop if it exists and return a copy of the tail. */
538 StrDupShortenPath(char *PathChop
, char *FilePath
)
540 int pclen
= strlen(PathChop
);
541 if (!strncmp(FilePath
, PathChop
, pclen
))
543 return strdup(FilePath
+pclen
);
547 return strdup(FilePath
);
552 DbgHelpAddLineNumber(PSRCCODEINFO LineInfo
, void *UserContext
)
554 struct DbgHelpStringTab
*tab
= (struct DbgHelpStringTab
*)UserContext
;
556 int fileId
, functionId
;
557 PSYMBOL_INFO pSymbol
= malloc(FIELD_OFFSET(SYMBOL_INFO
, Name
[MAX_SYM_NAME
]));
558 if (!pSymbol
) return FALSE
;
559 memset(pSymbol
, 0, FIELD_OFFSET(SYMBOL_INFO
, Name
[MAX_SYM_NAME
]));
561 /* If any file can be opened by relative path up to a certain level, then
566 char *end
= strrchr(LineInfo
->FileName
, '/');
569 end
= strrchr(LineInfo
->FileName
, '\\');
573 for (i
= (end
- LineInfo
->FileName
) - 1; i
>= 0; i
--)
575 if (LineInfo
->FileName
[i
] == '/' || LineInfo
->FileName
[i
] == '\\')
577 char *synthname
= malloc(strlen(tab
->SourcePath
) +
578 strlen(LineInfo
->FileName
+ i
+ 1)
580 strcpy(synthname
, tab
->SourcePath
);
581 strcat(synthname
, "/");
582 strcat(synthname
, LineInfo
->FileName
+ i
+ 1);
583 FILE *f
= fopen(synthname
, "r");
593 i
++; /* Be in the string or past the next slash */
594 tab
->PathChop
= malloc(i
+ 1);
595 memcpy(tab
->PathChop
, LineInfo
->FileName
, i
);
596 tab
->PathChop
[i
] = 0;
600 fileId
= DbgHelpAddStringToTable(tab
,
601 StrDupShortenPath(tab
->PathChop
,
602 LineInfo
->FileName
));
604 pSymbol
->SizeOfStruct
= sizeof(SYMBOL_INFO
);
605 pSymbol
->MaxNameLen
= MAX_SYM_NAME
;
607 if (!SymFromAddr(tab
->process
, LineInfo
->Address
, &disp
, pSymbol
))
609 //fprintf(stderr, "SymFromAddr failed.\n");
614 functionId
= DbgHelpAddStringToTable(tab
, strdup(pSymbol
->Name
));
616 if (LineInfo
->Address
== 0)
617 fprintf(stderr
, "Address is 0.\n");
619 tab
->lastLineEntry
= DbgHelpAddLineEntry(tab
);
620 tab
->lastLineEntry
->vma
= LineInfo
->Address
- LineInfo
->ModBase
;
621 tab
->lastLineEntry
->functionId
= functionId
;
622 tab
->lastLineEntry
->fileId
= fileId
;
623 tab
->lastLineEntry
->line
= LineInfo
->LineNumber
;
630 ConvertDbgHelp(void *process
, DWORD module_base
, char *SourcePath
,
631 ULONG
*SymbolsCount
, PROSSYM_ENTRY
*SymbolsBase
,
632 ULONG
*StringsLength
, void **StringsBase
)
634 char *strings
, *strings_copy
;
635 int i
, j
, bucket
, entry
;
636 PROSSYM_ENTRY rossym
;
637 struct DbgHelpStringTab strtab
= { 0 };
639 strtab
.process
= process
;
640 strtab
.module_base
= module_base
;
642 strtab
.Length
= 1024;
643 strtab
.Table
= calloc(1024, sizeof(const char **));
644 strtab
.Table
[0] = calloc(2, sizeof(const char *));
645 strtab
.Table
[0][0] = strdup(""); // The zero string
646 strtab
.CurLineEntries
= 0;
647 strtab
.LineEntries
= 16384;
648 strtab
.LineEntryData
= calloc(strtab
.LineEntries
, sizeof(struct DbgHelpLineEntry
));
649 strtab
.PathChop
= NULL
;
650 strtab
.SourcePath
= SourcePath
? SourcePath
: "";
652 SymEnumLines(process
, module_base
, NULL
, NULL
, DbgHelpAddLineNumber
, &strtab
);
654 /* Transcribe necessary strings */
655 *StringsLength
= strtab
.Bytes
;
656 strings
= strings_copy
= ((char *)(*StringsBase
= malloc(strtab
.Bytes
)));
658 /* Copy in strings */
659 for (i
= 0; i
< strtab
.Length
; i
++)
661 for (j
= 0; strtab
.Table
[i
] && strtab
.Table
[i
][j
]; j
++)
663 /* Each entry is replaced by its corresponding entry in our string
664 section. We can substract the strings origin to get an offset. */
665 char *toFree
= strtab
.Table
[i
][j
];
666 strtab
.Table
[i
][j
] = strcpy(strings_copy
, strtab
.Table
[i
][j
]);
668 strings_copy
+= strlen(strings_copy
) + 1;
672 assert(strings_copy
== strings
+ strtab
.Bytes
);
674 *SymbolsBase
= calloc(strtab
.CurLineEntries
, sizeof(ROSSYM_ENTRY
));
675 *SymbolsCount
= strtab
.CurLineEntries
;
677 /* Copy symbols into rossym entries */
678 for (i
= 0; i
< strtab
.CurLineEntries
; i
++)
680 rossym
= &(*SymbolsBase
)[i
];
681 rossym
->Address
= strtab
.LineEntryData
[i
].vma
;
682 bucket
= strtab
.LineEntryData
[i
].fileId
& 0x3ff;
683 entry
= strtab
.LineEntryData
[i
].fileId
>> 10;
684 rossym
->FileOffset
= strtab
.Table
[bucket
][entry
] - strings
;
685 bucket
= strtab
.LineEntryData
[i
].functionId
& 0x3ff;
686 entry
= strtab
.LineEntryData
[i
].functionId
>> 10;
687 rossym
->FunctionOffset
= strtab
.Table
[bucket
][entry
] - strings
;
688 rossym
->SourceLine
= strtab
.LineEntryData
[i
].line
;
692 for (i
= 0; i
< strtab
.Length
; i
++)
694 free(strtab
.Table
[i
]);
697 free(strtab
.LineEntryData
);
698 free(strtab
.PathChop
);
700 qsort(*SymbolsBase
, *SymbolsCount
, sizeof(ROSSYM_ENTRY
), (int (*)(const void *, const void *))CompareSymEntry
);
706 MergeStabsAndCoffs(ULONG
*MergedSymbolCount
, PROSSYM_ENTRY
*MergedSymbols
,
707 ULONG StabSymbolsCount
, PROSSYM_ENTRY StabSymbols
,
708 ULONG CoffSymbolsCount
, PROSSYM_ENTRY CoffSymbols
)
712 ULONG_PTR StabFunctionStartAddress
;
713 ULONG StabFunctionStringOffset
, NewStabFunctionStringOffset
;
715 *MergedSymbolCount
= 0;
716 if (StabSymbolsCount
== 0)
718 *MergedSymbols
= NULL
;
721 *MergedSymbols
= malloc((StabSymbolsCount
+ CoffSymbolsCount
) * sizeof(ROSSYM_ENTRY
));
722 if (*MergedSymbols
== NULL
)
724 fprintf(stderr
, "Unable to allocate memory for merged symbols\n");
728 StabFunctionStartAddress
= 0;
729 StabFunctionStringOffset
= 0;
731 for (StabIndex
= 0; StabIndex
< StabSymbolsCount
; StabIndex
++)
733 (*MergedSymbols
)[*MergedSymbolCount
] = StabSymbols
[StabIndex
];
734 for (j
= StabIndex
+ 1;
735 j
< StabSymbolsCount
&& StabSymbols
[j
].Address
== StabSymbols
[StabIndex
].Address
;
738 if (StabSymbols
[j
].FileOffset
!= 0 && (*MergedSymbols
)[*MergedSymbolCount
].FileOffset
== 0)
740 (*MergedSymbols
)[*MergedSymbolCount
].FileOffset
= StabSymbols
[j
].FileOffset
;
742 if (StabSymbols
[j
].FunctionOffset
!= 0 && (*MergedSymbols
)[*MergedSymbolCount
].FunctionOffset
== 0)
744 (*MergedSymbols
)[*MergedSymbolCount
].FunctionOffset
= StabSymbols
[j
].FunctionOffset
;
746 if (StabSymbols
[j
].SourceLine
!= 0 && (*MergedSymbols
)[*MergedSymbolCount
].SourceLine
== 0)
748 (*MergedSymbols
)[*MergedSymbolCount
].SourceLine
= StabSymbols
[j
].SourceLine
;
753 while (CoffIndex
< CoffSymbolsCount
&&
754 CoffSymbols
[CoffIndex
+ 1].Address
<= (*MergedSymbols
)[*MergedSymbolCount
].Address
)
758 NewStabFunctionStringOffset
= (*MergedSymbols
)[*MergedSymbolCount
].FunctionOffset
;
759 if (CoffSymbolsCount
> 0 &&
760 CoffSymbols
[CoffIndex
].Address
< (*MergedSymbols
)[*MergedSymbolCount
].Address
&&
761 StabFunctionStartAddress
< CoffSymbols
[CoffIndex
].Address
&&
762 CoffSymbols
[CoffIndex
].FunctionOffset
!= 0)
764 (*MergedSymbols
)[*MergedSymbolCount
].FunctionOffset
= CoffSymbols
[CoffIndex
].FunctionOffset
;
765 CoffSymbols
[CoffIndex
].FileOffset
= CoffSymbols
[CoffIndex
].FunctionOffset
= 0;
767 if (StabFunctionStringOffset
!= NewStabFunctionStringOffset
)
769 StabFunctionStartAddress
= (*MergedSymbols
)[*MergedSymbolCount
].Address
;
771 StabFunctionStringOffset
= NewStabFunctionStringOffset
;
772 (*MergedSymbolCount
)++;
774 /* Handle functions that have no analog in the upstream data */
775 for (CoffIndex
= 0; CoffIndex
< CoffSymbolsCount
; CoffIndex
++)
777 if (CoffSymbols
[CoffIndex
].Address
&&
778 CoffSymbols
[CoffIndex
].FunctionOffset
)
780 (*MergedSymbols
)[*MergedSymbolCount
] = CoffSymbols
[CoffIndex
];
781 (*MergedSymbolCount
)++;
785 qsort(*MergedSymbols
, *MergedSymbolCount
, sizeof(ROSSYM_ENTRY
), (int (*)(const void *, const void *)) CompareSymEntry
);
790 static PIMAGE_SECTION_HEADER
791 FindSectionForRVA(DWORD RVA
, unsigned NumberOfSections
, PIMAGE_SECTION_HEADER SectionHeaders
)
795 for (Section
= 0; Section
< NumberOfSections
; Section
++)
797 if (SectionHeaders
[Section
].VirtualAddress
<= RVA
&&
798 RVA
< SectionHeaders
[Section
].VirtualAddress
+ SectionHeaders
[Section
].Misc
.VirtualSize
)
800 return SectionHeaders
+ Section
;
808 ProcessRelocations(ULONG
*ProcessedRelocsLength
, void **ProcessedRelocs
,
809 void *RawData
, PIMAGE_OPTIONAL_HEADER OptHeader
,
810 unsigned NumberOfSections
, PIMAGE_SECTION_HEADER SectionHeaders
)
812 PIMAGE_SECTION_HEADER RelocSectionHeader
, TargetSectionHeader
;
813 PIMAGE_BASE_RELOCATION BaseReloc
, End
, AcceptedRelocs
;
816 if (OptHeader
->NumberOfRvaAndSizes
< IMAGE_DIRECTORY_ENTRY_BASERELOC
||
817 OptHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
== 0)
819 /* No relocation entries */
820 *ProcessedRelocsLength
= 0;
821 *ProcessedRelocs
= NULL
;
825 RelocSectionHeader
= FindSectionForRVA(OptHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
,
826 NumberOfSections
, SectionHeaders
);
827 if (RelocSectionHeader
== NULL
)
829 fprintf(stderr
, "Can't find section header for relocation data\n");
833 *ProcessedRelocs
= malloc(RelocSectionHeader
->SizeOfRawData
);
834 if (*ProcessedRelocs
== NULL
)
837 "Failed to allocate %u bytes for relocations\n",
838 (unsigned int)RelocSectionHeader
->SizeOfRawData
);
841 *ProcessedRelocsLength
= 0;
843 BaseReloc
= (PIMAGE_BASE_RELOCATION
) ((char *) RawData
+
844 RelocSectionHeader
->PointerToRawData
+
845 (OptHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
-
846 RelocSectionHeader
->VirtualAddress
));
847 End
= (PIMAGE_BASE_RELOCATION
) ((char *) BaseReloc
+
848 OptHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
);
850 while (BaseReloc
< End
&& BaseReloc
->SizeOfBlock
> 0)
852 TargetSectionHeader
= FindSectionForRVA(BaseReloc
->VirtualAddress
,
855 if (TargetSectionHeader
!= NULL
)
857 AcceptedRelocs
= *ProcessedRelocs
;
859 while (AcceptedRelocs
< (PIMAGE_BASE_RELOCATION
) ((char *) *ProcessedRelocs
+
860 *ProcessedRelocsLength
)
863 Found
= BaseReloc
->SizeOfBlock
== AcceptedRelocs
->SizeOfBlock
&&
864 memcmp(BaseReloc
, AcceptedRelocs
, AcceptedRelocs
->SizeOfBlock
) == 0;
865 AcceptedRelocs
= (PIMAGE_BASE_RELOCATION
) ((char *) AcceptedRelocs
+
866 AcceptedRelocs
->SizeOfBlock
);
870 memcpy((char *) *ProcessedRelocs
+ *ProcessedRelocsLength
,
872 BaseReloc
->SizeOfBlock
);
873 *ProcessedRelocsLength
+= BaseReloc
->SizeOfBlock
;
876 BaseReloc
= (PIMAGE_BASE_RELOCATION
)((char *) BaseReloc
+ BaseReloc
->SizeOfBlock
);
883 GetSectionName(void *StringsBase
, const BYTE
*SectionTitle
)
885 if (SectionTitle
[0] == '/')
887 int offset
= atoi((char*)SectionTitle
+1);
888 return ((BYTE
*)StringsBase
) + offset
;
895 CreateOutputFile(FILE *OutFile
, void *InData
,
896 PIMAGE_DOS_HEADER InDosHeader
, PIMAGE_FILE_HEADER InFileHeader
,
897 PIMAGE_OPTIONAL_HEADER InOptHeader
, PIMAGE_SECTION_HEADER InSectionHeaders
,
898 ULONG RosSymLength
, void *RosSymSection
)
900 ULONG StartOfRawData
;
902 void *OutHeader
, *ProcessedRelocs
, *PaddedRosSym
, *Data
;
903 unsigned char *PaddedStringTable
;
904 PIMAGE_DOS_HEADER OutDosHeader
;
905 PIMAGE_FILE_HEADER OutFileHeader
;
906 PIMAGE_OPTIONAL_HEADER OutOptHeader
;
907 PIMAGE_SECTION_HEADER OutSectionHeaders
, CurrentSectionHeader
;
910 ULONG ProcessedRelocsLength
;
911 ULONG RosSymOffset
, RosSymFileLength
;
912 ULONG PaddedStringTableLength
;
913 int InRelocSectionIndex
;
914 PIMAGE_SECTION_HEADER OutRelocSection
;
915 /* Each coff symbol is 18 bytes and the string table follows */
916 char *StringTable
= (char *)InData
+
917 InFileHeader
->PointerToSymbolTable
+ 18 * InFileHeader
->NumberOfSymbols
;
918 ULONG StringTableLength
= 0;
919 ULONG StringTableLocation
;
922 for (Section
= 0; Section
< InFileHeader
->NumberOfSections
; Section
++)
924 const BYTE
*SectionName
= GetSectionName(StringTable
,
925 InSectionHeaders
[Section
].Name
);
926 if (InSectionHeaders
[Section
].Name
[0] == '/')
928 StringTableLength
= atoi(InSectionHeaders
[Section
].Name
+1) + strlen(SectionName
) + 1;
930 if ((StartOfRawData
== 0 || InSectionHeaders
[Section
].PointerToRawData
< StartOfRawData
)
931 && InSectionHeaders
[Section
].PointerToRawData
!= 0
932 && (strncmp((char *) SectionName
, ".stab", 5)) != 0
933 && (strncmp((char *) SectionName
, ".debug_", 7)) != 0)
935 StartOfRawData
= InSectionHeaders
[Section
].PointerToRawData
;
938 OutHeader
= malloc(StartOfRawData
);
939 if (OutHeader
== NULL
)
942 "Failed to allocate %u bytes for output file header\n",
943 (unsigned int)StartOfRawData
);
946 memset(OutHeader
, '\0', StartOfRawData
);
948 OutDosHeader
= (PIMAGE_DOS_HEADER
) OutHeader
;
949 memcpy(OutDosHeader
, InDosHeader
, InDosHeader
->e_lfanew
+ sizeof(ULONG
));
951 OutFileHeader
= (PIMAGE_FILE_HEADER
)((char *) OutHeader
+ OutDosHeader
->e_lfanew
+ sizeof(ULONG
));
952 memcpy(OutFileHeader
, InFileHeader
, sizeof(IMAGE_FILE_HEADER
));
953 OutFileHeader
->PointerToSymbolTable
= 0;
954 OutFileHeader
->NumberOfSymbols
= 0;
955 OutFileHeader
->Characteristics
&= ~(IMAGE_FILE_LINE_NUMS_STRIPPED
| IMAGE_FILE_LOCAL_SYMS_STRIPPED
|
956 IMAGE_FILE_DEBUG_STRIPPED
);
958 OutOptHeader
= (PIMAGE_OPTIONAL_HEADER
)(OutFileHeader
+ 1);
959 memcpy(OutOptHeader
, InOptHeader
, sizeof(IMAGE_OPTIONAL_HEADER
));
960 OutOptHeader
->CheckSum
= 0;
962 OutSectionHeaders
= (PIMAGE_SECTION_HEADER
)((char *) OutOptHeader
+ OutFileHeader
->SizeOfOptionalHeader
);
964 if (ProcessRelocations(&ProcessedRelocsLength
,
968 InFileHeader
->NumberOfSections
,
973 if (InOptHeader
->NumberOfRvaAndSizes
< IMAGE_DIRECTORY_ENTRY_BASERELOC
||
974 InOptHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
== 0)
976 InRelocSectionIndex
= -1;
980 InRelocSectionIndex
= FindSectionForRVA(InOptHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
].VirtualAddress
,
981 InFileHeader
->NumberOfSections
, InSectionHeaders
) - InSectionHeaders
;
984 OutFileHeader
->NumberOfSections
= 0;
985 CurrentSectionHeader
= OutSectionHeaders
;
986 OutOptHeader
->SizeOfImage
= 0;
988 OutRelocSection
= NULL
;
990 StringTableLocation
= StartOfRawData
;
992 for (Section
= 0; Section
< InFileHeader
->NumberOfSections
; Section
++)
994 const BYTE
*SectionName
= GetSectionName(StringTable
,
995 InSectionHeaders
[Section
].Name
);
996 if ((strncmp((char *) SectionName
, ".stab", 5) != 0) &&
997 (strncmp((char *) SectionName
, ".debug_", 7)) != 0)
999 *CurrentSectionHeader
= InSectionHeaders
[Section
];
1000 CurrentSectionHeader
->PointerToLinenumbers
= 0;
1001 CurrentSectionHeader
->NumberOfLinenumbers
= 0;
1002 if (OutOptHeader
->SizeOfImage
< CurrentSectionHeader
->VirtualAddress
+
1003 CurrentSectionHeader
->Misc
.VirtualSize
)
1005 OutOptHeader
->SizeOfImage
= ROUND_UP(CurrentSectionHeader
->VirtualAddress
+
1006 CurrentSectionHeader
->Misc
.VirtualSize
,
1007 OutOptHeader
->SectionAlignment
);
1009 if (RosSymOffset
< CurrentSectionHeader
->PointerToRawData
+ CurrentSectionHeader
->SizeOfRawData
)
1011 RosSymOffset
= CurrentSectionHeader
->PointerToRawData
+ CurrentSectionHeader
->SizeOfRawData
;
1013 if (Section
== (ULONG
)InRelocSectionIndex
)
1015 OutRelocSection
= CurrentSectionHeader
;
1017 StringTableLocation
= CurrentSectionHeader
->PointerToRawData
+ CurrentSectionHeader
->SizeOfRawData
;
1018 OutFileHeader
->NumberOfSections
++;
1019 CurrentSectionHeader
++;
1023 if (OutRelocSection
== CurrentSectionHeader
- 1)
1025 OutOptHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_BASERELOC
].Size
= ProcessedRelocsLength
;
1026 if (OutOptHeader
->SizeOfImage
== OutRelocSection
->VirtualAddress
+
1027 ROUND_UP(OutRelocSection
->Misc
.VirtualSize
,
1028 OutOptHeader
->SectionAlignment
))
1030 OutOptHeader
->SizeOfImage
= OutRelocSection
->VirtualAddress
+
1031 ROUND_UP(ProcessedRelocsLength
,
1032 OutOptHeader
->SectionAlignment
);
1034 OutRelocSection
->Misc
.VirtualSize
= ProcessedRelocsLength
;
1035 if (RosSymOffset
== OutRelocSection
->PointerToRawData
+
1036 OutRelocSection
->SizeOfRawData
)
1038 RosSymOffset
= OutRelocSection
->PointerToRawData
+
1039 ROUND_UP(ProcessedRelocsLength
,
1040 OutOptHeader
->FileAlignment
);
1042 OutRelocSection
->SizeOfRawData
= ROUND_UP(ProcessedRelocsLength
,
1043 OutOptHeader
->FileAlignment
);
1046 if (RosSymLength
> 0)
1048 RosSymFileLength
= ROUND_UP(RosSymLength
, OutOptHeader
->FileAlignment
);
1049 memcpy(CurrentSectionHeader
->Name
, ".rossym", 8); /* We're lucky: string is exactly 8 bytes long */
1050 CurrentSectionHeader
->Misc
.VirtualSize
= RosSymLength
;
1051 CurrentSectionHeader
->VirtualAddress
= OutOptHeader
->SizeOfImage
;
1052 CurrentSectionHeader
->SizeOfRawData
= RosSymFileLength
;
1053 CurrentSectionHeader
->PointerToRawData
= RosSymOffset
;
1054 CurrentSectionHeader
->PointerToRelocations
= 0;
1055 CurrentSectionHeader
->PointerToLinenumbers
= 0;
1056 CurrentSectionHeader
->NumberOfRelocations
= 0;
1057 CurrentSectionHeader
->NumberOfLinenumbers
= 0;
1058 CurrentSectionHeader
->Characteristics
= IMAGE_SCN_MEM_READ
| IMAGE_SCN_MEM_DISCARDABLE
1059 | IMAGE_SCN_LNK_REMOVE
| IMAGE_SCN_TYPE_NOLOAD
;
1060 OutOptHeader
->SizeOfImage
= ROUND_UP(CurrentSectionHeader
->VirtualAddress
+ CurrentSectionHeader
->Misc
.VirtualSize
,
1061 OutOptHeader
->SectionAlignment
);
1062 OutFileHeader
->NumberOfSections
++;
1064 PaddedRosSym
= malloc(RosSymFileLength
);
1065 if (PaddedRosSym
== NULL
)
1068 "Failed to allocate %u bytes for padded .rossym\n",
1069 (unsigned int)RosSymFileLength
);
1072 memcpy(PaddedRosSym
, RosSymSection
, RosSymLength
);
1073 memset((char *) PaddedRosSym
+ RosSymLength
,
1075 RosSymFileLength
- RosSymLength
);
1077 /* Position the string table after our new section */
1078 StringTableLocation
= RosSymOffset
+ RosSymFileLength
;
1082 PaddedRosSym
= NULL
;
1085 /* Set the string table area in the header if we need it */
1086 if (StringTableLength
)
1088 OutFileHeader
->PointerToSymbolTable
= StringTableLocation
;
1089 OutFileHeader
->NumberOfSymbols
= 0;
1093 for (i
= 0; i
< StartOfRawData
/ 2; i
++)
1095 CheckSum
+= ((unsigned short*) OutHeader
)[i
];
1096 CheckSum
= 0xffff & (CheckSum
+ (CheckSum
>> 16));
1098 Length
= StartOfRawData
;
1099 for (Section
= 0; Section
< OutFileHeader
->NumberOfSections
; Section
++)
1101 DWORD SizeOfRawData
;
1102 if (OutRelocSection
== OutSectionHeaders
+ Section
)
1104 Data
= (void *) ProcessedRelocs
;
1105 SizeOfRawData
= ProcessedRelocsLength
;
1107 else if (RosSymLength
> 0 && Section
+ 1 == OutFileHeader
->NumberOfSections
)
1109 Data
= (void *) PaddedRosSym
;
1110 SizeOfRawData
= OutSectionHeaders
[Section
].SizeOfRawData
;
1114 Data
= (void *) ((char *) InData
+ OutSectionHeaders
[Section
].PointerToRawData
);
1115 SizeOfRawData
= OutSectionHeaders
[Section
].SizeOfRawData
;
1117 for (i
= 0; i
< SizeOfRawData
/ 2; i
++)
1119 CheckSum
+= ((unsigned short*) Data
)[i
];
1120 CheckSum
= 0xffff & (CheckSum
+ (CheckSum
>> 16));
1122 Length
+= OutSectionHeaders
[Section
].SizeOfRawData
;
1125 if (OutFileHeader
->PointerToSymbolTable
)
1127 int PaddingFrom
= (OutFileHeader
->PointerToSymbolTable
+ StringTableLength
) %
1128 OutOptHeader
->FileAlignment
;
1129 int PaddingSize
= PaddingFrom
? OutOptHeader
->FileAlignment
- PaddingFrom
: 0;
1131 PaddedStringTableLength
= StringTableLength
+ PaddingSize
;
1132 PaddedStringTable
= malloc(PaddedStringTableLength
);
1133 /* COFF string section is preceeded by a length */
1134 assert(sizeof(StringTableLength
) == 4);
1135 memcpy(PaddedStringTable
, &StringTableLength
, sizeof(StringTableLength
));
1136 /* We just copy enough of the string table to contain the strings we want
1137 The string table length technically counts as part of the string table
1139 memcpy(PaddedStringTable
+ 4, StringTable
+ 4, StringTableLength
- 4);
1140 memset(PaddedStringTable
+ StringTableLength
, 0, PaddingSize
);
1142 assert(OutFileHeader
->PointerToSymbolTable
% 2 == 0);
1143 for (i
= 0; i
< PaddedStringTableLength
/ 2; i
++)
1145 CheckSum
+= ((unsigned short*)PaddedStringTable
)[i
];
1146 CheckSum
= 0xffff & (CheckSum
+ (CheckSum
>> 16));
1148 Length
+= PaddedStringTableLength
;
1152 PaddedStringTable
= NULL
;
1156 OutOptHeader
->CheckSum
= CheckSum
;
1158 if (fwrite(OutHeader
, 1, StartOfRawData
, OutFile
) != StartOfRawData
)
1160 perror("Error writing output header\n");
1165 for (Section
= 0; Section
< OutFileHeader
->NumberOfSections
; Section
++)
1167 if (OutSectionHeaders
[Section
].SizeOfRawData
!= 0)
1169 DWORD SizeOfRawData
;
1170 fseek(OutFile
, OutSectionHeaders
[Section
].PointerToRawData
, SEEK_SET
);
1171 if (OutRelocSection
== OutSectionHeaders
+ Section
)
1173 Data
= (void *) ProcessedRelocs
;
1174 SizeOfRawData
= ProcessedRelocsLength
;
1176 else if (RosSymLength
> 0 && Section
+ 1 == OutFileHeader
->NumberOfSections
)
1178 Data
= (void *) PaddedRosSym
;
1179 SizeOfRawData
= OutSectionHeaders
[Section
].SizeOfRawData
;
1183 Data
= (void *) ((char *) InData
+ OutSectionHeaders
[Section
].PointerToRawData
);
1184 SizeOfRawData
= OutSectionHeaders
[Section
].SizeOfRawData
;
1186 if (fwrite(Data
, 1, SizeOfRawData
, OutFile
) != SizeOfRawData
)
1188 perror("Error writing section data\n");
1196 if (PaddedStringTable
)
1198 fseek(OutFile
, OutFileHeader
->PointerToSymbolTable
, SEEK_SET
);
1199 fwrite(PaddedStringTable
, 1, PaddedStringTableLength
, OutFile
);
1200 free(PaddedStringTable
);
1212 int main(int argc
, char* argv
[])
1214 PSYMBOLFILE_HEADER SymbolFileHeader
;
1215 PIMAGE_DOS_HEADER PEDosHeader
;
1216 PIMAGE_FILE_HEADER PEFileHeader
;
1217 PIMAGE_OPTIONAL_HEADER PEOptHeader
;
1218 PIMAGE_SECTION_HEADER PESectionHeaders
;
1222 void *StabStringBase
;
1223 ULONG StabStringsLength
;
1224 void *CoffBase
= NULL
;
1226 void *CoffStringBase
= NULL
;
1227 ULONG CoffStringsLength
;
1231 void *StringBase
= NULL
;
1232 ULONG StringsLength
= 0;
1233 ULONG StabSymbolsCount
= 0;
1234 PROSSYM_ENTRY StabSymbols
= NULL
;
1235 ULONG CoffSymbolsCount
= 0;
1236 PROSSYM_ENTRY CoffSymbols
= NULL
;
1237 ULONG MergedSymbolsCount
= 0;
1238 PROSSYM_ENTRY MergedSymbols
= NULL
;
1242 void *RosSymSection
;
1245 char elfhdr
[4] = { '\177', 'E', 'L', 'F' };
1246 BOOLEAN UseDbgHelp
= FALSE
;
1247 int arg
, argstate
= 0;
1248 char *SourcePath
= NULL
;
1250 for (arg
= 1; arg
< argc
; arg
++)
1259 if (!strcmp(argv
[arg
], "-s"))
1266 path1
= convert_path(argv
[arg
]);
1272 SourcePath
= strdup(argv
[arg
]);
1277 path2
= convert_path(argv
[arg
]);
1285 fprintf(stderr
, "Usage: rsym [-s <sources>] <input> <output>\n");
1289 FileData
= load_file(path1
, &FileSize
);
1292 fprintf(stderr
, "An error occured loading '%s'\n", path1
);
1296 file
= fopen(path1
, "rb");
1298 /* Check if MZ header exists */
1299 PEDosHeader
= (PIMAGE_DOS_HEADER
) FileData
;
1300 if (PEDosHeader
->e_magic
!= IMAGE_DOS_MAGIC
||
1301 PEDosHeader
->e_lfanew
== 0L)
1304 if (!memcmp(PEDosHeader
, elfhdr
, sizeof(elfhdr
)))
1306 perror("Input file is not a PE image.\n");
1311 /* Locate PE file header */
1312 /* sizeof(ULONG) = sizeof(MAGIC) */
1313 PEFileHeader
= (PIMAGE_FILE_HEADER
)((char *) FileData
+ PEDosHeader
->e_lfanew
+ sizeof(ULONG
));
1315 /* Locate optional header */
1316 assert(sizeof(ULONG
) == 4);
1317 PEOptHeader
= (PIMAGE_OPTIONAL_HEADER
)(PEFileHeader
+ 1);
1318 ImageBase
= PEOptHeader
->ImageBase
;
1320 /* Locate PE section headers */
1321 PESectionHeaders
= (PIMAGE_SECTION_HEADER
)((char *) PEOptHeader
+ PEFileHeader
->SizeOfOptionalHeader
);
1323 if (GetStabInfo(FileData
,
1335 if (StabsLength
== 0)
1337 // SYMOPT_AUTO_PUBLICS
1338 // SYMOPT_FAVOR_COMPRESSED
1339 // SYMOPT_LOAD_ANYTHING
1340 // SYMOPT_LOAD_LINES
1341 SymSetOptions(0x10000 | 0x800000 | 0x40 | 0x10);
1342 SymInitialize(FileData
, ".", 0);
1344 module_base
= SymLoadModule(FileData
, file
, path1
, path1
, 0, FileSize
) & 0xffffffff;
1346 if (ConvertDbgHelp(FileData
,
1359 SymUnloadModule(FileData
, module_base
);
1360 SymCleanup(FileData
);
1363 if (GetCoffInfo(FileData
,
1377 StringBase
= malloc(1 + StringsLength
+ CoffStringsLength
+
1378 (CoffsLength
/ sizeof(ROSSYM_ENTRY
)) * (E_SYMNMLEN
+ 1));
1379 if (StringBase
== NULL
)
1382 fprintf(stderr
, "Failed to allocate memory for strings table\n");
1385 /* Make offset 0 into an empty string */
1386 *((char *) StringBase
) = '\0';
1389 if (ConvertStabs(&StabSymbolsCount
,
1403 fprintf(stderr
, "Failed to allocate memory for strings table\n");
1409 StringBase
= realloc(StringBase
, StringsLength
+ CoffStringsLength
);
1413 fprintf(stderr
, "Failed to allocate memory for strings table\n");
1418 if (ConvertCoffs(&CoffSymbolsCount
,
1439 if (MergeStabsAndCoffs(&MergedSymbolsCount
,
1467 if (MergedSymbolsCount
== 0)
1470 RosSymSection
= NULL
;
1474 RosSymLength
= sizeof(SYMBOLFILE_HEADER
) +
1475 MergedSymbolsCount
* sizeof(ROSSYM_ENTRY
) +
1478 RosSymSection
= malloc(RosSymLength
);
1479 if (RosSymSection
== NULL
)
1481 free(MergedSymbols
);
1484 fprintf(stderr
, "Unable to allocate memory for .rossym section\n");
1487 memset(RosSymSection
, '\0', RosSymLength
);
1489 SymbolFileHeader
= (PSYMBOLFILE_HEADER
)RosSymSection
;
1490 SymbolFileHeader
->SymbolsOffset
= sizeof(SYMBOLFILE_HEADER
);
1491 SymbolFileHeader
->SymbolsLength
= MergedSymbolsCount
* sizeof(ROSSYM_ENTRY
);
1492 SymbolFileHeader
->StringsOffset
= SymbolFileHeader
->SymbolsOffset
+
1493 SymbolFileHeader
->SymbolsLength
;
1494 SymbolFileHeader
->StringsLength
= StringsLength
;
1496 memcpy((char *) RosSymSection
+ SymbolFileHeader
->SymbolsOffset
,
1498 SymbolFileHeader
->SymbolsLength
);
1500 memcpy((char *) RosSymSection
+ SymbolFileHeader
->StringsOffset
,
1502 SymbolFileHeader
->StringsLength
);
1504 free(MergedSymbols
);
1508 out
= fopen(path2
, "wb");
1511 perror("Cannot open output file");
1512 free(RosSymSection
);
1517 if (CreateOutputFile(out
,
1529 free(RosSymSection
);
1538 free(RosSymSection
);