//-------------------------------------------------------------------------- static bool load_name2(ushort index, ulong offset) { uint64 off, size; if ( index == ushort(-1) ) { off = dynstr_off; size = dynstr_size; } else { off = elf64 ? shdr64[index].sh_offset : shdr32[index].sh_offset; size = elf64 ? shdr64[index].sh_size : shdr32[index].sh_size; } if ( offset >= size ) { qsnprintf(name, sizeof(name), "bad offset %08lx", low(offset+off)); return false; } ulong pos = qltell(li); offset = low(offset + off); qlseek(li, offset); register char *p; register int i, j; bool ok = true; for(i = 0, p = name; i < sizeof(name)-1; i++, p++) if((j = qlgetc(li)) == EOF) { qstrncpy(p, "{truncated name}", sizeof(name)-(p-name)); ok = false; break; } else if((*p = (char)j) == '\0') break; if(i == sizeof(name)-1) { qstrncpy(p-5, "...", 5); ok = false; } qlseek(li, pos); return ok; }
//----------------------------------------------------------------------- static void read_fixup(linput_t *li) { fixup fix; const int size = offsetof(fixup, fixups); lread(li, &fix, size); uint32 fptr = qltell(li); ea_t sea = getsea(fix.where_IN); if ( sea != BADADDR ) { uchar *b = qnewarray(uchar, fix.length); if ( b == NULL ) nomem("read_fixup"); lread(li, b, fix.length); // show_hex(b, fix.length, "\nFIXUP SEG %04X, %04X BYTES, KIND %02X\n", // fix.where_IN, // fix.length, // b[0]); const uchar *ptr = b; const uchar *end = b + fix.length; while ( ptr < end ) { fixup_data_t fd; uint32 where_offset = 0; uint32 what_offset = 0; ushort what_in = 9; bool selfrel = false; bool isfar = false; fd.type = FIXUP_OFF32; switch ( *ptr++ ) { case 0x2C: // GEN isfar = true; ask_for_feedback("Untested relocation type"); case 0x24: // GEN where_offset = readdw(ptr, false); what_offset = readdw(ptr, false); what_in = (ushort)readdw(ptr, false); break; case 0x2D: isfar = true; case 0x25: // INTRA where_offset = readdw(ptr, false); what_offset = readdw(ptr, false); what_in = fix.where_IN; break; case 0x2A: // CALL where_offset = readdw(ptr, false); what_offset = 0; what_in = (ushort)readdw(ptr, false); selfrel = true; break; case 0x2E: // OFF32? isfar = true; case 0x26: where_offset = readdw(ptr, false); what_offset = 0; what_in = (ushort)readdw(ptr, false); break; default: ask_for_feedback("Unknown relocation type %02X", ptr[-1]); add_pgm_cmt("!!! Unknown relocation type %02X", ptr[-1]); break; } ea_t source = sea + where_offset; ea_t target = BADADDR; switch ( what_in >> 12 ) { case 0x02: // segments target = getsea(what_in); break; case 0x06: // externs target = xea + 4 * ((what_in & 0xFFF) - 1); fd.type |= FIXUP_EXTDEF; break; default: ask_for_feedback("Unknown relocation target %04X", what_in); add_pgm_cmt("!!! Unknown relocation target %04X", what_in); break; } segment_t *ts = getseg(target); fd.sel = ts ? (ushort)ts->sel : 0; if ( (fd.type & FIXUP_EXTDEF) == 0 ) { target += what_offset; what_offset = 0; } fd.off = target; fd.displacement = what_offset; target += what_offset; if ( selfrel ) { fd.type |= FIXUP_SELFREL; target -= source + 4; } set_fixup(source, &fd); put_long(source, target); if ( isfar ) { fd.type = FIXUP_SEG16; set_fixup(source+4, &fd); put_word(source+4, fd.sel); } } qfree(b); }
//----------------------------------------------------------------------------- // process a file record according to its "record_type". // return true if there is no more records to process. static bool process_record(linput_t *li, const uchar record_type, bool load) { bool finished = false; switch (record_type) { // A record with a header byte of $81 is a record that may contain code or // data from arbitrary segments. // // header : 1 byte // segment : 1 byte // gran : 1 byte // start_addr : 4 bytes (entry point) // length : 2 bytes // data : length bytes case 0x81: { mas_header_t header; memset(&header, 0, sizeof header); // read the header if (qlread(li, &header, sizeof header) != sizeof header) mas_error("unable to read header (%d bytes)", sizeof header); // granularities that differ from 1 are rare and mostly appear // in DSP CPU's that are not designed for byte processing. if (header.gran != 1) mas_error("unsupported granularity (%d)", header.gran); // set processor if (!mas_set_cpu(header.header)) mas_error("processor type '0x%X' is currently unsupported", header.header); if (!load) // we have the processor, nothing else to do { finished = true; break; } // get segment name const char *segname = mas_get_segname(header.segment); if (segname == NULL) mas_error("invalid segment '0x%X'", header.segment); #if defined(DEBUG) msg("MAS: ready to read %d bytes (0x%X -> 0x%X)\n", header.length, header.start_addr, header.start_addr + header.length); #endif // send code in the database file2base(li, qltell(li), header.start_addr, header.start_addr + header.length, FILEREG_PATCHABLE); // set selector sel_t selector = allocate_selector(0); // create segment add_segm(selector, header.start_addr, header.start_addr + header.length, segname, segname); } break; // The last record in a file bears the Header $00 and has only a string as // data field. This string does not have an explicit length specification; // its end is equal to the file's end. // // The string contains only the name of the program that created the file // and has no further meaning. // // creator : x bytes case 0x00: { ulong length = qlsize(li) - qltell(li); #if defined(DEBUG) msg("MAS: creator length : %ld bytes\n", length); #endif if (length >= sizeof creator) mas_error("creator length is too large (%ld >= %ld", length, sizeof creator); int tmp; if ((tmp = qlread(li, creator, length)) != length) mas_error("unable to read creator string (i read %d)", tmp); creator[tmp] = '\0'; } finished = true; break; // entry_point : 4 bytes case 0x80: { if (qlread(li, &entry_point, 4) != 4) mas_error("unable to read entry_point"); if (load) { #if defined(DEBUG) msg("MAS: detected entry point : 0x%X\n", entry_point); #endif inf.startIP = entry_point; // entry point segment_t *s = getseg(entry_point); inf.start_cs = s ? s->sel : 0; // selector of code } } break; default: // start_addr : 4 bytes // length : 2 bytes // data : length bytes if (record_type >= 0x01 && record_type <= 0x7F) { struct header { int start_addr; short length; } header; memset(&header, 0, sizeof header); // read the header if (qlread(li, &header, sizeof header) != sizeof header) mas_error("unable to read header (%d bytes)", sizeof header); if (load) { // send code in the database file2base(li, qltell(li), header.start_addr, header.start_addr + header.length, FILEREG_PATCHABLE); #if defined(DEBUG) msg("MAS: i've read %d DATA bytes (0x%X -> 0x%X)\n", header.length, header.start_addr, header.start_addr + header.length); #endif // set selector sel_t selector = allocate_selector(0); // create data segment add_segm(selector, header.start_addr, header.start_addr + header.length, "DATA", "DATA"); } else qlseek(li, qltell(li)+header.length); } else mas_error("invalid record type '0x%X'\n", record_type); } return finished; }