/* dos.c
* This file is part of Decomp - a disassembler. In this file are
* routines for handling various types of DOS/Win32 executable types
* i.e. PE, NE, MZ, and COM.
*
* Copyright (C) 2001 Jonathan duSaint <dusaint@earthlink.net>
*
* Started early Feb 2002.
*/
/* not implemented yet */
#include <stdio.h>
#include <string.h>
#include "decomp.h"
/* various defines for dos/win files */
#include "dos.h"
/* void */
/* com_get_file_info (struct file_info *fi) */
/* { */
/* } */
/* MZ (legacy DOS executable) section */
void
mz_get_file_info (struct file_info *fi)
{
}
char *
mz_read_strtab (struct file_info *fi)
{
return NULL;
}
struct symtab *
mz_get_next_symbol (struct file_info *fi, char *strtab)
{
return NULL;
}
/* NE (Win16 New Executable) section */
void
read_ne_header (struct ne_file_header *nh, FILE *fp)
{
d_read (nh->Signature, sizeof (char), 2, fp, 1);
d_read (&nh->LinkerMajorVersion, sizeof (BYTE), 1, fp, 0);
d_read (&nh->LinkerMinorVersion, sizeof (BYTE), 1, fp, 0);
d_read (&nh->EntryTableOffset, sizeof (WORD), 1, fp, 0);
d_read (&nh->EntryTableSize, sizeof (WORD), 1, fp, 0);
d_read (nh->Reserved, sizeof (BYTE), 4, fp, 1);
d_read (&nh->Flags, sizeof (WORD), 1, fp, 0);
d_read (&nh->AutoDataSegment, sizeof (WORD), 1, fp, 0);
d_read (&nh->HeapSize, sizeof (WORD), 1, fp, 0);
d_read (&nh->StackSize, sizeof (WORD), 1, fp, 0);
d_read (&nh->CS, sizeof (WORD), 1, fp, 0);
d_read (&nh->IP, sizeof (WORD), 1, fp, 0);
d_read (&nh->SS, sizeof (WORD), 1, fp, 0);
d_read (&nh->SP, sizeof (WORD), 1, fp, 0);
d_read (&nh->SegmentTableEntries, sizeof (WORD), 1, fp, 0);
d_read (&nh->ModuleRefTableEntries, sizeof (WORD), 1, fp, 0);
d_read (&nh->NonresidentNameTableSize, sizeof (WORD), 1, fp, 0);
d_read (&nh->SegmentTableOffset, sizeof (WORD), 1, fp, 0);
d_read (&nh->ResourceTableOffset, sizeof (WORD), 1, fp, 0);
d_read (&nh->ResidentNameTableOffset, sizeof (WORD), 1, fp, 0);
d_read (&nh->ModuleReferenceTableOffset, sizeof (WORD), 1, fp, 0);
d_read (&nh->ImportedNameTableOffset, sizeof (WORD), 1, fp, 0);
d_read (&nh->NonresidentNameTableOffset, sizeof (WORD), 1, fp, 0);
d_read (&nh->MovableEntryPoints, sizeof (WORD), 1, fp, 0);
d_read (&nh->Alignment, sizeof (WORD), 1, fp, 0);
d_read (&nh->ResourceSegments, sizeof (WORD), 1, fp, 0);
d_read (&nh->OperatingSystem, sizeof (BYTE), 1, fp, 0);
d_read (&nh->AdditionalInformation, sizeof (BYTE), 1, fp, 0);
d_read (&nh->FastLoadSectorOffset, sizeof (WORD), 1, fp, 0);
d_read (&nh->FastLoadSectorSize, sizeof (WORD), 1, fp, 0);
d_read (&nh->Reserved1, sizeof (WORD), 1, fp, 0);
d_read (&nh->WindowsVersion, sizeof (WORD), 1, fp, 0);
}
void
ne_read_segment_header (struct ne_segment_header *sh, FILE *fp)
{
d_read (&sh->SegmentDataSectorOffset, sizeof (WORD), 1, fp, 0);
d_read (&sh->SegmentLength, sizeof (WORD), 1, fp, 0);
d_read (&sh->Flags, sizeof (WORD), 1, fp, 0);
d_read (&sh->AllocationSize, sizeof (WORD), 1, fp, 0);
}
void
ne_get_file_info (struct file_info *fi)
{
int k, n_code = 0, n_data = 0;
WORD ne_header_pos, sector_size;
DWORD addr;
struct ne_file_header nh;
fi->bit_size = BS_16;
fi->arch = MT_IA32;
fi->endian = BO_LITTLE_ENDIAN;
/* position at NE header */
fseek (fi->fp, NE_POS_HEADER_OFFSET, SEEK_SET);
d_read (&ne_header_pos, sizeof (WORD), 1, fi->fp, 0);
fseek (fi->fp, ne_header_pos, SEEK_SET);
read_ne_header (&nh, fi->fp);
addr = fi->load_address = NE_MAKE_REAL_ADDRESS (nh.CS, nh.IP);
sector_size = 1 << nh.Alignment;
fi->data_sections = xmalloc ((nh.SegmentTableEntries + 1)
* sizeof (struct section_info *));
fi->code_sections = xmalloc ((nh.SegmentTableEntries + 1)
* sizeof (struct section_info *));
fseek (fi->fp, ne_header_pos + nh.SegmentTableOffset, SEEK_SET);
for (k = 0; k < nh.SegmentTableEntries; k++)
{
char *section_name;
WORD segment_size, loaded_segment_size;
char *flags;
struct ne_segment_header sh;
ne_read_segment_header (&sh, fi->fp);
/* NE doesn't have section names, so we create an arbitrary name */
section_name = xmalloc (18);
segment_size = sh.SegmentLength ? sh.SegmentLength : 0xffff;
loaded_segment_size = sh.AllocationSize ? sh.AllocationSize : 0xffff;
flags = "";
if (NE_DATA_SEGMENT (sh.Flags))
{
snprintf (section_name, 18, ".dataSection%d", n_data);
if (debug)
printf ("read data segment, idx %#x, offset %#x, size %#x\n", k,
sh.SegmentDataSectorOffset * sector_size, segment_size);
fi->data_sections[n_data] = alloc_section_info (section_name,
DATA_SECTION,
sh.SegmentDataSectorOffset * sector_size,
segment_size,
0, k, addr,
NULL, flags,
nh.Alignment);
put_data_limits (addr, addr + loaded_segment_size);
n_data++;
}
else if (NE_CODE_SEGMENT (sh.Flags))
{
snprintf (section_name, 18, ".codeSection%d", n_code);
if (debug)
printf ("read code segment, idx %#x, offset %#x, size %#x\n", k,
sh.SegmentDataSectorOffset * sector_size, segment_size);
fi->code_sections[n_code] = alloc_section_info (section_name,
CODE_SECTION,
sh.SegmentDataSectorOffset * sector_size,
segment_size,
0, k, addr,
NULL, flags,
nh.Alignment);
n_code++;
}
/* guess start address of next section */
addr = ((addr >> nh.Alignment) + 1) << nh.Alignment;
}
/* struct section_info *symtab; */
fi->symtab = NULL;
/* struct section_info *strtab; */
fi->strtab = NULL;
}
char *
ne_read_strtab (struct file_info *fi)
{
return NULL;
}
struct symtab *
ne_get_next_symbol (struct file_info *fi, char *strtab)
{
return NULL;
}
/* PE (Win32 Portable Executable) section */
char *pe_flags[] = {
"", /* no flags */
", \"w\"", /* writeable */
", \"x\"", /* executable */
", \"xw\"", /* executable and writeable */
};
char *
pe_get_flags (DWORD flags)
{
int index = 0;
index |= ((flags & IMAGE_SCN_MEM_WRITE) ? 1 : 0);
index |= ((flags & IMAGE_SCN_MEM_EXECUTE) ? 2 : 0);
return pe_flags[index];
}
int
pe_get_align (DWORD flags)
{
return 1 << (((flags >> 20) & 0xf) - 1);
}
void
read_pe_header (PCOFF_HEADER ch, FILE *fp)
{
d_read (&ch->PeSignature, sizeof (char), 4, fp, 1);
d_read (&ch->Machine, sizeof (WORD), 1, fp, 0);
d_read (&ch->NumberOfSections, sizeof (WORD), 1, fp, 0);
d_read (&ch->TimeDateStamp, sizeof (DWORD), 1, fp, 0);
d_read (&ch->PointerToSymbolTable, sizeof (DWORD), 1, fp, 0);
d_read (&ch->NumberOfSymbols, sizeof (DWORD), 1, fp, 0);
d_read (&ch->SizeOfOptionalHeader, sizeof (WORD), 1, fp, 0);
d_read (&ch->Characteristics, sizeof (WORD), 1, fp, 0);
}
void
read_pe_optional_header (PPE32_OPTIONAL_HEADER oh, FILE *fp, WORD oh_size)
{
WORD size = 0;
d_read (&oh->Magic, sizeof (WORD), 1, fp, 0);
size += sizeof (WORD);
d_read (&oh->MajorLinkerVersion, sizeof (BYTE), 1, fp, 0);
size += sizeof (BYTE);
d_read (&oh->MinorLinkerVersion, sizeof (BYTE), 1, fp, 0);
size += sizeof (BYTE);
d_read (&oh->SizeOfCode, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
d_read (&oh->SizeOfInitializedData, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
d_read (&oh->SizeOfUninitializedData, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
d_read (&oh->AddressOfEntryPoint, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
d_read (&oh->BaseOfCode, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
if (oh->Magic == PE32_MAGIC)
{
d_read (&oh->BaseOfData, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
}
else
oh->BaseOfData = 0;
if (oh->Magic == PE32_MAGIC)
{
d_read (&oh->ImageBase, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
}
else
{
QWORD temp;
d_read (&temp, sizeof (QWORD), 1, fp, 0);
size += sizeof (QWORD);
oh->ImageBase = (DWORD) temp;
}
d_read (&oh->SectionAlignment, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
d_read (&oh->FileAlignment, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
d_read (&oh->MajorOperatingSystemVersion, sizeof (WORD), 1, fp, 0);
size += sizeof (WORD);
d_read (&oh->MinorOperatingSystemVersion, sizeof (WORD), 1, fp, 0);
size += sizeof (WORD);
d_read (&oh->MajorImageVersion, sizeof (WORD), 1, fp, 0);
size += sizeof (WORD);
d_read (&oh->MinorImageVersion, sizeof (WORD), 1, fp, 0);
size += sizeof (WORD);
d_read (&oh->MajorSubsystemVersion, sizeof (WORD), 1, fp, 0);
size += sizeof (WORD);
d_read (&oh->MinorSubsystemVersion, sizeof (WORD), 1, fp, 0);
size += sizeof (WORD);
d_read (&oh->Reserved, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
d_read (&oh->SizeOfImage, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
d_read (&oh->SizeOfHeaders, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
d_read (&oh->CheckSum, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
d_read (&oh->Subsystem, sizeof (WORD), 1, fp, 0);
size += sizeof (WORD);
d_read (&oh->DLLCharacteristics, sizeof (WORD), 1, fp, 0);
size += sizeof (WORD);
if (oh->Magic == PE32_MAGIC)
{
d_read (&oh->SizeOfStackReserve, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
}
else
{
QWORD temp;
d_read (&temp, sizeof (QWORD), 1, fp, 0);
size += sizeof (QWORD);
oh->SizeOfStackReserve = (DWORD) temp;
}
if (oh->Magic == PE32_MAGIC)
{
d_read (&oh->SizeOfStackCommit, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
}
else
{
QWORD temp;
d_read (&temp, sizeof (QWORD), 1, fp, 0);
size += sizeof (QWORD);
oh->SizeOfStackCommit = (DWORD) temp;
}
if (oh->Magic == PE32_MAGIC)
{
d_read (&oh->SizeOfHeapReserve, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
}
else
{
QWORD temp;
d_read (&temp, sizeof (QWORD), 1, fp, 0);
size += sizeof (QWORD);
oh->SizeOfHeapReserve = (DWORD) temp;
}
if (oh->Magic == PE32_MAGIC)
{
d_read (&oh->SizeOfHeapCommit, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
}
else
{
QWORD temp;
d_read (&temp, sizeof (QWORD), 1, fp, 0);
size += sizeof (QWORD);
oh->SizeOfHeapCommit = (DWORD) temp;
}
d_read (&oh->LoaderFlags, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
d_read (&oh->NumberOfRvaAndSizes, sizeof (DWORD), 1, fp, 0);
size += sizeof (DWORD);
}
void
read_oh_data_directories (IMAGE_DATA_DIRECTORY idd[N_OHDD], FILE *fp,
DWORD n_dd)
{
int k;
for (k = 0; k < n_dd; k++)
{
d_read (&idd[k].RVA, sizeof (DWORD), 1, fp, 0);
d_read (&idd[k].Size, sizeof (DWORD), 1, fp, 0);
}
}
void
read_pe_section_header (PSECTION_HEADER sh, FILE *fp)
{
d_read (sh->Name, sizeof (char), 8, fp, 1);
d_read (&sh->VirtualSize, sizeof (DWORD), 1, fp, 0);
d_read (&sh->VirtualAddress, sizeof (DWORD), 1, fp, 0);
d_read (&sh->SizeOfRawData, sizeof (DWORD), 1, fp, 0);
d_read (&sh->PointerToRawData, sizeof (DWORD), 1, fp, 0);
d_read (&sh->PointerToRelocations, sizeof (DWORD), 1, fp, 0);
d_read (&sh->PointerToLinenumbers, sizeof (DWORD), 1, fp, 0);
d_read (&sh->NumberOfRelocations, sizeof (WORD), 1, fp, 0);
d_read (&sh->NumberOfLinenumbers, sizeof (WORD), 1, fp, 0);
d_read (&sh->Characteristics, sizeof (DWORD), 1, fp, 0);
}
char *
get_pe_name (char *raw_name)
{
char *name;
int count;
for (count = 0; count < 8; count++)
if (!raw_name[count]) break;
name = xmalloc (count + 1);
memcpy (name, raw_name, count);
return name;
}
void
pe_get_file_info (struct file_info *fi)
{
int n_code = 0, n_data = 0, k;
char *section_name;
DWORD pe_header_location;
COFF_HEADER ch;
PE32_OPTIONAL_HEADER oh;
SECTION_HEADER sh;
IMAGE_DATA_DIRECTORY idd[N_OHDD];
/* find the PE header */
fseek (fi->fp, PE_HEADER_OFFSET, SEEK_SET);
d_read (&pe_header_location, sizeof (DWORD), 1, fi->fp, 0);
fseek (fi->fp, pe_header_location, SEEK_SET);
read_pe_header (&ch, fi->fp);
switch (ch.Machine)
{
case IMAGE_FILE_MACHINE_ALPHA:
fi->arch = MT_ALPHA;
break;
case IMAGE_FILE_MACHINE_I386:
fi->arch = MT_IA32;
break;
default:
fi->arch = MT_UNK;
}
if (ch.Characteristics & IMAGE_FILE_BYTES_REVERSED_LO)
fi->endian = BO_LITTLE_ENDIAN;
else if (ch.Characteristics & IMAGE_FILE_BYTES_REVERSED_HI)
fi->endian = BO_BIG_ENDIAN;
if (ch.Characteristics & IMAGE_FILE_32BIT_MACHINE)
fi->bit_size = BS_32;
else if (ch.Characteristics & IMAGE_FILE_16BIT_MACHINE) /* won't see this */
fi->bit_size = BS_16;
else
fi->bit_size = BS_64;
/* handle symbol table and string table */
if (ch.PointerToSymbolTable)
{
long file_pos;
uint32_t strtab_size;
fi->symtab = alloc_section_info (".symtab", OTHER_SECTION,
ch.PointerToSymbolTable,
ch.NumberOfSymbols * SIZE_SYMBOL_TABLE,
SIZE_SYMBOL_TABLE, 0, 0, NULL,
NULL, 0);
/* read the size of the string table */
file_pos = ftell (fi->fp);
fseek (fi->fp, (ch.PointerToSymbolTable + (ch.NumberOfSymbols
* SIZE_SYMBOL_TABLE)),
SEEK_SET);
d_read (&strtab_size, sizeof (uint32_t), 1, fi->fp, 0);
fseek (fi->fp, file_pos, SEEK_SET);
strtab_size -= 4;
fi->strtab = alloc_section_info (".strtab", STRING_SECTION,
(ch.PointerToSymbolTable
+ (ch.NumberOfSymbols
* SIZE_SYMBOL_TABLE)) + 4,
strtab_size, 0, 0, 0, NULL, NULL, 0);
}
oh.NumberOfRvaAndSizes = 0;
read_pe_optional_header (&oh, fi->fp, ch.SizeOfOptionalHeader);
read_oh_data_directories (idd, fi->fp, oh.NumberOfRvaAndSizes);
/* find load address */
fi->load_address = oh.ImageBase + oh.AddressOfEntryPoint;
/* should be pointing at the section headers here */
fi->data_sections = xmalloc ((ch.NumberOfSections + 1)
* sizeof (struct section_info));
fi->code_sections = xmalloc ((ch.NumberOfSections + 1)
* sizeof (struct section_info));
for (k = 1; k < ch.NumberOfSections + 1; k++)
{
read_pe_section_header (&sh, fi->fp);
section_name = get_pe_name (sh.Name);
if (debug)
printf ("read %s, idx %#x, offset %#x\n", section_name, k,
sh.PointerToRawData);
if (sh.Characteristics & IMAGE_SCN_CNT_CODE) /* code section */
{
fi->code_sections[n_code] = alloc_section_info (section_name,
CODE_SECTION,
sh.PointerToRawData,
sh.SizeOfRawData,
0, k,
oh.ImageBase
+ sh.VirtualAddress,
NULL,
pe_get_flags (sh.Characteristics),
pe_get_align (sh.Characteristics));
n_code++;
put_data_limits (oh.ImageBase + sh.VirtualAddress,
oh.ImageBase + sh.VirtualAddress + sh.VirtualSize);
}
else if (sh.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA
|| sh.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
{
fi->data_sections[n_data] = alloc_section_info (section_name,
DATA_SECTION,
sh.PointerToRawData,
sh.SizeOfRawData,
0, k,
oh.ImageBase
+ sh.VirtualAddress,
NULL,
pe_get_flags (sh.Characteristics),
pe_get_align (sh.Characteristics));
n_data++;
put_data_limits (oh.ImageBase + sh.VirtualAddress,
oh.ImageBase + sh.VirtualAddress + sh.VirtualSize);
}
else /* not sure what this section could be */
{
if (debug)
printf ("unknown section: %s, flags: %08X\n", section_name,
sh.Characteristics);
xfree (section_name);
}
}
/* print debug info */
if (debug)
{
k = -1;
printf ("data:\n");
while (fi->data_sections[++k])
{
printf (" %s (%#lx), %d, %#lx, %#lx, %#lx\n",
fi->data_sections[k]->section_name,
fi->data_sections[k]->section_index,
fi->data_sections[k]->section_type,
fi->data_sections[k]->section_offset,
fi->data_sections[k]->section_size,
fi->data_sections[k]->load_address);
}
k = -1;
printf ("code:\n");
while (fi->code_sections[++k])
{
printf (" %s (%#lx), %d, %#lx, %#lx, %#lx\n",
fi->code_sections[k]->section_name,
fi->code_sections[k]->section_index,
fi->code_sections[k]->section_type,
fi->code_sections[k]->section_offset,
fi->code_sections[k]->section_size,
fi->code_sections[k]->load_address);
}
if (fi->symtab != NULL)
printf ("symtab:\n %s (%#lx), %d, %#lx, %#lx, %#lx\n",
fi->symtab->section_name,
fi->symtab->section_index,
fi->symtab->section_type,
fi->symtab->section_offset,
fi->symtab->section_size,
fi->symtab->load_address);
if (fi->strtab != NULL)
printf ("strtab:\n %s (%#lx), %d, %#lx, %#lx, %#lx\n",
fi->strtab->section_name,
fi->strtab->section_index,
fi->strtab->section_type,
fi->strtab->section_offset,
fi->strtab->section_size,
fi->strtab->load_address);
}
}
char *
pe_read_strtab (struct file_info *fi)
{
char *strtab;
if (fi->strtab == NULL) return NULL;
fseek (fi->fp, fi->strtab->section_offset, SEEK_SET);
strtab = xmalloc (fi->strtab->section_size);
d_read (strtab, sizeof (char), fi->strtab->section_size, fi->fp, 1);
return strtab;
}
/* pe_read_symbol
* Read a symbol from the symbol table.
*/
void
pe_read_symbol (PCOFF_SYMBOL_TABLE sym, FILE *fp)
{
DWORD temp;
d_read (&temp, sizeof (DWORD), 1, fp, 0);
fseek (fp, -4, SEEK_CUR);
if (temp != 0)
d_read (sym->Name.ShortName, sizeof (char), 8, fp, 1);
else
{
d_read (&sym->Name.LongName.Zeroes, sizeof (DWORD), 1, fp, 0);
d_read (&sym->Name.LongName.Offset, sizeof (DWORD), 1, fp, 0);
}
d_read (&sym->Value, sizeof (DWORD), 1, fp, 0);
d_read (&sym->SectionNumber, sizeof (WORD), 1, fp, 0);
d_read (&sym->Type, sizeof (WORD), 1, fp, 0);
d_read (&sym->StorageClass, sizeof (BYTE), 1, fp, 0);
d_read (&sym->NumberOfAuxSymbols, sizeof (BYTE), 1, fp, 0);
}
/* pe_read_aux_format_one
* Read in function definition information.
*/
void
pe_read_aux_format_one (PAUXILIARY_FORMAT_ONE af, FILE *fp)
{
d_read (&af->TagIndex, sizeof (DWORD), 1, fp, 0);
d_read (&af->TotalSize, sizeof (DWORD), 1, fp, 0);
d_read (&af->PointerToLinenumber, sizeof (DWORD), 1, fp, 0);
d_read (&af->PointerToNextFunction, sizeof (DWORD), 1, fp, 0);
d_read (&af->Unused, sizeof (BYTE), 2, fp, 0);
}
/* pe_read_aux_format_two
* Read in information on the .bf and .ef symbols.
*/
void
pe_read_aux_format_two (PAUXILIARY_FORMAT_TWO af, FILE *fp)
{
d_read (&af->Unused1, sizeof (BYTE), 4, fp, 0);
d_read (&af->Linenumber, sizeof (WORD), 1, fp, 0);
d_read (&af->Unused2, sizeof (BYTE), 6, fp, 0);
d_read (&af->PointerToNextFunction, sizeof (DWORD), 1, fp, 0);
d_read (&af->Unused3, sizeof (BYTE), 2, fp, 0);
}
/* pe_read_aux_format_three
* Read in information on weak external symbols.
*/
void
pe_read_aux_format_three (PAUXILIARY_FORMAT_THREE af, FILE *fp)
{
d_read (&af->TagIndex, sizeof (DWORD), 1, fp, 0);
d_read (&af->Characteristics, sizeof (DWORD), 1, fp, 0);
d_read (&af->Unused, sizeof (BYTE), 10, fp, 0);
}
/* pe_read_aux_format_four
* Read in information on a .file symbol.
*/
void
pe_read_aux_format_four (PAUXILIARY_FORMAT_FOUR af, FILE *fp)
{
d_read (af->FileName, sizeof (char), 18, fp, 1);
}
/* pe_read_aux_format_five
* Read in section definition information.
*/
void
pe_read_aux_format_five (PAUXILIARY_FORMAT_FIVE af, FILE *fp)
{
d_read (&af->Length, sizeof (DWORD), 1, fp, 0);
d_read (&af->NumberOfRelocations, sizeof (WORD), 1, fp, 0);
d_read (&af->NumberOfLineNumbers, sizeof (WORD), 1, fp, 0);
d_read (&af->CheckSum, sizeof (DWORD), 1, fp, 0);
d_read (&af->Number, sizeof (WORD), 1, fp, 0);
d_read (&af->Selection, sizeof (BYTE), 1, fp, 0);
d_read (&af->Unused, sizeof (BYTE), 3, fp, 0);
}
enum symbol_type
pe_get_symbol_type (WORD type, BYTE class)
{
if (((type >> 4) & 0xf) == IMAGE_SYM_DTYPE_FUNCTION) /* function */
{
if (class == IMAGE_SYM_CLASS_EXTERNAL)
return GLOBAL_FUNCTION;
else
return LOCAL_FUNCTION;
}
else /* data */
{
if (class == IMAGE_SYM_CLASS_EXTERNAL)
return GLOBAL_DATA;
else
return LOCAL_DATA;
}
return UNKNOWN_SYMBOL;
}
/* pe_get_next_symbol
* Read in the next symbol from the symbol table and return
* it as a struct symtab.
*/
struct symtab *
pe_get_next_symbol (struct file_info *fi, char *strtab)
{
struct symtab *sym;
COFF_SYMBOL_TABLE symbol;
sym = xmalloc (sizeof (struct symtab));
pe_read_symbol (&symbol, fi->fp);
/* get the symbol name */
if (symbol.Name.LongName.Zeroes != 0)
sym->name = get_pe_name (symbol.Name.ShortName);
else
{
sym->name = xmalloc (strlen (strtab + symbol.Name.LongName.Offset) + 1);
strcpy (sym->name, strtab + symbol.Name.LongName.Offset);
}
sym->address = symbol.Value; /* most likely */
if (symbol.SectionNumber < 1)
{
sym->address = 0;
sym->idx = 0;
}
else
sym->idx = symbol.SectionNumber;
/* if this is an external or static symbol, the load address is
the Value added to the load address of the section */
if (symbol.StorageClass == IMAGE_SYM_CLASS_EXTERNAL
|| symbol.StorageClass == IMAGE_SYM_CLASS_STATIC)
{
if (symbol.SectionNumber > 0)
{
/* need to find the section with the matching number */
int k;
for (k = 0; fi->code_sections[k] != NULL; k++)
if (fi->code_sections[k]->section_index == symbol.SectionNumber)
{
sym->address = (fi->code_sections[k]->load_address
+ symbol.Value);
goto GOT_SECTION_NUMBER;
}
for (k = 0; fi->data_sections[k] != NULL; k++)
if (fi->data_sections[k]->section_index == symbol.SectionNumber)
sym->address = (fi->data_sections[k]->load_address
+ symbol.Value);
GOT_SECTION_NUMBER:
;
}
}
sym->type = pe_get_symbol_type (symbol.Type, symbol.StorageClass);
switch (symbol.Type & 0xf)
{
case IMAGE_SYM_TYPE_CHAR:
case IMAGE_SYM_TYPE_BYTE:
sym->size = 1;
break;
case IMAGE_SYM_TYPE_SHORT:
sym->size = 2;
break;
case IMAGE_SYM_TYPE_INT:
case IMAGE_SYM_TYPE_LONG:
case IMAGE_SYM_TYPE_FLOAT:
case IMAGE_SYM_TYPE_UINT:
case IMAGE_SYM_TYPE_DWORD:
sym->size = 4;
break;
case IMAGE_SYM_TYPE_DOUBLE:
sym->size = 8;
break;
default:
sym->size = 0;
}
if (sym->size == 0 && ((symbol.Type >> 4) & 0xf) == IMAGE_SYM_DTYPE_POINTER)
{
if (fi->bit_size == BS_32)
sym->size = 4;
else if (fi->bit_size == BS_64)
sym->size = 8;
}
/* auxiliary data isn't necessarily used */
fseek (fi->fp, 18 * symbol.NumberOfAuxSymbols, SEEK_CUR);
if (debug)
printf ("%#lx:%s: size %lx, type %x, class %x, idx %lx\n", sym->address,
sym->name, sym->size, symbol.Type, symbol.StorageClass, sym->idx);
return sym;
}