msc.c 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500
  1. /*
  2. * MS debug info dumping utility
  3. *
  4. * Copyright 2006 Eric Pouech
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #include "config.h"
  21. #include "wine/port.h"
  22. #include <stdlib.h>
  23. #include <stdarg.h>
  24. #include <stdio.h>
  25. #ifdef HAVE_UNISTD_H
  26. # include <unistd.h>
  27. #endif
  28. #include <time.h>
  29. #ifdef HAVE_SYS_TYPES_H
  30. # include <sys/types.h>
  31. #endif
  32. #ifdef HAVE_SYS_STAT_H
  33. # include <sys/stat.h>
  34. #endif
  35. #ifdef HAVE_SYS_MMAN_H
  36. #include <sys/mman.h>
  37. #endif
  38. #include <fcntl.h>
  39. #include "windef.h"
  40. #include "winbase.h"
  41. #include "winedump.h"
  42. #include "wine/mscvpdb.h"
  43. #define PSTRING(adr, ofs) \
  44. ((const struct p_string*)((const char*)(adr) + (ofs)))
  45. static const char* p_string(const struct p_string* s)
  46. {
  47. static char tmp[256 + 1];
  48. memcpy(tmp, s->name, s->namelen);
  49. tmp[s->namelen] = '\0';
  50. return tmp;
  51. }
  52. struct full_value
  53. {
  54. enum {fv_integer, fv_longlong} type;
  55. union
  56. {
  57. int i;
  58. long long unsigned llu;
  59. } v;
  60. };
  61. static int full_numeric_leaf(struct full_value* fv, const unsigned short int* leaf)
  62. {
  63. unsigned short int type = *leaf++;
  64. int length = 2;
  65. fv->type = fv_integer;
  66. if (type < LF_NUMERIC)
  67. {
  68. fv->v.i = type;
  69. }
  70. else
  71. {
  72. switch (type)
  73. {
  74. case LF_CHAR:
  75. length += 1;
  76. fv->v.i = *(const char*)leaf;
  77. break;
  78. case LF_SHORT:
  79. length += 2;
  80. fv->v.i = *(const short*)leaf;
  81. break;
  82. case LF_USHORT:
  83. length += 2;
  84. fv->v.i = *leaf;
  85. break;
  86. case LF_LONG:
  87. length += 4;
  88. fv->v.i = *(const int*)leaf;
  89. break;
  90. case LF_ULONG:
  91. length += 4;
  92. fv->v.i = *(const unsigned int*)leaf;
  93. break;
  94. case LF_QUADWORD:
  95. length += 8;
  96. fv->type = fv_longlong;
  97. fv->v.llu = *(const long long int*)leaf;
  98. break;
  99. case LF_UQUADWORD:
  100. length += 8;
  101. fv->type = fv_longlong;
  102. fv->v.llu = *(const long long unsigned int*)leaf;
  103. break;
  104. case LF_REAL32:
  105. length += 4;
  106. printf(">>> unsupported leaf value %04x\n", type);
  107. fv->v.i = 0; /* FIXME */
  108. break;
  109. case LF_REAL48:
  110. length += 6;
  111. fv->v.i = 0; /* FIXME */
  112. printf(">>> unsupported leaf value %04x\n", type);
  113. break;
  114. case LF_REAL64:
  115. length += 8;
  116. fv->v.i = 0; /* FIXME */
  117. printf(">>> unsupported leaf value %04x\n", type);
  118. break;
  119. case LF_REAL80:
  120. length += 10;
  121. fv->v.i = 0; /* FIXME */
  122. printf(">>> unsupported leaf value %04x\n", type);
  123. break;
  124. case LF_REAL128:
  125. length += 16;
  126. fv->v.i = 0; /* FIXME */
  127. printf(">>> unsupported leaf value %04x\n", type);
  128. break;
  129. case LF_COMPLEX32:
  130. length += 4;
  131. fv->v.i = 0; /* FIXME */
  132. printf(">>> unsupported leaf value %04x\n", type);
  133. break;
  134. case LF_COMPLEX64:
  135. length += 8;
  136. fv->v.i = 0; /* FIXME */
  137. printf(">>> unsupported leaf value %04x\n", type);
  138. break;
  139. case LF_COMPLEX80:
  140. length += 10;
  141. fv->v.i = 0; /* FIXME */
  142. printf(">>> unsupported leaf value %04x\n", type);
  143. break;
  144. case LF_COMPLEX128:
  145. length += 16;
  146. fv->v.i = 0; /* FIXME */
  147. printf(">>> unsupported leaf value %04x\n", type);
  148. break;
  149. case LF_VARSTRING:
  150. length += 2 + *leaf;
  151. fv->v.i = 0; /* FIXME */
  152. printf(">>> unsupported leaf value %04x\n", type);
  153. break;
  154. default:
  155. printf(">>> Unsupported numeric leaf-id %04x\n", type);
  156. fv->v.i = 0;
  157. break;
  158. }
  159. }
  160. return length;
  161. }
  162. static const char* full_value_string(const struct full_value* fv)
  163. {
  164. static char tmp[128];
  165. switch (fv->type)
  166. {
  167. case fv_integer: sprintf(tmp, "0x%x", fv->v.i); break;
  168. case fv_longlong: sprintf(tmp, "0x%x%08x", (unsigned)(fv->v.llu >> 32), (unsigned)fv->v.llu); break;
  169. }
  170. return tmp;
  171. }
  172. static int numeric_leaf(int* value, const unsigned short int* leaf)
  173. {
  174. struct full_value fv;
  175. int len = full_numeric_leaf(&fv, leaf);
  176. switch (fv.type)
  177. {
  178. case fv_integer: *value = fv.v.i; break;
  179. case fv_longlong: *value = (unsigned)fv.v.llu; printf("bad conversion\n"); break;
  180. default: assert( 0 ); *value = 0;
  181. }
  182. return len;
  183. }
  184. static const char* get_attr(unsigned attr)
  185. {
  186. static char tmp[256];
  187. switch (attr & 3)
  188. {
  189. case 0: strcpy(tmp, ""); break;
  190. case 1: strcpy(tmp, "private "); break;
  191. case 2: strcpy(tmp, "protected "); break;
  192. case 3: strcpy(tmp, "public "); break;
  193. }
  194. switch ((attr >> 2) & 7)
  195. {
  196. case 0: strcat(tmp, ""); break;
  197. case 1: strcat(tmp, "virtual "); break;
  198. case 2: strcat(tmp, "static "); break;
  199. case 3: strcat(tmp, "friend "); break;
  200. case 4: strcat(tmp, "introducing virtual "); break;
  201. case 5: strcat(tmp, "pure virtual "); break;
  202. case 6: strcat(tmp, "pure introducing virtual "); break;
  203. case 7: strcat(tmp, "reserved "); break;
  204. }
  205. if ((attr >> 5) & 1) strcat(tmp, "pseudo ");
  206. if ((attr >> 6) & 1) strcat(tmp, "no-inherit ");
  207. if ((attr >> 7) & 1) strcat(tmp, "no-construct ");
  208. return tmp;
  209. }
  210. static const char* get_property(unsigned prop)
  211. {
  212. static char tmp[1024];
  213. unsigned pos = 0;
  214. if (!prop) return "none";
  215. #define X(s) {if (pos) tmp[pos++] = ';'; strcpy(tmp + pos, s); pos += strlen(s);}
  216. if (prop & 0x0001) X("packed");
  217. if (prop & 0x0002) X("w/{cd}tor");
  218. if (prop & 0x0004) X("w/overloaded-ops");
  219. if (prop & 0x0008) X("nested-class");
  220. if (prop & 0x0010) X("has-nested-classes");
  221. if (prop & 0x0020) X("w/overloaded-assign");
  222. if (prop & 0x0040) X("w/casting-methods");
  223. if (prop & 0x0080) X("forward");
  224. if (prop & 0x0100) X("scoped");
  225. #undef X
  226. if (prop & ~0x01FF) pos += sprintf(tmp, "unk%x", prop & ~0x01FF);
  227. else tmp[pos] = '\0';
  228. assert(pos < sizeof(tmp));
  229. return tmp;
  230. }
  231. static void do_field(const unsigned char* start, const unsigned char* end)
  232. {
  233. /*
  234. * A 'field list' is a CodeView-specific data type which doesn't
  235. * directly correspond to any high-level data type. It is used
  236. * to hold the collection of members of a struct, class, union
  237. * or enum type. The actual definition of that type will follow
  238. * later, and refer to the field list definition record.
  239. *
  240. * As we don't have a field list type ourselves, we look ahead
  241. * in the field list to try to find out whether this field list
  242. * will be used for an enum or struct type, and create a dummy
  243. * type of the corresponding sort. Later on, the definition of
  244. * the 'real' type will copy the member / enumeration data.
  245. */
  246. const unsigned char* ptr = start;
  247. const char* cstr;
  248. const struct p_string* pstr;
  249. int leaf_len, value;
  250. while (ptr < end)
  251. {
  252. const union codeview_fieldtype* fieldtype = (const union codeview_fieldtype*)ptr;
  253. if (*ptr >= 0xf0) /* LF_PAD... */
  254. {
  255. ptr +=* ptr & 0x0f;
  256. continue;
  257. }
  258. switch (fieldtype->generic.id)
  259. {
  260. case LF_ENUMERATE_V1:
  261. leaf_len = numeric_leaf(&value, &fieldtype->enumerate_v1.value);
  262. pstr = PSTRING(&fieldtype->enumerate_v1.value, leaf_len);
  263. printf("\t\tEnumerate V1: '%s' value:%d\n",
  264. p_string(pstr), value);
  265. ptr += 2 + 2 + leaf_len + 1 + pstr->namelen;
  266. break;
  267. case LF_ENUMERATE_V3:
  268. leaf_len = numeric_leaf(&value, &fieldtype->enumerate_v3.value);
  269. cstr = (const char*)&fieldtype->enumerate_v3.value + leaf_len;
  270. printf("\t\tEnumerate V3: '%s' value:%d\n",
  271. cstr, value);
  272. ptr += 2 + 2 + leaf_len + strlen(cstr) + 1;
  273. break;
  274. case LF_MEMBER_V1:
  275. leaf_len = numeric_leaf(&value, &fieldtype->member_v1.offset);
  276. pstr = PSTRING(&fieldtype->member_v1.offset, leaf_len);
  277. printf("\t\tMember V1: '%s' type:%x attr:%s @%d\n",
  278. p_string(pstr), fieldtype->member_v1.type,
  279. get_attr(fieldtype->member_v1.attribute), value);
  280. ptr += 2 + 2 + 2 + leaf_len + 1 + pstr->namelen;
  281. break;
  282. case LF_MEMBER_V2:
  283. leaf_len = numeric_leaf(&value, &fieldtype->member_v2.offset);
  284. pstr = PSTRING(&fieldtype->member_v2.offset, leaf_len);
  285. printf("\t\tMember V2: '%s' type:%x attr:%s @%d\n",
  286. p_string(pstr), fieldtype->member_v2.type,
  287. get_attr(fieldtype->member_v2.attribute), value);
  288. ptr += 2 + 2 + 4 + leaf_len + 1 + pstr->namelen;
  289. break;
  290. case LF_MEMBER_V3:
  291. leaf_len = numeric_leaf(&value, &fieldtype->member_v3.offset);
  292. cstr = (const char*)&fieldtype->member_v3.offset + leaf_len;
  293. printf("\t\tMember V3: '%s' type:%x attr:%s @%d\n",
  294. cstr, fieldtype->member_v3.type,
  295. get_attr(fieldtype->member_v3.attribute), value);
  296. ptr += 2 + 2 + 4 + leaf_len + strlen(cstr) + 1;
  297. break;
  298. case LF_ONEMETHOD_V1:
  299. switch ((fieldtype->onemethod_v1.attribute >> 2) & 7)
  300. {
  301. case 4: case 6:
  302. printf("\t\tVirtual-method V1: '%s' attr:%s type:%x vtable_offset:%u\n",
  303. p_string(&fieldtype->onemethod_virt_v1.p_name),
  304. get_attr(fieldtype->onemethod_virt_v1.attribute),
  305. fieldtype->onemethod_virt_v1.type,
  306. fieldtype->onemethod_virt_v1.vtab_offset);
  307. ptr += 2 + 2 + 2 + 4 + (1 + fieldtype->onemethod_virt_v1.p_name.namelen);
  308. break;
  309. default:
  310. printf("\t\tMethod V1: '%s' attr:%s type:%x\n",
  311. p_string(&fieldtype->onemethod_v1.p_name),
  312. get_attr(fieldtype->onemethod_v1.attribute),
  313. fieldtype->onemethod_v1.type);
  314. ptr += 2 + 2 + 2 + (1 + fieldtype->onemethod_v1.p_name.namelen);
  315. break;
  316. }
  317. break;
  318. case LF_ONEMETHOD_V2:
  319. switch ((fieldtype->onemethod_v2.attribute >> 2) & 7)
  320. {
  321. case 4: case 6:
  322. printf("\t\tVirtual-method V2: '%s' attr:%s type:%x vtable_offset:%u\n",
  323. p_string(&fieldtype->onemethod_virt_v2.p_name),
  324. get_attr(fieldtype->onemethod_virt_v2.attribute),
  325. fieldtype->onemethod_virt_v2.type,
  326. fieldtype->onemethod_virt_v2.vtab_offset);
  327. ptr += 2 + 2 + 4 + 4 + (1 + fieldtype->onemethod_virt_v2.p_name.namelen);
  328. break;
  329. default:
  330. printf("\t\tMethod V2: '%s' attr:%s type:%x\n",
  331. p_string(&fieldtype->onemethod_v2.p_name),
  332. get_attr(fieldtype->onemethod_v2.attribute),
  333. fieldtype->onemethod_v2.type);
  334. ptr += 2 + 2 + 4 + (1 + fieldtype->onemethod_v2.p_name.namelen);
  335. break;
  336. }
  337. break;
  338. case LF_ONEMETHOD_V3:
  339. switch ((fieldtype->onemethod_v3.attribute >> 2) & 7)
  340. {
  341. case 4: case 6:
  342. printf("\t\tVirtual-method V3: '%s' attr:%s type:%x vtable_offset:%u\n",
  343. fieldtype->onemethod_virt_v3.name,
  344. get_attr(fieldtype->onemethod_virt_v3.attribute),
  345. fieldtype->onemethod_virt_v3.type,
  346. fieldtype->onemethod_virt_v3.vtab_offset);
  347. ptr += 2 + 2 + 4 + 4 + (strlen(fieldtype->onemethod_virt_v3.name) + 1);
  348. break;
  349. default:
  350. printf("\t\tMethod V3: '%s' attr:%s type:%x\n",
  351. fieldtype->onemethod_v3.name,
  352. get_attr(fieldtype->onemethod_v3.attribute),
  353. fieldtype->onemethod_v3.type);
  354. ptr += 2 + 2 + 4 + (strlen(fieldtype->onemethod_v3.name) + 1);
  355. break;
  356. }
  357. break;
  358. case LF_METHOD_V1:
  359. printf("\t\tMethod V1: '%s' overloaded=#%d method-list=%x\n",
  360. p_string(&fieldtype->method_v1.p_name),
  361. fieldtype->method_v1.count, fieldtype->method_v1.mlist);
  362. ptr += 2 + 2 + 2 + (1 + fieldtype->method_v1.p_name.namelen);
  363. break;
  364. case LF_METHOD_V2:
  365. printf("\t\tMethod V2: '%s' overloaded=#%d method-list=%x\n",
  366. p_string(&fieldtype->method_v2.p_name),
  367. fieldtype->method_v2.count, fieldtype->method_v2.mlist);
  368. ptr += 2 + 2 + 4 + (1 + fieldtype->method_v2.p_name.namelen);
  369. break;
  370. case LF_METHOD_V3:
  371. printf("\t\tMethod V3: '%s' overloaded=#%d method-list=%x\n",
  372. fieldtype->method_v3.name,
  373. fieldtype->method_v3.count, fieldtype->method_v3.mlist);
  374. ptr += 2 + 2 + 4 + (strlen(fieldtype->method_v3.name) + 1);
  375. break;
  376. case LF_STMEMBER_V1:
  377. printf("\t\tStatic member V1: '%s' attr:%s type:%x\n",
  378. p_string(&fieldtype->stmember_v1.p_name),
  379. get_attr(fieldtype->stmember_v1.attribute),
  380. fieldtype->stmember_v1.type);
  381. ptr += 2 + 2 + 2 + (1 + fieldtype->stmember_v1.p_name.namelen);
  382. break;
  383. case LF_STMEMBER_V2:
  384. printf("\t\tStatic member V2: '%s' attr:%s type:%x\n",
  385. p_string(&fieldtype->stmember_v2.p_name),
  386. get_attr(fieldtype->stmember_v2.attribute),
  387. fieldtype->stmember_v2.type);
  388. ptr += 2 + 2 + 4 + (1 + fieldtype->stmember_v2.p_name.namelen);
  389. break;
  390. case LF_STMEMBER_V3:
  391. printf("\t\tStatic member V3: '%s' attr:%s type:%x\n",
  392. fieldtype->stmember_v3.name,
  393. get_attr(fieldtype->stmember_v3.attribute),
  394. fieldtype->stmember_v3.type);
  395. ptr += 2 + 2 + 4 + (strlen(fieldtype->stmember_v3.name) + 1);
  396. break;
  397. case LF_FRIENDFCN_V1:
  398. printf("\t\tFriend function V1: '%s' type:%x\n",
  399. p_string(&fieldtype->friendfcn_v1.p_name),
  400. fieldtype->friendfcn_v1.type);
  401. break;
  402. case LF_FRIENDFCN_V2:
  403. printf("\t\tFriend function V2: '%s' type:%x\n",
  404. p_string(&fieldtype->friendfcn_v2.p_name),
  405. fieldtype->friendfcn_v2.type);
  406. break;
  407. #if 0
  408. case LF_FRIENDFCN_V3:
  409. printf("\t\tFriend function V3: '%s' type:%x\n",
  410. fieldtype->friendfcn_v3.name,
  411. fieldtype->friendfcn_v3.type);
  412. break;
  413. #endif
  414. case LF_BCLASS_V1:
  415. leaf_len = numeric_leaf(&value, &fieldtype->bclass_v1.offset);
  416. printf("\t\tBase class V1: type:%x attr:%s @%d\n",
  417. fieldtype->bclass_v1.type,
  418. get_attr(fieldtype->bclass_v1.attribute), value);
  419. ptr += 2 + 2 + 2 + leaf_len;
  420. break;
  421. case LF_BCLASS_V2:
  422. leaf_len = numeric_leaf(&value, &fieldtype->bclass_v2.offset);
  423. printf("\t\tBase class V2: type:%x attr:%s @%d\n",
  424. fieldtype->bclass_v2.type,
  425. get_attr(fieldtype->bclass_v2.attribute), value);
  426. ptr += 2 + 2 + 4 + leaf_len;
  427. break;
  428. case LF_VBCLASS_V1:
  429. case LF_IVBCLASS_V1:
  430. leaf_len = numeric_leaf(&value, &fieldtype->vbclass_v1.vbpoff);
  431. printf("\t\t%sirtual base class V1: type:%x (ptr:%x) attr:%s vbpoff:%d ",
  432. (fieldtype->generic.id == LF_VBCLASS_V2) ? "V" : "Indirect v",
  433. fieldtype->vbclass_v1.btype, fieldtype->vbclass_v1.vbtype,
  434. get_attr(fieldtype->vbclass_v1.attribute), value);
  435. ptr += 2 + 2 + 2 + 2 + leaf_len;
  436. leaf_len = numeric_leaf(&value, (const unsigned short*)ptr);
  437. printf("vboff:%d\n", value);
  438. ptr += leaf_len;
  439. break;
  440. case LF_VBCLASS_V2:
  441. case LF_IVBCLASS_V2:
  442. leaf_len = numeric_leaf(&value, &fieldtype->vbclass_v1.vbpoff);
  443. printf("\t\t%sirtual base class V2: type:%x (ptr:%x) attr:%s vbpoff:%d ",
  444. (fieldtype->generic.id == LF_VBCLASS_V2) ? "V" : "Indirect v",
  445. fieldtype->vbclass_v2.btype, fieldtype->vbclass_v2.vbtype,
  446. get_attr(fieldtype->vbclass_v2.attribute), value);
  447. ptr += 2 + 2 + 4 + 4 + leaf_len;
  448. leaf_len = numeric_leaf(&value, (const unsigned short*)ptr);
  449. printf("vboff:%d\n", value);
  450. ptr += leaf_len;
  451. break;
  452. case LF_FRIENDCLS_V1:
  453. printf("\t\tFriend class V1: type:%x\n", fieldtype->friendcls_v1.type);
  454. break;
  455. case LF_FRIENDCLS_V2:
  456. printf("\t\tFriend class V2: type:%x\n", fieldtype->friendcls_v2.type);
  457. break;
  458. case LF_NESTTYPE_V1:
  459. printf("\t\tNested type V1: '%s' type:%x\n",
  460. p_string(&fieldtype->nesttype_v1.p_name),
  461. fieldtype->nesttype_v1.type);
  462. ptr += 2 + 2 + (1 + fieldtype->nesttype_v1.p_name.namelen);
  463. break;
  464. case LF_NESTTYPE_V2:
  465. printf("\t\tNested type V2: '%s' pad0:%u type:%x\n",
  466. p_string(&fieldtype->nesttype_v2.p_name),
  467. fieldtype->nesttype_v2._pad0, fieldtype->nesttype_v2.type);
  468. ptr += 2 + 2 + 4 + (1 + fieldtype->nesttype_v2.p_name.namelen);
  469. break;
  470. case LF_NESTTYPE_V3:
  471. printf("\t\tNested type V3: '%s' pad0:%u type:%x\n",
  472. fieldtype->nesttype_v3.name,
  473. fieldtype->nesttype_v3._pad0, fieldtype->nesttype_v3.type);
  474. ptr += 2 + 2 + 4 + (strlen(fieldtype->nesttype_v3.name) + 1);
  475. break;
  476. case LF_VFUNCTAB_V1:
  477. printf("\t\tVirtual function table V1: type:%x\n",
  478. fieldtype->vfunctab_v1.type);
  479. ptr += 2 + 2;
  480. break;
  481. case LF_VFUNCTAB_V2:
  482. printf("\t\tVirtual function table V2: type:%x\n",
  483. fieldtype->vfunctab_v2.type);
  484. ptr += 2 + 2 + 4;
  485. break;
  486. case LF_VFUNCOFF_V1:
  487. printf("\t\tVirtual function table offset V1: type:%x offset:%x\n",
  488. fieldtype->vfuncoff_v1.type, fieldtype->vfuncoff_v1.offset);
  489. break;
  490. case LF_VFUNCOFF_V2:
  491. printf("\t\tVirtual function table offset V2: type:%x offset:%x\n",
  492. fieldtype->vfuncoff_v2.type, fieldtype->vfuncoff_v2.offset);
  493. break;
  494. default:
  495. printf(">>> Unsupported field-id %x\n", fieldtype->generic.id);
  496. dump_data((const void*)fieldtype, 0x30, "\t");
  497. break;
  498. }
  499. }
  500. }
  501. static void codeview_dump_one_type(unsigned curr_type, const union codeview_type* type)
  502. {
  503. const union codeview_reftype* reftype = (const union codeview_reftype*)type;
  504. int i, leaf_len, value;
  505. unsigned int j;
  506. const char* str;
  507. switch (type->generic.id)
  508. {
  509. case LF_POINTER_V1:
  510. printf("\t%x => Pointer V1 to type:%x\n",
  511. curr_type, type->pointer_v1.datatype);
  512. break;
  513. case LF_POINTER_V2:
  514. printf("\t%x => Pointer V2 to type:%x\n",
  515. curr_type, type->pointer_v2.datatype);
  516. break;
  517. case LF_ARRAY_V1:
  518. leaf_len = numeric_leaf(&value, &type->array_v1.arrlen);
  519. printf("\t%x => Array V1-'%s'[%u type:%x] type:%x\n",
  520. curr_type, p_string(PSTRING(&type->array_v1.arrlen, leaf_len)),
  521. value, type->array_v1.idxtype, type->array_v1.elemtype);
  522. break;
  523. case LF_ARRAY_V2:
  524. leaf_len = numeric_leaf(&value, &type->array_v2.arrlen);
  525. printf("\t%x => Array V2-'%s'[%u type:%x] type:%x\n",
  526. curr_type, p_string(PSTRING(&type->array_v2.arrlen, leaf_len)),
  527. value, type->array_v2.idxtype, type->array_v2.elemtype);
  528. break;
  529. case LF_ARRAY_V3:
  530. leaf_len = numeric_leaf(&value, &type->array_v3.arrlen);
  531. str = (const char*)&type->array_v3.arrlen + leaf_len;
  532. printf("\t%x => Array V3-'%s'[%u type:%x] type:%x\n",
  533. curr_type, str, value,
  534. type->array_v3.idxtype, type->array_v3.elemtype);
  535. break;
  536. /* a bitfields is a CodeView specific data type which represent a bitfield
  537. * in a structure or a class. For now, we store it in a SymTag-like type
  538. * (so that the rest of the process is seamless), but check at udt inclusion
  539. * type for its presence
  540. */
  541. case LF_BITFIELD_V1:
  542. printf("\t%x => Bitfield V1:%x offset:%u #bits:%u\n",
  543. curr_type, reftype->bitfield_v1.type, reftype->bitfield_v1.bitoff,
  544. reftype->bitfield_v1.nbits);
  545. break;
  546. case LF_BITFIELD_V2:
  547. printf("\t%x => Bitfield V2:%x offset:%u #bits:%u\n",
  548. curr_type, reftype->bitfield_v2.type, reftype->bitfield_v2.bitoff,
  549. reftype->bitfield_v2.nbits);
  550. break;
  551. case LF_FIELDLIST_V1:
  552. case LF_FIELDLIST_V2:
  553. printf("\t%x => Fieldlist\n", curr_type);
  554. do_field(reftype->fieldlist.list, (const BYTE*)type + reftype->generic.len + 2);
  555. break;
  556. case LF_STRUCTURE_V1:
  557. case LF_CLASS_V1:
  558. leaf_len = numeric_leaf(&value, &type->struct_v1.structlen);
  559. printf("\t%x => %s V1 '%s' elts:%u property:%s fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
  560. curr_type, type->generic.id == LF_CLASS_V1 ? "Class" : "Struct",
  561. p_string(PSTRING(&type->struct_v1.structlen, leaf_len)),
  562. type->struct_v1.n_element, get_property(type->struct_v1.property),
  563. type->struct_v1.fieldlist, type->struct_v1.derived,
  564. type->struct_v1.vshape, value);
  565. break;
  566. case LF_STRUCTURE_V2:
  567. case LF_CLASS_V2:
  568. leaf_len = numeric_leaf(&value, &type->struct_v2.structlen);
  569. printf("\t%x => %s V2 '%s' elts:%u property:%s\n"
  570. " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
  571. curr_type, type->generic.id == LF_CLASS_V2 ? "Class" : "Struct",
  572. p_string(PSTRING(&type->struct_v2.structlen, leaf_len)),
  573. type->struct_v2.n_element, get_property(type->struct_v2.property),
  574. type->struct_v2.fieldlist, type->struct_v2.derived,
  575. type->struct_v2.vshape, value);
  576. break;
  577. case LF_STRUCTURE_V3:
  578. case LF_CLASS_V3:
  579. leaf_len = numeric_leaf(&value, &type->struct_v3.structlen);
  580. str = (const char*)&type->struct_v3.structlen + leaf_len;
  581. printf("\t%x => %s V3 '%s' elts:%u property:%s\n"
  582. " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
  583. curr_type, type->generic.id == LF_CLASS_V3 ? "Class" : "Struct",
  584. str, type->struct_v3.n_element, get_property(type->struct_v3.property),
  585. type->struct_v3.fieldlist, type->struct_v3.derived,
  586. type->struct_v3.vshape, value);
  587. break;
  588. case LF_UNION_V1:
  589. leaf_len = numeric_leaf(&value, &type->union_v1.un_len);
  590. printf("\t%x => Union V1 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
  591. curr_type, p_string(PSTRING(&type->union_v1.un_len, leaf_len)),
  592. type->union_v1.count, get_property(type->union_v1.property),
  593. type->union_v1.fieldlist, value);
  594. break;
  595. case LF_UNION_V2:
  596. leaf_len = numeric_leaf(&value, &type->union_v2.un_len);
  597. printf("\t%x => Union V2 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
  598. curr_type, p_string(PSTRING(&type->union_v2.un_len, leaf_len)),
  599. type->union_v2.count, get_property(type->union_v2.property),
  600. type->union_v2.fieldlist, value);
  601. break;
  602. case LF_UNION_V3:
  603. leaf_len = numeric_leaf(&value, &type->union_v3.un_len);
  604. str = (const char*)&type->union_v3.un_len + leaf_len;
  605. printf("\t%x => Union V3 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
  606. curr_type, str, type->union_v3.count,
  607. get_property(type->union_v3.property),
  608. type->union_v3.fieldlist, value);
  609. break;
  610. case LF_ENUM_V1:
  611. printf("\t%x => Enum V1 '%s' type:%x field-type:%x count:%u property:%s\n",
  612. curr_type, p_string(&type->enumeration_v1.p_name),
  613. type->enumeration_v1.type,
  614. type->enumeration_v1.fieldlist,
  615. type->enumeration_v1.count,
  616. get_property(type->enumeration_v1.property));
  617. break;
  618. case LF_ENUM_V2:
  619. printf("\t%x => Enum V2 '%s' type:%x field-type:%x count:%u property:%s\n",
  620. curr_type, p_string(&type->enumeration_v2.p_name),
  621. type->enumeration_v2.type,
  622. type->enumeration_v2.fieldlist,
  623. type->enumeration_v2.count,
  624. get_property(type->enumeration_v2.property));
  625. break;
  626. case LF_ENUM_V3:
  627. printf("\t%x => Enum V3 '%s' type:%x field-type:%x count:%u property:%s\n",
  628. curr_type, type->enumeration_v3.name,
  629. type->enumeration_v3.type,
  630. type->enumeration_v3.fieldlist,
  631. type->enumeration_v3.count,
  632. get_property(type->enumeration_v3.property));
  633. break;
  634. case LF_ARGLIST_V1:
  635. printf("\t%x => Arglist V1(#%u):", curr_type, reftype->arglist_v1.num);
  636. for (i = 0; i < reftype->arglist_v1.num; i++)
  637. {
  638. printf(" %x", reftype->arglist_v1.args[i]);
  639. }
  640. printf("\n");
  641. break;
  642. case LF_ARGLIST_V2:
  643. printf("\t%x => Arglist V2(#%u):", curr_type, reftype->arglist_v2.num);
  644. for (j = 0; j < reftype->arglist_v2.num; j++)
  645. {
  646. printf("\t %x", reftype->arglist_v2.args[j]);
  647. }
  648. printf("\t\n");
  649. break;
  650. case LF_PROCEDURE_V1:
  651. /* FIXME: unknown could be the calling convention for the proc */
  652. printf("\t%x => Procedure V1 ret_type:%x call:%x (#%u args_type:%x)\n",
  653. curr_type, type->procedure_v1.rvtype,
  654. type->procedure_v1.call, type->procedure_v1.params,
  655. type->procedure_v1.arglist);
  656. break;
  657. case LF_PROCEDURE_V2:
  658. printf("\t%x => Procedure V2 ret_type:%x unk:%x (#%u args_type:%x)\n",
  659. curr_type, type->procedure_v2.rvtype,
  660. type->procedure_v2.call, type->procedure_v2.params,
  661. type->procedure_v2.arglist);
  662. break;
  663. case LF_MFUNCTION_V2:
  664. printf("\t%x => MFunction V2 ret-type:%x call:%x class-type:%x this-type:%x\n"
  665. "\t\t#args:%x args-type:%x this_adjust:%x\n",
  666. curr_type,
  667. type->mfunction_v2.rvtype,
  668. type->mfunction_v2.call,
  669. type->mfunction_v2.class_type,
  670. type->mfunction_v2.this_type,
  671. type->mfunction_v2.params,
  672. type->mfunction_v2.arglist,
  673. type->mfunction_v2.this_adjust);
  674. break;
  675. case LF_MODIFIER_V1:
  676. printf("\t%x => Modifier V1 type:%x modif:%x\n",
  677. curr_type, type->modifier_v1.type, type->modifier_v1.attribute);
  678. break;
  679. case LF_MODIFIER_V2:
  680. printf("\t%x => Modifier V2 type:%x modif:%x\n",
  681. curr_type, type->modifier_v2.type, type->modifier_v2.attribute);
  682. break;
  683. case LF_METHODLIST_V1:
  684. {
  685. const unsigned short* pattr = (const unsigned short*)((const char*)type + 4);
  686. printf("\t%x => Method list\n", curr_type);
  687. while ((const char*)pattr < (const char*)type + type->generic.len + 2)
  688. {
  689. switch ((*pattr >> 2) & 7)
  690. {
  691. case 4: case 6:
  692. printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
  693. get_attr(pattr[0]), pattr[1],
  694. *(const unsigned*)(&pattr[2]));
  695. pattr += 3;
  696. break;
  697. default:
  698. printf("\t\t\tattr:%s type:%x\n",
  699. get_attr(pattr[0]), pattr[1]);
  700. pattr += 2;
  701. }
  702. }
  703. }
  704. break;
  705. case LF_METHODLIST_V2:
  706. {
  707. const unsigned* pattr = (const unsigned*)((const char*)type + 4);
  708. printf("\t%x => Method list\n", curr_type);
  709. while ((const char*)pattr < (const char*)type + type->generic.len + 2)
  710. {
  711. switch ((*pattr >> 2) & 7)
  712. {
  713. case 4: case 6:
  714. printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
  715. get_attr(pattr[0]), pattr[1], pattr[2]);
  716. pattr += 3;
  717. break;
  718. default:
  719. printf("\t\t\tattr:%s type:%x\n",
  720. get_attr(pattr[0]), pattr[1]);
  721. pattr += 2;
  722. }
  723. }
  724. }
  725. break;
  726. case LF_VTSHAPE_V1:
  727. {
  728. int count = *(const unsigned short*)((const char*)type + 4);
  729. int shift = 0;
  730. const char* ptr = (const char*)type + 6;
  731. const char* desc[] = {"Near", "Far", "Thin", "Disp to outermost",
  732. "Pointer to metaclass", "Near32", "Far32"};
  733. printf("\t%x => VT Shape #%d: ", curr_type, count);
  734. while (count--)
  735. {
  736. if (((*ptr << shift) & 0xF) <= 6)
  737. printf("%s ", desc[(*ptr << shift) & 0xF]);
  738. else
  739. printf("%x ", (*ptr << shift) & 0xF);
  740. if (shift == 0) shift = 4; else {shift = 0; ptr++;}
  741. }
  742. printf("\n");
  743. }
  744. break;
  745. case LF_DERIVED_V1:
  746. printf("\t%x => Derived V1(#%u):", curr_type, reftype->derived_v1.num);
  747. for (i = 0; i < reftype->derived_v1.num; i++)
  748. {
  749. printf(" %x", reftype->derived_v1.drvdcls[i]);
  750. }
  751. printf("\n");
  752. break;
  753. case LF_DERIVED_V2:
  754. printf("\t%x => Derived V2(#%u):", curr_type, reftype->derived_v2.num);
  755. for (j = 0; j < reftype->derived_v2.num; j++)
  756. {
  757. printf(" %x", reftype->derived_v2.drvdcls[j]);
  758. }
  759. printf("\n");
  760. break;
  761. default:
  762. printf(">>> Unsupported type-id %x for %x\n", type->generic.id, curr_type);
  763. dump_data((const void*)type, type->generic.len + 2, "");
  764. break;
  765. }
  766. }
  767. BOOL codeview_dump_types_from_offsets(const void* table, const DWORD* offsets, unsigned num_types)
  768. {
  769. unsigned long i;
  770. for (i = 0; i < num_types; i++)
  771. {
  772. codeview_dump_one_type(0x1000 + i,
  773. (const union codeview_type*)((const char*)table + offsets[i]));
  774. }
  775. return TRUE;
  776. }
  777. BOOL codeview_dump_types_from_block(const void* table, unsigned long len)
  778. {
  779. unsigned int curr_type = 0x1000;
  780. const unsigned char*ptr = table;
  781. while (ptr - (const unsigned char*)table < len)
  782. {
  783. const union codeview_type* type = (const union codeview_type*)ptr;
  784. codeview_dump_one_type(curr_type, type);
  785. curr_type++;
  786. ptr += (type->generic.len + 2 + 3) & ~3;
  787. }
  788. return TRUE;
  789. }
  790. BOOL codeview_dump_symbols(const void* root, unsigned long size)
  791. {
  792. unsigned int i;
  793. int length;
  794. char* curr_func = NULL;
  795. int nest_block = 0;
  796. /*
  797. * Loop over the different types of records and whenever we
  798. * find something we are interested in, record it and move on.
  799. */
  800. for (i = 0; i < size; i += length)
  801. {
  802. const union codeview_symbol* sym = (const union codeview_symbol*)((const char*)root + i);
  803. length = sym->generic.len + 2;
  804. if (!sym->generic.id || length < 4) break;
  805. switch (sym->generic.id)
  806. {
  807. /*
  808. * Global and local data symbols. We don't associate these
  809. * with any given source file.
  810. */
  811. case S_GDATA32_ST:
  812. case S_LDATA32_ST:
  813. printf("\tS-%s-Data V2 '%s' %04x:%08x type:%08x\n",
  814. sym->generic.id == S_GDATA32_ST ? "Global" : "Local",
  815. get_symbol_str(p_string(&sym->data_v2.p_name)),
  816. sym->data_v2.segment, sym->data_v2.offset, sym->data_v2.symtype);
  817. break;
  818. case S_LDATA32:
  819. case S_GDATA32:
  820. /* EPP case S_DATA32: */
  821. printf("\tS-%s-Data V3 '%s' (%04x:%08x) type:%08x\n",
  822. sym->generic.id == S_GDATA32 ? "Global" : "Local",
  823. get_symbol_str(sym->data_v3.name),
  824. sym->data_v3.segment, sym->data_v3.offset,
  825. sym->data_v3.symtype);
  826. break;
  827. case S_PUB32_ST:
  828. printf("\tS-Public V2 '%s' %04x:%08x type:%08x\n",
  829. get_symbol_str(p_string(&sym->public_v2.p_name)),
  830. sym->public_v2.segment, sym->public_v2.offset,
  831. sym->public_v2.symtype);
  832. break;
  833. case S_PUB32:
  834. /* not completely sure of those two anyway */
  835. case S_PROCREF:
  836. case S_LPROCREF:
  837. printf("\tS-Public%s V3 '%s' %04x:%08x type:%08x\n",
  838. sym->generic.id == S_PUB32 ? "" :
  839. (sym->generic.id == S_PROCREF ? "<subkind1" : "<subkind2"),
  840. get_symbol_str(sym->public_v3.name),
  841. sym->public_v3.segment,
  842. sym->public_v3.offset, sym->public_v3.symtype);
  843. break;
  844. /*
  845. * Sort of like a global function, but it just points
  846. * to a thunk, which is a stupid name for what amounts to
  847. * a PLT slot in the normal jargon that everyone else uses.
  848. */
  849. case S_THUNK32_ST:
  850. printf("\tS-Thunk V1 '%s' (%04x:%08x#%x) type:%x\n",
  851. p_string(&sym->thunk_v1.p_name),
  852. sym->thunk_v1.segment, sym->thunk_v1.offset,
  853. sym->thunk_v1.thunk_len, sym->thunk_v1.thtype);
  854. curr_func = strdup(p_string(&sym->thunk_v1.p_name));
  855. break;
  856. case S_THUNK32:
  857. printf("\tS-Thunk V3 '%s' (%04x:%08x#%x) type:%x\n",
  858. sym->thunk_v3.name,
  859. sym->thunk_v3.segment, sym->thunk_v3.offset,
  860. sym->thunk_v3.thunk_len, sym->thunk_v3.thtype);
  861. curr_func = strdup(sym->thunk_v3.name);
  862. break;
  863. /* Global and static functions */
  864. case S_GPROC32_16t:
  865. case S_LPROC32_16t:
  866. printf("\tS-%s-Proc V1: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
  867. sym->generic.id == S_GPROC32_16t ? "Global" : "-Local",
  868. p_string(&sym->proc_v1.p_name),
  869. sym->proc_v1.segment, sym->proc_v1.offset,
  870. sym->proc_v1.proc_len, sym->proc_v1.proctype,
  871. sym->proc_v1.flags);
  872. printf("\t Debug: start=%08x end=%08x\n",
  873. sym->proc_v1.debug_start, sym->proc_v1.debug_end);
  874. if (nest_block)
  875. {
  876. printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
  877. nest_block = 0;
  878. }
  879. curr_func = strdup(p_string(&sym->proc_v1.p_name));
  880. /* EPP unsigned int pparent; */
  881. /* EPP unsigned int pend; */
  882. /* EPP unsigned int next; */
  883. break;
  884. case S_GPROC32_ST:
  885. case S_LPROC32_ST:
  886. printf("\tS-%s-Proc V2: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
  887. sym->generic.id == S_GPROC32_ST ? "Global" : "-Local",
  888. p_string(&sym->proc_v2.p_name),
  889. sym->proc_v2.segment, sym->proc_v2.offset,
  890. sym->proc_v2.proc_len, sym->proc_v2.proctype,
  891. sym->proc_v2.flags);
  892. printf("\t Debug: start=%08x end=%08x\n",
  893. sym->proc_v2.debug_start, sym->proc_v2.debug_end);
  894. if (nest_block)
  895. {
  896. printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
  897. nest_block = 0;
  898. }
  899. curr_func = strdup(p_string(&sym->proc_v2.p_name));
  900. /* EPP unsigned int pparent; */
  901. /* EPP unsigned int pend; */
  902. /* EPP unsigned int next; */
  903. break;
  904. case S_LPROC32:
  905. case S_GPROC32:
  906. printf("\tS-%s-Procedure V3 '%s' (%04x:%08x#%x) type:%x attr:%x\n",
  907. sym->generic.id == S_GPROC32 ? "Global" : "Local",
  908. sym->proc_v3.name,
  909. sym->proc_v3.segment, sym->proc_v3.offset,
  910. sym->proc_v3.proc_len, sym->proc_v3.proctype,
  911. sym->proc_v3.flags);
  912. printf("\t Debug: start=%08x end=%08x\n",
  913. sym->proc_v3.debug_start, sym->proc_v3.debug_end);
  914. if (nest_block)
  915. {
  916. printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
  917. nest_block = 0;
  918. }
  919. curr_func = strdup(sym->proc_v3.name);
  920. /* EPP unsigned int pparent; */
  921. /* EPP unsigned int pend; */
  922. /* EPP unsigned int next; */
  923. break;
  924. /* Function parameters and stack variables */
  925. case S_BPREL32_16t:
  926. printf("\tS-BP-relative V1: '%s' @%d type:%x (%s)\n",
  927. p_string(&sym->stack_v1.p_name),
  928. sym->stack_v1.offset, sym->stack_v1.symtype, curr_func);
  929. break;
  930. case S_BPREL32_ST:
  931. printf("\tS-BP-relative V2: '%s' @%d type:%x (%s)\n",
  932. p_string(&sym->stack_v2.p_name),
  933. sym->stack_v2.offset, sym->stack_v2.symtype, curr_func);
  934. break;
  935. case S_BPREL32:
  936. printf("\tS-BP-relative V3: '%s' @%d type:%x (in %s)\n",
  937. sym->stack_v3.name, sym->stack_v3.offset,
  938. sym->stack_v3.symtype, curr_func);
  939. break;
  940. case S_REGREL32:
  941. printf("\tS-Reg-relative V3: '%s' @%d type:%x reg:%x (in %s)\n",
  942. sym->regrel_v3.name, sym->regrel_v3.offset,
  943. sym->regrel_v3.symtype, sym->regrel_v3.reg, curr_func);
  944. break;
  945. case S_REGISTER_16t:
  946. printf("\tS-Register V1 '%s' in %s type:%x register:%x\n",
  947. p_string(&sym->register_v1.p_name),
  948. curr_func, sym->register_v1.reg, sym->register_v1.type);
  949. break;
  950. case S_REGISTER_ST:
  951. printf("\tS-Register V2 '%s' in %s type:%x register:%x\n",
  952. p_string(&sym->register_v2.p_name),
  953. curr_func, sym->register_v2.reg, sym->register_v2.type);
  954. break;
  955. case S_REGISTER:
  956. printf("\tS-Register V3 '%s' in %s type:%x register:%x\n",
  957. sym->register_v3.name,
  958. curr_func, sym->register_v3.reg, sym->register_v3.type);
  959. break;
  960. case S_BLOCK32_ST:
  961. printf("\tS-Block V1 '%s' in '%s' (%04x:%08x#%08x)\n",
  962. p_string(&sym->block_v1.p_name),
  963. curr_func,
  964. sym->block_v1.segment, sym->block_v1.offset,
  965. sym->block_v1.length);
  966. nest_block++;
  967. break;
  968. case S_BLOCK32:
  969. printf("\tS-Block V3 '%s' in '%s' (%04x:%08x#%08x) parent:%u end:%x\n",
  970. sym->block_v3.name, curr_func,
  971. sym->block_v3.segment, sym->block_v3.offset, sym->block_v3.length,
  972. sym->block_v3.parent, sym->block_v3.end);
  973. nest_block++;
  974. break;
  975. /* Additional function information */
  976. case S_FRAMEPROC:
  977. printf("\tS-Frame-Info V2: frame-size:%x unk2:%x unk3:%x saved-regs-sz:%x eh(%04x:%08x) flags:%08x\n",
  978. sym->frame_info_v2.sz_frame,
  979. sym->frame_info_v2.unknown2,
  980. sym->frame_info_v2.unknown3,
  981. sym->frame_info_v2.sz_saved_regs,
  982. sym->frame_info_v2.eh_sect,
  983. sym->frame_info_v2.eh_offset,
  984. sym->frame_info_v2.flags);
  985. break;
  986. case S_FRAMECOOKIE:
  987. printf("\tSecurity Cookie V3 @%d unk:%x\n",
  988. sym->security_cookie_v3.offset, sym->security_cookie_v3.unknown);
  989. break;
  990. case S_END:
  991. if (nest_block)
  992. {
  993. nest_block--;
  994. printf("\tS-End-Of block (%u)\n", nest_block);
  995. }
  996. else
  997. {
  998. printf("\tS-End-Of %s\n", curr_func);
  999. free(curr_func);
  1000. curr_func = NULL;
  1001. }
  1002. break;
  1003. case S_COMPILE:
  1004. {
  1005. const char* machine;
  1006. const char* lang;
  1007. switch (sym->compiland_v1.unknown & 0xFF)
  1008. {
  1009. case 0x00: machine = "Intel 8080"; break;
  1010. case 0x01: machine = "Intel 8086"; break;
  1011. case 0x02: machine = "Intel 80286"; break;
  1012. case 0x03: machine = "Intel 80386"; break;
  1013. case 0x04: machine = "Intel 80486"; break;
  1014. case 0x05: machine = "Intel Pentium"; break;
  1015. case 0x10: machine = "MIPS R4000"; break;
  1016. default:
  1017. {
  1018. static char tmp[16];
  1019. sprintf(tmp, "machine=%x", sym->compiland_v1.unknown & 0xFF);
  1020. machine = tmp;
  1021. }
  1022. break;
  1023. }
  1024. switch ((sym->compiland_v1.unknown >> 8) & 0xFF)
  1025. {
  1026. case 0x00: lang = "C"; break;
  1027. case 0x01: lang = "C++"; break;
  1028. case 0x02: lang = "Fortran"; break;
  1029. case 0x03: lang = "Masm"; break;
  1030. case 0x04: lang = "Pascal"; break;
  1031. case 0x05: lang = "Basic"; break;
  1032. case 0x06: lang = "Cobol"; break;
  1033. default:
  1034. {
  1035. static char tmp[16];
  1036. sprintf(tmp, "language=%x", (sym->compiland_v1.unknown >> 8) & 0xFF);
  1037. lang = tmp;
  1038. }
  1039. break;
  1040. }
  1041. printf("\tS-Compiland V1 '%s' %s %s unk:%x\n",
  1042. p_string(&sym->compiland_v1.p_name), machine, lang,
  1043. sym->compiland_v1.unknown >> 16);
  1044. }
  1045. break;
  1046. case S_COMPILE2_ST:
  1047. printf("\tS-Compiland V2 '%s'\n",
  1048. p_string(&sym->compiland_v2.p_name));
  1049. dump_data((const void*)sym, sym->generic.len + 2, " ");
  1050. {
  1051. const char* ptr = sym->compiland_v2.p_name.name + sym->compiland_v2.p_name.namelen;
  1052. while (*ptr)
  1053. {
  1054. printf("\t\t%s => ", ptr); ptr += strlen(ptr) + 1;
  1055. printf("%s\n", ptr); ptr += strlen(ptr) + 1;
  1056. }
  1057. }
  1058. break;
  1059. case S_OBJNAME:
  1060. printf("\tS-Compiland V3 '%s' unknown:%x\n",
  1061. sym->compiland_v3.name, sym->compiland_v3.unknown);
  1062. break;
  1063. case S_OBJNAME_ST:
  1064. printf("\tS-ObjName V1 sig:%.4s '%s'\n",
  1065. sym->objname_v1.signature, p_string(&sym->objname_v1.p_name));
  1066. break;
  1067. case S_LABEL32_ST:
  1068. printf("\tS-Label V1 '%s' in '%s' (%04x:%08x)\n",
  1069. p_string(&sym->label_v1.p_name),
  1070. curr_func, sym->label_v1.segment, sym->label_v1.offset);
  1071. break;
  1072. case S_LABEL32:
  1073. printf("\tS-Label V3 '%s' in '%s' (%04x:%08x) flag:%x\n",
  1074. sym->label_v3.name, curr_func, sym->label_v3.segment,
  1075. sym->label_v3.offset, sym->label_v3.flags);
  1076. break;
  1077. case S_CONSTANT_ST:
  1078. {
  1079. int vlen;
  1080. struct full_value fv;
  1081. vlen = full_numeric_leaf(&fv, &sym->constant_v2.cvalue);
  1082. printf("\tS-Constant V2 '%s' = %s type:%x\n",
  1083. p_string(PSTRING(&sym->constant_v2.cvalue, vlen)),
  1084. full_value_string(&fv), sym->constant_v2.type);
  1085. }
  1086. break;
  1087. case S_CONSTANT:
  1088. {
  1089. int vlen;
  1090. struct full_value fv;
  1091. vlen = full_numeric_leaf(&fv, &sym->constant_v3.cvalue);
  1092. printf("\tS-Constant V3 '%s' = %s type:%x\n",
  1093. (const char*)&sym->constant_v3.cvalue + vlen,
  1094. full_value_string(&fv), sym->constant_v3.type);
  1095. }
  1096. break;
  1097. case S_UDT_16t:
  1098. printf("\tS-Udt V1 '%s': type:0x%x\n",
  1099. p_string(&sym->udt_v1.p_name), sym->udt_v1.type);
  1100. break;
  1101. case S_UDT_ST:
  1102. printf("\tS-Udt V2 '%s': type:0x%x\n",
  1103. p_string(&sym->udt_v2.p_name), sym->udt_v2.type);
  1104. break;
  1105. case S_UDT:
  1106. printf("\tS-Udt V3 '%s': type:0x%x\n",
  1107. sym->udt_v3.name, sym->udt_v3.type);
  1108. break;
  1109. /*
  1110. * These are special, in that they are always followed by an
  1111. * additional length-prefixed string which is *not* included
  1112. * into the symbol length count. We need to skip it.
  1113. */
  1114. case S_PROCREF_ST:
  1115. printf("\tS-Procref V1 "); goto doaref;
  1116. case S_DATAREF_ST:
  1117. printf("\tS-Dataref V1 "); goto doaref;
  1118. case S_LPROCREF_ST:
  1119. printf("\tS-L-Procref V1 "); goto doaref;
  1120. doaref:
  1121. {
  1122. const struct p_string* pname;
  1123. pname = PSTRING(sym, length);
  1124. length += (pname->namelen + 1 + 3) & ~3;
  1125. printf("\t%08x %08x %08x '%s'\n",
  1126. *(((const DWORD*)sym) + 1), *(((const DWORD*)sym) + 2), *(((const DWORD*)sym) + 3),
  1127. p_string(pname));
  1128. }
  1129. break;
  1130. case S_COMPILE2: /* info about tool used to create CU */
  1131. {
  1132. const unsigned short* ptr = ((const unsigned short*)sym) + 2;
  1133. const char* x1;
  1134. const char* x2 = (const char*)&ptr[9];
  1135. /* FIXME: what are all those values for ? */
  1136. printf("\tTool V3 unk=%04x%04x%04x front=%d.%d.%d.0 back=%d.%d.%d.0 %s\n",
  1137. ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
  1138. ptr[8], x2);
  1139. while (*(x1 = x2 + strlen(x2) + 1))
  1140. {
  1141. x2 = x1 + strlen(x1) + 1;
  1142. if (!*x2) break;
  1143. printf("\t\t%s: %s\n", x1, x2);
  1144. }
  1145. }
  1146. break;
  1147. case S_COMPILE3:
  1148. {
  1149. const unsigned short* ptr = ((const unsigned short*)sym) + 2;
  1150. printf("\tTool info V3: unk=%04x%04x%04x front=%d.%d.%d.%d back=%d.%d.%d.%d %s\n",
  1151. ptr[0], ptr[1], ptr[2],
  1152. ptr[3], ptr[4], ptr[5], ptr[6],
  1153. ptr[7], ptr[8], ptr[9], ptr[10],
  1154. (const char*)(ptr + 11));
  1155. }
  1156. break;
  1157. case S_ENVBLOCK:
  1158. {
  1159. const char* x1 = (const char*)sym + 4 + 1;
  1160. const char* x2;
  1161. printf("\tTool conf V3\n");
  1162. while (*x1)
  1163. {
  1164. x2 = x1 + strlen(x1) + 1;
  1165. if (!*x2) break;
  1166. printf("\t\t%s: %s\n", x1, x2);
  1167. x1 = x2 + strlen(x2) + 1;
  1168. }
  1169. }
  1170. break;
  1171. case S_ALIGN:
  1172. /* simply skip it */
  1173. break;
  1174. case S_SSEARCH:
  1175. printf("\tSSearch V1: (%04x:%08x)\n",
  1176. sym->ssearch_v1.segment, sym->ssearch_v1.offset);
  1177. break;
  1178. case S_SECTION:
  1179. printf("\tSSection Info: seg=%04x ?=%04x rva=%08x size=%08x attr=%08x %s\n",
  1180. *(const unsigned short*)((const char*)sym + 4),
  1181. *(const unsigned short*)((const char*)sym + 6),
  1182. *(const unsigned*)((const char*)sym + 8),
  1183. *(const unsigned*)((const char*)sym + 12),
  1184. *(const unsigned*)((const char*)sym + 16),
  1185. (const char*)sym + 20);
  1186. break;
  1187. case S_COFFGROUP:
  1188. printf("\tSSubSection Info: addr=%04x:%08x size=%08x attr=%08x %s\n",
  1189. *(const unsigned short*)((const char*)sym + 16),
  1190. *(const unsigned*)((const char*)sym + 12),
  1191. *(const unsigned*)((const char*)sym + 4),
  1192. *(const unsigned*)((const char*)sym + 8),
  1193. (const char*)sym + 18);
  1194. break;
  1195. case S_EXPORT:
  1196. printf("\tSEntryPoint: id=%x '%s'\n",
  1197. *(const unsigned*)((const char*)sym + 4), (const char*)sym + 8);
  1198. break;
  1199. case S_LTHREAD32_16t:
  1200. case S_GTHREAD32_16t:
  1201. printf("\tS-Thread %s Var V1 '%s' seg=%04x offset=%08x type=%x\n",
  1202. sym->generic.id == S_LTHREAD32_16t ? "global" : "local",
  1203. p_string(&sym->thread_v1.p_name),
  1204. sym->thread_v1.segment, sym->thread_v1.offset, sym->thread_v1.symtype);
  1205. break;
  1206. case S_LTHREAD32_ST:
  1207. case S_GTHREAD32_ST:
  1208. printf("\tS-Thread %s Var V2 '%s' seg=%04x offset=%08x type=%x\n",
  1209. sym->generic.id == S_LTHREAD32_ST ? "global" : "local",
  1210. p_string(&sym->thread_v2.p_name),
  1211. sym->thread_v2.segment, sym->thread_v2.offset, sym->thread_v2.symtype);
  1212. break;
  1213. case S_LTHREAD32:
  1214. case S_GTHREAD32:
  1215. printf("\tS-Thread %s Var V3 '%s' seg=%04x offset=%08x type=%x\n",
  1216. sym->generic.id == S_LTHREAD32 ? "global" : "local", sym->thread_v3.name,
  1217. sym->thread_v3.segment, sym->thread_v3.offset, sym->thread_v3.symtype);
  1218. break;
  1219. default:
  1220. printf(">>> Unsupported symbol-id %x sz=%d\n", sym->generic.id, sym->generic.len + 2);
  1221. dump_data((const void*)sym, sym->generic.len + 2, " ");
  1222. }
  1223. }
  1224. return TRUE;
  1225. }
  1226. void codeview_dump_linetab(const char* linetab, BOOL pascal_str, const char* pfx)
  1227. {
  1228. const char* ptr = linetab;
  1229. int nfile, nseg, nline;
  1230. int i, j, k;
  1231. const unsigned int* filetab;
  1232. const unsigned int* lt_ptr;
  1233. const struct startend* start;
  1234. nfile = *(const short*)linetab;
  1235. filetab = (const unsigned int*)(linetab + 2 * sizeof(short));
  1236. printf("%s%d files with %d ???\n", pfx, nfile, *(const short*)(linetab + sizeof(short)));
  1237. for (i = 0; i < nfile; i++)
  1238. {
  1239. ptr = linetab + filetab[i];
  1240. nseg = *(const short*)ptr;
  1241. ptr += 2 * sizeof(short);
  1242. lt_ptr = (const unsigned int*)ptr;
  1243. start = (const struct startend*)(lt_ptr + nseg);
  1244. /*
  1245. * Now snarf the filename for all of the segments for this file.
  1246. */
  1247. if (pascal_str)
  1248. {
  1249. char filename[MAX_PATH];
  1250. const struct p_string* p_fn;
  1251. p_fn = (const struct p_string*)(start + nseg);
  1252. memset(filename, 0, sizeof(filename));
  1253. memcpy(filename, p_fn->name, p_fn->namelen);
  1254. printf("%slines for file #%d/%d %s %d\n", pfx, i, nfile, filename, nseg);
  1255. }
  1256. else
  1257. printf("%slines for file #%d/%d %s %d\n", pfx, i, nfile, (const char*)(start + nseg), nseg);
  1258. for (j = 0; j < nseg; j++)
  1259. {
  1260. ptr = linetab + *lt_ptr++;
  1261. nline = *(const short*)(ptr + 2);
  1262. printf("%s %04x:%08x-%08x #%d\n",
  1263. pfx, *(const short*)(ptr + 0), start[j].start, start[j].end, nline);
  1264. ptr += 4;
  1265. for (k = 0; k < nline; k++)
  1266. {
  1267. printf("%s %x %d\n",
  1268. pfx, ((const unsigned int*)ptr)[k],
  1269. ((const unsigned short*)((const unsigned int*)ptr + nline))[k]);
  1270. }
  1271. }
  1272. }
  1273. }
  1274. void codeview_dump_linetab2(const char* linetab, DWORD size, const char* strimage, DWORD strsize, const char* pfx)
  1275. {
  1276. unsigned i;
  1277. const struct codeview_linetab2* lt2;
  1278. const struct codeview_linetab2* lt2_files = NULL;
  1279. const struct codeview_lt2blk_lines* lines_blk;
  1280. const struct codeview_linetab2_file*fd;
  1281. /* locate LT2_FILES_BLOCK (if any) */
  1282. lt2 = (const struct codeview_linetab2*)linetab;
  1283. while ((const char*)(lt2 + 1) < linetab + size)
  1284. {
  1285. if (lt2->header == LT2_FILES_BLOCK)
  1286. {
  1287. lt2_files = lt2;
  1288. break;
  1289. }
  1290. lt2 = codeview_linetab2_next_block(lt2);
  1291. }
  1292. if (!lt2_files)
  1293. {
  1294. printf("%sNo LT2_FILES_BLOCK found\n", pfx);
  1295. return;
  1296. }
  1297. lt2 = (const struct codeview_linetab2*)linetab;
  1298. while ((const char*)(lt2 + 1) < linetab + size)
  1299. {
  1300. /* FIXME: should also check that whole lbh fits in linetab + size */
  1301. switch (lt2->header)
  1302. {
  1303. case LT2_LINES_BLOCK:
  1304. lines_blk = (const struct codeview_lt2blk_lines*)lt2;
  1305. printf("%sblock from %04x:%08x #%x (%x lines) fo=%x\n",
  1306. pfx, lines_blk->seg, lines_blk->start, lines_blk->size,
  1307. lines_blk->nlines, lines_blk->file_offset);
  1308. /* FIXME: should check that file_offset is within the LT2_FILES_BLOCK we've seen */
  1309. fd = (const struct codeview_linetab2_file*)((const char*)lt2_files + 8 + lines_blk->file_offset);
  1310. printf("%s md5=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
  1311. pfx, fd->md5[ 0], fd->md5[ 1], fd->md5[ 2], fd->md5[ 3],
  1312. fd->md5[ 4], fd->md5[ 5], fd->md5[ 6], fd->md5[ 7],
  1313. fd->md5[ 8], fd->md5[ 9], fd->md5[10], fd->md5[11],
  1314. fd->md5[12], fd->md5[13], fd->md5[14], fd->md5[15]);
  1315. /* FIXME: should check that string is within strimage + strsize */
  1316. printf("%s file=%s\n", pfx, strimage ? strimage + fd->offset : "--none--");
  1317. for (i = 0; i < lines_blk->nlines; i++)
  1318. {
  1319. printf("%s offset=%08x line=%d\n",
  1320. pfx, lines_blk->l[i].offset, lines_blk->l[i].lineno ^ 0x80000000);
  1321. }
  1322. break;
  1323. case LT2_FILES_BLOCK: /* skip */
  1324. break;
  1325. default:
  1326. printf("%sblock end %x\n", pfx, lt2->header);
  1327. lt2 = (const struct codeview_linetab2*)(linetab + size);
  1328. continue;
  1329. }
  1330. lt2 = codeview_linetab2_next_block(lt2);
  1331. }
  1332. }