update to ida 7.6, add builds
This commit is contained in:
724
idasdk76/ldr/aof/aof.cpp
Normal file
724
idasdk76/ldr/aof/aof.cpp
Normal file
@@ -0,0 +1,724 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-97 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@estar.msk.su
|
||||
* FIDO: 2:5020/209
|
||||
*
|
||||
* ARM Object File Loader
|
||||
* ----------------------
|
||||
* This module allows IDA to load ARM object files into
|
||||
* its database and to disassemble them correctly.
|
||||
*
|
||||
* NOTE 1: for the moment only B/BL instruction relocations are
|
||||
* supported. I cannot find other relocation examples so
|
||||
* they are not implemented yet.
|
||||
*
|
||||
* NOTE 2: Thumb modules are not supported.
|
||||
*
|
||||
* This module automatically detects the byte sex and sets inf.mf
|
||||
* variable accrodingly.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../idaldr.h"
|
||||
#include "aof.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
NORETURN static void nomem(void)
|
||||
{
|
||||
nomem("AOF loader");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void *read_chunk(linput_t *li, const chunk_entry_t &ce)
|
||||
{
|
||||
void *chunk = qalloc_array<char>(ce.size);
|
||||
if ( chunk == NULL )
|
||||
nomem();
|
||||
qlseek(li, ce.file_offset);
|
||||
lread(li, chunk, ce.size);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void check_chunk_ptr(
|
||||
const chunk_entry_t &ce,
|
||||
const void *chunkstart,
|
||||
const void *chunkptr,
|
||||
size_t ptrsize)
|
||||
{
|
||||
const char *p0 = (const char*)chunkstart;
|
||||
const char *p1 = (const char*)chunkptr;
|
||||
if ( p1 < p0 || p1 + ptrsize < p0 || (p1 + ptrsize - p0) > ce.size )
|
||||
loader_failure("Corrupted file");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void check_chunk_str(
|
||||
const chunk_entry_t &ce,
|
||||
const void *chunkstart,
|
||||
const void *chunkptr)
|
||||
{
|
||||
const char *p0 = (const char*)chunkstart;
|
||||
const char *p1 = (const char*)chunkptr;
|
||||
if ( p1 >= p0 )
|
||||
{
|
||||
const char *chunk_end = p0 + ce.size;
|
||||
while ( p1 < chunk_end )
|
||||
{
|
||||
if ( *p1 == '\0' )
|
||||
return;
|
||||
++p1;
|
||||
}
|
||||
}
|
||||
loader_failure("Corrupted file");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// check input file format. if recognized, then return 1
|
||||
// and fill 'fileformatname'.
|
||||
// otherwise return 0
|
||||
//
|
||||
static int idaapi accept_file(
|
||||
qstring *fileformatname,
|
||||
qstring *processor,
|
||||
linput_t *li,
|
||||
const char *)
|
||||
{
|
||||
chunk_header_t hd;
|
||||
if ( qlread(li, &hd, sizeof(hd)) != sizeof(hd) )
|
||||
return 0;
|
||||
if ( hd.ChunkFileId != AOF_MAGIC && hd.ChunkFileId != AOF_MAGIC_B )
|
||||
return 0;
|
||||
if ( hd.num_chunks > hd.max_chunks )
|
||||
return 0;
|
||||
|
||||
*fileformatname = "ARM Object File";
|
||||
*processor = "arm";
|
||||
return 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void create32(
|
||||
sel_t sel,
|
||||
ea_t start_ea,
|
||||
ea_t end_ea,
|
||||
const char *name,
|
||||
const char *classname)
|
||||
{
|
||||
set_selector(sel, 0);
|
||||
|
||||
segment_t s;
|
||||
s.sel = sel;
|
||||
s.start_ea = start_ea;
|
||||
s.end_ea = end_ea;
|
||||
s.align = saRelByte;
|
||||
s.comb = scPub;
|
||||
s.bitness = 1; // 32-bit
|
||||
|
||||
if ( !add_segm_ex(&s, name, classname, ADDSEG_NOSREG|ADDSEG_SPARSE) )
|
||||
loader_failure();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static ea_t get_area_base(int idx)
|
||||
{
|
||||
segment_t *s = get_segm_by_sel(idx+1);
|
||||
if ( s == NULL )
|
||||
return BADADDR;
|
||||
return s->start_ea;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static ea_t find_area(
|
||||
const chunk_entry_t &ce,
|
||||
const area_header_t *ah,
|
||||
int maxarea,
|
||||
const char *strings,
|
||||
const char *areaname)
|
||||
{
|
||||
for ( int i=0; i < maxarea; i++, ah++ )
|
||||
{
|
||||
const char *name = strings + size_t(ah->name);
|
||||
check_chunk_str(ce, strings, name);
|
||||
if ( streq(name, areaname) )
|
||||
return get_area_base(i);
|
||||
}
|
||||
return BADADDR;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static ea_t create_spec_seg(
|
||||
int *nsegs,
|
||||
int nelem,
|
||||
const char *name,
|
||||
uchar seg_type)
|
||||
{
|
||||
ea_t ea = BADADDR;
|
||||
if ( nelem != 0 )
|
||||
{
|
||||
nelem *= 4;
|
||||
ea = free_chunk(inf_get_max_ea(), nelem, 0xFFF);
|
||||
(*nsegs)++;
|
||||
create32(*nsegs, ea, ea+nelem, name, CLASS_DATA);
|
||||
segment_t *s = getseg(ea);
|
||||
s->type = seg_type;
|
||||
s->update();
|
||||
set_arm_segm_flags(s->start_ea, 2 << SEGFL_SHIFT); // alignment
|
||||
}
|
||||
return ea;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void process_name(ea_t ea, const char *name, uint32 flags, bool iscode)
|
||||
{
|
||||
// ignore aux names -- they hinder data creation
|
||||
if ( strstr(name, "$litpool_e$") != NULL )
|
||||
return;
|
||||
if ( flags & SF_PUB )
|
||||
{
|
||||
add_entry(ea, ea, name, iscode, AEF_IDBENC);
|
||||
make_name_public(ea);
|
||||
}
|
||||
else
|
||||
{
|
||||
force_name(ea, name, SN_IDBENC);
|
||||
}
|
||||
if ( flags & SF_WEAK )
|
||||
make_name_weak(ea);
|
||||
if ( flags & SF_ICASE )
|
||||
add_extra_cmt(ea, true, "Case-insensitive label");
|
||||
if ( flags & SF_STRNG )
|
||||
add_extra_cmt(ea, true, "Strong name");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void reloc_insn(ea_t ea, uint32 rvalue, uint32 type)
|
||||
{
|
||||
uint32 code = get_dword(ea);
|
||||
switch ( (code >> 24) & 0xF )
|
||||
{
|
||||
case 0x0A: // B
|
||||
case 0x0B: // BL
|
||||
{
|
||||
int32 off = code & 0x00FFFFFFL;
|
||||
if ( off & 0x00800000L )
|
||||
off |= ~0x00FFFFFFL; // extend sign
|
||||
off <<= 2;
|
||||
off += rvalue;
|
||||
off >>= 2;
|
||||
off &= 0xFFFFFFL;
|
||||
code &= 0xFF000000L;
|
||||
code |= off;
|
||||
put_dword(ea, code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
warning("This relocation type is not implemented yet\n"
|
||||
"\3%a: reloc insn rvalue=%x, rt=%lx", ea, rvalue,
|
||||
type & RF_II);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void swap_chunk_entry(chunk_entry_t *ce)
|
||||
{
|
||||
ce->file_offset = swap32(ce->file_offset);
|
||||
ce->size = swap32(ce->size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void swap_aof_header(aof_header_t *ahd)
|
||||
{
|
||||
ahd->obj_file_type = swap32(ahd->obj_file_type);
|
||||
ahd->version = swap32(ahd->version);
|
||||
ahd->num_areas = swap32(ahd->num_areas);
|
||||
ahd->num_syms = swap32(ahd->num_syms);
|
||||
ahd->entry_area = swap32(ahd->entry_area);
|
||||
ahd->entry_offset = swap32(ahd->entry_offset);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void swap_area_header(area_header_t *ah)
|
||||
{
|
||||
ah->name = swap32(ah->name);
|
||||
ah->flags = swap32(ah->flags);
|
||||
ah->size = swap32(ah->size);
|
||||
ah->num_relocs = swap32(ah->num_relocs);
|
||||
ah->baseaddr = swap32(ah->baseaddr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void swap_sym(sym_t *s)
|
||||
{
|
||||
s->name = swap32(s->name);
|
||||
s->flags = swap32(s->flags);
|
||||
s->value = swap32(s->value);
|
||||
s->area = swap32(s->area);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// load file into the database.
|
||||
//
|
||||
void idaapi load_file(linput_t *li, ushort /*neflag*/, const char * /*fileformatname*/)
|
||||
{
|
||||
int i;
|
||||
chunk_header_t hd;
|
||||
set_processor_type("arm", SETPROC_LOADER);
|
||||
lread(li, &hd, sizeof(hd));
|
||||
if ( hd.ChunkFileId == AOF_MAGIC_B ) // BIG ENDIAN
|
||||
{
|
||||
inf_set_be(true);
|
||||
hd.max_chunks = swap32(hd.max_chunks);
|
||||
hd.num_chunks = swap32(hd.num_chunks);
|
||||
}
|
||||
|
||||
validate_array_count_or_die(li, hd.max_chunks, sizeof(chunk_entry_t), "Number of chunks");
|
||||
chunk_entry_t *ce = qalloc_array<chunk_entry_t>(size_t(hd.max_chunks));
|
||||
if ( ce == NULL )
|
||||
nomem();
|
||||
lread(li, ce, sizeof(chunk_entry_t)*size_t(hd.max_chunks));
|
||||
if ( inf_is_be() )
|
||||
for ( i=0; i < hd.max_chunks; i++ )
|
||||
swap_chunk_entry(ce+i);
|
||||
|
||||
int head = -1; // AOF Header
|
||||
int area = -1; // Areas
|
||||
int idfn = -1; // Identification
|
||||
int symt = -1; // Symbol Table
|
||||
int strt = -1; // String Table
|
||||
|
||||
for ( i=0; i < hd.max_chunks; i++ )
|
||||
{
|
||||
if ( ce[i].file_offset == 0 )
|
||||
continue;
|
||||
if ( strneq(ce[i].chunkId, OBJ_HEAD, sizeof(ce[i].chunkId)) )
|
||||
head = i;
|
||||
if ( strneq(ce[i].chunkId, OBJ_AREA, sizeof(ce[i].chunkId)) )
|
||||
area = i;
|
||||
if ( strneq(ce[i].chunkId, OBJ_IDFN, sizeof(ce[i].chunkId)) )
|
||||
idfn = i;
|
||||
if ( strneq(ce[i].chunkId, OBJ_SYMT, sizeof(ce[i].chunkId)) )
|
||||
symt = i;
|
||||
if ( strneq(ce[i].chunkId, OBJ_STRT, sizeof(ce[i].chunkId)) )
|
||||
strt = i;
|
||||
}
|
||||
if ( head == -1 || area == -1 || strt == -1 || symt == -1 || idfn == -1 )
|
||||
{
|
||||
qfree(ce);
|
||||
loader_failure("One of required chunks is missing");
|
||||
}
|
||||
|
||||
char *strings = (char *)read_chunk(li, ce[strt]);
|
||||
aof_header_t *ahd = (aof_header_t *)read_chunk(li, ce[head]);
|
||||
check_chunk_ptr(ce[head], ahd, ahd, sizeof(aof_header_t));
|
||||
if ( inf_is_be() )
|
||||
swap_aof_header(ahd);
|
||||
|
||||
//
|
||||
// Areas
|
||||
//
|
||||
|
||||
area_header_t *ah = (area_header_t *)(ahd + 1);
|
||||
if ( inf_is_be() )
|
||||
{
|
||||
for ( i=0; i < ahd->num_areas; i++ )
|
||||
{
|
||||
check_chunk_ptr(ce[head], ahd, ah+i, sizeof(area_header_t));
|
||||
swap_area_header(ah+i);
|
||||
}
|
||||
}
|
||||
qoff64_t offset = ce[area].file_offset;
|
||||
inf_set_specsegs(inf_is_64bit() ? 8 : 4);
|
||||
ea_t ea = to_ea(inf_get_baseaddr(), 0);
|
||||
for ( i=0; i < ahd->num_areas; i++, ah++ )
|
||||
{
|
||||
check_chunk_ptr(ce[head], ahd, ah, sizeof(area_header_t));
|
||||
if ( ah->flags & AREA_DEBUG )
|
||||
{
|
||||
offset += ah->size;
|
||||
offset += qoff64_t(ah->num_relocs) * sizeof(reloc_t);
|
||||
continue;
|
||||
}
|
||||
if ( ah->flags & AREA_ABS )
|
||||
{
|
||||
ea = ah->baseaddr;
|
||||
if ( free_chunk(ea, ah->size, 1) != ea )
|
||||
error("Cannot allocate area at %a", ea);
|
||||
}
|
||||
else
|
||||
{
|
||||
ea = free_chunk(ea, ah->size, 0xFFF);
|
||||
}
|
||||
if ( (ah->flags & AREA_BSS) == 0 )
|
||||
{
|
||||
ea_t end = ea + ah->size;
|
||||
uint64 fsize = qlsize(li);
|
||||
if ( offset > fsize
|
||||
|| fsize-offset < ah->size
|
||||
|| end < ea )
|
||||
{
|
||||
loader_failure("Corrupted file");
|
||||
}
|
||||
file2base(li, offset, ea, end, FILEREG_PATCHABLE);
|
||||
offset += ah->size;
|
||||
}
|
||||
const char *name = strings + size_t(ah->name);
|
||||
check_chunk_str(ce[strt], strings, name);
|
||||
const char *classname;
|
||||
if ( ah->flags & AREA_CODE )
|
||||
classname = CLASS_CODE;
|
||||
else if ( ah->flags & (AREA_BSS|AREA_COMREF) )
|
||||
classname = CLASS_BSS;
|
||||
else
|
||||
classname = CLASS_DATA;
|
||||
create32(i+1, ea, ea+ah->size, name, classname);
|
||||
|
||||
segment_t *s = getseg(ea);
|
||||
ushort sflags = (ah->flags & 0x1F) << SEGFL_SHIFT; // alignment
|
||||
if ( ah->flags & AREA_BASED )
|
||||
sflags |= (SEGFL_BASED|ah->get_based_reg());
|
||||
if ( ah->flags & AREA_PIC )
|
||||
sflags |= SEGFL_PIC;
|
||||
if ( ah->flags & AREA_REENTR )
|
||||
sflags |= SEGFL_REENTR;
|
||||
if ( ah->flags & AREA_HALFW )
|
||||
sflags |= SEGFL_HALFW;
|
||||
if ( ah->flags & AREA_INTER )
|
||||
sflags |= SEGFL_INTER;
|
||||
if ( ah->flags & AREA_COMMON )
|
||||
sflags |= SEGFL_COMDEF;
|
||||
if ( ah->flags & (AREA_COMMON|AREA_COMREF) )
|
||||
s->comb = scCommon;
|
||||
if ( ah->flags & AREA_RDONLY )
|
||||
s->perm = SEGPERM_READ;
|
||||
if ( ah->flags & AREA_ABS )
|
||||
s->align = saAbs;
|
||||
s->update();
|
||||
set_arm_segm_flags(s->start_ea, sflags);
|
||||
|
||||
if ( i == 0 )
|
||||
{
|
||||
create_filename_cmt();
|
||||
char *id = (char *)read_chunk(li, ce[idfn]);
|
||||
check_chunk_str(ce[idfn], id, id);
|
||||
add_pgm_cmt("Translator : %s", id);
|
||||
qfree(id);
|
||||
}
|
||||
|
||||
if ( ah->flags & AREA_CODE )
|
||||
{
|
||||
if ( (ah->flags & AREA_32BIT) == 0 )
|
||||
add_pgm_cmt("The 26-bit area");
|
||||
if ( (ah->flags & AREA_EXTFP) != 0 )
|
||||
add_pgm_cmt("Extended FP instructions are used");
|
||||
if ( (ah->flags & AREA_NOCHK) != 0 )
|
||||
add_pgm_cmt("No Software Stack Check");
|
||||
if ( (ah->flags & AREA_THUMB) != 0 )
|
||||
add_pgm_cmt("Thumb code area");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (ah->flags & AREA_SHARED) != 0 )
|
||||
add_pgm_cmt("Shared Library Stub Data");
|
||||
}
|
||||
ea += ah->size;
|
||||
offset += qoff64_t(ah->num_relocs) * sizeof(reloc_t);
|
||||
}
|
||||
int nsegs = i;
|
||||
|
||||
//
|
||||
// Symbol Table
|
||||
//
|
||||
|
||||
ah = (area_header_t *)(ahd + 1);
|
||||
uint32 *delta = qalloc_array<uint32>(size_t(ahd->num_syms));
|
||||
if ( delta == NULL )
|
||||
nomem();
|
||||
memset(delta, 0, sizeof(uint32)*size_t(ahd->num_syms));
|
||||
sym_t *syms = (sym_t *)read_chunk(li, ce[symt]);
|
||||
if ( inf_is_be() )
|
||||
{
|
||||
for ( i=0; i < ahd->num_syms; i++ )
|
||||
{
|
||||
check_chunk_ptr(ce[symt], syms, syms+i, sizeof(sym_t));
|
||||
swap_sym(syms+i);
|
||||
}
|
||||
}
|
||||
int n_undef = 0;
|
||||
int n_abs = 0;
|
||||
int n_comm = 0;
|
||||
|
||||
for ( i=0; i < ahd->num_syms; i++ )
|
||||
{
|
||||
sym_t *s = syms + i;
|
||||
check_chunk_ptr(ce[symt], syms, syms+i, sizeof(sym_t));
|
||||
if ( s->flags & SF_DEF )
|
||||
{
|
||||
if ( s->flags & SF_ABS )
|
||||
{
|
||||
n_abs++;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *areaname = strings + size_t(s->area);
|
||||
check_chunk_str(ce[strt], strings, areaname);
|
||||
ea_t areabase = find_area(ce[strt], ah, size_t(ahd->num_areas), strings, areaname);
|
||||
delta[i] = (uint32)areabase;
|
||||
ea_t symea = areabase + s->value;
|
||||
const char *name = strings + size_t(s->name);
|
||||
check_chunk_str(ce[strt], strings, name);
|
||||
if ( s->value == 0 && strcmp(areaname, name) == 0 )
|
||||
continue; // HACK!
|
||||
process_name(symea, name, s->flags, segtype(areabase) == SEG_CODE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (s->flags & SF_PUB) && (s->flags & SF_COMM) ) // ref to common
|
||||
n_comm++;
|
||||
else
|
||||
n_undef++;
|
||||
}
|
||||
}
|
||||
|
||||
ea_t abs_ea = create_spec_seg(&nsegs, n_abs, NAME_ABS, SEG_ABSSYM);
|
||||
ea_t undef_ea = create_spec_seg(&nsegs, n_undef, NAME_UNDEF, SEG_XTRN);
|
||||
ea_t comm_ea = create_spec_seg(&nsegs, n_comm, NAME_COMMON, SEG_COMM);
|
||||
if ( n_abs+n_undef+n_comm != 0 )
|
||||
{
|
||||
for ( i=0; i < ahd->num_syms; i++ )
|
||||
{
|
||||
sym_t *s = syms + i;
|
||||
const char *name = strings + size_t(s->name);
|
||||
check_chunk_str(ce[strt], strings, name);
|
||||
if ( s->flags & SF_DEF )
|
||||
{
|
||||
if ( s->flags & SF_ABS )
|
||||
{
|
||||
if ( inf_get_specsegs() == 8 )
|
||||
{
|
||||
put_qword(abs_ea, s->value);
|
||||
create_qword(abs_ea, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
put_dword(abs_ea, s->value);
|
||||
create_dword(abs_ea, 4);
|
||||
}
|
||||
process_name(abs_ea, name, s->flags, false);
|
||||
delta[i] = s->value;
|
||||
s->value = uint32(abs_ea - delta[i]);
|
||||
abs_ea += inf_get_specsegs();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (s->flags & SF_PUB) && (s->flags & SF_COMM) ) // ref to common
|
||||
{
|
||||
if ( inf_get_specsegs() == 8 )
|
||||
put_qword(comm_ea, s->value);
|
||||
else
|
||||
put_dword(comm_ea, s->value);
|
||||
process_name(comm_ea, name, s->flags, false);
|
||||
delta[i] = (uint32)comm_ea;
|
||||
comm_ea += inf_get_specsegs();
|
||||
}
|
||||
else
|
||||
{
|
||||
put_dword(undef_ea, 0xE1A0F00E); // RET
|
||||
process_name(undef_ea, name, s->flags, false);
|
||||
delta[i] = (uint32)undef_ea;
|
||||
undef_ea += inf_get_specsegs();
|
||||
}
|
||||
s->value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Relocations
|
||||
//
|
||||
|
||||
offset = ce[area].file_offset;
|
||||
for ( i=0; i < ahd->num_areas; i++, ah++ )
|
||||
{
|
||||
if ( ah->flags & AREA_DEBUG )
|
||||
{
|
||||
offset += ah->size;
|
||||
offset += qoff64_t(ah->num_relocs) * sizeof(reloc_t);
|
||||
continue;
|
||||
}
|
||||
if ( (ah->flags & AREA_BSS) == 0 )
|
||||
offset += ah->size;
|
||||
qlseek(li, offset);
|
||||
ea_t base = get_area_base(i);
|
||||
validate_array_count(li, &ah->num_relocs, sizeof(reloc_t), "Number of relocs", offset);
|
||||
for ( int j=0; j < ah->num_relocs; j++ )
|
||||
{
|
||||
reloc_t r;
|
||||
lread(li, &r, sizeof(reloc_t));
|
||||
if ( inf_is_be() )
|
||||
{
|
||||
r.type = swap32(r.type);
|
||||
r.offset = swap32(r.offset);
|
||||
}
|
||||
size_t sid = r.sid();
|
||||
ea_t rvalue;
|
||||
ea_t target;
|
||||
fixup_data_t fd;
|
||||
if ( r.type & RF_A )
|
||||
{
|
||||
if ( sid >= ahd->num_syms )
|
||||
loader_failure("Bad relocation record at file offset %" FMT_64 "x", qltell(li)-sizeof(reloc_t));
|
||||
rvalue = delta[sid];
|
||||
target = syms[sid].value + rvalue;
|
||||
fd.set_extdef();
|
||||
}
|
||||
else
|
||||
{
|
||||
rvalue = get_area_base((int)sid);
|
||||
target = rvalue;
|
||||
if ( rvalue == BADADDR )
|
||||
loader_failure("Bad reference to area %" FMT_Z " at file offset %" FMT_64 "x", sid, qltell(li)-sizeof(reloc_t));
|
||||
}
|
||||
segment_t *s = getseg(target);
|
||||
if ( s == NULL )
|
||||
loader_failure("Can't find area for relocation target %a at %" FMT_64 "x", target, qltell(li)-sizeof(reloc_t));
|
||||
fd.sel = s->sel;
|
||||
fd.off = target - get_segm_base(s);
|
||||
if ( (r.type & RF_R) != 0 )
|
||||
{
|
||||
if ( (r.type & RF_A) != 0 )
|
||||
{
|
||||
// R=1 B=0 or R=1 B=1
|
||||
// This specifies PC-relative relocation: to the subject field
|
||||
// is added the difference between the relocation value and
|
||||
// the base of the area containing the subject field.
|
||||
// In pseudo C:
|
||||
// subject_field = subject_field +
|
||||
// (relocation_value -
|
||||
// base_of_area_containing(subject_field))
|
||||
rvalue -= base;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// As a special case, if A is 0, and the relocation value is
|
||||
// specified as the base of the area containing the subject
|
||||
// field, it is not added and:
|
||||
// subject_field = subject_field -
|
||||
// base_of_area_containing(subject_field)
|
||||
// This caters for relocatable PC-relative branches to fixed
|
||||
// target addresses. If R is 1, B is usually 0. A B value of 1
|
||||
// is used to denote that the inter-link-unit value of a
|
||||
// branch destination is to be used, rather than the more
|
||||
// usual intra-link-unit value.
|
||||
rvalue = -base;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (r.type & RF_B) != 0 )
|
||||
{ // R=0 B=1
|
||||
// This specifies based area relocation. The relocation value
|
||||
// must be an address within a based data area. The subject
|
||||
// field is incremented by the difference between this value
|
||||
// and the base address of the consolidated based area group
|
||||
// (the linker consolidates all areas based on the same base
|
||||
// register into a single, contiguous region of the output
|
||||
// image). In pseudo C:
|
||||
// subject_field = subject_field +
|
||||
// (relocation_value -
|
||||
// base_of_area_group_containing(relocation_value))
|
||||
// For example, when generating re-entrant code, the C
|
||||
// compiler places address constants in an adcon area based
|
||||
// on register sb, and loads them using sb relative LDRs.
|
||||
// At link time, separate adcon areas will be merged and sb
|
||||
// will no longer point where presumed at compile time. B
|
||||
// type relocation of the LDR instructions corrects for this.
|
||||
rvalue -= get_area_base((int)sid);
|
||||
}
|
||||
else
|
||||
{ // R=0 B=0
|
||||
// This specifies plain additive relocation: the relocation
|
||||
// value is added to the subject field. In pseudo C:
|
||||
// subject_field = subject_field + relocation_value
|
||||
/* nothing to do */;
|
||||
}
|
||||
}
|
||||
ea_t relea = base + r.offset;
|
||||
switch ( r.type & RF_FT )
|
||||
{
|
||||
case RF_FT_BYTE: // 00 the field to be relocated is a byte
|
||||
fd.set_type(FIXUP_OFF8);
|
||||
fd.displacement = get_byte(relea);
|
||||
add_byte(relea, (uint32)rvalue);
|
||||
break;
|
||||
case RF_FT_HALF: // 01 the field to be relocated is a halfword (two bytes)
|
||||
fd.set_type(FIXUP_OFF16);
|
||||
fd.displacement = get_word(relea);
|
||||
add_word(relea, rvalue);
|
||||
break;
|
||||
case RF_FT_WORD: // 10 the field to be relocated is a word (four bytes)
|
||||
fd.set_type(FIXUP_OFF32);
|
||||
fd.displacement = get_dword(relea);
|
||||
add_dword(relea, rvalue);
|
||||
break;
|
||||
case RF_FT_INSN: // 11 the field to be relocated is an instruction or instruction sequence
|
||||
reloc_insn(relea, (uint32)rvalue, r.type);
|
||||
break;
|
||||
}
|
||||
fd.set(relea);
|
||||
}
|
||||
offset += qoff64_t(ah->num_relocs) * sizeof(reloc_t);
|
||||
}
|
||||
|
||||
if ( ahd->entry_area != 0 )
|
||||
{
|
||||
inf_set_start_cs(ahd->entry_area);
|
||||
inf_set_start_ip(ahd->entry_offset);
|
||||
inf_set_start_ea(ahd->entry_offset);
|
||||
}
|
||||
|
||||
qfree(syms);
|
||||
qfree(delta);
|
||||
qfree(ahd);
|
||||
qfree(strings);
|
||||
qfree(ce);
|
||||
inf_set_baseaddr(0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// LOADER DESCRIPTION BLOCK
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
loader_t LDSC =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
0, // loader flags
|
||||
//
|
||||
// check input file format. if recognized, then return 1
|
||||
// and fill 'fileformatname'.
|
||||
// otherwise return 0
|
||||
//
|
||||
accept_file,
|
||||
//
|
||||
// load file into the database.
|
||||
//
|
||||
load_file,
|
||||
//
|
||||
// create output file from the database.
|
||||
// this function may be absent.
|
||||
//
|
||||
NULL,
|
||||
// take care of a moved segment (fix up relocations, for example)
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
246
idasdk76/ldr/aof/aof.h
Normal file
246
idasdk76/ldr/aof/aof.h
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-97 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@estar.msk.su
|
||||
* FIDO: 2:5020/209
|
||||
*
|
||||
* ARM Object File Loader
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AOF_H__
|
||||
#define __AOF_H__
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct chunk_header_t
|
||||
{
|
||||
uint32 ChunkFileId;
|
||||
#define AOF_MAGIC 0xC3CBC6C5L // magic value of chunk file
|
||||
#define AOF_MAGIC_B 0xC5C6CBC3L // magic value of chunk file (big endian)
|
||||
uint32 max_chunks; // defines the number of the entries in the
|
||||
// header, fixed when the file is created.
|
||||
uint32 num_chunks; // defines how many chunks are currently used in
|
||||
// the file, which can vary from 0 to maxChunks.
|
||||
// It is redundant in that it can be found by scanning
|
||||
// the entries.
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct chunk_entry_t
|
||||
{
|
||||
char chunkId[8]; // an 8-byte field identifying what data the chunk
|
||||
// contains. Note that this is an 8-byte field, not
|
||||
// a 2-word field, so it has the same byte order
|
||||
// independent of endianness.
|
||||
#define OBJ_HEAD "OBJ_HEAD" // AOF Header
|
||||
#define OBJ_AREA "OBJ_AREA" // Areas
|
||||
#define OBJ_IDFN "OBJ_IDFN" // Identification
|
||||
#define OBJ_SYMT "OBJ_SYMT" // Symbol Table
|
||||
#define OBJ_STRT "OBJ_STRT" // String Table
|
||||
uint32 file_offset; // a one-word field defining the byte offset within
|
||||
// the file of the start of the chunk. All chunks are
|
||||
// word-aligned, so it must be divisible by four.
|
||||
// A value of zero indicates that the chunk entry
|
||||
// is unused.
|
||||
uint32 size; // a one-word field defining the exact byte size
|
||||
// of the chunk's contents (which need not be a
|
||||
// multiple of four).
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct aof_header_t
|
||||
{
|
||||
uint32 obj_file_type; // the value 0xC5E2D080 marks the file as being in
|
||||
// relocatable object format (the usual output of
|
||||
// compilers and assemblers and the usual input to
|
||||
// the linker). The endianness of the object code
|
||||
// can be deduced from this value and must be
|
||||
// identical to the endianness of the containing
|
||||
// chunk file.
|
||||
#define OBJ_FILE_TYPE_MAGIC 0xC5E2D080L
|
||||
uint32 version; // encodes the version of AOF with which the object
|
||||
// file complies
|
||||
// version 1.50 is denoted by decimal 150
|
||||
// version 2.00 is denoted by decimal 200
|
||||
// this version is denoted by decimal 310 (0x136)
|
||||
uint32 num_areas; // Number of Areas
|
||||
uint32 num_syms; // Number of Symbols
|
||||
uint32 entry_area; // Entry Area Index. in the range 1 to Number of
|
||||
// Areas, gives the 1-origin index in the following
|
||||
// array of area headers of the area containing the
|
||||
// entry point. The entry address is defined to be
|
||||
// the base address of this area plus Entry Offset.
|
||||
// A value of 0 for Entry Area Index signifies that
|
||||
// no program entry address is defined by this AOF
|
||||
// file.
|
||||
uint32 entry_offset;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct area_header_t
|
||||
{
|
||||
uint32 name; // Area name (offset into string table)
|
||||
uint32 flags; // Attributes + Alignment
|
||||
// The least significant eight bits of this word
|
||||
// encode the alignment of the start of the area as a
|
||||
// power of 2 and must have a value between 2 and 32.
|
||||
#define AREA_ABS 0x00000100L // The absolute attribute: denotes that the
|
||||
// area must be placed at its Base Address.
|
||||
// This bit is not usually set by language
|
||||
// processors.
|
||||
#define AREA_CODE 0x00000200L // CODE (otherwise DATA)
|
||||
#define AREA_COMMON 0x00000400L // The area is a common definition.
|
||||
#define AREA_COMREF 0x00000800L // The area is a reference to a common block:
|
||||
// preclude the area having initializing data
|
||||
// (see AREA_BSS). In effect, AREA_COMREF
|
||||
// implies AREA_BSS.
|
||||
// If both bits AREA_COMMON and AREA_COMREF
|
||||
// are set, bit AREA_COMREF is ignored.
|
||||
#define AREA_BSS 0x00001000L // Zero-initialized: the area has no
|
||||
// initializing data in this object file,
|
||||
// and that the area contents are missing from
|
||||
// the OBJ_AREA chunk.
|
||||
#define AREA_RDONLY 0x00002000L // Readonly area
|
||||
#define AREA_PIC 0x00004000L // The position independent (PI) area
|
||||
#define AREA_DEBUG 0x00008000L // The debugging table.
|
||||
|
||||
// CODE areas only:
|
||||
|
||||
#define AREA_32BIT 0x00010000L // 32-bit area (not 26bit)
|
||||
#define AREA_REENTR 0x00020000L // The re-entrant area
|
||||
#define AREA_EXTFP 0x00040000L // Extended floating-point instruction set
|
||||
// is used in the area.
|
||||
#define AREA_NOCHK 0x00080000L // No Software Stack Check
|
||||
#define AREA_THUMB 0x00100000L // Thumb code area
|
||||
#define AREA_HALFW 0x00200000L // Halfword instructions may be present
|
||||
#define AREA_INTER 0x00400000L // Area has been compiled to be suitable for
|
||||
// ARM/Thumb interworking.
|
||||
|
||||
// DATA areas only:
|
||||
|
||||
#define AREA_BASED 0x00100000L // Based area
|
||||
inline int get_based_reg() { return int(flags >> 24) & 15; }
|
||||
|
||||
#define AREA_SHARED 0x00200000L // Shared Library Stub Data
|
||||
|
||||
uint32 size; // Area Size. Gives the size of the area in bytes,
|
||||
// which must be a multiple of 4. Unless the
|
||||
// "Not Initialised" bit (bit 12) is set in the area
|
||||
// attributes, there must be this number of bytes
|
||||
// for this area in the OBJ_AREA chunk.
|
||||
// If the "Not Initialised" bit is set, there must be
|
||||
// no initializing bytes for this area in the
|
||||
// OBJ_AREA chunk.
|
||||
uint32 num_relocs; // Number of Relocations. Specifies the number of
|
||||
// relocation directives which apply to this area
|
||||
// (which is equivalent to the number of relocation
|
||||
// records following the area's contents in the
|
||||
// OBJ_AREA chunk.
|
||||
uint32 baseaddr; // Base Address or 0. Is unused unless the area has
|
||||
// the absolute attribute. In this case, the field
|
||||
// records the base address of the area. In general,
|
||||
// giving an area a base address prior to linking
|
||||
// will cause problems for the linker and may prevent
|
||||
// linking altogether, unless only a single object
|
||||
// file is involved.
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// segment flag bits in IDA for ARM module:
|
||||
// the bits are kept in netnode().altval(seg_start_ea)
|
||||
|
||||
#ifdef _NETNODE_HPP
|
||||
#define SEGFL_NETNODE_NAME "$ arm segflags"
|
||||
#define SEGFL_BREG 0x000F
|
||||
#define SEGFL_PIC 0x0010
|
||||
#define SEGFL_REENTR 0x0020
|
||||
#define SEGFL_HALFW 0x0040
|
||||
#define SEGFL_INTER 0x0080
|
||||
#define SEGFL_COMDEF 0x0100
|
||||
#define SEGFL_BASED 0x0200
|
||||
#define SEGFL_ALIGN 0x7C00
|
||||
#define SEGFL_SHIFT 10
|
||||
|
||||
inline void set_arm_segm_flags(ea_t ea, ushort flags)
|
||||
{
|
||||
netnode n;
|
||||
n.create(SEGFL_NETNODE_NAME);
|
||||
n.altset_ea(ea, flags);
|
||||
}
|
||||
|
||||
inline ushort get_arm_segm_flags(ea_t ea)
|
||||
{
|
||||
return (ushort)netnode(SEGFL_NETNODE_NAME).altval_ea(ea);
|
||||
}
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct reloc_t
|
||||
{
|
||||
uint32 offset;
|
||||
uint32 type; // Low 24bits are SID
|
||||
size_t sid(void) { return size_t(type & 0x00FFFFFFL); }
|
||||
#define RF_II 0x60000000uL // if RF_FT == 11, then:
|
||||
// 00 no constraint (the linker may modify as many contiguous instructions as it needs to)
|
||||
// 01 the linker will modify at most 1 instruction
|
||||
// 10 the linker will modify at most 2 instructions
|
||||
// 11 the linker will modify at most 3 instructions
|
||||
#define RF_B 0x10000000uL // Based
|
||||
#define RF_A 0x08000000uL // 1: The subject field is relocated by the
|
||||
// value of the symbol of which SID is the
|
||||
// zero-origin index in the symbol table
|
||||
// chunk.
|
||||
// 0: The subject field is relocated by the
|
||||
// base of the area of which SID is the
|
||||
// zero-origin index in the array of areas,
|
||||
// (or, equivalently, in the array of area
|
||||
// headers).
|
||||
#define RF_R 0x04000000uL // PC relative
|
||||
#define RF_FT 0x03000000uL
|
||||
#define RF_FT_BYTE 0x00000000uL // 00 the field to be relocated is a byte
|
||||
#define RF_FT_HALF 0x01000000uL // 01 the field to be relocated is a halfword (two bytes)
|
||||
#define RF_FT_WORD 0x02000000uL // 10 the field to be relocated is a word (four bytes)
|
||||
#define RF_FT_INSN 0x03000000uL // 11 the field to be relocated is an instruction or instruction sequence
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct sym_t
|
||||
{
|
||||
uint32 name; // Offset in the string table (in chunk OBJ_STRT) of
|
||||
// the character string name of the symbol.
|
||||
uint32 flags; // Attributes.
|
||||
#define SF_DEF 0x00000001 // Symbol is defined in this file
|
||||
#define SF_PUB 0x00000002 // Symbol has a global scope
|
||||
#define SF_ABS 0x00000004 // Absolute attribute
|
||||
#define SF_ICASE 0x00000008 // Case-insensitive attribute
|
||||
#define SF_WEAK 0x00000010 // Weak attribute
|
||||
#define SF_STRNG 0x00000020 // Strong attribute
|
||||
#define SF_COMM 0x00000040 // Common attribute
|
||||
// Code symbols only:
|
||||
#define SF_CDATA 0x00000100 // Code area datum attribute
|
||||
#define SF_FPREG 0x00000200 // FP args in FP regs attribute
|
||||
#define SF_LEAF 0x00000800 // Simple leaf function attribute
|
||||
#define SF_THUMB 0x00001000 // Thumb symbol
|
||||
uint32 value; // is meaningful only if the symbol is a defining
|
||||
// occurrence (bit 0 of Attributes set), or a common
|
||||
// symbol (bit 6 of Attributes set):
|
||||
// - if the symbol is absolute (bits 0-2 of
|
||||
// Attributes set), this field contains the value
|
||||
// of the symbol
|
||||
// - if the symbol is a common symbol (bit 6 of
|
||||
// Attributes set), this contains the byte length
|
||||
// of the referenced common area
|
||||
// - otherwise, value is interpreted as an offset
|
||||
// from the base address of the area named by
|
||||
// Area Name, which must be an area defined in
|
||||
// this object file
|
||||
uint32 area; // Area Name is meaningful only if the symbol is a
|
||||
// non-absolute defining occurrence (bit 0 of
|
||||
// Attributes set, bit 2 unset). In this case it
|
||||
// gives the index into the string table for the name
|
||||
// of the area in which the symbol is defined (which
|
||||
// must be an area in this object file).
|
||||
};
|
||||
|
||||
#endif
|
||||
20
idasdk76/ldr/aof/makefile
Normal file
20
idasdk76/ldr/aof/makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
PROC=aof
|
||||
|
||||
include ../loader.mak
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# the 'unlib' target must be called explicitly
|
||||
.PHONY:
|
||||
unlib: $(F)unlib$(B)
|
||||
$(F)unlib$(B): $(call dumb_target, pro, $(F)unlib$(O))
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)aof$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
|
||||
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
|
||||
$(I)xref.hpp ../idaldr.h aof.cpp aof.h
|
||||
$(F)unlib$(O) : $(I)fpro.h $(I)llong.hpp $(I)pro.h aof.h unlib.cpp
|
||||
199
idasdk76/ldr/aof/unlib.cpp
Normal file
199
idasdk76/ldr/aof/unlib.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-97 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@estar.msk.su
|
||||
* FIDO: 2:5020/209
|
||||
*
|
||||
* ARM Object Librarian (Unpacker)
|
||||
*
|
||||
* This program unpacks a library. It extracts all the modules
|
||||
* from the input library and puts them into separate files.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pro.h>
|
||||
#include <fpro.h>
|
||||
#include "aof.h"
|
||||
|
||||
#define LIB_DIRY "LIB_DIRY" // Directory
|
||||
#define LIB_TIME "LIB_TIME" // Time stamp
|
||||
#define LIB_VRSN "LIB_VRSN" // Version
|
||||
#define LIB_DATA "LIB_DATA" // Data
|
||||
#define OFL_SYMT "OFL_SYMT" // Symbol table
|
||||
#define OFL_TIME "OFL_TIME" // Time stamp
|
||||
|
||||
static FILE *outfp = NULL;
|
||||
static char outfile[QMAXPATH] = "";
|
||||
static char infile[QMAXPATH] = "";
|
||||
static char modname[MAXSTR] = "";
|
||||
static int mf = 0;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
static void fatal(const char *format,...)
|
||||
{
|
||||
if ( infile[0] != '\0' && modname[0] != '\0' )
|
||||
qeprintf("Fatal [%s] (%s): ",infile,modname);
|
||||
va_list va;
|
||||
va_start(va,format);
|
||||
qveprintf(format,va);
|
||||
va_end(va);
|
||||
qeprintf("\n");
|
||||
qfclose(outfp);
|
||||
unlink(outfile);
|
||||
// qeprintf("press enter to exit.\n");
|
||||
// getchar();
|
||||
qexit(1);
|
||||
}
|
||||
|
||||
void warning(const char *format,...)
|
||||
{
|
||||
qeprintf("Warning [%s] (%s): ",infile,modname);
|
||||
va_list va;
|
||||
va_start(va,format);
|
||||
qveprintf(format,va);
|
||||
va_end(va);
|
||||
qeprintf("\n");
|
||||
}
|
||||
|
||||
static void nomem(const char *format,...)
|
||||
{
|
||||
char buf[512];
|
||||
va_list va;
|
||||
va_start(va,format);
|
||||
qvsnprintf(buf, sizeof(buf), format, va);
|
||||
va_end(va);
|
||||
fatal("No memory: %s",buf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void *read_chunk(FILE *fp, chunk_entry_t *ce, int32 i)
|
||||
{
|
||||
size_t idx = size_t(i);
|
||||
void *chunk = qalloc_array<char>(ce[idx].size);
|
||||
if ( chunk == NULL )
|
||||
nomem("chunk size %d",size_t(ce[idx].size));
|
||||
qfseek(fp,ce[idx].file_offset,SEEK_SET);
|
||||
if ( qfread(fp,chunk,size_t(ce[idx].size)) != ce[idx].size )
|
||||
fatal("Chunk read error: %s",strerror(errno));
|
||||
return chunk;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static uint32 swap(uint32 x)
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32 l;
|
||||
char c[4];
|
||||
} u;
|
||||
char chr;
|
||||
u.l = x;
|
||||
chr = u.c[3]; u.c[3] = u.c[0]; u.c[0] = chr;
|
||||
chr = u.c[2]; u.c[2] = u.c[1]; u.c[1] = chr;
|
||||
return u.l;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void swap_chunk_entry(chunk_entry_t *ce)
|
||||
{
|
||||
ce->file_offset = swap(ce->file_offset);
|
||||
ce->size = swap(ce->size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int i;
|
||||
qeprintf("ARM Library unpacker. Copyright 1997 by Ilfak Guilfanov. Version 1.00\n");
|
||||
if ( argc < 2 )
|
||||
fatal("Usage: unlib libfile");
|
||||
qstrncpy(infile, argv[1], sizeof(infile));
|
||||
FILE *fp = qfopen(infile,"rb");
|
||||
if ( fp == NULL )
|
||||
fatal("Can't open library %s",infile);
|
||||
chunk_header_t hd;
|
||||
if ( qfread(fp, &hd, sizeof(hd)) != sizeof(hd)
|
||||
|| (hd.ChunkFileId != AOF_MAGIC && hd.ChunkFileId != AOF_MAGIC_B) )
|
||||
{
|
||||
fatal("Bad library format");
|
||||
}
|
||||
if ( hd.ChunkFileId == AOF_MAGIC_B ) // BIG ENDIAN
|
||||
{
|
||||
mf = 1;
|
||||
hd.max_chunks = swap(hd.max_chunks);
|
||||
hd.num_chunks = swap(hd.num_chunks);
|
||||
}
|
||||
|
||||
chunk_entry_t *ce = qalloc_array<chunk_entry_t>(hd.max_chunks);
|
||||
if ( ce == NULL )
|
||||
nomem("chunk entries (%d)",size_t(hd.max_chunks));
|
||||
qfread(fp, ce, sizeof(chunk_entry_t)*size_t(hd.max_chunks));
|
||||
if ( mf )
|
||||
for ( i=0; i < hd.max_chunks; i++ )
|
||||
swap_chunk_entry(ce+i);
|
||||
|
||||
int vrsn = -1;
|
||||
int diry = -1;
|
||||
int data = 0;
|
||||
for ( i=0; i < hd.max_chunks; i++ )
|
||||
{
|
||||
if ( ce[i].file_offset == 0 )
|
||||
continue;
|
||||
if ( strncmp(ce[i].chunkId,LIB_DIRY,sizeof(ce[i].chunkId)) == 0 )
|
||||
diry = i;
|
||||
if ( strncmp(ce[i].chunkId,LIB_VRSN,sizeof(ce[i].chunkId)) == 0 )
|
||||
vrsn = i;
|
||||
if ( strncmp(ce[i].chunkId,LIB_DATA,sizeof(ce[i].chunkId)) == 0 )
|
||||
data++;
|
||||
}
|
||||
if ( diry == -1 )
|
||||
fatal("Can't find library directory!");
|
||||
if ( data == 0 )
|
||||
fatal("No modules in the library!");
|
||||
if ( vrsn == -1 )
|
||||
fatal("Can't determine library version!");
|
||||
uint32 *version = (uint32 *)read_chunk(fp,ce,vrsn);
|
||||
if ( mf )
|
||||
*version = swap(*version);
|
||||
if ( *version != 1 )
|
||||
fatal("Wrong library version (%ld)",*version);
|
||||
qfree(version);
|
||||
|
||||
uint32 *dir = (uint32 *)read_chunk(fp,ce,diry);
|
||||
uint32 *end = dir + size_t(ce[diry].size/4);
|
||||
while ( dir < end )
|
||||
{
|
||||
uint32 idx = *dir++;
|
||||
/* uint32 elen = */ *dir++;
|
||||
uint32 dlen = *dir++;
|
||||
if ( mf )
|
||||
{
|
||||
idx = swap(idx);
|
||||
dlen = swap(dlen);
|
||||
}
|
||||
if ( idx != 0 )
|
||||
{
|
||||
printf("%d. %s\n",idx,dir);
|
||||
qstrncpy(modname,(char *)dir,sizeof(modname));
|
||||
modname[sizeof(modname)-1] = '\0';
|
||||
void *core = read_chunk(fp,ce,idx);
|
||||
outfp = qfopen(modname,"wb");
|
||||
if ( outfp == NULL )
|
||||
{
|
||||
warning("Can't open output file %s",modname);
|
||||
}
|
||||
else
|
||||
{
|
||||
qfwrite(outfp,core,size_t(ce[size_t(idx)].size));
|
||||
qfclose(outfp);
|
||||
}
|
||||
qfree(core);
|
||||
}
|
||||
dir += size_t(dlen/4);
|
||||
}
|
||||
qfree(dir);
|
||||
|
||||
qfclose(fp);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user