reactos/sdk/tools/rsym/raddr2line.c

193 lines
4 KiB
C

/*
* Usage: raddr2line input-file address/offset
*
* This is a tool and is compiled using the host compiler,
* i.e. on Linux gcc and not mingw-gcc (cross-compiler).
* Therefore we can't include SDK headers and we have to
* duplicate some definitions here.
* Also note that the internal functions are "old C-style",
* returning an int, where a return of 0 means success and
* non-zero is failure.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "rsym.h"
/* Assume if an offset > ABS_TRESHOLD, then it must be absolute */
#define ABS_TRESHOLD 0x00400000L
size_t fixup_offset ( size_t ImageBase, size_t offset )
{
if (offset > ABS_TRESHOLD)
offset -= ImageBase;
return offset;
}
long
my_atoi ( const char* a )
{
int i = 0;
const char* fmt = "%x";
if ( *a == '0' )
{
switch ( *++a )
{
case 'x':
fmt = "%x";
++a;
break;
case 'd':
fmt = "%d";
++a;
break;
default:
fmt = "%o";
break;
}
}
sscanf ( a, fmt, &i );
return i;
}
PIMAGE_SECTION_HEADER
find_rossym_section ( PIMAGE_FILE_HEADER PEFileHeader,
PIMAGE_SECTION_HEADER PESectionHeaders )
{
size_t i;
for ( i = 0; i < PEFileHeader->NumberOfSections; i++ )
{
if ( 0 == strcmp ( (char*)PESectionHeaders[i].Name, ".rossym" ) )
return &PESectionHeaders[i];
}
return NULL;
}
int
find_and_print_offset (
void* data,
size_t offset )
{
PSYMBOLFILE_HEADER RosSymHeader = (PSYMBOLFILE_HEADER)data;
PROSSYM_ENTRY Entries = (PROSSYM_ENTRY)((char*)data + RosSymHeader->SymbolsOffset);
char* Strings = (char*)data + RosSymHeader->StringsOffset;
size_t symbols = RosSymHeader->SymbolsLength / sizeof(ROSSYM_ENTRY);
size_t i;
//if ( RosSymHeader->SymbolsOffset )
for ( i = 0; i < symbols; i++ )
{
if ( Entries[i].Address > offset )
{
if ( !i-- )
return 1;
else
{
PROSSYM_ENTRY e = &Entries[i];
printf ( "%s:%u (%s)\n",
&Strings[e->FileOffset],
(unsigned int)e->SourceLine,
&Strings[e->FunctionOffset] );
return 0;
}
}
}
return 1;
}
int
process_data ( const void* FileData, size_t offset )
{
PIMAGE_DOS_HEADER PEDosHeader;
PIMAGE_FILE_HEADER PEFileHeader;
PIMAGE_OPTIONAL_HEADER PEOptHeader;
PIMAGE_SECTION_HEADER PESectionHeaders;
PIMAGE_SECTION_HEADER PERosSymSectionHeader;
size_t ImageBase;
int res;
/* Check if MZ header exists */
PEDosHeader = (PIMAGE_DOS_HEADER)FileData;
if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC || PEDosHeader->e_lfanew == 0L)
{
perror("Input file is not a PE image.\n");
return 1;
}
/* Locate PE file header */
/* sizeof(ULONG) = sizeof(MAGIC) */
PEFileHeader = (PIMAGE_FILE_HEADER)((char *)FileData + PEDosHeader->e_lfanew + sizeof(ULONG));
/* Locate optional header */
PEOptHeader = (PIMAGE_OPTIONAL_HEADER)(PEFileHeader + 1);
ImageBase = PEOptHeader->ImageBase;
/* Locate PE section headers */
PESectionHeaders = (PIMAGE_SECTION_HEADER)((char *) PEOptHeader + PEFileHeader->SizeOfOptionalHeader);
/* make sure offset is what we want */
offset = fixup_offset ( ImageBase, offset );
/* find rossym section */
PERosSymSectionHeader = find_rossym_section (
PEFileHeader, PESectionHeaders );
if ( !PERosSymSectionHeader )
{
fprintf ( stderr, "Couldn't find rossym section in executable\n" );
return 1;
}
res = find_and_print_offset ( (char*)FileData + PERosSymSectionHeader->PointerToRawData,
offset );
if ( res )
printf ( "??:0\n" );
return res;
}
int
process_file ( const char* file_name, size_t offset )
{
void* FileData;
size_t FileSize;
int res = 1;
FileData = load_file ( file_name, &FileSize );
if ( !FileData )
{
fprintf ( stderr, "An error occured loading '%s'\n", file_name );
}
else
{
res = process_data ( FileData, offset );
free ( FileData );
}
return res;
}
int main ( int argc, const char** argv )
{
char* path;
size_t offset;
int res;
if ( argc != 3 )
{
fprintf(stderr, "Usage: raddr2line <exefile> <offset>\n");
exit(1);
}
path = convert_path ( argv[1] );
offset = my_atoi ( argv[2] );
res = process_file ( path, offset );
free ( path );
return res;
}