Example #1
0
//--------------------------------------------------------------------------
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;
}
Example #2
0
//-----------------------------------------------------------------------
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);
  }
Example #3
0
//-----------------------------------------------------------------------------
// 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;
}