Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

749 lines
19 KiB

  1. /* generate wowit.h and wowit.c from wow.it
  2. *
  3. * 20-Feb-1997 DaveHart created
  4. */
  5. #include <time.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <io.h>
  10. #include <sys\stat.h>
  11. #include <fcntl.h>
  12. #include <windows.h>
  13. VOID ErrorAbort(PSZ pszMsg);
  14. BYTE GetReturnOpcode(PSZ *ppsz);
  15. PSZ GetApiName(PSZ *ppsz);
  16. PSZ GetApi32Name(PSZ *ppsz, PSZ pszApi16);
  17. BYTE GetArgOpcode(PSZ *ppsz);
  18. PSZ GetOpcodeName(BYTE bInstr);
  19. PSZ GetLine(PSZ pszBuf, int cbBuf, FILE *fp);
  20. VOID ReadTypeNames(FILE *fIn, PSZ szTypesPrefix, PSZ *OpcodeNamesArray, int *pnOpcodeNames);
  21. PSZ DateTimeString(VOID);
  22. #define IS_RET_OPCODE(b) (b & 0x80)
  23. #define MAX_IT_INSTR 16
  24. typedef struct tagITINSTR {
  25. int cbInstr;
  26. int offSwamp;
  27. BYTE Instr[MAX_IT_INSTR];
  28. } ITINSTR;
  29. #define MAX_INSTR_TABLE_SIZE 512
  30. ITINSTR InstrTable[MAX_INSTR_TABLE_SIZE];
  31. int iNextInstrSlot = 0;
  32. typedef struct tagTHUNKTABLESLOT {
  33. PSZ pszAPI;
  34. PSZ pszAPI32; // if Win32 routine name doesn't match pszAPI
  35. int iInstrSlot;
  36. int cbInstr; // how much of this slot we're using
  37. } THUNKTABLESLOT;
  38. #define MAX_THUNK_TABLE_SIZE 1024
  39. THUNKTABLESLOT ThunkTable[MAX_THUNK_TABLE_SIZE];
  40. int iNextThunkSlot = 0;
  41. #define MAX_ARG_OPCODE_NAMES 32
  42. PSZ ArgOpcodeNames[MAX_ARG_OPCODE_NAMES];
  43. int nArgOpcodeNames = 0;
  44. #define MAX_RET_OPCODE_NAMES 32
  45. PSZ RetOpcodeNames[MAX_RET_OPCODE_NAMES];
  46. int nRetOpcodeNames = 0;
  47. static char szArgumentTypes[] = "Argument Types:";
  48. static char szReturnTypes[] = "Return Types:";
  49. int __cdecl main(int argc, char **argv)
  50. {
  51. FILE *fIn, *fOutH, *fOutC;
  52. char szBuf[256], szOff1[32], szOff2[32];
  53. PSZ psz, pszAPI, pszAPI32;
  54. ITINSTR ThisInstr;
  55. BYTE bRetInstr;
  56. BYTE *pbInstr;
  57. int i, iSwampOffset;
  58. int iMaxArgs = 0;
  59. int cbDiff;
  60. if (argc != 2) {
  61. ErrorAbort("Usage:\n genwowit <inputfile>\n");
  62. }
  63. if (!(fIn = fopen(argv[1], "rt"))) {
  64. ErrorAbort("Unable to open input file\n");
  65. }
  66. //
  67. // The input file (wow.it) uses # to begin comment lines.
  68. // Aside from comments, it must begin with two special lines
  69. // to define the available type names for arguments and
  70. // function return values.
  71. //
  72. // They look like:
  73. //
  74. // Argument Types: WORD, INT, DWORD, LPDWORD, PTR, PTRORATOM, HGDI, HUSER, COLOR, HINST, HICON, POINT, 16ONLY, 32ONLY;
  75. // Return Types: DWORD, WORD, INT, HGDI, HUSER, ZERO, HICON, ONE, HPRNDWP;
  76. //
  77. // Read these lines into the ArgOpcodeNames and RetOpcodeNames arrays.
  78. //
  79. ReadTypeNames(fIn, szArgumentTypes, ArgOpcodeNames, &nArgOpcodeNames);
  80. if(nArgOpcodeNames > MAX_ARG_OPCODE_NAMES) {
  81. ErrorAbort("Too many ARG op codes!\n");
  82. }
  83. ReadTypeNames(fIn, szReturnTypes, RetOpcodeNames, &nRetOpcodeNames);
  84. if(nRetOpcodeNames > MAX_RET_OPCODE_NAMES) {
  85. ErrorAbort("Too many RET op codes!\n");
  86. }
  87. //
  88. // Each input line in the main part has a very restricted syntax:
  89. //
  90. // RETTYPE Api16[=Api32](TYPE1, TYPE2, ... TYPEn); # comment
  91. //
  92. // If Api32 isn't specified it's the same as Api16.
  93. // The types come from the set above only.
  94. //
  95. // Actually everything following the ) is ignored now.
  96. //
  97. while (GetLine(szBuf, sizeof szBuf, fIn)) {
  98. psz = szBuf;
  99. //
  100. // Pick up the type, space-delimited, leaving psz at API name start
  101. //
  102. bRetInstr = GetReturnOpcode(&psz);
  103. //
  104. // Pick up the API name, leaving psz pointing past the open-paren or
  105. // to '=' char
  106. //
  107. pszAPI = GetApiName(&psz);
  108. //
  109. // Pick up the 32-bit name if it exists
  110. //
  111. pszAPI32 = GetApi32Name(&psz, pszAPI);
  112. //
  113. // Pick up the arg types into Instr array
  114. //
  115. memset(&ThisInstr, 0, sizeof ThisInstr);
  116. pbInstr = ThisInstr.Instr;
  117. while (*psz && *psz != ')') {
  118. *pbInstr++ = GetArgOpcode(&psz);
  119. }
  120. //
  121. // Keep track of the max used args
  122. //
  123. iMaxArgs = max(iMaxArgs, (pbInstr - ThisInstr.Instr));
  124. //
  125. // Tack on the return opcode
  126. //
  127. *pbInstr++ = bRetInstr;
  128. //
  129. // Record instruction bytes used for this one.
  130. //
  131. ThisInstr.cbInstr = (pbInstr - ThisInstr.Instr);
  132. //
  133. // Make sure we haven't overrun
  134. //
  135. if ( ThisInstr.cbInstr > MAX_IT_INSTR ) {
  136. printf("Thunk for %s too many args (%d) increase MAX_IT_INSTR beyond %d.\n",
  137. pszAPI, ThisInstr.cbInstr, MAX_IT_INSTR);
  138. ErrorAbort("Increase MAX_IT_INSTR in intthunk.h\n");
  139. }
  140. //
  141. // Now we have a fully-formed opcode stream, see if we can pack it
  142. // in with any previously recorded ones. Walk through the table
  143. // from the start looking for any entry which already contains this
  144. // opcode sequence (possibly as part of a longer sequence) or which
  145. // is itself contained by this opcode sequence. If we find one,
  146. // change it to be the longer sequence if needed and use it. We'll
  147. // distinguish later between the multiple uses using the cbInstr in
  148. // each thunk table entry. The logic here assumes the matches will
  149. // always be at the end, since ret opcodes always have 0x80 bit set
  150. // and no others do, and each sequence ends with one.
  151. //
  152. for (i = 0; i < iNextInstrSlot; i++) {
  153. //if (0 == memcmp(Instr, InstrTable[i], sizeof Instr)) {
  154. // break;
  155. //}
  156. //
  157. // Is ThisInstr a subsequence of this table entry?
  158. //
  159. if (ThisInstr.cbInstr <= InstrTable[i].cbInstr &&
  160. 0 == memcmp(ThisInstr.Instr,
  161. InstrTable[i].Instr + (InstrTable[i].cbInstr -
  162. ThisInstr.cbInstr),
  163. ThisInstr.cbInstr)) {
  164. break;
  165. }
  166. //
  167. // Is this table entry a subsequence of ThisInstr?
  168. //
  169. if (InstrTable[i].cbInstr < ThisInstr.cbInstr &&
  170. 0 == memcmp(InstrTable[i].Instr,
  171. ThisInstr.Instr + (ThisInstr.cbInstr -
  172. InstrTable[i].cbInstr),
  173. InstrTable[i].cbInstr)) {
  174. //
  175. // Blast the longer ThisInstr over the existing shorter
  176. // instruction.
  177. //
  178. memcpy(&InstrTable[i], &ThisInstr, sizeof InstrTable[i]);
  179. break;
  180. }
  181. //
  182. // Check the next instruction table entry.
  183. //
  184. }
  185. //
  186. // If we didn't find a match, add to the end.
  187. //
  188. if (i == iNextInstrSlot) {
  189. memcpy(&InstrTable[i], &ThisInstr, sizeof InstrTable[i]);
  190. iNextInstrSlot++;
  191. if (iNextInstrSlot == MAX_INSTR_TABLE_SIZE) {
  192. ErrorAbort("Increase MAX_INSTR_TABLE_SIZE in genwowit.c\n");
  193. }
  194. }
  195. //
  196. // Add this one to the thunk table.
  197. //
  198. ThunkTable[iNextThunkSlot].pszAPI = pszAPI;
  199. ThunkTable[iNextThunkSlot].pszAPI32 = pszAPI32;
  200. ThunkTable[iNextThunkSlot].iInstrSlot = i;
  201. ThunkTable[iNextThunkSlot].cbInstr = ThisInstr.cbInstr;
  202. iNextThunkSlot++;
  203. if (iNextThunkSlot == MAX_THUNK_TABLE_SIZE) {
  204. ErrorAbort("Increase MAX_THUNK_TABLE_SIZE in genwowit.c\n");
  205. }
  206. }
  207. fclose(fIn);
  208. //
  209. // Now we're ready to output the results.
  210. //
  211. if (!(fOutH = fopen("wowit.h", "wt"))) {
  212. ErrorAbort("Cannot open wowit.h output file\n");
  213. }
  214. fprintf(fOutH,
  215. "//\n"
  216. "// DO NOT EDIT.\n"
  217. "//\n"
  218. "// wowit.h generated by genwowit.exe from wow.it on\n"
  219. "//\n"
  220. "// %s\n"
  221. "//\n\n", DateTimeString());
  222. fprintf(fOutH, "#include \"intthunk.h\"\n\n");
  223. fprintf(fOutH, "#define MAX_IT_ARGS %d\n\n", iMaxArgs);
  224. //
  225. // Spit out the two types of opcode manifests.
  226. //
  227. for (i = 0; i < nArgOpcodeNames; i++) {
  228. fprintf(fOutH, "#define IT_%-20s ( (UCHAR) 0x%x )\n", ArgOpcodeNames[i], i);
  229. }
  230. fprintf(fOutH, "\n#define IT_RETMASK ( (UCHAR) 0x80 )\n");
  231. for (i = 0; i < nRetOpcodeNames; i++) {
  232. sprintf(szBuf, "%sRET", RetOpcodeNames[i]);
  233. fprintf(fOutH, "#define IT_%-20s ( IT_RETMASK | (UCHAR) 0x%x )\n", szBuf, i);
  234. }
  235. fprintf(fOutH, "\n");
  236. //
  237. // ITID_ manifests map an API name to its slot
  238. // in the thunk table. Each one looks like:
  239. //
  240. // #define ITID_ApiName 0
  241. //
  242. for (i = 0; i < iNextThunkSlot; i++) {
  243. fprintf(fOutH, "#define ITID_%-40s %d\n", ThunkTable[i].pszAPI, i);
  244. }
  245. fprintf(fOutH, "\n#define ITID_MAX %d\n", i-1);
  246. fclose(fOutH);
  247. //
  248. // wowit.c has two tables, the instruction table and
  249. // the thunk table.
  250. //
  251. if (!(fOutC = fopen("wowit.c", "wt"))) {
  252. ErrorAbort("Cannot open wowit.c output file\n");
  253. }
  254. fprintf(fOutC,
  255. "//\n"
  256. "// DO NOT EDIT.\n"
  257. "//\n"
  258. "// wowit.c generated by genwowit.exe from wow.it on\n"
  259. "//\n"
  260. "// %s\n"
  261. "//\n\n", DateTimeString());
  262. fprintf(fOutC, "#include \"precomp.h\"\n");
  263. fprintf(fOutC, "#pragma hdrstop\n");
  264. fprintf(fOutC, "#define WOWIT_C\n");
  265. fprintf(fOutC, "#include \"wowit.h\"\n\n");
  266. //
  267. // Spit out the instruction table, packing bytes in the process
  268. // and filling in the aoffInstrTable array with offsets for each
  269. // entry in this program's InstrTable. Those offsets are used
  270. // in writing the final thunk table.
  271. //
  272. iSwampOffset = 0;
  273. fprintf(fOutC, "CONST BYTE InstrSwamp[] = {\n");
  274. for (i = 0; i < iNextInstrSlot; i++) {
  275. fprintf(fOutC, " /* %3d 0x%-3x */ ", i, iSwampOffset);
  276. pbInstr = InstrTable[i].Instr;
  277. InstrTable[i].offSwamp = iSwampOffset;
  278. do {
  279. fprintf(fOutC, "%s, ", GetOpcodeName(*pbInstr));
  280. iSwampOffset++;
  281. } while (!IS_RET_OPCODE(*pbInstr++));
  282. fprintf(fOutC, "\n");
  283. }
  284. fprintf(fOutC, "};\n\n");
  285. fprintf(fOutC, "CONST INT_THUNK_TABLEENTRY IntThunkTable[] = {\n");
  286. for (i = 0; i < iNextThunkSlot; i++) {
  287. //
  288. // Concatenate the API name followed by a comma into
  289. // szBuf, so the combination can be left-justified in the output.
  290. //
  291. sprintf(szBuf, "%s,", ThunkTable[i].pszAPI32);
  292. //
  293. // cbDiff is the offset into the instruction stream where
  294. // this thunks instruction stream begins.
  295. //
  296. cbDiff = InstrTable[ ThunkTable[i].iInstrSlot ].cbInstr -
  297. ThunkTable[i].cbInstr;
  298. //
  299. // Format the swamp offset so it can be left-justified in the output.
  300. //
  301. sprintf(szOff1, "%x",
  302. InstrTable[ ThunkTable[i].iInstrSlot ].offSwamp + cbDiff);
  303. //
  304. // If this thunk table entry will point past the start of
  305. // an instruction (because of sharing), format the offset
  306. // past the start of the instruction into szOff2
  307. //
  308. if (cbDiff) {
  309. sprintf(szOff2, "+ %d ", cbDiff);
  310. } else {
  311. szOff2[0] = '\0';
  312. }
  313. fprintf(fOutC,
  314. " /* %3d */ { (FARPROC) %-32s InstrSwamp + 0x%-4s }, /* %d %s*/ \n",
  315. i,
  316. szBuf,
  317. szOff1,
  318. ThunkTable[i].iInstrSlot,
  319. szOff2);
  320. }
  321. fprintf(fOutC, "};\n\n");
  322. fclose(fOutC);
  323. printf("Generated wowit.h and wowit.c from wow.it\n"
  324. "%d thunks, %d unique instruction streams, %d instruction bytes, %d max args.\n",
  325. iNextThunkSlot, iNextInstrSlot, iSwampOffset, iMaxArgs);
  326. return 0;
  327. }
  328. BYTE GetReturnOpcode(PSZ *ppsz)
  329. {
  330. int i;
  331. char szBuf[32];
  332. PSZ psz;
  333. //
  334. // Copy the name up to the first space to szBuf,
  335. // then skip any remaining spaces leaving caller's
  336. // pointer pointing at API name.
  337. //
  338. psz = szBuf;
  339. while (**ppsz != ' ') {
  340. *psz++ = *((*ppsz)++);
  341. };
  342. *psz = 0;
  343. if(strlen(szBuf) > 32-1) {
  344. ErrorAbort("Return Opcode too long.\n");
  345. }
  346. // advance to the API name start
  347. while (**ppsz == ' ') {
  348. (*ppsz)++;
  349. };
  350. i = 0;
  351. while (i < nRetOpcodeNames &&
  352. strcmp(szBuf, RetOpcodeNames[i])) {
  353. i++;
  354. }
  355. if (i == nRetOpcodeNames) {
  356. printf("%s is not a valid return type.\n", szBuf);
  357. ErrorAbort("Invalid return type.\n");
  358. }
  359. return (BYTE)i | 0x80;
  360. }
  361. PSZ GetApiName(PSZ *ppsz)
  362. {
  363. char szBuf[128];
  364. PSZ psz;
  365. //
  366. // Copy the name up to the first space or open-paren or equals sign
  367. // to szBuf, then skip any remaining spaces and open-parens leaving caller's
  368. // pointer pointing at first arg type or equals sign
  369. //
  370. psz = szBuf;
  371. while (**ppsz != ' ' && **ppsz != '(' && **ppsz != '=') {
  372. *psz++ = *((*ppsz)++);
  373. };
  374. *psz = 0;
  375. if(strlen(szBuf) > 128-1) {
  376. ErrorAbort("API Name too long.\n");
  377. }
  378. // advance to 1st parameter type or '=' char if any
  379. while (**ppsz == ' ' || **ppsz == '(') {
  380. (*ppsz)++;
  381. };
  382. if (!strlen(szBuf)) {
  383. ErrorAbort("Empty API name\n");
  384. }
  385. return _strdup(szBuf);
  386. }
  387. PSZ GetApi32Name(PSZ *ppsz, PSZ pszApi16)
  388. {
  389. char szBuf[128];
  390. PSZ psz;
  391. if (**ppsz != '=') {
  392. return pszApi16;
  393. }
  394. (*ppsz)++; // skip =
  395. //
  396. // Copy the name up to the first space or open-paren
  397. // to szBuf, then skip any remaining spaces and open-parens leaving caller's
  398. // pointer pointing at first arg type
  399. //
  400. psz = szBuf;
  401. while (**ppsz != ' ' && **ppsz != '(') {
  402. *psz++ = *((*ppsz)++);
  403. };
  404. *psz = 0;
  405. if(strlen(szBuf) > 128-1) {
  406. ErrorAbort("API32 Name too long.\n");
  407. }
  408. // advance to the 1st parameter type
  409. while (**ppsz == ' ' || **ppsz == '(') {
  410. (*ppsz)++;
  411. };
  412. if (!strlen(szBuf)) {
  413. ErrorAbort("Empty API32 name\n");
  414. }
  415. return _strdup(szBuf);
  416. }
  417. BYTE GetArgOpcode(PSZ *ppsz)
  418. {
  419. char szBuf[32];
  420. PSZ psz;
  421. int i;
  422. //
  423. // Copy the name up to the first space or comma close-paren
  424. // to szBuf, then skip any remaining spaces and commas,
  425. // leaving caller's pointer pointing at next arg type
  426. // or close-paren.
  427. //
  428. psz = szBuf;
  429. while (**ppsz != ' ' && **ppsz != ',' && **ppsz != ')') {
  430. *psz++ = *((*ppsz)++);
  431. };
  432. *psz = 0;
  433. if(strlen(szBuf) > 32-1) {
  434. ErrorAbort("Opcode too long.\n");
  435. }
  436. while (**ppsz == ' ' || **ppsz == ',') {
  437. (*ppsz)++;
  438. };
  439. //
  440. // szBuf has the type name, find it in the table.
  441. //
  442. i = 0;
  443. while (i < nArgOpcodeNames &&
  444. strcmp(szBuf, ArgOpcodeNames[i])) {
  445. i++;
  446. }
  447. if (i == nArgOpcodeNames) {
  448. printf("%s is not a valid arg type.\n", szBuf);
  449. ErrorAbort("Invalid arg type.\n");
  450. }
  451. return (BYTE)i;
  452. }
  453. PSZ GetOpcodeName(BYTE bInstr)
  454. {
  455. char szBuf[64];
  456. if (!IS_RET_OPCODE(bInstr)) {
  457. sprintf(szBuf, "IT_%s", ArgOpcodeNames[bInstr]);
  458. } else {
  459. sprintf(szBuf, "IT_%sRET", RetOpcodeNames[bInstr & 0x7f]);
  460. }
  461. return _strdup(szBuf);
  462. }
  463. VOID ErrorAbort(PSZ pszMsg)
  464. {
  465. printf("GENWOWIT : fatal error GWI0001: Unable to process wow.it: %s\n", pszMsg);
  466. exit(1);
  467. }
  468. //
  469. // Read a line from the input file skipping
  470. // comment lines with '#' in the first column.
  471. //
  472. PSZ GetLine(PSZ pszBuf, int cbBuf, FILE *fp)
  473. {
  474. do {
  475. pszBuf = fgets(pszBuf, cbBuf, fp);
  476. } while (pszBuf && '#' == *pszBuf);
  477. if(pszBuf) {
  478. pszBuf[cbBuf-1] = '\0';
  479. }
  480. return pszBuf;
  481. }
  482. //
  483. // Read one of the two special lines at the start that
  484. // define the available types.
  485. //
  486. VOID ReadTypeNames(FILE *fIn, PSZ pszTypesPrefix, PSZ *OpcodeNamesArray, int *pnOpcodeNames)
  487. {
  488. char chSave, szBuf[512];
  489. PSZ psz, pszType;
  490. if ( ! GetLine(szBuf, sizeof szBuf, fIn) ||
  491. _memicmp(szBuf, pszTypesPrefix, strlen(pszTypesPrefix)) ) {
  492. ErrorAbort("First line of input file must be 'Argument Types:', second 'Return Types:' ...\n");
  493. }
  494. psz = szBuf + strlen(pszTypesPrefix);
  495. //
  496. // Skip whitespace and commas
  497. //
  498. while (' ' == *psz || '\t' == *psz) {
  499. psz++;
  500. }
  501. if ( ! *psz) {
  502. ErrorAbort("No types found.\n");
  503. }
  504. do {
  505. //
  506. // Now we're looking at the first character of the type name.
  507. //
  508. pszType = psz;
  509. //
  510. // Find next whitespace, comma, semi, or null and turn it into a null.
  511. // This turns this type name into a zero-terminated string.
  512. //
  513. while (*psz && ' ' != *psz && '\t' != *psz && ',' != *psz && ';' != *psz) {
  514. psz++;
  515. }
  516. chSave = *psz;
  517. *psz = 0;
  518. OpcodeNamesArray[*pnOpcodeNames] = _strdup(pszType);
  519. (*pnOpcodeNames)++;
  520. *psz = chSave;
  521. //
  522. // Skip whitespace and commas
  523. //
  524. while (' ' == *psz || '\t' == *psz || ',' == *psz) {
  525. psz++;
  526. }
  527. } while (*psz && ';' != *psz);
  528. if(';' != *psz) {
  529. ErrorAbort("Semi-colon not found. Size of szBuf[] probably needs to be increased.\n");
  530. }
  531. if ( ! *pnOpcodeNames) {
  532. ErrorAbort("No types found.\n");
  533. }
  534. }
  535. //
  536. // Return a formatted date/time string for now.
  537. // Only checks system time once so that wowit.c and wowit.h
  538. // will have same date/time string.
  539. //
  540. PSZ DateTimeString(VOID)
  541. {
  542. static char sz[256];
  543. static int fSetupAlready;
  544. if (!fSetupAlready) {
  545. time_t UnixTimeNow;
  546. struct tm *ptmNow;
  547. fSetupAlready = TRUE;
  548. _tzset();
  549. time(&UnixTimeNow);
  550. ptmNow = localtime(&UnixTimeNow);
  551. strftime(sz, sizeof sz, "%#c", ptmNow);
  552. strcat(sz, " (");
  553. strcat(sz, _strupr(_tzname[0])); // naughty me
  554. strcat(sz, ")");
  555. }
  556. return sz;
  557. }