/* * Dump a typelib (tlb) file * * Copyright 2006 Jacek Caban * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include "wine/port.h" #include #include #include #include "windef.h" #include "winedump.h" #define MSFT_MAGIC 0x5446534d #define HELPDLLFLAG 0x0100 enum TYPEKIND { TKIND_ENUM = 0, TKIND_RECORD, TKIND_MODULE, TKIND_INTERFACE, TKIND_DISPATCH, TKIND_COCLASS, TKIND_ALIAS, TKIND_UNION, TKIND_MAX }; enum VARENUM { VT_EMPTY = 0, VT_NULL = 1, VT_I2 = 2, VT_I4 = 3, VT_R4 = 4, VT_R8 = 5, VT_CY = 6, VT_DATE = 7, VT_BSTR = 8, VT_DISPATCH = 9, VT_ERROR = 10, VT_BOOL = 11, VT_VARIANT = 12, VT_UNKNOWN = 13, VT_DECIMAL = 14, VT_I1 = 16, VT_UI1 = 17, VT_UI2 = 18, VT_UI4 = 19, VT_I8 = 20, VT_UI8 = 21, VT_INT = 22, VT_UINT = 23, VT_VOID = 24, VT_HRESULT = 25, VT_PTR = 26, VT_SAFEARRAY = 27, VT_CARRAY = 28, VT_USERDEFINED = 29, VT_LPSTR = 30, VT_LPWSTR = 31, VT_RECORD = 36, VT_INT_PTR = 37, VT_UINT_PTR = 38, VT_FILETIME = 64, VT_BLOB = 65, VT_STREAM = 66, VT_STORAGE = 67, VT_STREAMED_OBJECT = 68, VT_STORED_OBJECT = 69, VT_BLOB_OBJECT = 70, VT_CF = 71, VT_CLSID = 72, VT_VERSIONED_STREAM = 73, VT_BSTR_BLOB = 0xfff, VT_VECTOR = 0x1000, VT_ARRAY = 0x2000, VT_BYREF = 0x4000, VT_RESERVED = 0x8000, VT_ILLEGAL = 0xffff, VT_ILLEGALMASKED = 0xfff, VT_TYPEMASK = 0xfff }; struct seg_t; typedef BOOL (*dump_seg_t)(struct seg_t*); typedef struct seg_t { const char *name; dump_seg_t func; int offset; int length; } seg_t; static seg_t segdir[]; enum SEGDIRTYPE { SEGDIR_TYPEINFO, SEGDIR_IMPINFO, SEGDIR_IMPFILES, SEGDIR_REF, SEGDIR_GUIDHASH, SEGDIR_GUID, SEGDIR_NAMEHASH, SEGDIR_NAME, SEGDIR_STRING, SEGDIR_TYPEDESC, SEGDIR_ARRAYDESC, SEGDIR_CUSTDATA, SEGDIR_CDGUID, SEGDIR_res0e, SEGDIR_res0f }; static int offset=0; static int indent; static int typeinfo_cnt; static int header_flags = 0; static BOOL msft_eof = FALSE; static int msft_typeinfo_offs[1000]; static int msft_typeinfo_kind[1000]; static int msft_typeinfo_impltypes[1000]; static int msft_typeinfo_elemcnt[1000]; static int msft_typeinfo_cnt = 0; static const void *tlb_read(int size) { const void *ret = PRD(offset, size); if(ret) offset += size; else msft_eof = TRUE; return ret; } static int tlb_read_int(void) { const int *ret = tlb_read(sizeof(int)); return ret ? *ret : -1; } static int tlb_read_short(void) { const short *ret = tlb_read(sizeof(short)); return ret ? *ret : -1; } static int tlb_read_byte(void) { const unsigned char *ret = tlb_read(sizeof(char)); return ret ? *ret : -1; } static void print_offset(void) { int i; printf("%04x: ", offset); for(i=0; i= VT_EMPTY && vartype <= VT_LPWSTR) printf("%s\n", vartypes[vartype]); else printf("unk %d\n", vartype); } static void print_ctl2(const char *name) { int len; const char *buf; print_offset(); len = tlb_read_short(); printf("%s = %d \"", name, len); len >>= 2; buf = tlb_read(len); fwrite(buf, len, 1, stdout); printf("\""); len += 2; while(len++ & 3) printf("\\%02x", tlb_read_byte()); printf("\n"); } static void dump_binary(int n) { int i; for(i = 1; i <= n; i++) { switch(i & 0x0f) { case 0: printf("%02x\n", tlb_read_byte()); break; case 1: print_offset(); /* fall through */ default: printf("%02x ", tlb_read_byte()); } } if(n&0x0f) printf("\n"); } static int dump_msft_varflags(void) { static const char *syskind[] = { "SYS_WIN16", "SYS_WIN32", "SYS_MAC", "SYS_WIN64", "unknown" }; int kind, flags; print_offset(); flags = tlb_read_int(); kind = flags & 0xf; if (kind > 3) kind = 4; printf("varflags = %08x, syskind = %s\n", flags, syskind[kind]); return flags; } static void dump_msft_version(void) { int version; print_offset(); version = tlb_read_int(); printf("version = %d.%d\n", version & 0xff, version >> 16); } static void dump_msft_header(void) { print_begin_block("Header"); print_hex("magic1"); print_hex("magic2"); print_hex("posguid"); print_hex("lcid"); print_hex("lcid2"); header_flags = dump_msft_varflags(); dump_msft_version(); print_hex("flags"); typeinfo_cnt = print_dec("ntypeinfos"); print_dec("helpstring"); print_dec("helpstringcontext"); print_dec("helpcontext"); print_dec("nametablecount"); print_dec("nametablechars"); print_hex("NameOffset"); print_hex("helpfile"); print_hex("CustomDataOffset"); print_hex("res44"); print_hex("res48"); print_hex("dispatchpos"); print_hex("res50"); print_end_block(); } static int dump_msft_typekind(void) { static const char *tkind[TKIND_MAX] = { "TKIND_ENUM", "TKIND_RECORD", "TKIND_MODULE", "TKIND_INTERFACE", "TKIND_DISPATCH", "TKIND_COCLASS", "TKIND_ALIAS", "TKIND_UNION" }; int ret, typekind; print_offset(); ret = tlb_read_int(); typekind = ret & 0xf; printf("typekind = %s, align = %d\n", typekind < TKIND_MAX ? tkind[typekind] : "unknown", (ret >> 11) & 0x1f); return ret; } static void dump_msft_typeinfobase(void) { print_begin_block_id("TypeInfoBase", msft_typeinfo_cnt); msft_typeinfo_kind[msft_typeinfo_cnt] = dump_msft_typekind(); msft_typeinfo_offs[msft_typeinfo_cnt] = print_hex("memoffset"); print_hex("res2"); print_hex("res3"); print_hex("res4"); print_hex("res5"); msft_typeinfo_elemcnt[msft_typeinfo_cnt] = print_hex("cElement"); print_hex("res7"); print_hex("res8"); print_hex("res9"); print_hex("resA"); print_hex("posguid"); print_hex("flags"); print_hex("NameOffset"); print_hex("version"); print_hex("docstringoffs"); print_hex("docstringcontext"); print_hex("helpcontext"); print_hex("oCustData"); msft_typeinfo_impltypes[msft_typeinfo_cnt++] = print_short_hex("cImplTypes"); print_short_hex("bSizeVftt"); print_dec("size"); print_hex("datatype1"); print_hex("datatype2"); print_hex("res18"); print_hex("res19"); print_end_block(); } static BOOL dump_msft_typeinfobases(seg_t *seg) { int i; for(i = 0; offset < seg->offset+seg->length; i++) dump_msft_typeinfobase(); assert(offset == seg->offset+seg->length); return TRUE; } static void dump_msft_impinfo(int n) { print_begin_block_id("ImpInfo", n); print_hex("flags"); print_hex("oImpInfo"); print_hex("oGuid"); print_end_block(); } static BOOL dump_msft_impinfos(seg_t *seg) { int i; for(i = 0; offset < seg->offset+seg->length; i++) dump_msft_impinfo(i); assert(offset == seg->offset+seg->length); return TRUE; } static void dump_msft_impfile(int n) { print_begin_block_id("ImpFile", n); print_hex("guid"); print_hex("lcid"); print_hex("version"); print_ctl2("impfile"); print_end_block(); } static BOOL dump_msft_impfiles(seg_t *seg) { int i; for(i = 0; offset < seg->offset+seg->length; i++) dump_msft_impfile(i); assert(offset == seg->offset+seg->length); return TRUE; } static BOOL dump_msft_reftabs(seg_t *seg) { print_begin_block("RefTab"); dump_binary(seg->length); /* FIXME */ print_end_block(); return TRUE; } static BOOL dump_msft_guidhashtab(seg_t *seg) { print_begin_block("GuidHashTab"); dump_binary(seg->length); /* FIXME */ print_end_block(); assert(offset == seg->offset+seg->length); return TRUE; } static void dump_msft_guidentry(int n) { print_begin_block_id("GuidEntry", n); print_guid("guid"); print_hex("hreftype"); print_hex("next_hash"); print_end_block(); } static BOOL dump_msft_guidtab(seg_t *seg) { int i; for(i = 0; offset < seg->offset+seg->length; i++) dump_msft_guidentry(i); assert(offset == seg->offset+seg->length); return TRUE; } static BOOL dump_msft_namehashtab(seg_t *seg) { print_begin_block("NameHashTab"); dump_binary(seg->length); /* FIXME */ print_end_block(); return TRUE; } static void dump_string(int len, int align_off) { printf("\""); fwrite(tlb_read(len), len, 1, stdout); printf("\" "); while((len++ + align_off) & 3) printf("\\%2.2x", tlb_read_byte()); } static void dump_msft_name(int base, int n) { int len; print_begin_block_id("Name", n); print_hex("hreftype"); print_hex("next_hash"); len = print_hex("namelen")&0xff; print_offset(); printf("name = "); dump_string(len, 0); printf("\n"); print_end_block(); } static BOOL dump_msft_nametab(seg_t *seg) { int i, base = offset; for(i = 0; offset < seg->offset+seg->length; i++) dump_msft_name(base, i); assert(offset == seg->offset+seg->length); return TRUE; } static void dump_msft_string(int n) { int len; print_begin_block_id("String", n); len = print_short_hex("stringlen"); print_offset(); printf("string = "); dump_string(len, 2); if(len < 3) { for(len = 0; len < 4; len++) printf("\\%2.2x", tlb_read_byte()); } printf("\n"); print_end_block(); } static BOOL dump_msft_stringtab(seg_t *seg) { int i; for(i = 0; offset < seg->offset+seg->length; i++) dump_msft_string(i); assert(offset == seg->offset+seg->length); return TRUE; } static void dump_msft_typedesc(int n) { print_begin_block_id("TYPEDESC", n); print_hex("hreftype"); print_hex("vt"); print_end_block(); } static BOOL dump_msft_typedesctab(seg_t *seg) { int i; print_begin_block("TypedescTab"); for(i = 0; offset < seg->offset+seg->length; i++) dump_msft_typedesc(i); print_end_block(); assert(offset == seg->offset+seg->length); return TRUE; } static BOOL dump_msft_arraydescs(seg_t *seg) { print_begin_block("ArrayDescriptions"); dump_binary(seg->length); /* FIXME */ print_end_block(); return TRUE; } static BOOL dump_msft_custdata(seg_t *seg) { unsigned short vt; unsigned i, n; print_begin_block("CustData"); for(i=0; offset < seg->offset+seg->length; i++) { print_offset(); vt = tlb_read_short(); printf("vt %d", vt); n = tlb_read_int(); switch(vt) { case VT_BSTR: printf(" len %d: ", n); dump_string(n, 2); printf("\n"); break; default: printf(": %x ", n); printf("\\%2.2x ", tlb_read_byte()); printf("\\%2.2x\n", tlb_read_byte()); } } print_end_block(); return TRUE; } static void dump_msft_cdguid(int n) { print_begin_block_id("CGUid", n); print_hex("GuidOffset"); print_hex("DataOffset"); print_hex("next"); print_end_block(); } static BOOL dump_msft_cdguids(seg_t *seg) { int i; for(i = 0; offset < seg->offset+seg->length; i++) dump_msft_cdguid(i); assert(offset == seg->offset+seg->length); return TRUE; } static BOOL dump_msft_res0e(seg_t *seg) { print_begin_block("res0e"); dump_binary(seg->length); print_end_block(); return TRUE; } static BOOL dump_msft_res0f(seg_t *seg) { print_begin_block("res0f"); dump_binary(seg->length); print_end_block(); return TRUE; } /* Used for function return value and arguments type */ static void dump_msft_datatype(const char *name) { int datatype; print_offset(); datatype = tlb_read_int(); printf("%s = %08x", name, datatype); if (datatype < 0) { printf(", "); print_vartype(datatype); } else { const short *vt; if (datatype > segdir[SEGDIR_TYPEDESC].length) { printf(", invalid offset\n"); return; } /* FIXME: in case of VT_USERDEFINED use hreftype */ vt = PRD(segdir[SEGDIR_TYPEDESC].offset + datatype, 4*sizeof(short)); datatype = vt[0] & VT_TYPEMASK; if (datatype == VT_PTR) { printf(", VT_PTR -> "); if (vt[3] < 0) datatype = vt[2]; else { vt = PRD(segdir[SEGDIR_TYPEDESC].offset + vt[2], 4*sizeof(short)); datatype = *vt; } } else { printf(", "); datatype = *vt; } print_vartype(datatype); } } static void dump_defaultvalue(int id) { int offset; print_offset(); offset = tlb_read_int(); printf("default value[%d] = %08x", id, offset); if (offset == -1) printf("\n"); else if (offset < 0) { printf(", "); print_vartype((offset & 0x7c000000) >> 26); } else { const unsigned short *vt; if (offset > segdir[SEGDIR_CUSTDATA].length) { printf(", invalid offset\n"); return; } vt = PRD(segdir[SEGDIR_CUSTDATA].offset + offset, sizeof(*vt)); printf(", "); print_vartype(*vt); } } static void dump_msft_func(int n) { int size, args_cnt, i, extra_attr, fkccic; print_begin_block_id("FuncRecord", n); size = print_short_hex("size"); print_short_hex("index"); dump_msft_datatype("retval type"); print_hex("flags"); print_short_hex("VtableOffset"); print_short_hex("funcdescsize"); fkccic = print_hex("FKCCIC"); args_cnt = print_short_hex("nrargs"); print_short_hex("noptargs"); extra_attr = size/sizeof(INT) - 6 - args_cnt*(fkccic&0x1000 ? 4 : 3); if(extra_attr) print_hex("helpcontext"); if(extra_attr >= 2) print_hex("oHelpString"); if(extra_attr >= 3) print_hex("toEntry"); if(extra_attr >= 4) print_hex("res9"); if(extra_attr >= 5) print_hex("resA"); if(extra_attr >= 6) print_hex("HelpStringContext"); if(extra_attr >= 7) print_hex("oCustData"); for(i = 0; i < extra_attr-7; i++) print_hex_id("oArgCustData", i); if(fkccic & 0x1000) { for(i=0; i < args_cnt; i++) dump_defaultvalue(i); } for(i=0; i < args_cnt; i++) { print_begin_block_id("param", i); /* FIXME: Handle default values */ dump_msft_datatype("datatype"); print_hex("name"); print_hex("paramflags"); print_end_block(); } print_end_block(); } static void dump_msft_var(int n) { INT size; print_begin_block_id("VarRecord", n); size = print_hex("recsize")&0x1ff; print_hex("DataType"); print_hex("flags"); print_short_hex("VarKind"); print_short_hex("vardescsize"); print_hex("OffsValue"); if(size > 5*sizeof(INT)) dump_binary(size - 5*sizeof(INT)); print_end_block(); } static void dump_msft_ref(int n) { print_begin_block_id("RefRecord", n); print_hex("reftype"); print_hex("flags"); print_hex("oCustData"); print_hex("onext"); print_end_block(); } static void dump_msft_coclass(int n) { int i; print_dec("size"); for(i=0; i < msft_typeinfo_impltypes[n]; i++) dump_msft_ref(i); } static BOOL dump_msft_typeinfo(int n) { int i; print_begin_block_id("TypeInfo", n); if((msft_typeinfo_kind[n] & 0xf) == TKIND_COCLASS) { dump_msft_coclass(n); print_end_block(); return TRUE; } print_dec("size"); for(i = 0; i < LOWORD(msft_typeinfo_elemcnt[n]); i++) dump_msft_func(i); for(i = 0; i < HIWORD(msft_typeinfo_elemcnt[n]); i++) dump_msft_var(i); for(i = 0; i < LOWORD(msft_typeinfo_elemcnt[n]); i++) print_hex_id("func %d id", i); for(i = 0; i < HIWORD(msft_typeinfo_elemcnt[n]); i++) print_hex_id("var %d id", i); for(i = 0; i < LOWORD(msft_typeinfo_elemcnt[n]); i++) print_hex_id("func %d name", i); for(i = 0; i < HIWORD(msft_typeinfo_elemcnt[n]); i++) print_hex_id("var %d name", i); for(i = 0; i < LOWORD(msft_typeinfo_elemcnt[n]); i++) print_hex_id("func %d offset", i); for(i = 0; i < HIWORD(msft_typeinfo_elemcnt[n]); i++) print_hex_id("var %d offset", i); print_end_block(); return TRUE; } static seg_t segdir[] = { {"TypeInfoTab", dump_msft_typeinfobases, -1, -1}, {"ImpInfo", dump_msft_impinfos, -1, -1}, {"ImpFiles", dump_msft_impfiles, -1, -1}, {"RefTab", dump_msft_reftabs, -1, -1}, {"GuidHashTab", dump_msft_guidhashtab, -1, -1}, {"GuidTab", dump_msft_guidtab, -1, -1}, {"NameHashTab", dump_msft_namehashtab, -1, -1}, {"pNameTab", dump_msft_nametab, -1, -1}, {"pStringTab", dump_msft_stringtab, -1, -1}, {"TypedescTab", dump_msft_typedesctab, -1, -1}, {"ArrayDescriptions", dump_msft_arraydescs, -1, -1}, {"CustData", dump_msft_custdata, -1, -1}, {"CDGuid", dump_msft_cdguids, -1, -1}, {"res0e", dump_msft_res0e, -1, -1}, {"res0f", dump_msft_res0f, -1, -1} }; static void dump_msft_seg(seg_t *seg) { print_begin_block(seg->name); seg->offset = print_hex("offset"); seg->length = print_dec("length"); print_hex("res08"); print_hex("res0c"); print_end_block(); } static void dump_msft_segdir(void) { int i; print_begin_block("SegDir"); for(i=0; i < sizeof(segdir)/sizeof(segdir[0]); i++) dump_msft_seg(segdir+i); print_end_block(); } static BOOL dump_offset(void) { int i; for(i=0; i < sizeof(segdir)/sizeof(segdir[0]); i++) if(segdir[i].offset == offset) return segdir[i].func(segdir+i); for(i=0; i < msft_typeinfo_cnt; i++) if(msft_typeinfo_offs[i] == offset) return dump_msft_typeinfo(i); return FALSE; } enum FileSig get_kind_msft(void) { const DWORD *sig = PRD(0, sizeof(DWORD)); return sig && *sig == MSFT_MAGIC ? SIG_MSFT : SIG_UNKNOWN; } void msft_dump(void) { int i; dump_msft_header(); for(i=0; i < typeinfo_cnt; i++) print_hex_id("typeinfo %d offset", i); if(header_flags & HELPDLLFLAG) print_hex("help dll offset"); print_offset(); printf("\n"); dump_msft_segdir(); while(!msft_eof) { if(!dump_offset()) print_hex("unknown"); } }