/* * Load a method header list block */ void CVmImageLoader::load_mhls(VMG_ ulong siz) { char buf[512]; ulong cnt; ulong i; /* read the count */ read_data(buf, 4, &siz); cnt = t3rp4u(buf); /* allocate space for the list */ G_debugger->alloc_method_header_list(cnt); /* read the entries */ for (i = 0 ; cnt != 0 ; ) { size_t cur; char *p; /* read as many as we can fit, up to the number remaining */ cur = sizeof(buf) / 4; if (cur > cnt) cur = (size_t)cnt; /* read the chunk */ read_data(buf, cur * 4, &siz); /* deduct the number we just read from the number remaining */ cnt -= cur; /* process these entries */ for (p = buf ; cur != 0 ; --cur, ++i, p += 4) G_debugger->set_method_header(i, t3rp4u(p)); } }
/* load image data */ void CVmObjClass::load_image_data(VMG_ vm_obj_id_t self, const char *ptr, size_t siz) { /* make sure the length is valid */ if (siz < 8) err_throw(VMERR_INVAL_METACLASS_DATA); /* allocate or reallocate the extension */ vm_intcls_ext *ext = alloc_ext(vmg0_); /* * read the metaclass index and modifier object ID; note that modifier * objects are always root set objects, so there's no need to worry * about fixups */ ext->meta_idx = osrp2(ptr+2); ext->mod_obj = (vm_obj_id_t)t3rp4u(ptr+4); /* if we have a class state value, read it */ ext->class_state.set_nil(); if (siz >= 2+4+VMB_DATAHOLDER) vmb_get_dh(ptr+8, &ext->class_state); /* register myself */ register_meta(vmg_ self); }
/* * Get only the value portion of a vm_val_t from a portable data holder */ void vmb_get_dh_val(const char *buf, vm_val_t *val) { /* read the format appropriate to the type */ switch((vm_datatype_t)buf[0]) { case VM_OBJ: case VM_OBJX: /* get the object ID from the UINT4 */ val->val.obj = (vm_obj_id_t)t3rp4u(buf+1); break; case VM_PROP: /* get the property ID from the UINT2 */ val->val.prop = (vm_prop_id_t)osrp2(buf+1); break; case VM_INT: val->val.intval = osrp4(buf+1); break; case VM_BIFPTR: case VM_BIFPTRX: /* read the function index and set index as UINT2s */ val->val.bifptr.func_idx = osrp2(buf+1); val->val.bifptr.set_idx = osrp2(buf+3); break; case VM_ENUM: /* get the enumerated constant value from the UINT4 */ val->val.enumval = t3rp4u(buf+1); break; case VM_SSTRING: case VM_DSTRING: case VM_LIST: case VM_CODEOFS: case VM_FUNCPTR: /* get the offset value from the UINT4 */ val->val.ofs = t3rp4u(buf+1); break; default: /* other types have no additional data or cannot be put in a DH */ break; } }
/* * Show an exception table */ void CTcT3Unasm::show_exc_table(class CTcUnasSrc *src, class CTcUnasOut *out, unsigned long base_ofs) { unsigned entries; char ch[10]; /* read the number of entries */ src->next_byte(ch); src->next_byte(ch+1); /* show the entries */ for (entries = osrp2(ch) ; entries != 0 ; --entries) { unsigned long start_ofs; unsigned long end_ofs; unsigned exc_obj_id; unsigned long catch_ofs; /* read the code start offset */ src->next_byte(ch); src->next_byte(ch+1); start_ofs = base_ofs + osrp2(ch); /* read the code end offset */ src->next_byte(ch); src->next_byte(ch+1); end_ofs = base_ofs + osrp2(ch); /* read the object ID */ src->next_byte(ch); src->next_byte(ch+1); src->next_byte(ch+2); src->next_byte(ch+3); exc_obj_id = base_ofs + t3rp4u(ch); /* read the catch offset */ src->next_byte(ch); src->next_byte(ch+1); catch_ofs = base_ofs + osrp2(ch); /* show it */ out->print(" from %lx to %lx object %x catch %lx\n", start_ofs, end_ofs, exc_obj_id, catch_ofs); } }
/* * Read a fixup list from an object file */ void CTcAbsFixup:: load_fixup_list_from_object_file(CVmFile *fp, const textchar_t *obj_fname, CTcAbsFixup **list_head) { uint fixup_cnt; /* read the fixups */ for (fixup_cnt = fp->read_uint2() ; fixup_cnt != 0 ; --fixup_cnt) { char buf[5]; char stream_id; ulong fixup_ofs; CTcDataStream *stream; /* read the fixup data */ fp->read_bytes(buf, 5); stream_id = buf[0]; fixup_ofs = t3rp4u(buf+1); /* find the stream for the ID */ stream = CTcDataStream::get_stream_from_id(stream_id, obj_fname); /* if the stream is invalid, ignore this record */ if (stream == 0) continue; /* * the fixup offset is relative to the starting offset of the * stream for the current object file - adjust it accordingly */ fixup_ofs += stream->get_object_file_start_ofs(); /* create the fixup and add it to the list */ add_abs_fixup(list_head, stream, fixup_ofs); } }
/* * load a Global Symbols block */ void CVmImageLoader::load_gsym(VMG_ ulong siz) { char buf[TOK_SYM_MAX_LEN + 128]; /* * if there's no global symbol table, merely load into the runtime * symbol table, since we don't seem to need the information for * debugging */ if (G_prs->get_global_symtab() == 0) { /* load it into the runtime reflection symbol table */ load_runtime_symtab_from_gsym(vmg_ siz); /* we're done */ return; } /* * remember the starting seek position and size, so we can re-read the * block into the runtime symbol table */ long init_seek_pos = fp_->get_seek(); ulong init_siz = siz; /* * note that we have a GSYM block - this implies that the image was * linked for debugging */ has_gsym_ = TRUE; /* read the symbol count */ read_data(buf, 4, &siz); ulong cnt = t3rp4u(buf); /* read the symbols and populate the global symbol table */ for ( ; cnt != 0 ; --cnt) { char *sym_name; size_t sym_len; size_t dat_len; CTcSymbol *sym; tc_symtype_t sym_type; char *dat; /* read the symbol's length, extra data length, and type code */ read_data(buf, 6, &siz); sym_len = osrp2(buf); dat_len = osrp2(buf + 2); sym_type = (tc_symtype_t)osrp2(buf + 4); /* check the lengths to make sure they don't overflow our buffer */ if (sym_len > TOK_SYM_MAX_LEN) { /* * this symbol name is too long - skip the symbol and its * extra data entirely */ skip_data(sym_len + dat_len, &siz); /* go on to the next symbol */ continue; } else if (dat_len + sym_len > sizeof(buf)) { /* * the extra data block is too long - truncate the extra * data so that we don't overflow our buffer, but proceed * anyway with the truncated extra data */ read_data(buf, sizeof(buf), &siz); /* skip the remainder of the extra data */ skip_data(sym_len + dat_len - sizeof(buf), &siz); } else { /* read the symbol's name and its type-specific data */ read_data(buf, sym_len + dat_len, &siz); } /* get the pointer to the extra data (after the name) */ dat = buf + sym_len; /* * allocate a copy of the symbol name in parser memory - this is * necessary because the symbol objects themselves always come * from parser memory, and hence never get individually deleted */ sym_name = (char *)G_prsmem->alloc(sym_len); memcpy(sym_name, buf, sym_len); /* create the new symbol table entry, depending on its type */ switch(sym_type) { case TC_SYM_FUNC: /* create the function symbol */ sym = new CTcSymFunc( sym_name, sym_len, FALSE, (int)osrp2(dat + 4), /* argc */ /* * the optional argument count is present in 3.1+ records, * which are at least 10 bytes; otherwise there aren't any * optional arguments */ (dat_len >= 10 ? osrp2(dat+8) : 0), /* opt_argc */ dat[6] != 0, /* varargs */ dat[7] != 0, /* has_retval */ FALSE, /* is_multimethod */ FALSE, /* is_multimethod_base */ FALSE); /* is_extern */ /* add the reverse mapping entry */ G_debugger->add_rev_sym(sym_name, sym_len, sym_type, t3rp4u(dat)); /* set the function's absolute address */ ((CTcSymFunc *)sym)->set_abs_addr(t3rp4u(dat)); break; case TC_SYM_OBJ: /* create the object symbol */ sym = new CTcSymObj(sym_name, sym_len, FALSE, t3rp4u(dat), FALSE, TC_META_TADSOBJ, 0); /* if there's a modifying object, store it */ if (dat_len >= 8) ((CTcSymObj *)sym)->set_modifying_obj_id(t3rp4u(dat + 4)); else ((CTcSymObj *)sym)->set_modifying_obj_id(VM_INVALID_OBJ); /* add the reverse mapping entry */ G_debugger->add_rev_sym(sym_name, sym_len, sym_type, t3rp4u(dat)); break; case TC_SYM_PROP: /* create the property symbol */ sym = new CTcSymProp(sym_name, sym_len, FALSE, osrp2(dat)); /* set the 'dictionary property' flag if present */ if (dat_len >= 3 && (buf[2] & 1) != 0) ((CTcSymProp *)sym)->set_vocab(TRUE); /* add the reverse mapping entry */ G_debugger->add_rev_sym(sym_name, sym_len, sym_type, osrp2(dat)); break; case TC_SYM_ENUM: /* create the enumerator symbol */ sym = new CTcSymEnum(sym_name, sym_len, FALSE, t3rp4u(dat), (dat_len >= 5 && (buf[4] & 1) != 0)); /* add the reverse mapping entry */ G_debugger->add_rev_sym(sym_name, sym_len, sym_type, t3rp4u(dat)); break; case TC_SYM_BIF: /* create the built-in function symbol */ sym = new CTcSymBif(sym_name, sym_len, FALSE, osrp2(dat + 2), /* function set ID */ osrp2(dat), /* function index */ dat[4] != 0, /* has_retval */ osrp2(dat + 5), /* min_argc */ osrp2(dat + 7), /* max_argc */ dat[9] != 0); /* varargs */ /* add the reverse mapping entry */ G_debugger->add_rev_sym(sym_name, sym_len, sym_type, (osrp2(dat+2) << 16) | osrp2(dat)); break; case TC_SYM_EXTFN: /* not currently supported */ sym = 0; break; case TC_SYM_METACLASS: /* create the metaclass symbol */ sym = new CTcSymMetaclass(sym_name, sym_len, FALSE, osrp2(dat), t3rp4u(dat + 2)); /* * add a reverse mapping symbol for the object instance * (note that we add this as an object, not a metaclass, * since it refers to the IntrinsicClass instance) */ if ((vm_obj_id_t)t3rp4u(dat + 2) != VM_INVALID_OBJ) G_debugger->add_rev_sym(sym_name, sym_len, TC_SYM_OBJ, t3rp4u(dat + 2)); break; default: /* ignore other types of symbols */ sym = 0; break; } /* if the symbol was valid, add it to the global symbol table */ if (sym != 0) G_prs->get_global_symtab()->add_entry(sym); } /* * Seek back to the starting position, and then load the GSYM data * into the runtime reflection symbol table */ fp_->seek(init_seek_pos); load_runtime_symtab_from_gsym(vmg_ init_siz); }
/* * Read a stream from an object file */ void CTcDataStream::load_object_file(CVmFile *fp, const textchar_t *fname) { ulong stream_len; ulong rem; char buf[1024]; ulong start_ofs; ulong anchor_cnt; /* read the length of the stream */ stream_len = fp->read_uint4(); /* remember my starting offset */ start_ofs = get_ofs(); /* read the stream bytes */ for (rem = stream_len ; rem != 0 ; ) { size_t cur; /* read up to a buffer-full, or however much is left */ cur = sizeof(buf); if (cur > rem) cur = rem; /* read this chunk */ fp->read_bytes(buf, cur); /* add this chunk to the stream */ write(buf, cur); /* deduct the amount we've read from the amount remaining */ rem -= cur; } /* * Read the anchors. For each anchor, we must fix up the anchor by * adding the base address of the stream we just read - the original * anchor offsets in the object file reflect a base stream offset of * zero, but we could be loading the stream after a bunch of other * data have already been loaded into the stream. * * First, read the number of anchors, then loop through the anchors * and read each one. */ for (anchor_cnt = fp->read_uint4() ; anchor_cnt != 0 ; --anchor_cnt) { ulong anchor_ofs; size_t sym_len; CTcStreamAnchor *anchor; /* read this anchor */ fp->read_bytes(buf, 6); /* get the offset, and adjust for the new stream base offset */ anchor_ofs = t3rp4u(buf) + start_ofs; /* get the length of the owning symbol's name, if any */ sym_len = osrp2(buf+4); /* if there's a symbol name, read it */ if (sym_len != 0) { CTcSymbol *owner_sym; /* read the symbol name */ fp->read_bytes(buf, sym_len); /* look it up in the global symbol table */ owner_sym = G_prs->get_global_symtab()->find(buf, sym_len); if (owner_sym == 0) { /* * the owner symbol doesn't exist - this is an internal * inconsistency in the object file, because the anchor * symbol must always be defined in the same file and * hence should have been loaded already; complain and * go on */ G_tcmain->log_error(0, 0, TC_SEV_ERROR, TCERR_OBJFILE_INT_SYM_MISSING, (int)sym_len, buf, fname); /* we can't create the anchor */ anchor = 0; } else { /* create the anchor based on the symbol */ anchor = add_anchor(owner_sym, owner_sym->get_fixup_list_anchor(), anchor_ofs); /* set the anchor in the symbol */ owner_sym->set_anchor(anchor); } } else { /* create the anchor with no external references */ anchor = add_anchor(0, 0, anchor_ofs); } /* load the fixup list */ CTcAbsFixup:: load_fixup_list_from_object_file(fp, fname, anchor->fixup_list_head_); } }
/* * Read an object ID fixup list from an object file */ void CTcIdFixup::load_object_file(CVmFile *fp, const void *xlat, ulong xlat_cnt, tcgen_xlat_type xlat_type, size_t stream_element_size, const textchar_t *fname, CTcIdFixup **fixup_list_head) { ulong cnt; /* read the count, then read the fixups */ for (cnt = fp->read_uint4() ; cnt != 0 ; --cnt) { char buf[9]; ulong ofs; ulong old_id; ulong new_id; CTcDataStream *stream; /* read the next fixup */ fp->read_bytes(buf, 9); stream = CTcDataStream::get_stream_from_id(buf[0], fname); ofs = t3rp4u(buf+1); old_id = t3rp4u(buf+5); /* if the stream was invalid, ignore this record */ if (stream == 0) continue; /* adjust the offset for the stream's start in this object file */ ofs += stream->get_object_file_start_ofs(); /* apply the fixup if a translation table was provided */ if (xlat != 0) { /* make sure the count is in range - if it's not, ignore it */ if (old_id >= xlat_cnt) { /* note the problem */ G_tcmain->log_error(0, 0, TC_SEV_ERROR, TCERR_OBJFILE_INVAL_OBJ_ID, fname); /* ignore the record */ continue; } /* look up the new ID */ switch(xlat_type) { case TCGEN_XLAT_OBJ: new_id = ((const tctarg_obj_id_t *)xlat)[old_id]; break; case TCGEN_XLAT_PROP: new_id = ((const tctarg_prop_id_t *)xlat)[old_id]; break; case TCGEN_XLAT_ENUM: new_id = ((const ulong *)xlat)[old_id]; break; } /* apply the fixup */ if (stream_element_size == 2) stream->write2_at(ofs, (uint)new_id); else stream->write4_at(ofs, new_id); } else { /* use the original ID for now */ new_id = old_id; } /* * If we're keeping object fixups in the new file, create a * fixup for the reference. Note that the fixup is for the new * ID, not the old ID, because we've already translated the * value in the stream to the new ID. */ if (fixup_list_head != 0) CTcIdFixup::add_fixup(fixup_list_head, stream, ofs, new_id); } }
/* * Find a resource in a tads 2 game file */ static int t2_find_res(osfildef *fp, const char *resname, tads_resinfo *info) { char buf[300]; unsigned long startpos; size_t resname_len; int found; /* we haven't found what we're looking for yet */ found = FALSE; /* note the length of the name we're seeking */ resname_len = strlen(resname); /* * note the seek location of the start of the tads 2 game file stream * within the file - if the game file is embedded in a larger file * stream, the seek locations we find within the file are relative to * this starting location */ startpos = osfpos(fp); /* * skip past the tads 2 file header (13 bytes for the signature, 7 * bytes for the version header, 2 bytes for the flags, 26 bytes for * the timestamp) */ osfseek(fp, 13 + 7 + 2 + 26, OSFSK_CUR); /* * scan the sections in the file; stop on $EOF, and skip everything * else but HTMLRES, which is the section type that */ for (;;) { unsigned long endofs; /* read the section type and next-section pointer */ if (osfrb(fp, buf, 1) || osfrb(fp, buf + 1, (int)((unsigned char)buf[0] + 4))) { /* failed to read it - give up */ return FALSE; } /* note the ending position of this section */ endofs = t3rp4u(buf + 1 + (unsigned char)buf[0]); /* check the type */ if (buf[0] == 7 && memcmp(buf+1, "HTMLRES", 7) == 0) { unsigned long entry_cnt; unsigned long i; /* * It's a multimedia resource block. Read the index table * header (which contains the number of entries and a reserved * uint32). */ if (osfrb(fp, buf, 8)) return FALSE; /* get the number of entries from the header */ entry_cnt = t3rp4u(buf); /* read the entries */ for (i = 0 ; i < entry_cnt ; ++i) { unsigned long res_ofs; unsigned long res_siz; unsigned short name_len; /* read the entry header */ if (osfrb(fp, buf, 10)) return FALSE; /* parse the header */ res_ofs = t3rp4u(buf); res_siz = t3rp4u(buf + 4); name_len = osrp2(buf + 8); /* read the entry's name */ if (name_len > sizeof(buf) || osfrb(fp, buf, name_len)) return FALSE; /* * if it matches the name we're looking for, note that we * found it */ if (name_len == resname_len && memicmp(resname, buf, name_len) == 0) { /* * note that we found it, and note its resource size * and offset in the return structure - but keep * scanning the rest of the directory, since we need * to know where the directory ends to know where the * actual resources begin */ found = TRUE; info->seek_pos = res_ofs; info->siz = res_siz; } } /* * if we found our resource, the current seek position is the * base of the offset we found in the directory; so fix up the * offset to give the actual file location */ if (found) { /* fix up the offset with the actual file location */ info->seek_pos += osfpos(fp); /* tell the caller we found it */ return TRUE; } /* we didn't find it - seek to the end of this section */ osfseek(fp, endofs + startpos, OSFSK_SET); } else if (buf[0] == 4 && memcmp(buf+1, "$EOF", 4) == 0) { /* * that's the end of the file - we've finished without finding * the resource, so return failure */ return FALSE; } else { /* * this isn't a section we're interested in - skip to the end * of the section and keep going */ osfseek(fp, endofs + startpos, OSFSK_SET); } } }
/* * Find a resource in a T3 image file */ static int t3_find_res(osfildef *fp, const char *resname, tads_resinfo *info) { char buf[256]; size_t resname_len; /* note the length of the name we're seeking */ resname_len = strlen(resname); /* * skip the file header - 11 bytes for the signature, 2 bytes for the * format version, 32 reserved bytes, and 24 bytes for the timestamp */ osfseek(fp, 11 + 2 + 32 + 24, OSFSK_CUR); /* scan the data blocks */ for (;;) { unsigned long siz; /* read the block header */ if (osfrb(fp, buf, 10)) return FALSE; /* get the block size */ siz = t3rp4u(buf + 4); /* check the type */ if (memcmp(buf, "MRES", 4) == 0) { unsigned long base_ofs; unsigned int entry_cnt; unsigned int i; /* * remember the current seek position - the data seek location * for each index entry is given as an offset from this * location */ base_ofs = osfpos(fp); /* read the number of entries */ if (osfrb(fp, buf, 2)) return FALSE; /* parse the entry count */ entry_cnt = osrp2(buf); /* read the entries */ for (i = 0 ; i < entry_cnt ; ++i) { unsigned long entry_ofs; unsigned long entry_siz; unsigned int entry_name_len; char *p; size_t rem; /* read this index entry's header */ if (osfrb(fp, buf, 9)) return FALSE; /* parse the header */ entry_ofs = t3rp4u(buf); entry_siz = t3rp4u(buf + 4); entry_name_len = (unsigned char)buf[8]; /* read the entry's name */ if (osfrb(fp, buf, entry_name_len)) return FALSE; /* XOR the bytes of the name with 0xFF */ for (p = buf, rem = entry_name_len ; rem != 0 ; ++p, --rem) *p ^= 0xFF; /* if this is the one we're looking for, return it */ if (entry_name_len == resname_len && memicmp(resname, buf, resname_len) == 0) { /* * fill in the return information - note that the * entry offset given in the header is an offset from * data block's starting location, so fix this up to * an absolute seek location for the return value */ info->seek_pos = base_ofs + entry_ofs; info->siz = entry_siz; /* return success */ return TRUE; } } } else if (memcmp(buf, "EOF ", 4) == 0) { /* * end of file - we've finished without finding the resource, * so return failure */ return FALSE; } else { /* * we don't care about anything else - just skip this block * and keep going; to skip the block, simply seek ahead by the * size of the block's contents as given in the block header */ osfseek(fp, siz, OSFSK_CUR); } } }
/* * disassemble an instruction */ void CTcT3Unasm::disasm_instr(CTcUnasSrc *src, CTcUnasOut *out, char ch_op) { t3_instr_info_t *info; int i; ulong acc; char ch[10]; ulong prv_ofs = src->get_ofs(); /* get the information on this instruction */ info = &instr_info[(int)(uchar)ch_op]; out->print("%8lx %-14.14s ", src->get_ofs() - 1, info->nm); /* check the instruction type */ switch((uchar)ch_op) { case OPC_SWITCH: /* * It's a switch instruction - special handling is required, * since this instruction doesn't fit any of the normal * patterns. First, get the number of elements in the case * table - this is a UINT2 value at the start of the table. */ src->next_byte(ch); src->next_byte(ch+1); acc = osrp2(ch); /* display the count */ out->print("0x%x\n", (uint)acc); /* display the table */ for (i = 0 ; i < (int)acc ; ++i) { const char *dt; char valbuf[128]; const char *val = valbuf; /* note the current offset */ prv_ofs = src->get_ofs(); /* read the DATAHOLDER value */ src->next_byte(ch); src->next_byte(ch+1); src->next_byte(ch+2); src->next_byte(ch+3); src->next_byte(ch+4); /* read the jump offset */ src->next_byte(ch+5); src->next_byte(ch+6); /* * stop looping if the offset hasn't changed - this probably * means we're stuck trying to interpret as a "switch" some * data at the end of the stream that happens to look like a * switch but really isn't (such as an exception table, or * debug records) */ if (src->get_ofs() == prv_ofs) break; /* show the value */ switch(ch[0]) { case VM_NIL: dt = "nil"; val = ""; break; case VM_TRUE: dt = "true"; val = ""; break; case VM_OBJ: dt = "object"; sprintf(valbuf, "0x%08lx", t3rp4u(ch+1)); break; case VM_PROP: dt = "prop"; sprintf(valbuf, "0x%04x", osrp2(ch+1)); break; case VM_INT: dt = "int"; sprintf(valbuf, "0x%08lx", t3rp4u(ch+1)); break; case VM_ENUM: dt = "enum"; sprintf(valbuf, "0x%08lx", t3rp4u(ch+1)); break; case VM_SSTRING: dt = "sstring"; sprintf(valbuf, "0x%08lx", t3rp4u(ch+1)); break; case VM_LIST: dt = "list"; sprintf(valbuf, "0x%08lx", t3rp4u(ch+1)); break; case VM_FUNCPTR: dt = "funcptr"; sprintf(valbuf, "0x%08lx", t3rp4u(ch+1)); break; default: dt = "???"; val = "???"; break; } /* show the slot data */ out->print(" 0x%08lx %-8.8s(%-10.10s) " "-> +0x%04lx (0x%08lx)\n", src->get_ofs() - 7, dt, val, osrp2(ch+5), src->get_ofs() - 2 + osrp2s(ch+5)); } /* read and show the 'default' jump offset */ src->next_byte(ch); src->next_byte(ch+1); out->print(" 0x%08lx default " "-> +0x%04lx (0x%08lx)\n", src->get_ofs() - 2, osrp2(ch), src->get_ofs() - 2 + osrp2s(ch)); /* done */ break; default: /* show all parameters */ for (i = 0 ; i < info->op_cnt ; ++i) { /* add a separator if this isn't the first one */ if (i != 0) out->print(", "); /* display the operand */ switch(info->op_type[i]) { case T3OP_TYPE_8S: /* 8-bit signed integer */ src->next_byte(ch); out->print("0x%x", (int)ch[0]); break; case T3OP_TYPE_8U: /* 8-bit unsigned integer */ src->next_byte(ch); out->print("0x%x", (uint)(uchar)ch[0]); break; case T3OP_TYPE_16S: /* 16-bit signed integer */ src->next_byte(ch); src->next_byte(ch+1); acc = osrp2s(ch); out->print("0x%x", (int)acc); break; case T3OP_TYPE_16U: /* 16-bit unsigned integer */ src->next_byte(ch); src->next_byte(ch+1); acc = osrp2(ch); out->print("0x%x", (uint)acc); break; case T3OP_TYPE_32S: /* 32-bit signed integer */ src->next_byte(ch); src->next_byte(ch+1); src->next_byte(ch+2); src->next_byte(ch+3); acc = t3rp4u(ch); out->print("0x%lx", acc); break; case T3OP_TYPE_32U: /* 32-bit unsigned integer */ src->next_byte(ch); src->next_byte(ch+1); src->next_byte(ch+2); src->next_byte(ch+3); acc = t3rp4u(ch); out->print("0x%lx", acc); break; case T3OP_TYPE_STR: /* string offset */ src->next_byte(ch); src->next_byte(ch+1); src->next_byte(ch+2); src->next_byte(ch+3); acc = t3rp4u(ch); out->print("string(0x%lx)", acc); break; case T3OP_TYPE_LIST: /* list offset */ src->next_byte(ch); src->next_byte(ch+1); src->next_byte(ch+2); src->next_byte(ch+3); acc = t3rp4u(ch); out->print("list(0x%lx)", acc); break; case T3OP_TYPE_CODE_ABS: /* 32-bit absolute code address */ src->next_byte(ch); src->next_byte(ch+1); src->next_byte(ch+2); src->next_byte(ch+3); acc = t3rp4u(ch); out->print("code(0x%08lx)", acc); break; case T3OP_TYPE_CODE_REL: /* 16-bit relative code address */ src->next_byte(ch); src->next_byte(ch+1); acc = osrp2s(ch); if ((long)acc < 0) out->print("-0x%04x (0x%08lx)", -(int)acc, src->get_ofs() - 2 + acc); else out->print("+0x%04x (0x%08lx)", acc, src->get_ofs() - 2 + acc); break; case T3OP_TYPE_OBJ: /* object ID */ src->next_byte(ch); src->next_byte(ch+1); src->next_byte(ch+2); src->next_byte(ch+3); acc = t3rp4u(ch); out->print("object(0x%lx)", acc); break; case T3OP_TYPE_PROP: /* property ID */ src->next_byte(ch); src->next_byte(ch+1); acc = osrp2(ch); out->print("property(0x%x)", (uint)acc); break; case T3OP_TYPE_ENUM: /* enum */ src->next_byte(ch); src->next_byte(ch+1); src->next_byte(ch+2); src->next_byte(ch+3); acc = t3rp4u(ch); out->print("enum(0x%lx)", acc); break; case T3OP_TYPE_CTX_ELE: /* context element identifier */ src->next_byte(ch); switch(ch[0]) { case PUSHCTXELE_TARGPROP: out->print("targetprop"); break; case PUSHCTXELE_TARGOBJ: out->print("targetobj"); break; case PUSHCTXELE_DEFOBJ: out->print("definingobj"); break; default: out->print("0x%x", (int)ch[0]); break; } break; case T3OP_TYPE_INLINE_STR: /* get the string length */ src->next_byte(ch); src->next_byte(ch+1); /* show it */ out->print("string(inline)"); /* skip the string */ for (acc = osrp2(ch) ; acc != 0 ; --acc) src->next_byte(ch); /* done */ break; default: out->print("...unknown type..."); break; } } /* end the line */ out->print("\n"); } }