Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- tools/winedump/dump.c | 2 +- tools/winedump/tlb.c | 1222 +++++++++++++++++++++++++++++++++++-- tools/winedump/winedump.h | 6 +- 3 files changed, 1187 insertions(+), 43 deletions(-)
diff --git a/tools/winedump/dump.c b/tools/winedump/dump.c index e84e473ea7..f608075d7b 100644 --- a/tools/winedump/dump.c +++ b/tools/winedump/dump.c @@ -241,7 +241,7 @@ dumpers[] = {SIG_LNK, get_kind_lnk, lnk_dump}, {SIG_EMF, get_kind_emf, emf_dump}, {SIG_FNT, get_kind_fnt, fnt_dump}, - {SIG_MSFT, get_kind_msft, msft_dump}, + {SIG_TLB, get_kind_tlb, tlb_dump}, {SIG_UNKNOWN, NULL, NULL} /* sentinel */ };
diff --git a/tools/winedump/tlb.c b/tools/winedump/tlb.c index df1ea4b576..e7301688df 100644 --- a/tools/winedump/tlb.c +++ b/tools/winedump/tlb.c @@ -2,6 +2,7 @@ * Dump a typelib (tlb) file * * Copyright 2006 Jacek Caban + * Copyright 2015 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -30,6 +31,7 @@ #include "winedump.h"
#define MSFT_MAGIC 0x5446534d +#define SLTG_MAGIC 0x47544c53 #define HELPDLLFLAG 0x0100
enum TYPEKIND { @@ -109,7 +111,7 @@ typedef struct seg_t { int offset; int length; } seg_t; -static seg_t segdir[]; +static seg_t segdir[15];
enum SEGDIRTYPE { SEGDIR_TYPEINFO, @@ -141,6 +143,12 @@ static int msft_typeinfo_impltypes[1000]; static int msft_typeinfo_elemcnt[1000]; static int msft_typeinfo_cnt = 0;
+static const char * const tkind[TKIND_MAX] = { + "TKIND_ENUM", "TKIND_RECORD", "TKIND_MODULE", + "TKIND_INTERFACE", "TKIND_DISPATCH", "TKIND_COCLASS", + "TKIND_ALIAS", "TKIND_UNION" +}; + static const void *tlb_read(int size) { const void *ret = PRD(offset, size);
@@ -160,7 +168,7 @@ static int tlb_read_int(void)
static int tlb_read_short(void) { - const short *ret = tlb_read(sizeof(short)); + const unsigned short *ret = tlb_read(sizeof(short)); return ret ? *ret : -1; }
@@ -173,9 +181,6 @@ static int tlb_read_byte(void) static void print_offset(void) { int i; - - printf("%04x: ", offset); - for(i=0; i<indent; i++) printf(" "); } @@ -199,15 +204,21 @@ static void print_end_block(void) indent--; print_offset(); printf("}\n"); +} + +static int print_byte(const char *name) +{ + unsigned char ret; print_offset(); - printf("\n"); + printf("%s = %02xh\n", name, ret=tlb_read_byte()); + return ret; }
static int print_hex(const char *name) { int ret; print_offset(); - printf("%s = %08x\n", name, ret=tlb_read_int()); + printf("%s = %08xh\n", name, ret=tlb_read_int()); return ret; }
@@ -222,7 +233,15 @@ static int print_short_hex(const char *name) { int ret; print_offset(); - printf("%s = %xh\n", name, ret=tlb_read_short()); + printf("%s = %04xh\n", name, ret=tlb_read_short()); + return ret; +} + +static int print_short_dec(const char *name) +{ + int ret; + print_offset(); + printf("%s = %d\n", name, ret=tlb_read_short()); return ret; }
@@ -286,25 +305,47 @@ static void print_ctl2(const char *name) printf("\n"); }
-static void dump_binary(int n) +static int tlb_isprint(unsigned char c) { - int i; + return c >= 32; +}
- 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()); +static void dump_binary(int size) +{ + const unsigned char *ptr; + int i, j; + + if (!size) return; + + ptr = tlb_read(size); + if (!ptr) return; + + print_offset(); + printf("%08x: ", offset - size); + + for (i = 0; i < size; i++) + { + printf("%02x%c", ptr[i], (i % 16 == 7) ? '-' : ' '); + if ((i % 16) == 15) + { + printf( " " ); + for (j = 0; j < 16; j++) + printf("%c", tlb_isprint(ptr[i-15+j]) ? ptr[i-15+j] : '.'); + if (i < size-1) + { + printf("\n"); + print_offset(); + printf("%08x: ", offset - size + i + 1); + } } } - - if(n&0x0f) - printf("\n"); + if (i % 16) + { + printf("%*s ", 3 * (16-(i%16)), ""); + for (j = 0; j < i % 16; j++) + printf("%c", tlb_isprint(ptr[i-(i%16)+j]) ? ptr[i-(i%16)+j] : '.'); + } + printf("\n"); }
static int dump_msft_varflags(void) @@ -324,10 +365,10 @@ static int dump_msft_varflags(void)
static void dump_msft_version(void) { - int version; + unsigned version; print_offset(); version = tlb_read_int(); - printf("version = %d.%d\n", version & 0xff, version >> 16); + printf("version = %u.%u\n", version & 0xffff, version >> 16); }
static void dump_msft_header(void) @@ -361,11 +402,6 @@ static void dump_msft_header(void)
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(); @@ -520,11 +556,36 @@ static BOOL dump_msft_namehashtab(seg_t *seg) return TRUE; }
-static void dump_string(int len, int align_off) +static void print_string0(void) +{ + unsigned char c; + + printf("""); + while ((c = tlb_read_byte()) != 0) + { + if (isprint(c)) + fwrite(&c, 1, 1, stdout); + else + { + char buf[16]; + sprintf(buf, "\%u", c); + fwrite(buf, 1, strlen(buf), stdout); + } + } + printf("""); +} + +static void print_string(int len) { printf("""); fwrite(tlb_read(len), len, 1, stdout); - printf("" "); + printf("""); +} + +static void dump_string(int len, int align_off) +{ + print_string(len); + printf(" "); while((len++ + align_off) & 3) printf("\%2.2x", tlb_read_byte()); } @@ -960,13 +1021,7 @@ static BOOL dump_offset(void) 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) +static void msft_dump(void) { int i;
@@ -987,3 +1042,1092 @@ void msft_dump(void) print_hex("unknown"); } } + +/****************************** SLTG Typelibs ******************************/ + +struct block_entry +{ + DWORD len; + WORD index_string; + WORD next; +}; + +struct bitstream +{ + const BYTE *buffer; + DWORD length; + WORD current; +}; + +#include "pshpack1.h" +struct sltg_typeinfo_header +{ + short magic; + int href_table; + int res06; + int elem_table; + int res0e; + int version; + int res16; + struct + { + unsigned unknown1 : 3; + unsigned flags : 16; + unsigned unknown2 : 5; + unsigned typekind : 8; + } misc; + int res1e; +}; + +struct sltg_member_header +{ + short res00; + short res02; + char res04; + int extra; +}; + +struct sltg_tail +{ + unsigned short cFuncs; + unsigned short cVars; + unsigned short cImplTypes; + unsigned short res06; /* always 0000 */ + unsigned short funcs_off; /* offset to functions (starting from the member header) */ + unsigned short vars_off; /* offset to vars (starting from the member header) */ + unsigned short impls_off; /* offset to implemented types (starting from the member header) */ + unsigned short funcs_bytes; /* bytes used by function data */ + unsigned short vars_bytes; /* bytes used by var data */ + unsigned short impls_bytes; /* bytes used by implemented type data */ + unsigned short tdescalias_vt; /* for TKIND_ALIAS */ + unsigned short res16; /* always ffff */ + unsigned short res18; /* always 0000 */ + unsigned short res1a; /* always 0000 */ + unsigned short simple_alias; /* tdescalias_vt is a vt rather than an offset? */ + unsigned short res1e; /* always 0000 */ + unsigned short cbSizeInstance; + unsigned short cbAlignment; + unsigned short res24; + unsigned short res26; + unsigned short cbSizeVft; + unsigned short res2a; /* always ffff */ + unsigned short res2c; /* always ffff */ + unsigned short res2e; /* always ffff */ + unsigned short res30; /* always ffff */ + unsigned short res32; + unsigned short res34; +}; + +struct sltg_variable +{ + char magic; /* 0x0a */ + char flags; + short next; + short name; + short byte_offs; /* pos in struct, or offset to const type or const data (if flags & 0x08) */ + short type; /* if flags & 0x02 this is the type, else offset to type */ + int memid; + short helpcontext; /* ?? */ + short helpstring; /* ?? */ +#if 0 + short varflags; /* only present if magic & 0x20 */ +#endif +}; +#include "poppack.h" + +static const char *lookup_code(const BYTE *table, DWORD table_size, struct bitstream *bits) +{ + const BYTE *p = table; + + while (p < table + table_size && *p == 0x80) + { + if (p + 2 >= table + table_size) return NULL; + + if (!(bits->current & 0xff)) + { + if (!bits->length) return NULL; + bits->current = (*bits->buffer << 8) | 1; + bits->buffer++; + bits->length--; + } + + if (bits->current & 0x8000) + { + p += 3; + } + else + { + p = table + (*(p + 2) | (*(p + 1) << 8)); + } + + bits->current <<= 1; + } + + if (p + 1 < table + table_size && *(p + 1)) + { + /* FIXME: Whats the meaning of *p? */ + const BYTE *q = p + 1; + while (q < table + table_size && *q) q++; + return (q < table + table_size) ? (const char *)(p + 1) : NULL; + } + + return NULL; +} + +static const char *decode_string(const BYTE *table, const char *stream, DWORD stream_length, DWORD *read_bytes) +{ + char *buf; + DWORD buf_size, table_size; + const char *p; + struct bitstream bits; + + bits.buffer = (const BYTE *)stream; + bits.length = stream_length; + bits.current = 0; + + buf_size = *(const WORD *)table; + table += sizeof(WORD); + table_size = *(const DWORD *)table; + table += sizeof(DWORD); + + buf = malloc(buf_size); + buf[0] = 0; + + while ((p = lookup_code(table, table_size, &bits))) + { + if (buf[0]) strcat(buf, " "); + assert(strlen(buf) + strlen(p) + 1 <= buf_size); + strcat(buf, p); + } + + if (read_bytes) *read_bytes = stream_length - bits.length; + + return buf; +} + +static void print_sltg_name(const char *name) +{ + unsigned short len = tlb_read_short(); + print_offset(); + printf("%s = %#x (", name, len); + if (len != 0xffff) print_string(len); + printf(")\n"); +} + +static int dump_sltg_header(int *sltg_first_blk, int *size_of_index) +{ + int n_file_blocks; + + print_begin_block("Header"); + + print_hex("magic"); + n_file_blocks = print_short_dec("# file blocks"); + print_short_hex("res06"); + *size_of_index = print_short_hex("size of index"); + *sltg_first_blk = print_short_dec("first block"); + print_guid("guid"); + print_hex("res1c"); + print_hex("res20"); + + print_end_block(); + + return n_file_blocks; +} + +static void dump_sltg_index(int count) +{ + int i; + + printf("index:\n"); + + print_string0(); + printf("\n"); + print_string0(); + printf("\n"); + + for (i = 0; i < count - 2; i++) + { + print_string0(); + printf("\n"); + } + + printf("\n"); +} + +static void dump_sltg_pad9(void) +{ + printf("pad9:\n"); + dump_binary(9); + printf("\n"); +} + +static void dump_sltg_block_entry(int idx, const char *index) +{ + char name[32]; + short index_offset; + + sprintf(name, "Block entry %d", idx); + print_begin_block(name); + + print_hex("len"); + index_offset = tlb_read_short(); + print_offset(); + printf("index string = %xh "%s"\n", index_offset, index + index_offset); + print_short_hex("next"); + + print_end_block(); +} + +static void dump_sltg_library_block(void) +{ + print_begin_block("Library block entry"); + + print_short_hex("magic"); + print_short_hex("res02"); + print_sltg_name("name"); + print_short_hex("res06"); + print_sltg_name("helpstring"); + print_sltg_name("helpfile"); + print_hex("helpcontext"); + print_short_hex("syskind"); + print_short_hex("lcid"); + print_hex("res12"); + print_short_hex("libflags"); + dump_msft_version(); + print_guid("uuid"); + + print_end_block(); +} + +static void skip_sltg_library_block(void) +{ + unsigned short skip; + + tlb_read_short(); + tlb_read_short(); + skip = tlb_read_short(); + if (skip != 0xffff) tlb_read(skip); + tlb_read_short(); + skip = tlb_read_short(); + if (skip != 0xffff) tlb_read(skip); + skip = tlb_read_short(); + if (skip != 0xffff) tlb_read(skip); + tlb_read_int(); + tlb_read_short(); + tlb_read_short(); + tlb_read_int(); + tlb_read_short(); + tlb_read_int(); + tlb_read(sizeof(GUID)); +} + +static void dump_sltg_other_typeinfo(int idx, const char *hlp_strings) +{ + int hlpstr_len, saved_offset; + char name[32]; + + sprintf(name, "Other typeinfo %d", idx); + print_begin_block(name); + + print_sltg_name("index name"); + print_sltg_name("other name"); + print_short_hex("res1a"); + print_short_hex("name offset"); + + print_offset(); + hlpstr_len = tlb_read_short(); + if (hlpstr_len) + { + const char *str; + + saved_offset = offset; + str = tlb_read(hlpstr_len); + str = decode_string((const BYTE *)hlp_strings, str, hlpstr_len, NULL); + printf("helpstring: "%s"\n", str); + + offset = saved_offset; + print_offset(); + printf("helpstring encoded bits: %d bytes\n", hlpstr_len); + dump_binary(hlpstr_len); + } + else + printf("helpstring: ""\n"); + + print_short_hex("res20"); + print_hex("helpcontext"); + print_short_hex("res26"); + print_guid("uuid"); + print_short_dec("typekind"); + + print_end_block(); +} + +static void skip_sltg_other_typeinfo(void) +{ + unsigned short skip; + + skip = tlb_read_short(); + if (skip != 0xffff) tlb_read(skip); + skip = tlb_read_short(); + if (skip != 0xffff) tlb_read(skip); + tlb_read_short(); + tlb_read_short(); + skip = tlb_read_short(); + if (skip) tlb_read(skip); + tlb_read_short(); + tlb_read_int(); + tlb_read_short(); + tlb_read(sizeof(GUID)); + tlb_read_short(); +} + +static void sltg_print_simple_type(short type) +{ + print_offset(); + if ((type & 0x0f00) == 0x0e00) + printf("*"); + printf("%04x | (%d)\n", type & 0xff80, type & 0x7f); +} + +static void dump_safe_array(int array_offset) +{ + int i, cDims, saved_offset = offset; + + offset = array_offset; + + print_offset(); + printf("safe array starts at %#x\n", offset); + + cDims = print_short_dec("cDims"); + print_short_hex("fFeatures"); + print_dec("cbElements"); + print_dec("cLocks"); + print_hex("pvData"); + + for (i = 0; i < cDims; i++) + dump_binary(8); /* sizeof(SAFEARRAYBOUND) */ + + print_offset(); + printf("safe array ends at %#x\n", offset); + offset = saved_offset; +} + +static int sltg_print_compound_type(int vars_start_offset, int type_offset) +{ + short type, vt; + int type_bytes, saved_offset = offset; + + offset = vars_start_offset + type_offset; + print_offset(); + printf("type description starts at %#x\n", offset); + + for (;;) + { + do + { + type = tlb_read_short(); + vt = type & 0x7f; + + if (vt == VT_PTR) + { + print_offset(); + printf("%04x | VT_PTR\n", type & 0xff80); + } + } while (vt == VT_PTR); + + if (vt == VT_USERDEFINED) + { + short href = tlb_read_short(); + print_offset(); + if ((type & 0x0f00) == 0x0e00) + printf("*"); + printf("%04x | VT_USERDEFINED (href %d)\n", type & 0xff80, href); + break; + } + else if (vt == VT_CARRAY) + { + short off; + + off = tlb_read_short(); + print_offset(); + printf("VT_CARRAY: offset %#x (+%#x=%#x)\n", + off, vars_start_offset, off + vars_start_offset); + dump_safe_array(vars_start_offset + off); + + /* type description follows */ + print_offset(); + printf("array element type:\n"); + continue; + } + else if (vt == VT_SAFEARRAY) + { + short off; + + off = tlb_read_short(); + print_offset(); + printf("VT_SAFEARRAY: offset %#x (+%#x=%#x)\n", + off, vars_start_offset, off + vars_start_offset); + dump_safe_array(vars_start_offset + off); + break; + } + else + { + sltg_print_simple_type(type); + break; + } + } + + print_offset(); + printf("type description ends at %#x\n", offset); + type_bytes = offset - saved_offset; + offset = saved_offset; + + return type_bytes; +} + +static void dump_type(int len, const char *hlp_strings) +{ + union + { + struct + { + unsigned unknown1 : 3; + unsigned flags : 13; + unsigned unknown2 : 8; + unsigned typekind : 8; + } s; + unsigned flags; + } misc; + int typeinfo_start_offset, extra, member_offset, href_offset, i; + int vars_header_bytes = 0, vars_bytes = 0, saved_offset; + const void *block; + const struct sltg_typeinfo_header *ti; + const struct sltg_member_header *mem; + const struct sltg_tail *tail; + + typeinfo_start_offset = offset; + block = tlb_read(len); + offset = typeinfo_start_offset; + + ti = block; + mem = (const struct sltg_member_header *)((char *)block + ti->elem_table); + tail = (const struct sltg_tail *)((char *)(mem + 1) + mem->extra); + + typeinfo_start_offset = offset; + + print_short_hex("magic"); + href_offset = tlb_read_int(); + print_offset(); + if (href_offset != -1) + printf("href offset = %#x (+%#x=%#x)\n", + href_offset, typeinfo_start_offset, href_offset + typeinfo_start_offset); + else + printf("href offset = ffffffffh\n"); + print_hex("res06"); + member_offset = tlb_read_int(); + print_offset(); + printf("member offset = %#x (+%#x=%#x)\n", + member_offset, typeinfo_start_offset, member_offset + typeinfo_start_offset); + print_hex("res0e"); + print_hex("version"); + print_hex("res16"); + misc.flags = print_hex("misc"); + print_offset(); + printf("misc: unknown1 %02x, flags %04x, unknown2 %02x, typekind %u (%s)\n", + misc.s.unknown1, misc.s.flags, misc.s.unknown2, misc.s.typekind, + misc.s.typekind < TKIND_MAX ? tkind[misc.s.typekind] : "unknown"); + print_hex("res1e"); + + if (href_offset != -1) + { + int i, number; + + print_begin_block("href_table"); + + print_short_hex("magic"); + print_hex("res02"); + print_hex("res06"); + print_hex("res0a"); + print_hex("res0e"); + print_hex("res12"); + print_hex("res16"); + print_hex("res1a"); + print_hex("res1e"); + print_hex("res22"); + print_hex("res26"); + print_hex("res2a"); + print_hex("res2e"); + print_hex("res32"); + print_hex("res36"); + print_hex("res3a"); + print_hex("res3e"); + print_short_hex("res42"); + number = print_hex("number"); + + for (i = 0; i < number; i += 8) + dump_binary(8); + + print_short_hex("res50"); + print_byte("res52"); + print_hex("res53"); + + for (i = 0; i < number/8; i++) + print_sltg_name("name"); + + print_byte("resxx"); + + print_end_block(); + } + + print_offset(); + printf("member_header starts at %#x, current offset = %#x\n", typeinfo_start_offset + member_offset, offset); + member_offset = offset; + print_short_hex("res00"); + print_short_hex("res02"); + print_byte("res04"); + extra = print_hex("extra"); + + if (misc.s.typekind == TKIND_RECORD || misc.s.typekind == TKIND_ENUM) + { + int vars_start_offset = offset; + + for (i = 0; i < tail->cVars; i++) + { + char name[32]; + int saved_off; + char magic, flags; + short next, value; + + sprintf(name, "variable %d", i); + print_begin_block(name); + + saved_off = offset; + dump_binary(sizeof(struct sltg_variable)); + offset = saved_off; + + magic = print_byte("magic"); + flags = print_byte("flags"); + next = tlb_read_short(); + print_offset(); + if (next != -1) + printf("next offset = %#x (+%#x=%#x)\n", + next, vars_start_offset, next + vars_start_offset); + else + printf("next offset = ffffh\n"); + print_short_hex("name"); + + if (flags & 0x40) + print_short_hex("dispatch"); + else if (flags & 0x10) + { + if (flags & 0x08) + print_short_hex("const value"); + else + { + value = tlb_read_short(); + print_offset(); + printf("byte offset = %#x (+%#x=%#x)\n", + value, vars_start_offset, value + vars_start_offset); + } + } + else + print_short_hex("oInst"); + + value = tlb_read_short(); + if (!(flags & 0x02)) + { + print_offset(); + printf("type offset = %#x (+%#x=%#x)\n", + value, vars_start_offset, value + vars_start_offset); + print_offset(); + printf("type:\n"); + vars_bytes += sltg_print_compound_type(vars_start_offset, value); + } + else + { + print_offset(); + printf("type:\n"); + sltg_print_simple_type(value); + } + + print_hex("memid"); + print_short_hex("helpcontext"); + + value = tlb_read_short(); + print_offset(); + if (value != -1) + { + const char *str; + DWORD hlpstr_maxlen; + + printf("helpstring offset = %#x (+%#x=%#x)\n", + value, vars_start_offset, value + vars_start_offset); + + saved_offset = offset; + + offset = value + vars_start_offset; + + hlpstr_maxlen = member_offset + sizeof(struct sltg_member_header) + mem->extra - offset; + + str = tlb_read(hlpstr_maxlen); + str = decode_string((const BYTE *)hlp_strings, str, hlpstr_maxlen, &hlpstr_maxlen); + print_offset(); + printf("helpstring: "%s"\n", str); + + offset = value + vars_start_offset; + print_offset(); + printf("helpstring encoded bits: %d bytes\n", hlpstr_maxlen); + dump_binary(hlpstr_maxlen); + + offset = saved_offset; + } + else + printf("helpstring offset = ffffh\n"); + + if (magic & 0x20) + { + print_short_hex("varflags"); + vars_header_bytes += 2; + } + + vars_header_bytes += sizeof(struct sltg_variable); + + if (next != -1) + { + if (offset != vars_start_offset + next) + dump_binary(vars_start_offset + next - offset); + } + + print_end_block(); + } + } + else if (misc.s.typekind == TKIND_INTERFACE || misc.s.typekind == TKIND_COCLASS) + { + short next, i; + int funcs_start_offset = offset; + + for (i = 0; i < tail->cImplTypes; i++) + { + char name[32]; + + sprintf(name, "impl.type %d (current offset %#x)", i, offset); + print_begin_block(name); + + print_short_hex("res00"); + next = tlb_read_short(); + print_offset(); + if (next != -1) + printf("next offset = %#x (+%#x=%#x)\n", + next, funcs_start_offset, next + funcs_start_offset); + else + printf("next offset = ffffh\n"); + print_short_hex("res04"); + print_byte("impltypeflags"); + print_byte("res07"); + print_short_hex("res08"); + print_short_hex("ref"); + print_short_hex("res0c"); + print_short_hex("res0e"); + print_short_hex("res10"); + print_short_hex("res12"); + print_short_hex("pos in table"); + + print_end_block(); + } + + for (i = 0; i < tail->cFuncs; i++) + { + char name[32]; + BYTE magic, flags; + short args_off, value, n_params, j; + + sprintf(name, "function %d (current offset %#x)", i, offset); + print_begin_block(name); + + magic = print_byte("magic"); + flags = tlb_read_byte(); + print_offset(); + printf("invoke_kind = %u\n", flags >> 4); + next = tlb_read_short(); + print_offset(); + if (next != -1) + printf("next offset = %#x (+%#x=%#x)\n", + next, funcs_start_offset, next + funcs_start_offset); + else + printf("next offset = ffffh\n"); + print_short_hex("name"); + print_hex("dispid"); + print_short_hex("helpcontext"); + + value = tlb_read_short(); + print_offset(); + if (value != -1) + { + const char *str; + DWORD hlpstr_maxlen; + + printf("helpstring offset = %#x (+%#x=%#x)\n", + value, funcs_start_offset, value + funcs_start_offset); + + saved_offset = offset; + + offset = value + funcs_start_offset; + + hlpstr_maxlen = member_offset + sizeof(struct sltg_member_header) + mem->extra - offset; + + str = tlb_read(hlpstr_maxlen); + str = decode_string((const BYTE *)hlp_strings, str, hlpstr_maxlen, &hlpstr_maxlen); + print_offset(); + printf("helpstring: "%s"\n", str); + + offset = value + funcs_start_offset; + print_offset(); + printf("helpstring encoded bits: %d bytes\n", hlpstr_maxlen); + dump_binary(hlpstr_maxlen); + + offset = saved_offset; + } + else + printf("helpstring offset = ffffh\n"); + + args_off = tlb_read_short(); + print_offset(); + if (args_off != -1) + printf("args off = %#x (+%#x=%#x)\n", + args_off, funcs_start_offset, args_off + funcs_start_offset); + else + printf("args off = ffffh\n"); + flags = tlb_read_byte(); + n_params = flags >> 3; + print_offset(); + printf("callconv %u, cParams %u\n", flags & 0x7, n_params); + + flags = tlb_read_byte(); + print_offset(); + printf("retnextop %02x, cParamsOpt %u\n", flags, (flags & 0x7e) >> 1); + + value = print_short_hex("rettype"); + if (!(flags & 0x80)) + { + print_offset(); + printf("rettype offset = %#x (+%#x=%#x)\n", + value, funcs_start_offset, value + funcs_start_offset); + print_offset(); + printf("rettype:\n"); + sltg_print_compound_type(funcs_start_offset, value); + } + else + { + print_offset(); + printf("rettype:\n"); + sltg_print_simple_type(value); + } + + print_short_hex("vtblpos"); + if (magic & 0x20) + print_short_hex("funcflags"); + + if (n_params) + { + offset = args_off + funcs_start_offset; + print_offset(); + printf("arguments start at %#x\n", offset); + } + + for (j = 0; j < n_params; j++) + { + char name[32]; + unsigned short name_offset; + + sprintf(name, "arg %d", j); + print_begin_block(name); + + name_offset = tlb_read_short(); + print_offset(); + printf("name: %04xh\n", name_offset); + + value = tlb_read_short(); + print_offset(); + printf("type/offset %04xh\n", value); + if (name_offset & 1) /* type follows */ + { + print_offset(); + printf("type follows, using current offset for type\n"); + offset -= 2; + value = offset - funcs_start_offset; + } + + print_offset(); + printf("arg[%d] off = %#x (+%#x=%#x)\n", + j, value, funcs_start_offset, value + funcs_start_offset); + print_offset(); + printf("type:\n"); + value = sltg_print_compound_type(funcs_start_offset, value); + if (name_offset & 1) + offset += value; + + print_end_block(); + } + + if (n_params) + { + print_offset(); + printf("arguments end at %#x\n", offset); + } + + if (next != -1) + { + if (offset != funcs_start_offset + next) + dump_binary(funcs_start_offset + next - offset); + } + + print_end_block(); + } + } + else + { + printf("skipping %#x bytes\n", extra); + dump_binary(extra); + } + + if (offset < member_offset + sizeof(struct sltg_member_header) + mem->extra) + { + print_offset(); + printf("skipping %d bytes\n", member_offset + (int)sizeof(struct sltg_member_header) + mem->extra - offset); + dump_binary(member_offset + sizeof(struct sltg_member_header) + mem->extra - offset); + } + + print_offset(); + printf("dumped %d (%#x) bytes\n", offset - typeinfo_start_offset, offset - typeinfo_start_offset); + len -= offset - typeinfo_start_offset; + print_offset(); + printf("sltg_tail %d (%#x) bytes:\n", len, len); + saved_offset = offset; + dump_binary(len); + offset = saved_offset; + print_short_hex("cFuncs"); + print_short_hex("cVars"); + print_short_hex("cImplTypes"); + print_short_hex("res06"); + print_short_hex("funcs_off"); + print_short_hex("vars_off"); + print_short_hex("impls_off"); + print_short_hex("funcs_bytes"); + print_short_hex("vars_bytes"); + print_short_hex("impls_bytes"); + print_short_hex("tdescalias_vt"); + print_short_hex("res16"); + print_short_hex("res18"); + print_short_hex("res1a"); + print_short_hex("simple_alias"); + print_short_hex("res1e"); + print_short_hex("cbSizeInstance"); + print_short_hex("cbAlignment"); + print_short_hex("res24"); + print_short_hex("res26"); + print_short_hex("cbSizeVft"); + print_short_hex("res2a"); + print_short_hex("res2c"); + print_short_hex("res2e"); + print_short_hex("res30"); + print_short_hex("res32"); + print_short_hex("res34"); + offset = saved_offset + len; +} + +static void sltg_dump(void) +{ + int i, n_file_blocks, n_first_blk, size_of_index; + int name_table_start, name_table_size, saved_offset; + int libblk_start, libblk_len, hlpstr_len, len; + const char *index, *hlp_strings; + const struct block_entry *entry; + + n_file_blocks = dump_sltg_header(&n_first_blk, &size_of_index); + + saved_offset = offset; + entry = tlb_read((n_file_blocks - 1) * sizeof(*entry)); + if (!entry) return; + index = tlb_read(size_of_index); + if (!index) return; + offset = saved_offset; + + for (i = 0; i < n_file_blocks - 1; i++) + dump_sltg_block_entry(i, index); + + saved_offset = offset; + dump_sltg_index(n_file_blocks); + assert(offset - saved_offset == size_of_index); + + dump_sltg_pad9(); + + /* read the helpstrings for later decoding */ + saved_offset = offset; + + for (i = n_first_blk - 1; entry[i].next != 0; i = entry[i].next - 1) + tlb_read(entry[i].len); + + libblk_start = offset; + skip_sltg_library_block(); + tlb_read(0x40); + typeinfo_cnt = tlb_read_short(); + + for (i = 0; i < typeinfo_cnt; i++) + skip_sltg_other_typeinfo(); + + len = tlb_read_int(); + hlpstr_len = (libblk_start + len) - offset; + hlp_strings = tlb_read(hlpstr_len); + assert(hlp_strings != NULL); + /* check the helpstrings header values */ + len = *(int *)(hlp_strings + 2); + assert(hlpstr_len == len + 6); + + offset = saved_offset; + + for (i = n_first_blk - 1; entry[i].next != 0; i = entry[i].next - 1) + { + short magic; + char name[32]; + + saved_offset = offset; + + sprintf(name, "Block %d", i); + print_begin_block(name); + magic = tlb_read_short(); + assert(magic == 0x0501); + offset -= 2; + dump_binary(entry[i].len); + print_end_block(); + + offset = saved_offset; + + print_begin_block(name); + dump_type(entry[i].len, hlp_strings); + print_end_block(); + + offset = saved_offset + entry[i].len; + } + + libblk_len = entry[i].len; + + libblk_start = offset; + dump_sltg_library_block(); + + printf("skipping 0x40 bytes\n"); + dump_binary(0x40); + printf("\n"); + typeinfo_cnt = print_short_dec("typeinfo count"); + printf("\n"); + + for (i = 0; i < typeinfo_cnt; i++) + dump_sltg_other_typeinfo(i, hlp_strings); + + len = print_hex("offset from start of library block to name table"); + printf("%#x + %#x = %#x\n", libblk_start, len, libblk_start + len); + len = (libblk_start + len) - offset; + printf("skipping %#x bytes (encoded/compressed helpstrings)\n", len); + printf("max string length: %#x, strings length %#x\n", *(short *)hlp_strings, *(int *)(hlp_strings + 2)); + dump_binary(len); + printf("\n"); + + len = print_short_hex("name table jump"); + if (len == 0xffff) + { + printf("skipping 0x000a bytes\n"); + dump_binary(0x000a); + printf("\n"); + } + else if (len == 0x0200) + { + printf("skipping 0x002a bytes\n"); + dump_binary(0x002a); + printf("\n"); + } + else + { + printf("FIXME: please report! (%#x)\n", len); + assert(0); + } + + printf("skipping 0x200 bytes\n"); + dump_binary(0x200); + printf("\n"); + + name_table_size = print_hex("name table size"); + + name_table_start = offset; + printf("name table offset = %#x\n\n", offset); + + while (offset < name_table_start + name_table_size) + { + int aligned_len; + + dump_binary(8); + print_string0(); + printf("\n"); + + len = offset - name_table_start; + aligned_len = (len + 0x1f) & ~0x1f; + if (aligned_len - len < 4) + dump_binary(aligned_len - len); + else + dump_binary(len & 1); + printf("\n"); + } + + print_hex("01ffff01"); + len = print_hex("length"); + printf("skipping %#x bytes\n", len); + dump_binary(len); + printf("\n"); + + len = (libblk_start + libblk_len) - offset; + printf("skipping libblk remainder %#x bytes\n", len); + dump_binary(len); + printf("\n"); + + /* FIXME: msodumper/olestream.py parses this block differently + print_short_hex("unknown"); + print_short_hex("byte order mark"); + i = tlb_read_short(); + printf("version = %u.%u\n", i & 0xff, i >> 8); + print_short_hex("system identifier"); + print_hex("unknown"); + printf("\n"); + */ + printf("skipping 12 bytes\n"); + dump_binary(12); + printf("\n"); + + print_guid("uuid"); + printf("\n"); + + /* 0x0008,"TYPELIB",0 */ + dump_binary(12); + printf("\n"); + + printf("skipping 12 bytes\n"); + dump_binary(12); + printf("\n"); + + printf("skipping remainder 0x10 bytes\n"); + dump_binary(0x10); + printf("\n"); +} + +void tlb_dump(void) +{ + const DWORD *sig = PRD(0, sizeof(DWORD)); + if (*sig == MSFT_MAGIC) + msft_dump(); + else + sltg_dump(); +} + +enum FileSig get_kind_tlb(void) +{ + const DWORD *sig = PRD(0, sizeof(DWORD)); + if (sig && (*sig == MSFT_MAGIC || *sig == SLTG_MAGIC)) return SIG_TLB; + return SIG_UNKNOWN; +} diff --git a/tools/winedump/winedump.h b/tools/winedump/winedump.h index 339cee32f0..ea95b27b09 100644 --- a/tools/winedump/winedump.h +++ b/tools/winedump/winedump.h @@ -214,7 +214,7 @@ const char *get_machine_str(int mach);
/* file dumping functions */ enum FileSig {SIG_UNKNOWN, SIG_DOS, SIG_PE, SIG_DBG, SIG_PDB, SIG_NE, SIG_LE, SIG_MDMP, SIG_COFFLIB, SIG_LNK, - SIG_EMF, SIG_FNT, SIG_MSFT}; + SIG_EMF, SIG_FNT, SIG_TLB};
const void* PRD(unsigned long prd, unsigned long len); unsigned long Offset(const void* ptr); @@ -251,8 +251,8 @@ enum FileSig get_kind_pdb(void); void pdb_dump(void); enum FileSig get_kind_fnt(void); void fnt_dump( void ); -enum FileSig get_kind_msft(void); -void msft_dump(void); +enum FileSig get_kind_tlb(void); +void tlb_dump(void);
BOOL codeview_dump_symbols(const void* root, unsigned long size); BOOL codeview_dump_types_from_offsets(const void* table, const DWORD* offsets, unsigned num_types);
Hi Dmitry,
On 07/09/2018 08:26 AM, Dmitry Timoshkov wrote:
@@ -173,9 +181,6 @@ static int tlb_read_byte(void) static void print_offset(void) { int i;
- printf("%04x: ", offset);
- for(i=0; i<indent; i++) printf(" ");
}
Why are you dropping printing offset? For this and other helper function changes, it would be nice to have separated patches.
Thanks,
Jacek
Jacek Caban jacek@codeweavers.com wrote:
On 07/09/2018 08:26 AM, Dmitry Timoshkov wrote:
@@ -173,9 +181,6 @@ static int tlb_read_byte(void) static void print_offset(void) { int i;
- printf("%04x: ", offset);
- for(i=0; i<indent; i++) printf(" ");
}
Why are you dropping printing offset?
It just adds noise. Once you compare old and new output perhaps you will agree with the change.
For this and other helper function changes, it would be nice to have separated patches.
I considered splitting the whole patch into a series, but the dumper is a result of pretty old investigation for which I still have full commit sequence, but the end result is very different from the very first patch, and unless you would like to see the way of thinking there's really nothing interesting or fascinating there: once I've found a new .tlb for my collection I had to adapt the dumper. The changes in the helpers are part of this investiagtion work, and I don't see a nice way to split them in separate patches.
On 07/09/2018 02:33 PM, Dmitry Timoshkov wrote:
Jacek Caban jacek@codeweavers.com wrote:
On 07/09/2018 08:26 AM, Dmitry Timoshkov wrote:
@@ -173,9 +181,6 @@ static int tlb_read_byte(void) static void print_offset(void) { int i;
- printf("%04x: ", offset);
- for(i=0; i<indent; i++) printf(" ");
}
Why are you dropping printing offset?
It just adds noise. Once you compare old and new output perhaps you will agree with the change.
It's been a while since I worked with typelibs, but as far as I remember a lot of records use offsets and for that having them printed was useful. Would it make sense to have a command line option to control if they are printed?
For this and other helper function changes, it would be nice to have separated patches.
I considered splitting the whole patch into a series, but the dumper is a result of pretty old investigation for which I still have full commit sequence, but the end result is very different from the very first patch, and unless you would like to see the way of thinking there's really nothing interesting or fascinating there: once I've found a new .tlb for my collection I had to adapt the dumper. The changes in the helpers are part of this investiagtion work, and I don't see a nice way to split them in separate patches.
I'm probably fine with having SLTG dumper part as one huge patch. I didn't have deeper look at that part yet, unrelated changes caught my attention. Those are easy to split and not really related to core part of the patch. print_offset(), for example, could use a separated patch on its own (although I'm not sure if I like this one, as above). Adding ...h suffix to hex values is also unrelated to the core patch. Same for dump_binary(), it could be a separated patch.
Thanks, Jacek
Jacek Caban jacek@codeweavers.com wrote:
static void print_offset(void) { int i;
- printf("%04x: ", offset);
- for(i=0; i<indent; i++) printf(" ");
}
Why are you dropping printing offset?
It just adds noise. Once you compare old and new output perhaps you will agree with the change.
It's been a while since I worked with typelibs, but as far as I remember a lot of records use offsets and for that having them printed was useful. Would it make sense to have a command line option to control if they are printed?
The way it looked before my change was 0000: Header { 0000: magic1 = 5446534d 0004: magic2 = 00010002 0008: posguid = 00000000 000c: lcid = 00000419 0010: lcid2 = 00000419 0014: varflags = 00000051, syskind = SYS_WIN32
That's not how other dumpers' output look like, and printing an offset before every value is very confusing IMO, unless someone really expects to see the output similar to the hex viewer, but then again other dumpers don't do that, and I personally don't find prepending each line with an offset useful.
After my change it is
Header { magic1 = 5446534dh magic2 = 00010002h posguid = 00000000h lcid = 00000419h lcid2 = 00000419h varflags = 00000051, syskind = SYS_WIN32