Source code of Windows XP (NT5)
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.

3620 lines
85 KiB

  1. // Copyright (c) 1994-1999 Microsoft Corporation
  2. #include <nt.h>
  3. #include <ntrtl.h>
  4. #include <nturtl.h>
  5. #include <windows.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <stdarg.h>
  10. #include "gen.h"
  11. BOOLEAN bDebug = FALSE;
  12. BOOLEAN bExitClean= TRUE;
  13. char szNULL[]="";
  14. char szVARGS[]="...";
  15. char szCONST[] = "const";
  16. char szVOLATILE[] = "volatile";
  17. char szREGISTER[] = "register";
  18. char szEXTERN[] = "extern";
  19. char sz_CDECL[] = "__cdecl";
  20. char szCDECL[] = "_cdecl";
  21. char szSTDCALL[] = "__stdcall";
  22. char sz__FASTCALL[] = "__fastcall";
  23. char szUNALIGNED[] = "__unaligned";
  24. char szTYPEDEF[] = "typedef";
  25. char szCHAR[] = "char";
  26. char szINT[] = "int";
  27. char szLONG[] = "long";
  28. char szSHORT[] = "short";
  29. char szDOUBLE[] = "double";
  30. char szENUM[] = "enum";
  31. char szFLOAT[] = "float";
  32. char szSTRUCT[] = "struct";
  33. char szUNION[] = "union";
  34. char szVOID[] = "void";
  35. char szINT64[] = "_int64";
  36. char sz_INT64[] = "__int64";
  37. char sz__PTR64[] = "__ptr64";
  38. char szFUNC[] = "()";
  39. char szSIGNED[] = "signed";
  40. char szUNSIGNED[] = "unsigned";
  41. char szSTATIC[] = "static";
  42. char szIN[] = "__in";
  43. char szOUT[] = "__out";
  44. char szINOUT[] = "__in __out";
  45. char szGUID[] = "GUID";
  46. char sz__W64[] = "__w64";
  47. char szPragma[] = "#pragma";
  48. char szPack[] = "pack";
  49. char szPush[] = "push";
  50. char szPop[] = "pop";
  51. char szFUNCTIONS[] = "Functions";
  52. char szSTRUCTURES[] = "Structures";
  53. char szTYPEDEFS[] = "TypeDefs";
  54. char szUNSIGNEDCHAR[] = "unsigned char";
  55. char szUNSIGNEDSHORT[] = "unsigned short";
  56. char szUNSIGNEDLONG[] = "unsigned long";
  57. DEFBASICTYPES DefaultBasicTypes[] = {
  58. { "unsigned int" },
  59. { "int" },
  60. { "short int" },
  61. { "unsigned short int" },
  62. { "long int" },
  63. { "unsigned long int" },
  64. { "char" },
  65. { "unsigned char" },
  66. { szINT64 },
  67. { sz_INT64 },
  68. { szGUID },
  69. { szDOUBLE },
  70. { szFLOAT },
  71. { szENUM },
  72. { szSTRUCT },
  73. { szUNION },
  74. { szVOID },
  75. { szFUNC }
  76. };
  77. CHAR szVTBL[] = "VTBL";
  78. #define NUMDEFBASICTYPES sizeof(DefaultBasicTypes)/sizeof(DEFBASICTYPES);
  79. // List mapping TokenTypes to human-readable strings. TK_NONE, TK_IDENTIFIER,
  80. // TK_NUMBER, and TK_STRING must be special-cased.
  81. char *TokenString[] = {
  82. "", // TK_NONE
  83. "", // TK_IDENTIFIER
  84. "", // TK_NUMBER
  85. "+", // TK_PLUS
  86. "-", // TK_MINUS
  87. "*", // TK_STAR
  88. "/", // TK_DIVIDE
  89. "[", // TK_LSQUARE
  90. "]", // TK_RSQUARE
  91. "{", // TK_LBRACE
  92. "}", // TK_RBRACE
  93. "(", // TK_LPAREN
  94. ")", // TK_RPAREN
  95. "...", // TK_VARGS
  96. "const", // TK_CONST
  97. "volatile", // TK_VOLATILE
  98. "register", // TK_REGISTER
  99. "extern", // TK_EXTERN
  100. "__cdecl", // TK_CDECL
  101. "__stdcall", // TK_STDCALL
  102. "typedef", // TK_TYPEDEF
  103. "static", // TK_STATIC
  104. ",", // TK_COMMA
  105. ";", // TK_SEMI
  106. "struct", // TK_STRUCT
  107. "union", // TK_UNION
  108. "enum", // TK_ENUM
  109. "__inline", // TK_INLINE
  110. ":", // TK_COLON
  111. "=", // TK_ASSIGN
  112. ".", // TK_DOT
  113. "<<", // TK_LSHIFT
  114. ">>", // TK_RSHIFT
  115. "<", // TK_LESS
  116. ">", // TK_GREATER
  117. "__unaligned", // TK_UNALIGNED
  118. "__declspec", // TK_DECLSPEC
  119. "__restrict", // TK_RESTRICT (MIPS-only keyword - a pointer modifier)
  120. "__fastcall", // TK_FASTCALL
  121. "__in", // TK_IN
  122. "__out", // TK_OUT
  123. "__in __out", // TK_INOUT
  124. "&", // TK_BITWISE_AND
  125. "|", // TK_BITWISE_OR
  126. "&&", // TK_LOGICAL_AND
  127. "||", // TK_LOGICAL_OR
  128. "%", // TK_MOD
  129. "^", // TK_XOR
  130. "!", // TK_NOT
  131. "~", // TK_TILDE
  132. "", // TK_STRING
  133. "sizeof", // TK_SIZEOF
  134. "template", // TK_TEMPLATE
  135. "__w64", // TK___W64
  136. "" // TK_EOS
  137. };
  138. // List of keyword names. When an identifier is recognized, it is
  139. // compared against this list, and if it matches, TK_IDENTIFIER is
  140. // replaced by the appropriate keyword token id.
  141. //
  142. // NOTE: This must remain in sorted order.
  143. TOKENMATCH KeywordList[] = {
  144. { TK_CDECL, "__cdecl" },
  145. { TK_DECLSPEC, "__declspec" },
  146. { TK_FASTCALL, "__fastcall" },
  147. { TK_INLINE, "__forceinline" },
  148. { TK_IN, "__in" },
  149. { TK_INLINE, "__inline" },
  150. { TK_OUT, "__out" },
  151. { TK_RESTRICT, "__restrict" },
  152. { TK_STDCALL, "__stdcall" },
  153. { TK_UNALIGNED, "__unaligned" },
  154. { TK___W64, "__w64" },
  155. { TK_CDECL, "_cdecl" },
  156. { TK_FASTCALL, "_fastcall" },
  157. { TK_INLINE, "_inline" },
  158. { TK_STRUCT, "class" },
  159. { TK_CONST, "const" },
  160. { TK_ENUM, "enum" },
  161. { TK_EXTERN, "extern" },
  162. { TK_INLINE, "inline" },
  163. { TK_REGISTER, "register" },
  164. { TK_SIZEOF, "sizeof" },
  165. { TK_STATIC, "static" },
  166. { TK_STRUCT, "struct" },
  167. { TK_TEMPLATE, "template" },
  168. { TK_TYPEDEF, "typedef" },
  169. { TK_UNION, "union" },
  170. { TK_VOLATILE, "volatile" },
  171. { TK_NONE, NULL }
  172. };
  173. LIST_ENTRY OpenFileHead= {&OpenFileHead, &OpenFileHead};
  174. typedef struct _OpenFileEntry {
  175. LIST_ENTRY FileEntry;
  176. HANDLE hFile;
  177. FILE *fp;
  178. char FileName[MAX_PATH+1];
  179. } OPENFILEENTRY, *POPENFILEENTRY;
  180. TOKEN Tokens[MAX_TOKENS_IN_STATEMENT];
  181. int CurrentTokenIndex;
  182. void
  183. CheckForKeyword(
  184. PTOKEN Token
  185. );
  186. BOOL
  187. ConsoleControlHandler(
  188. DWORD dwCtrlType
  189. )
  190. /*++
  191. Routine Description:
  192. Called if user hits Ctrl+C or Ctrl+Break. Closes all open files,
  193. allowing for a graceful exit.
  194. Arguments:
  195. dwCtrlType -- ????
  196. Return Value:
  197. ????
  198. --*/
  199. {
  200. CloseOpenFileList(TRUE);
  201. return FALSE;
  202. }
  203. BOOL
  204. AddOpenFile(
  205. char *FileName,
  206. FILE *fp,
  207. HANDLE hFile
  208. )
  209. /*++
  210. Routine Description:
  211. Records that a file has been opened. If an error occurs within
  212. the app, files in this list will be closed.
  213. Arguments:
  214. FileName -- name of open file
  215. fp -- OPTIONAL file pointer
  216. hFile -- OPTIONAL file handle
  217. Return Value:
  218. TRUE if file added to the list, FALSE if failure (probably out of memory)
  219. --*/
  220. {
  221. POPENFILEENTRY pofe;
  222. pofe = GenHeapAlloc(sizeof(OPENFILEENTRY));
  223. if (!pofe) {
  224. ErrMsg("AddOpenWriteFile: insuf memory: %s\n", strerror(errno));
  225. return FALSE;
  226. }
  227. pofe->fp = fp;
  228. pofe->hFile = hFile;
  229. strcpy(pofe->FileName, FileName);
  230. InsertHeadList(&OpenFileHead, &pofe->FileEntry);
  231. return TRUE;
  232. }
  233. void
  234. DelOpenFile(
  235. FILE *fp,
  236. HANDLE hFile
  237. )
  238. /*++
  239. Routine Description:
  240. Deletes a file from the open file list. Note that the file is not
  241. closed, the caller must do that.
  242. Arguments:
  243. fp -- OPTIONAL file pointer
  244. hFile -- OPTIONAL file handle
  245. Return Value:
  246. None.
  247. --*/
  248. {
  249. PLIST_ENTRY Next;
  250. POPENFILEENTRY pofe;
  251. Next = OpenFileHead.Flink;
  252. while (Next != &OpenFileHead) {
  253. pofe = CONTAINING_RECORD(Next, OPENFILEENTRY, FileEntry);
  254. if ((fp && pofe->fp == fp) || (hFile && pofe->hFile == hFile)) {
  255. RemoveEntryList(&pofe->FileEntry);
  256. GenHeapFree(pofe);
  257. return;
  258. }
  259. Next= Next->Flink;
  260. }
  261. }
  262. void
  263. CloseOpenFileList(
  264. BOOL DeleteFiles
  265. )
  266. /*++
  267. Routine Description:
  268. Closes all open files and optionally deletes the files themselves.
  269. Arguments:
  270. DeleteFiles -- TRUE if open files are to be deleted.
  271. Return Value:
  272. None.
  273. --*/
  274. {
  275. PLIST_ENTRY Next;
  276. POPENFILEENTRY pofe;
  277. Next = OpenFileHead.Flink;
  278. while (Next != &OpenFileHead) {
  279. pofe = CONTAINING_RECORD(Next, OPENFILEENTRY, FileEntry);
  280. if (pofe->fp) {
  281. fclose(pofe->fp);
  282. } else if (pofe->hFile) {
  283. CloseHandle(pofe->hFile);
  284. }
  285. if (DeleteFiles && bExitClean) {
  286. DeleteFile(pofe->FileName);
  287. }
  288. // cheat, skip mem cleanup since we know we are exiting
  289. // GenHeapFree(pofe);
  290. Next= Next->Flink;
  291. }
  292. }
  293. void
  294. DumpKnownTypes(
  295. PKNOWNTYPES pKnownTypes,
  296. FILE *fp
  297. )
  298. /*++
  299. Routine Description:
  300. Outputs the contents of a PKNOWNTYPES in a semi-readable format.
  301. Arguments:
  302. pKnownTypes -- type to output
  303. fp -- destination of the output
  304. Return Value:
  305. None.
  306. --*/
  307. {
  308. fprintf(fp,"%2.1x|%2.1x|%2.1x|%2.1x|%s|%s|%s|%s|%s|\n",
  309. pKnownTypes->Flags,
  310. pKnownTypes->IndLevel,
  311. pKnownTypes->RetIndLevel,
  312. pKnownTypes->Size,
  313. pKnownTypes->BasicType,
  314. pKnownTypes->BaseName ? pKnownTypes->BaseName : szNULL,
  315. pKnownTypes->FuncRet ? pKnownTypes->FuncRet : szNULL,
  316. pKnownTypes->FuncMod ? pKnownTypes->FuncMod : szNULL,
  317. pKnownTypes->TypeName
  318. );
  319. }
  320. void
  321. DumpTypesInfo(
  322. PTYPESINFO pTypesInfo,
  323. FILE *fp
  324. )
  325. /*++
  326. Routine Description:
  327. Outputs the contents of a PTYPESINFO in a semi-readable format.
  328. Arguments:
  329. pTypesInfo -- type to output
  330. fp -- destination of the output
  331. Return Value:
  332. None.
  333. --*/
  334. {
  335. fprintf(fp,"%2.1x|%2.1x|%2.1x|%2.1x|%s|%s|%s|%s|%s|\n",
  336. pTypesInfo->Flags,
  337. pTypesInfo->IndLevel,
  338. pTypesInfo->RetIndLevel,
  339. pTypesInfo->Size,
  340. pTypesInfo->BasicType,
  341. pTypesInfo->BaseName ? pTypesInfo->BaseName : szNULL,
  342. pTypesInfo->FuncRet ? pTypesInfo->FuncRet : szNULL,
  343. pTypesInfo->FuncMod ? pTypesInfo->FuncMod : szNULL,
  344. pTypesInfo->TypeName
  345. );
  346. }
  347. void
  348. FreeTypesList(
  349. PRBTREE ptree
  350. )
  351. /*++
  352. Routine Description:
  353. Frees an entire red-black tree.
  354. Arguments:
  355. ptree -- tree to free.
  356. Return Value:
  357. None.
  358. --*/
  359. {
  360. PKNOWNTYPES pNext, pNode;
  361. pNode = ptree->pLastNodeInserted;
  362. while (pNode) {
  363. pNext = pNode->Next;
  364. GenHeapFree(pNode);
  365. pNode = pNext;
  366. }
  367. RBInitTree(ptree);
  368. }
  369. PKNOWNTYPES
  370. GetBasicType(
  371. char *sTypeName,
  372. PRBTREE TypeDefsList,
  373. PRBTREE StructsList
  374. )
  375. /*++
  376. Routine Description:
  377. Determines the basic type of a typedef.
  378. Arguments:
  379. sTypeName -- type name to look up
  380. TypeDefsList -- list of typedefs
  381. StructsList -- list of structs
  382. Return Value:
  383. Ptr to the KNOWNTYPES for the basic type, or NULL if no basic type
  384. found.
  385. --*/
  386. {
  387. PKNOWNTYPES pkt, pktLast;
  388. //
  389. // go down the typedef list
  390. //
  391. pktLast = NULL;
  392. for (pkt = GetNameFromTypesList(TypeDefsList, sTypeName);
  393. (pkt != NULL) && (pkt != pktLast); ) {
  394. pktLast = pkt;
  395. pkt = GetNameFromTypesList(TypeDefsList, pktLast->BaseName);
  396. }
  397. //
  398. // see what the the final typedef stands for
  399. //
  400. if (pktLast == NULL) {
  401. pkt = GetNameFromTypesList(StructsList, sTypeName);
  402. } else {
  403. if (strcmp(pktLast->BasicType, szSTRUCT)) {
  404. pkt = pktLast;
  405. } else {
  406. // if base type a struct get its definition
  407. pkt = GetNameFromTypesList(StructsList, pktLast->BaseName);
  408. }
  409. }
  410. return pkt;
  411. }
  412. PDEFBASICTYPES
  413. GetDefBasicType(
  414. char *pBasicType
  415. )
  416. /*++
  417. Routine Description:
  418. Determines if a typename is a basic type, and if so, which one.
  419. Arguments:
  420. pBasicType -- typename to examine
  421. Return Value:
  422. Ptr to the basic type info if pBasicType is a basic type.
  423. NULL if the type is not a default basic type (int, sort, struct, etc.)
  424. --*/
  425. {
  426. PDEFBASICTYPES pDefBasicTypes = DefaultBasicTypes;
  427. int i = NUMDEFBASICTYPES;
  428. do {
  429. if (!strcmp(pDefBasicTypes->BasicType, pBasicType)) {
  430. return pDefBasicTypes;
  431. }
  432. pDefBasicTypes++;
  433. } while (--i);
  434. return NULL;
  435. }
  436. PKNOWNTYPES
  437. GetNameFromTypesList(
  438. PRBTREE pKnownTypes,
  439. char *pTypeName
  440. )
  441. /*++
  442. Routine Description:
  443. Searches a type list for a type name.
  444. Arguments:
  445. pKnownType -- type list to search
  446. pTypeName -- type name to look for
  447. Return Value:
  448. Ptr to the type info if pTypeName is in the list.
  449. NULL if the type was not found.
  450. --*/
  451. {
  452. //
  453. // Find the entry in the Red/Black tree
  454. //
  455. return RBFind(pKnownTypes, pTypeName);
  456. }
  457. PVOID
  458. TypesListMalloc(
  459. ULONG Len
  460. )
  461. /*++
  462. Routine Description:
  463. Default memory allocator used to allocate a new KNOWNTYPES.
  464. It can be overridden by setting fpTypesListMalloc.
  465. Arguments:
  466. Len -- number of bytes of memory to allocate.
  467. Return Value:
  468. Ptr to the memory or NULL of out-of-memory.
  469. --*/
  470. {
  471. return GenHeapAlloc(Len);
  472. }
  473. PVOID (*fpTypesListMalloc)(ULONG Len) = TypesListMalloc;
  474. VOID
  475. ReplaceInfoInKnownTypes(
  476. PKNOWNTYPES pKnownTypes,
  477. PTYPESINFO pTypesInfo
  478. )
  479. {
  480. BYTE *pNames;
  481. int Len;
  482. int SizeBasicType, SizeBaseName, SizeMembers, SizeFuncMod, SizeFuncRet;
  483. int SizeTypeName, SizeBaseType, SizeMethods, SizeIMethods, SizeFileName;
  484. SizeBasicType = strlen(pTypesInfo->BasicType) + 1;
  485. SizeBaseName = strlen(pTypesInfo->BaseName) + 1;
  486. SizeFuncRet = strlen(pTypesInfo->FuncRet) + 1;
  487. SizeFuncMod = strlen(pTypesInfo->FuncMod) + 1;
  488. SizeTypeName = strlen(pTypesInfo->TypeName) + 1;
  489. SizeMembers = pTypesInfo->dwMemberSize;
  490. SizeBaseType = strlen(pTypesInfo->BaseType) + 1;
  491. SizeFileName = strlen(pTypesInfo->FileName) + 1;
  492. SizeMethods = SizeOfMultiSz(pTypesInfo->Methods);
  493. SizeIMethods = SizeOfMultiSz(pTypesInfo->IMethods);
  494. // The extra sizeof(DWORD) allows the Members[] array to be DWORD-aligned
  495. Len = SizeBasicType + SizeBaseName + SizeMembers + SizeFuncMod +
  496. SizeFuncRet + SizeTypeName + SizeBaseType + SizeFileName + SizeMethods + SizeIMethods + sizeof(DWORD_PTR);
  497. pNames = (*fpTypesListMalloc)(Len);
  498. if (!pNames) {
  499. fprintf(stderr, "%s pKnownTypes failed: ", ErrMsgPrefix, strerror(errno));
  500. DumpTypesInfo(pTypesInfo, stderr);
  501. ExitErrMsg(FALSE, "Out of memory!\n");
  502. }
  503. memset(pNames, 0, Len);
  504. pKnownTypes->Flags = pTypesInfo->Flags;
  505. pKnownTypes->IndLevel = pTypesInfo->IndLevel;
  506. pKnownTypes->RetIndLevel = pTypesInfo->RetIndLevel;
  507. pKnownTypes->Size = pTypesInfo->Size;
  508. pKnownTypes->iPackSize = pTypesInfo->iPackSize;
  509. pKnownTypes->gGuid = pTypesInfo->gGuid;
  510. pKnownTypes->dwVTBLSize = pTypesInfo->dwVTBLSize;
  511. pKnownTypes->dwVTBLOffset = pTypesInfo->dwVTBLOffset;
  512. pKnownTypes->TypeId = pTypesInfo->TypeId;
  513. pKnownTypes->LineNumber = pTypesInfo->LineNumber;
  514. pKnownTypes->dwCurrentPacking = pTypesInfo->dwCurrentPacking;
  515. pKnownTypes->dwScopeLevel = pTypesInfo->dwScopeLevel;
  516. pKnownTypes->dwArrayElements = pTypesInfo->dwArrayElements;
  517. pKnownTypes->dwBaseSize = pTypesInfo->dwBaseSize;
  518. pKnownTypes->pTypedefBase = pTypesInfo->pTypedefBase;
  519. Len = 0;
  520. pKnownTypes->BasicType = pNames + Len;
  521. strcpy(pKnownTypes->BasicType, pTypesInfo->BasicType);
  522. Len += SizeBasicType;
  523. pKnownTypes->BaseName = pNames + Len;
  524. strcpy(pKnownTypes->BaseName, pTypesInfo->BaseName);
  525. Len += SizeBaseName;
  526. pKnownTypes->FuncRet = pNames + Len;
  527. strcpy(pKnownTypes->FuncRet, pTypesInfo->FuncRet);
  528. Len += SizeFuncRet;
  529. pKnownTypes->FuncMod = pNames + Len;
  530. strcpy(pKnownTypes->FuncMod, pTypesInfo->FuncMod);
  531. Len += SizeFuncMod;
  532. if (SizeFileName > 0) {
  533. pKnownTypes->FileName = pNames + Len;
  534. strcpy(pKnownTypes->FileName, pTypesInfo->FileName);
  535. Len += SizeFileName;
  536. }
  537. else pKnownTypes->FileName = NULL;
  538. // Ensure that Members[] is DWORD-aligned, so the structures within the
  539. // Members[] are aligned.
  540. Len = (Len+sizeof(DWORD_PTR)) & ~(sizeof(DWORD_PTR)-1);
  541. if (SizeMembers == 0) {
  542. pKnownTypes->Members = NULL;
  543. pKnownTypes->pmeminfo = NULL;
  544. pKnownTypes->pfuncinfo = NULL;
  545. }
  546. else {
  547. pKnownTypes->Members = pNames + Len;
  548. memcpy(pKnownTypes->Members, pTypesInfo->Members, SizeMembers);
  549. //
  550. // Fix up pointers within the Members data, so they point into the
  551. // pKnownTypes data instead of the pTypesInfo.
  552. //
  553. pKnownTypes->pfuncinfo = RelocateTypesInfo(pKnownTypes->Members,
  554. pTypesInfo);
  555. if (pTypesInfo->TypeKind == TypeKindStruct) {
  556. pKnownTypes->pmeminfo = (PMEMBERINFO)pKnownTypes->Members;
  557. }
  558. Len += SizeMembers;
  559. }
  560. if (SizeMethods == 0) pKnownTypes->Methods = NULL;
  561. else {
  562. pKnownTypes->Methods = pNames + Len;
  563. memcpy(pKnownTypes->Methods, pTypesInfo->Methods, SizeMethods);
  564. Len += SizeMethods;
  565. }
  566. if (SizeIMethods == 0) pKnownTypes->IMethods = NULL;
  567. else {
  568. pKnownTypes->IMethods = pNames + Len;
  569. memcpy(pKnownTypes->IMethods, pTypesInfo->IMethods, SizeIMethods);
  570. Len += SizeIMethods;
  571. }
  572. pKnownTypes->BaseType = pNames + Len;
  573. strcpy(pKnownTypes->BaseType, pTypesInfo->BaseType);
  574. Len += SizeBaseType;
  575. pKnownTypes->TypeName = pNames + Len;
  576. strcpy(pKnownTypes->TypeName, pTypesInfo->TypeName);
  577. Len += SizeTypeName;
  578. }
  579. PKNOWNTYPES
  580. AddToTypesList(
  581. PRBTREE pTree,
  582. PTYPESINFO pTypesInfo
  583. )
  584. /*++
  585. Routine Description:
  586. Adds a PTYPESINFO to the list of known types.
  587. This function makes the following ASSUMPTIONS:
  588. 1. The MEMBERINFO buffer passed in the TYPESINFO structure is all
  589. allocated from one contiguous block of memory, ie completely
  590. contained within the Members[] buffer.
  591. 2. The MEMBERINFO buffer built in the KNOWNTYPESINFO structure is
  592. also allocated from one contiguous block of memory.
  593. The code requires this since it will block copy the entire data
  594. structure and then "fixup" the pointers within the MEMBERINFO elements.
  595. Arguments:
  596. pTree -- types list to add the new type to
  597. pTypesInfo -- the type to add.
  598. Return Value:
  599. Ptr to the new PKNOWNTYPES, or NULL if out-of-memory.
  600. --*/
  601. {
  602. PKNOWNTYPES pKnownTypes;
  603. pKnownTypes = (*fpTypesListMalloc)(sizeof(KNOWNTYPES));
  604. if (!pKnownTypes) {
  605. fprintf(stderr, "%s pKnownTypes failed: ", ErrMsgPrefix, strerror(errno));
  606. DumpTypesInfo(pTypesInfo, stderr);
  607. return pKnownTypes;
  608. }
  609. memset(pKnownTypes, 0, sizeof(KNOWNTYPES));
  610. ReplaceInfoInKnownTypes(pKnownTypes, pTypesInfo);
  611. RBInsert(pTree, pKnownTypes);
  612. if (bDebug) {
  613. DumpKnownTypes(pKnownTypes, stdout);
  614. }
  615. return pKnownTypes;
  616. }
  617. void
  618. ReplaceInTypesList(
  619. PKNOWNTYPES pKnownTypes,
  620. PTYPESINFO pTypesInfo
  621. )
  622. /*++
  623. Routine Description:
  624. Replaces an existing PKNOWNTYPES with a new PTYPESINFO. The old data
  625. is overwritten with new data, so pointers to the old PKNOWNTYPES will
  626. still be valid.
  627. This function makes the following ASSUMPTIONS:
  628. 1. The MEMBERINFO buffer passed in the TYPESINFO structure is all
  629. allocated from one contiguous block of memory, ie completely
  630. contained within the Members[] buffer.
  631. 2. The MEMBERINFO buffer built in the KNOWNTYPESINFO structure is
  632. also allocated from one contiguous block of memory.
  633. The code requires this since it will block copy the entire data
  634. structure and then "fixup" the pointers within the MEMBERINFO elements.
  635. Arguments:
  636. pKnownTypes -- type to overwrite
  637. pTypesInfo -- the type to add.
  638. Return Value:
  639. None.
  640. --*/
  641. {
  642. ReplaceInfoInKnownTypes(pKnownTypes, pTypesInfo);
  643. if (bDebug) {
  644. DumpKnownTypes(pKnownTypes, stdout);
  645. }
  646. }
  647. PFUNCINFO
  648. RelocateTypesInfo(
  649. char *dest,
  650. PTYPESINFO src
  651. )
  652. /*++
  653. Routine Description:
  654. Adjusts pointers within the Members[] array which point back into
  655. the Members[]. After a TYPESINFO is copied, the destination TYPESINFO
  656. or KNOWNTYPES Members[] array must be relocated.
  657. Arguments:
  658. dest -- start of the destination Members[] data
  659. src -- the source TYPESINFO from which the Members[] was copied
  660. Return Value:
  661. Address for first pfuncinfo within dest, NULL if dest does not contain
  662. funcinfos. Destination Members[] data is relocated no matter what.
  663. --*/
  664. {
  665. INT_PTR iPtrFix;
  666. PMEMBERINFO pmeminfo;
  667. PFUNCINFO pfuncinfo;
  668. PFUNCINFO pfuncinfoRet = NULL;
  669. iPtrFix = (INT_PTR)(dest - src->Members);
  670. if (src->TypeKind == TypeKindStruct) {
  671. pmeminfo = (PMEMBERINFO)dest;
  672. while (pmeminfo != NULL) {
  673. if (pmeminfo->pmeminfoNext != NULL) {
  674. pmeminfo->pmeminfoNext = (PMEMBERINFO)
  675. ((char *)pmeminfo->pmeminfoNext + iPtrFix);
  676. }
  677. if (pmeminfo->sName != NULL) {
  678. if (pmeminfo->sName < src->Members || pmeminfo->sName > &src->Members[FUNCMEMBERSIZE]) {
  679. ExitErrMsg(FALSE, "RelocateTypesInfo: sName not within Members[]\n");
  680. }
  681. pmeminfo->sName += iPtrFix;
  682. }
  683. if (pmeminfo->sType != NULL) {
  684. if (pmeminfo->sType < src->Members || pmeminfo->sType > &src->Members[FUNCMEMBERSIZE]) {
  685. ExitErrMsg(FALSE, "RelocateTypesInfo: sType not within Members[]\n");
  686. }
  687. pmeminfo->sType += iPtrFix;
  688. }
  689. pmeminfo = pmeminfo->pmeminfoNext;
  690. }
  691. } else if (src->TypeKind == TypeKindFunc) {
  692. //
  693. // Make pfuncinfo point into the 'dest' array by fixing up the
  694. // source pointer.
  695. //
  696. pfuncinfo = (PFUNCINFO)((INT_PTR)src->pfuncinfo + iPtrFix);
  697. if ((char *)pfuncinfo < dest || (char *)pfuncinfo > dest+FUNCMEMBERSIZE) {
  698. ExitErrMsg(FALSE, "RelocateTypesInfo: pfuncinfo bad\n");
  699. }
  700. pfuncinfoRet = pfuncinfo;
  701. while (pfuncinfo != NULL) {
  702. if (pfuncinfo->pfuncinfoNext) {
  703. pfuncinfo->pfuncinfoNext = (PFUNCINFO)
  704. ((char *)pfuncinfo->pfuncinfoNext + iPtrFix);
  705. }
  706. if (pfuncinfo->sName != NULL) {
  707. if (pfuncinfo->sName < src->Members || pfuncinfo->sName > &src->Members[FUNCMEMBERSIZE]) {
  708. ExitErrMsg(FALSE, "RelocateTypesInfo: sName not within Members[]\n");
  709. }
  710. pfuncinfo->sName += iPtrFix;
  711. }
  712. if (pfuncinfo->sType != NULL) {
  713. if (pfuncinfo->sType < src->Members || pfuncinfo->sType > &src->Members[FUNCMEMBERSIZE]) {
  714. ExitErrMsg(FALSE, "RelocateTypesInfo: sType not within Members[]\n");
  715. }
  716. pfuncinfo->sType += iPtrFix;
  717. }
  718. pfuncinfo = pfuncinfo->pfuncinfoNext;
  719. }
  720. }
  721. return pfuncinfoRet;
  722. }
  723. BOOL
  724. ParseTypes(
  725. PRBTREE pTypesList,
  726. PTYPESINFO pTypesInfo,
  727. PKNOWNTYPES *ppKnownTypes
  728. )
  729. /*++
  730. Routine Description:
  731. Parses the Tokens[] and recognizes the following syntaxes:
  732. BasicType
  733. DerivedType
  734. unsigned|signed <int type>
  735. unsigned|signed
  736. unsigned|signed short|long int
  737. short|long int
  738. Arguments:
  739. pTypesList -- list of known types
  740. pTypesInfo -- [OPTIONAL OUT] info about the type that was recognized
  741. ppKnownTypes -- [OPTIONAL OUT] KNOWNTYPES info about the type
  742. Return Value:
  743. TRUE - type was recognized. pTypeInfo and ppKnownTypes are set,
  744. CurrentToken() points to token following the type.
  745. FALSE - type not recognized.
  746. --*/
  747. {
  748. PKNOWNTYPES pkt;
  749. char TypeName[MAX_PATH];
  750. char *SizeMod = NULL;
  751. char *SignMod = NULL;
  752. BOOL fLoopMore;
  753. if (pTypesInfo) {
  754. memset(pTypesInfo, 0, sizeof(TYPESINFO));
  755. }
  756. switch (CurrentToken()->TokenType) {
  757. case TK_STRUCT:
  758. case TK_UNION:
  759. case TK_ENUM:
  760. ConsumeToken();
  761. break;
  762. case TK_VARGS:
  763. pkt = GetNameFromTypesList(pTypesList, szVARGS);
  764. ConsumeToken();
  765. goto PKTExit;
  766. default:
  767. break;
  768. }
  769. //
  770. // Process 'long', 'short', 'signed' and 'unsigned' modifiers
  771. //
  772. while (CurrentToken()->TokenType == TK_IDENTIFIER) {
  773. if (strcmp(CurrentToken()->Name, szLONG) == 0) {
  774. SizeMod = szLONG;
  775. } else if (strcmp(CurrentToken()->Name, szSHORT) == 0) {
  776. SizeMod = szSHORT;
  777. } else if (strcmp(CurrentToken()->Name, szUNSIGNED) == 0) {
  778. SignMod = szUNSIGNED;
  779. } else if (strcmp(CurrentToken()->Name, szSIGNED) == 0) {
  780. SignMod = NULL;
  781. } else {
  782. break;
  783. }
  784. ConsumeToken();
  785. }
  786. //
  787. // Convert the modifier list into a standardized type string and
  788. // look it up.
  789. //
  790. TypeName[0] = '\0';
  791. if (SignMod) {
  792. strcpy(TypeName, SignMod);
  793. }
  794. if (SizeMod) {
  795. if (TypeName[0]) {
  796. strcat(TypeName, " ");
  797. }
  798. strcat(TypeName, SizeMod);
  799. }
  800. //
  801. // Append the type name to the optional list of type modifiers
  802. //
  803. if (CurrentToken()->TokenType != TK_IDENTIFIER) {
  804. if (TypeName[0] == '\0') {
  805. return FALSE; // no qualifiers, so not a type
  806. }
  807. //
  808. // Append the implict 'int' on the end of the type qualifiers
  809. //
  810. strcat(TypeName, " ");
  811. strcat(TypeName, szINT);
  812. } else {
  813. char *Name = CurrentToken()->Name;
  814. if (strcmp(Name, szVOID) == 0 ||
  815. strcmp(Name, szINT) == 0 ||
  816. strcmp(Name, szINT64) == 0 ||
  817. strcmp(Name, sz_INT64) == 0 ||
  818. strcmp(Name, szCHAR) == 0 ||
  819. strcmp(Name, szFLOAT) == 0 ||
  820. strcmp(Name, szDOUBLE) == 0) {
  821. // Append the intrinsic type to the list of type modifiers
  822. if (TypeName[0]) {
  823. strcat(TypeName, " ");
  824. }
  825. strcat(TypeName, Name);
  826. //
  827. // Don't worry about explicitly disallowing things like
  828. // 'unsigned double' or 'short char'. They won't be
  829. // in the pTypesList, so the parse will fail.
  830. //
  831. ConsumeToken();
  832. } else if (TypeName[0]) {
  833. //
  834. // The identifier is not an intrinsic type, and type modifiers
  835. // were seen. The identifier is a variable name, not part of the
  836. // type name. The type name is implicitly 'int'.
  837. //
  838. strcat(TypeName, " ");
  839. strcat(TypeName, szINT);
  840. } else {
  841. //
  842. // The identifier is not an intrinsic type, and no type
  843. // modifiers have been seen. It is probably a typedef name.
  844. //
  845. strcpy(TypeName, Name);
  846. ConsumeToken();
  847. }
  848. }
  849. //
  850. // Look up the type name with all of its glorious modifiers
  851. //
  852. pkt = GetNameFromTypesList(pTypesList, TypeName);
  853. if (!pkt) {
  854. //
  855. // Type not found
  856. //
  857. return FALSE;
  858. }
  859. PKTExit:
  860. if (pTypesInfo) {
  861. BUFALLOCINFO bufallocinfo;
  862. char *ps;
  863. PFUNCINFO pfuncinfoSrc = pkt->pfuncinfo;
  864. PMEMBERINFO pmeminfoSrc = pkt->pmeminfo;
  865. BufAllocInit(&bufallocinfo, pTypesInfo->Members, sizeof(pTypesInfo->Members), 0);
  866. pTypesInfo->Flags = pkt->Flags;
  867. pTypesInfo->IndLevel = pkt->IndLevel;
  868. pTypesInfo->Size = pkt->Size;
  869. pTypesInfo->iPackSize = pkt->iPackSize;
  870. strcpy(pTypesInfo->BasicType,pkt->BasicType);
  871. if (pkt->BaseName) {
  872. strcpy(pTypesInfo->BaseName,pkt->BaseName);
  873. }
  874. strcpy(pTypesInfo->TypeName,pkt->TypeName);
  875. if (pfuncinfoSrc) {
  876. PFUNCINFO pfuncinfoDest = NULL;
  877. pTypesInfo->pfuncinfo = BufPointer(&bufallocinfo);
  878. pTypesInfo->TypeKind = TypeKindFunc;
  879. while (pfuncinfoSrc) {
  880. pfuncinfoDest = AllocFuncInfoAndLink(&bufallocinfo, pfuncinfoDest);
  881. if (!pfuncinfoDest) {
  882. ExitErrMsg(FALSE, "ParseTypes - out of memory at line %d\n", __LINE__);
  883. }
  884. pfuncinfoDest->fIsPtr64 = pfuncinfoSrc->fIsPtr64;
  885. pfuncinfoDest->tkPreMod = pfuncinfoSrc->tkPreMod;
  886. pfuncinfoDest->tkSUE = pfuncinfoSrc->tkSUE;
  887. pfuncinfoDest->tkPrePostMod = pfuncinfoSrc->tkPrePostMod;
  888. pfuncinfoDest->IndLevel = pfuncinfoSrc->IndLevel;
  889. pfuncinfoDest->tkPostMod = pfuncinfoSrc->tkPostMod;
  890. ps = BufPointer(&bufallocinfo);
  891. pfuncinfoDest->sType = ps;
  892. strcpy(ps, pfuncinfoSrc->sType);
  893. BufAllocate(&bufallocinfo, strlen(ps)+1);
  894. if (pfuncinfoSrc->sName) {
  895. ps = BufPointer(&bufallocinfo);
  896. pfuncinfoDest->sName = ps;
  897. strcpy(ps, pfuncinfoSrc->sName);
  898. BufAllocate(&bufallocinfo, strlen(ps)+1);
  899. }
  900. pfuncinfoSrc = pfuncinfoSrc->pfuncinfoNext;
  901. }
  902. } else if (pmeminfoSrc) {
  903. PMEMBERINFO pmeminfoDest = NULL;
  904. pTypesInfo->TypeKind = TypeKindStruct;
  905. while (pmeminfoSrc) {
  906. pmeminfoDest = AllocMemInfoAndLink(&bufallocinfo, pmeminfoDest);
  907. pmeminfoDest->dwOffset = pmeminfoSrc->dwOffset;
  908. if (pmeminfoSrc->sName) {
  909. ps = BufPointer(&bufallocinfo);
  910. pmeminfoDest->sName = ps;
  911. strcpy(ps, pmeminfoSrc->sName);
  912. BufAllocate(&bufallocinfo, strlen(ps)+1);
  913. }
  914. if (pmeminfoSrc->sType) {
  915. ps = BufPointer(&bufallocinfo);
  916. pmeminfoDest->sType = ps;
  917. strcpy(ps, pmeminfoSrc->sType);
  918. BufAllocate(&bufallocinfo, strlen(ps)+1);
  919. }
  920. pmeminfoSrc = pmeminfoSrc->pmeminfoNext;
  921. }
  922. }
  923. pTypesInfo->dwMemberSize = bufallocinfo.dwLen;
  924. }
  925. if (ppKnownTypes) {
  926. *ppKnownTypes = pkt;
  927. }
  928. return TRUE;
  929. }
  930. void
  931. __cdecl ErrMsg(
  932. char *pch,
  933. ...
  934. )
  935. /*++
  936. Routine Description:
  937. Displays an error message to stderr in a format that BUILD can find.
  938. Use this instead of fprintf(stderr, ...).
  939. Arguments:
  940. pch -- printf-style format string
  941. ... -- printf-style args
  942. Return Value:
  943. None. Message formatted and sent to stderr.
  944. --*/
  945. {
  946. va_list pArg;
  947. fputs(ErrMsgPrefix, stderr);
  948. va_start(pArg, pch);
  949. vfprintf(stderr, pch, pArg);
  950. }
  951. void
  952. __cdecl ExitErrMsg(
  953. BOOL bSysError,
  954. char *pch,
  955. ...
  956. )
  957. /*++
  958. Routine Description:
  959. Displays an error message to stderr in a format that BUILD can find.
  960. Use this instead of fprintf(stderr, ...).
  961. Arguments:
  962. bSysErr -- TRUE if the value of errno should be printed with the error
  963. pch -- printf-style format string
  964. ... -- printf-style args
  965. Return Value:
  966. None. Message formatted and sent to stderr, open files closed and
  967. deleted, process terminated.
  968. --*/
  969. {
  970. va_list pArg;
  971. if (bSysError) {
  972. fprintf(stderr, "%s System ERROR %s", ErrMsgPrefix, strerror(errno));
  973. } else {
  974. fprintf(stderr, "%s ERROR ", ErrMsgPrefix);
  975. }
  976. va_start(pArg, pch);
  977. vfprintf(stderr, pch, pArg);
  978. CloseOpenFileList(TRUE);
  979. //
  980. // Flush stdout and stderr buffers, so that the last few printfs
  981. // get sent back to BUILD before ExitProcess() destroys them.
  982. //
  983. fflush(stdout);
  984. fflush(stderr);
  985. ExitProcess(1);
  986. }
  987. void
  988. __cdecl DbgPrintf(
  989. char *pch,
  990. ...
  991. )
  992. /*++
  993. Routine Description:
  994. Displays a message to stdout if bDebug is set.
  995. Arguments:
  996. pch -- printf-style format string
  997. ... -- printf-style args
  998. Return Value:
  999. None. Message formatted and sent to stderr.
  1000. --*/
  1001. {
  1002. va_list pArg;
  1003. if (!bDebug) {
  1004. return;
  1005. }
  1006. va_start(pArg, pch);
  1007. vfprintf(stdout, pch, pArg);
  1008. }
  1009. char *
  1010. ReadEntireFile(
  1011. HANDLE hFile,
  1012. DWORD *pBytesRead
  1013. )
  1014. /*++
  1015. Routine Description:
  1016. Allocates memory on the local heap and reads an entire file into it.
  1017. Arguments:
  1018. hFile -- file to read in
  1019. bBytesRead -- [OUT] number of bytes read from the file
  1020. Return Value:
  1021. pointer to the memory allocated for the file, or NULL on error.
  1022. --*/
  1023. {
  1024. DWORD Bytes;
  1025. char *pch = NULL;
  1026. if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == 0xffffffff ||
  1027. (Bytes = GetFileSize(hFile, NULL)) == 0xffffffff) {
  1028. goto ErrorExit;
  1029. }
  1030. pch = GenHeapAlloc(Bytes);
  1031. if (!pch) {
  1032. return NULL;
  1033. }
  1034. if (!ReadFile(hFile, pch, Bytes, pBytesRead, NULL) ||
  1035. *pBytesRead != Bytes) {
  1036. DbgPrintf("BytesRead %d Bytes %d\n", *pBytesRead, Bytes);
  1037. GenHeapFree(pch);
  1038. pch = NULL;
  1039. }
  1040. ErrorExit:
  1041. if (!pch) {
  1042. DbgPrintf("GetLastError %d\n", GetLastError());
  1043. }
  1044. return pch;
  1045. }
  1046. HANDLE
  1047. CreateTempFile(
  1048. void
  1049. )
  1050. /*++
  1051. Routine Description:
  1052. Creates and opens a temporary file. It will be deleted when it is
  1053. closed.
  1054. Arguments:
  1055. None.
  1056. Return Value:
  1057. File handle, or INVALID_HANDLE_VALUE on error.
  1058. --*/
  1059. {
  1060. DWORD dw;
  1061. char PathName[MAX_PATH+1];
  1062. char FileName[2*MAX_PATH];
  1063. HANDLE hFile = INVALID_HANDLE_VALUE;
  1064. dw = GetTempPath(MAX_PATH, PathName);
  1065. if (!dw || dw > MAX_PATH) {
  1066. strcpy(PathName, ".");
  1067. }
  1068. dw = GetTempFileName(PathName, "thk", 0, FileName);
  1069. if (!dw) {
  1070. strcpy(PathName, ".");
  1071. dw = GetTempFileName(PathName, "thk", 0, FileName);
  1072. if (!dw) {
  1073. DbgPrintf("GetTempFileName %s GLE=%d\n", FileName, GetLastError());
  1074. }
  1075. }
  1076. hFile = CreateFile(FileName,
  1077. GENERIC_READ | GENERIC_WRITE,
  1078. FILE_SHARE_READ,
  1079. NULL,
  1080. OPEN_ALWAYS,
  1081. FILE_ATTRIBUTE_TEMPORARY |
  1082. FILE_FLAG_DELETE_ON_CLOSE |
  1083. FILE_FLAG_SEQUENTIAL_SCAN,
  1084. 0
  1085. );
  1086. if (hFile == INVALID_HANDLE_VALUE) {
  1087. DbgPrintf("Create %s GLE=%d\n", FileName, GetLastError());
  1088. }
  1089. return hFile;
  1090. }
  1091. size_t
  1092. CopyToken(
  1093. char *pDst,
  1094. char *pSrc,
  1095. size_t Size
  1096. )
  1097. /*++
  1098. Routine Description:
  1099. Copies a token (a separator-delimited string) from pSrc to pDst.
  1100. Arguments:
  1101. pDst -- destination to write the token to
  1102. pSrc -- source to copy token from
  1103. Size -- number of bytes available at pDst.
  1104. Return Value:
  1105. Number of bytes copied from pSrc to pDst.
  1106. --*/
  1107. {
  1108. size_t i = 0;
  1109. while (!IsSeparator(*pSrc) && i < Size) {
  1110. i++;
  1111. *pDst++ = *pSrc++;
  1112. }
  1113. *pDst = '\0';
  1114. return i;
  1115. }
  1116. char *
  1117. SkipKeyWord(
  1118. char *pSrc,
  1119. char *pKeyWord
  1120. )
  1121. /*++
  1122. Routine Description:
  1123. If the first word at pSrc matches the specified keyword, then skip
  1124. over that keyword.
  1125. Arguments:
  1126. pSrc -- source string to examine
  1127. pKeyWord -- keyword to try and match
  1128. Return Value:
  1129. pSrc unchanged if keyword not matched. If keyword matched, returns
  1130. ptr to text following the keyword after pSrc.
  1131. --*/
  1132. {
  1133. int LenKeyWord;
  1134. char *pch;
  1135. LenKeyWord = strlen(pKeyWord);
  1136. pch = pSrc + LenKeyWord;
  1137. if (!strncmp(pSrc, pKeyWord, LenKeyWord) && IsSeparator(*pch)) {
  1138. pSrc = GetNextToken(pch - 1);
  1139. }
  1140. return pSrc;
  1141. }
  1142. BOOL
  1143. IsSeparator(
  1144. char ch
  1145. )
  1146. /*++
  1147. Routine Description:
  1148. Determines if a character is a separator or not.
  1149. over that keyword.
  1150. Arguments:
  1151. ch -- character to examine.
  1152. Return Value:
  1153. TRUE if the character is a separator, FALSE if not.
  1154. --*/
  1155. {
  1156. switch (ch) {
  1157. case ' ':
  1158. case '|':
  1159. case '(':
  1160. case ')':
  1161. case '*':
  1162. case ',':
  1163. case '{':
  1164. case '}':
  1165. case ';':
  1166. case '[':
  1167. case ']':
  1168. case '=':
  1169. case '\n':
  1170. case '\r':
  1171. case ':':
  1172. case '.':
  1173. case '\0':
  1174. return TRUE;
  1175. }
  1176. return FALSE;
  1177. }
  1178. /*
  1179. * GetNextToken
  1180. */
  1181. char *
  1182. GetNextToken(
  1183. char *pSrc
  1184. )
  1185. /*++
  1186. Routine Description:
  1187. Scans the input string and returns the next separator-delimited string.
  1188. Arguments:
  1189. pSrc -- input string
  1190. Return Value:
  1191. Ptr to start of the next separator char which isn't a space.
  1192. --*/
  1193. {
  1194. if (!*pSrc) {
  1195. return pSrc;
  1196. }
  1197. if (!IsSeparator(*pSrc++)) {
  1198. while (*pSrc && !IsSeparator(*pSrc)) {
  1199. pSrc++;
  1200. }
  1201. }
  1202. while (*pSrc && *pSrc == ' ') {
  1203. pSrc++;
  1204. }
  1205. return pSrc;
  1206. }
  1207. void
  1208. DeleteAllocCvmHeap(
  1209. HANDLE hCvmHeap
  1210. )
  1211. /*++
  1212. Routine Description:
  1213. Cleans up the mapped shared memory.
  1214. Arguments:
  1215. hCvmHeap -- memory to clean up.
  1216. Return Value:
  1217. None.
  1218. --*/
  1219. {
  1220. NTSTATUS Status;
  1221. CVMHEAPINFO *pcvmheap = (CVMHEAPINFO *)hCvmHeap;
  1222. Status = NtFreeVirtualMemory(NtCurrentProcess(),
  1223. (PVOID *)&pcvmheap->uBaseAddress,
  1224. &pcvmheap->uRegionSize,
  1225. MEM_RELEASE);
  1226. if (!NT_SUCCESS(Status)) {
  1227. DbgPrintf("Error freeing CVM %x", Status);
  1228. }
  1229. }
  1230. HANDLE
  1231. CreateAllocCvmHeap(
  1232. ULONG_PTR uBaseAddress,
  1233. ULONG_PTR uReserveSize,
  1234. ULONG_PTR uRegionSize,
  1235. ULONG_PTR uUncomitted,
  1236. ULONG_PTR uUnReserved,
  1237. ULONG_PTR uAvailable
  1238. )
  1239. /*++
  1240. Routine Description:
  1241. Allocates a region of memory and makes it into a heap.
  1242. Arguments:
  1243. uBaseAddress -- base address to allocate the heap at
  1244. uReserveSize -- number of bytes to reserve
  1245. uRegionSize -- size of the region
  1246. uUncomitted -- amount of uncommitted memory
  1247. uUnReserved -- amount of unreserved memory
  1248. uAvailable -- amount of available memory
  1249. Return Value:
  1250. Handle to the heap, or NULL on error.
  1251. --*/
  1252. {
  1253. CVMHEAPINFO *pcvmheap;
  1254. NTSTATUS Status;
  1255. PULONG_PTR pBaseAddress= NULL;
  1256. pcvmheap = GenHeapAlloc(sizeof(CVMHEAPINFO));
  1257. if (pcvmheap == NULL) {
  1258. return NULL;
  1259. }
  1260. pcvmheap->uBaseAddress = uBaseAddress;
  1261. pcvmheap->uReserveSize = uReserveSize;
  1262. pcvmheap->uRegionSize = uRegionSize;
  1263. pcvmheap->uUncomitted = uUncomitted;
  1264. pcvmheap->uUnReserved = uUnReserved;
  1265. pcvmheap->uAvailable = uAvailable;
  1266. //
  1267. // Reserve enuf contiguous address space, for expected needs
  1268. //
  1269. Status = NtAllocateVirtualMemory(NtCurrentProcess(),
  1270. (PVOID *)&pcvmheap->uBaseAddress,
  1271. 0,
  1272. &pcvmheap->uReserveSize,
  1273. MEM_RESERVE,
  1274. PAGE_NOACCESS
  1275. );
  1276. if (!NT_SUCCESS(Status)) {
  1277. //
  1278. // May want to retry this, with a different base address
  1279. //
  1280. ErrMsg(
  1281. "Unable to reserve vm %x %x %x\n",
  1282. pcvmheap->uBaseAddress,
  1283. pcvmheap->uReserveSize,
  1284. Status
  1285. );
  1286. return NULL;
  1287. }
  1288. pcvmheap->uUnReserved = pcvmheap->uBaseAddress + pcvmheap->uReserveSize;
  1289. //
  1290. // Commit the first page, we will grow this a page at a time
  1291. // as its needed.
  1292. //
  1293. pcvmheap->uAvailable = pcvmheap->uBaseAddress;
  1294. Status = NtAllocateVirtualMemory(NtCurrentProcess(),
  1295. (PVOID *)&pcvmheap->uAvailable,
  1296. 0,
  1297. &pcvmheap->uRegionSize,
  1298. MEM_COMMIT,
  1299. PAGE_READWRITE
  1300. );
  1301. if (!NT_SUCCESS(Status)) {
  1302. //
  1303. // May want to retry this, with a different base address
  1304. //
  1305. ErrMsg(
  1306. "Unable to commit vm %x %x %x\n",
  1307. pcvmheap->uBaseAddress,
  1308. pcvmheap->uReserveSize,
  1309. Status
  1310. );
  1311. return NULL;
  1312. }
  1313. pcvmheap->uUncomitted = pcvmheap->uBaseAddress + pcvmheap->uRegionSize;
  1314. // paranoia!
  1315. if (pcvmheap->uAvailable != pcvmheap->uBaseAddress) {
  1316. ErrMsg(
  1317. "commit pvAvailable(%x) != gBaseAddress(%x)\n",
  1318. pcvmheap->uAvailable,
  1319. pcvmheap->uBaseAddress
  1320. );
  1321. return NULL;
  1322. }
  1323. DbgPrintf("Ppm: BaseAddress %x\n", pcvmheap->uBaseAddress);
  1324. return pcvmheap;
  1325. }
  1326. PVOID
  1327. GetCvmHeapBaseAddress(
  1328. HANDLE hCvmHeap
  1329. )
  1330. /*++
  1331. Routine Description:
  1332. Returns the base address of a heap.
  1333. Arguments:
  1334. hCvmHeap -- heap to examine
  1335. Return Value:
  1336. Base address, or NULL.
  1337. --*/
  1338. {
  1339. CVMHEAPINFO *pcvmheap = (CVMHEAPINFO *)hCvmHeap;
  1340. return pcvmheap == NULL ? NULL : (PVOID)pcvmheap->uBaseAddress;
  1341. }
  1342. PVOID
  1343. GetCvmHeapAvailable(
  1344. HANDLE hCvmHeap
  1345. )
  1346. /*++
  1347. Routine Description:
  1348. Returns the number of bytes available in a heap.
  1349. Arguments:
  1350. hCvmHeap -- heap to examine
  1351. Return Value:
  1352. Bytes available, or NULL.
  1353. --*/
  1354. {
  1355. CVMHEAPINFO *pcvmheap = (CVMHEAPINFO *)hCvmHeap;
  1356. return pcvmheap == NULL ? NULL : (PVOID)pcvmheap->uAvailable;
  1357. }
  1358. PVOID
  1359. AllocCvm(
  1360. HANDLE hCvmHeap,
  1361. ULONG_PTR Size
  1362. )
  1363. /*++
  1364. Routine Description:
  1365. Allocate memory from a heap.
  1366. Arguments:
  1367. hCvmHeam -- heap to allocate from
  1368. Size -- number of bytes to allocate
  1369. Return Value:
  1370. Ptr to allocated memory, or NULL of insufficient memory.
  1371. --*/
  1372. {
  1373. CVMHEAPINFO *pcvmheapinfo = (CVMHEAPINFO *)hCvmHeap;
  1374. NTSTATUS Status;
  1375. ULONG_PTR Available;
  1376. ULONG_PTR AlignedSize;
  1377. if (pcvmheapinfo == NULL) {
  1378. return NULL;
  1379. }
  1380. //
  1381. // Round the allocation up to the next-highest multiple of 8, so that
  1382. // allocations are correctly aligned.
  1383. //
  1384. AlignedSize = (Size + 7) & ~7;
  1385. Available = pcvmheapinfo->uAvailable;
  1386. pcvmheapinfo->uAvailable += AlignedSize;
  1387. if (pcvmheapinfo->uAvailable >= pcvmheapinfo->uUnReserved) {
  1388. ErrMsg("AllocCvm: Allocation Size exceeds reserved size\n");
  1389. return NULL;
  1390. }
  1391. if (pcvmheapinfo->uAvailable >= pcvmheapinfo->uUncomitted) {
  1392. //
  1393. // Commit enuf pages to exceed the requested allocation size
  1394. //
  1395. Status = NtAllocateVirtualMemory(NtCurrentProcess(),
  1396. (PVOID *)&pcvmheapinfo->uUncomitted,
  1397. 0,
  1398. &Size,
  1399. MEM_COMMIT,
  1400. PAGE_READWRITE
  1401. );
  1402. if (!NT_SUCCESS(Status)) {
  1403. ErrMsg(
  1404. "Unable to commit vm %x %x %x\n",
  1405. pcvmheapinfo->uBaseAddress,
  1406. Size,
  1407. Status
  1408. );
  1409. return NULL;
  1410. }
  1411. pcvmheapinfo->uUncomitted += Size;
  1412. }
  1413. return (PVOID)Available;
  1414. }
  1415. void ParseIndirection(
  1416. DWORD *pIndLevel,
  1417. DWORD *pdwSize,
  1418. DWORD *pFlags,
  1419. PTOKENTYPE ptkPrePostMod,
  1420. PTOKENTYPE ptkPostMod
  1421. )
  1422. /*++
  1423. Routine Description:
  1424. Parse any indirection level specificiations ('*') taking into
  1425. account const, volatile, and __ptr64 modifiers. For example:
  1426. void * const __ptr64 ** const * __ptr64 would be valid.
  1427. NOTE: the pointer is a 64-bit pointer only if the last pointer
  1428. declared is modified by __ptr64.
  1429. Arguments:
  1430. pIndlevel -- [OUT] indirection level (number of '*'s)
  1431. pdwSize -- [OUT] size of the type (4 or 8)
  1432. pFlags -- [OUT] BTI_ flags
  1433. ptkPrePostMod -- [OUT] TK_CONST, TK_VOLATILE, or TK_NONE, depending
  1434. on modifiers seen before the first '*'
  1435. ptkPostMod -- [OUT] TK_CONST, TK_VOLATILE, or TK_NONE, depending
  1436. on modifiers seen after the first '*'
  1437. Return Value:
  1438. None. May not consume any tokens if there are no levels of indirection.
  1439. --*/
  1440. {
  1441. int IndLevel = 0;
  1442. DWORD dwSize = 0;
  1443. DWORD Flags = 0;
  1444. BOOL fStopScanning = FALSE;
  1445. TOKENTYPE tkPrePostMod = TK_NONE;
  1446. TOKENTYPE tkPostMod = TK_NONE;
  1447. do {
  1448. switch (CurrentToken()->TokenType) {
  1449. case TK_BITWISE_AND:
  1450. ////////////////////////////////////////////////////////////////////
  1451. //The ref operator in C++ is equilivalent to * const in C
  1452. //This implies that & should be treated as a * but add a postmod of const.
  1453. /////////////////////////////////////////////////////////////////////
  1454. tkPostMod = TK_CONST;
  1455. case TK_STAR:
  1456. IndLevel++;
  1457. dwSize = SIZEOFPOINTER;
  1458. Flags &= ~BTI_PTR64;
  1459. ConsumeToken();
  1460. break;
  1461. case TK_CONST:
  1462. case TK_VOLATILE:
  1463. //
  1464. // The caller may be interrested in whether the 'const' or
  1465. // 'volatile' keywords are before or after the '*'
  1466. //
  1467. if (IndLevel) {
  1468. tkPostMod = CurrentToken()->TokenType;
  1469. } else {
  1470. tkPrePostMod = CurrentToken()->TokenType;
  1471. }
  1472. ConsumeToken();
  1473. break;
  1474. case TK_IDENTIFIER:
  1475. if (strcmp(CurrentToken()->Name, sz__PTR64) == 0) {
  1476. dwSize = SIZEOFPOINTER64;
  1477. Flags |= BTI_PTR64;
  1478. ConsumeToken();
  1479. break;
  1480. }
  1481. default:
  1482. fStopScanning = TRUE;
  1483. break;
  1484. }
  1485. } while (!fStopScanning);
  1486. if (pIndLevel != NULL) {
  1487. *pIndLevel += IndLevel;
  1488. }
  1489. if ((pdwSize != NULL) && (dwSize != 0)) {
  1490. *pdwSize = dwSize;
  1491. }
  1492. if (pFlags != NULL) {
  1493. *pFlags |= Flags;
  1494. }
  1495. if (ptkPostMod) {
  1496. *ptkPostMod = tkPostMod;
  1497. }
  1498. if (ptkPrePostMod) {
  1499. *ptkPrePostMod = tkPrePostMod;
  1500. }
  1501. }
  1502. BOOL
  1503. IsTokenSeparator(
  1504. void
  1505. )
  1506. /*++
  1507. Routine Description:
  1508. Determines if a token is a separator character or not.
  1509. Arguments:
  1510. None. Examines CurrentToken()->TokenType.
  1511. Return Value:
  1512. TRUE if CurrentToken() is a separator, FALSE if not.
  1513. --*/
  1514. {
  1515. switch (CurrentToken()->TokenType) {
  1516. case TK_LPAREN:
  1517. case TK_RPAREN:
  1518. case TK_STAR:
  1519. case TK_BITWISE_AND:
  1520. case TK_COMMA:
  1521. case TK_LBRACE:
  1522. case TK_RBRACE:
  1523. case TK_SEMI:
  1524. case TK_LSQUARE:
  1525. case TK_RSQUARE:
  1526. case TK_COLON:
  1527. return TRUE;
  1528. default:
  1529. return FALSE;
  1530. }
  1531. }
  1532. VOID
  1533. ReleaseToken(
  1534. PTOKEN Token
  1535. )
  1536. {
  1537. /*++
  1538. Routine Description:
  1539. Releases any additional memory associated with a token.
  1540. Arguments:
  1541. dest - [IN] ptr to the token.
  1542. Return Value:
  1543. --*/
  1544. if (Token->TokenType == TK_IDENTIFIER ||
  1545. Token->TokenType == TK_STRING) {
  1546. GenHeapFree(Token->Name);
  1547. }
  1548. Token->TokenType = TK_NONE;
  1549. Token->Value = 0;
  1550. Token->dwValue = 0;
  1551. }
  1552. void
  1553. ResetLexer(
  1554. void
  1555. )
  1556. /*++
  1557. Routine Description:
  1558. Resets the lexer in preparation to analyze a new statement.
  1559. Arguments:
  1560. None.
  1561. Return Value:
  1562. None. Lexer's state reset.
  1563. --*/
  1564. {
  1565. int TokenCount;
  1566. for (TokenCount = 0;
  1567. TokenCount < MAX_TOKENS_IN_STATEMENT &&
  1568. Tokens[TokenCount].TokenType != TK_EOS;
  1569. ++TokenCount) {
  1570. ReleaseToken(&Tokens[TokenCount]);
  1571. }
  1572. CurrentTokenIndex = 0;
  1573. }
  1574. __inline
  1575. VOID
  1576. InitializeToken(
  1577. PTOKEN Token
  1578. )
  1579. /*++
  1580. Routine Description:
  1581. Initialize a token so the lexer can fill it in.
  1582. Arguments:
  1583. Token -- TOKEN to initialize
  1584. Return Value:
  1585. None.
  1586. --*/
  1587. {
  1588. // The number parser expects Value to be 0.
  1589. Token->TokenType = TK_NONE;
  1590. Token->Value = 0;
  1591. Token->dwValue = 0;
  1592. }
  1593. void
  1594. ProcessEscapes(
  1595. char *String
  1596. )
  1597. /*++
  1598. Routine Description:
  1599. Process escape characters, replacing them by the proper char.
  1600. Arguments:
  1601. String -- null-terminated string to process
  1602. Return Value:
  1603. None. Conversion is done in-place.
  1604. --*/
  1605. {
  1606. char *pDest;
  1607. char *pSrc;
  1608. char c;
  1609. int i;
  1610. pSrc = pDest = String;
  1611. while (*pSrc) {
  1612. if (*pSrc != '\\') {
  1613. *pDest = *pSrc;
  1614. pSrc++;
  1615. pDest++;
  1616. } else {
  1617. pSrc++;
  1618. switch (*pSrc) {
  1619. case 'n':
  1620. c = '\n';
  1621. break;
  1622. case 't':
  1623. c = '\t';
  1624. break;
  1625. case 'v':
  1626. c = '\v';
  1627. break;
  1628. case 'b':
  1629. c = '\b';
  1630. break;
  1631. case 'r':
  1632. c = '\r';
  1633. break;
  1634. case 'f':
  1635. c = '\f';
  1636. break;
  1637. case 'a':
  1638. c = '\a';
  1639. break;
  1640. case '\\':
  1641. c = '\\';
  1642. break;
  1643. case '?':
  1644. c = '\?';
  1645. break;
  1646. case '\'':
  1647. c = '\'';
  1648. break;
  1649. case '\"':
  1650. c = '\"';
  1651. break;
  1652. case '0':
  1653. case '1':
  1654. case '2':
  1655. case '3':
  1656. case '4':
  1657. case '5':
  1658. case '6':
  1659. case '7':
  1660. // Octal number
  1661. c = 0;
  1662. for (i=0; i<3;++i) {
  1663. c = (c * 8) + (*pSrc) - '0';
  1664. pSrc++;
  1665. if (*pSrc < '0' || *pSrc > '7') {
  1666. // hit end of number
  1667. break;
  1668. }
  1669. }
  1670. break;
  1671. case 'x':
  1672. case 'X':
  1673. // Hex number
  1674. pSrc++;
  1675. c = 0;
  1676. for (i=0; i<3;++i) {
  1677. char digit;
  1678. digit = *pSrc;
  1679. if (digit >= '0' && digit <= '9') {
  1680. digit -= '0';
  1681. } else if (digit >= 'a' && digit <= 'f') {
  1682. digit = digit - 'a' + 10;
  1683. } else if (digit >= 'A' && digit <= 'A') {
  1684. digit = digit - 'A' + 10;
  1685. } else {
  1686. // hit end of number
  1687. break;
  1688. }
  1689. c = (c * 16) + digit;
  1690. pSrc++;
  1691. }
  1692. break;
  1693. default:
  1694. // Parse error in the string literal.
  1695. goto Exit;
  1696. }
  1697. *pDest = c;
  1698. pDest++;
  1699. }
  1700. }
  1701. Exit:
  1702. // Write the new null-terminator in
  1703. *pDest = '\0';
  1704. }
  1705. char *
  1706. LexOneLine(
  1707. char *p,
  1708. BOOL fStopAtStatement,
  1709. BOOL *pfLexDone
  1710. )
  1711. /*++
  1712. Routine Description:
  1713. Performs lexical analysis on a single line of input. The lexer
  1714. may stop before consuming an entire line of input, so the caller
  1715. must closely examine the return code before grabbing the next line.
  1716. __inline functions are deleted by the lexer. The lexer consumes input
  1717. until it encounters a '{' (assumed to be the start of the function
  1718. body), then consumes input until the matching '}' is found (assumed to
  1719. be the end of the function body).
  1720. "template" is deleted by the lexer and treated as if it was
  1721. an "__inline" keyword... it consumes everything upto '{' then
  1722. keeps consuming until a matching '}' is found. That makes unknwn.h
  1723. work.
  1724. Lexer unwraps extern "C" {} blocks.
  1725. 'static' and '__unaligned' keywords are deleted by the lexer.
  1726. Preprocessor directives are handled via a callout to
  1727. HandlePreprocessorDirective().
  1728. Arguments:
  1729. p -- ptr into the line of input
  1730. fStopAtStatement -- TRUE if caller wants lexer to stop at ';' at
  1731. file-scope. FALSE if caller wants lexer to stop
  1732. at ')' at file-scope.
  1733. pfLexDone -- [OUT] lexer sets this to TRUE if the analysis
  1734. is complete. Lexer sets this to FALSE if
  1735. it needs another line of input from the caller.
  1736. Return Value:
  1737. ptr into the line of input where lexing left off, or NULL if entire
  1738. line was consumed.
  1739. CurrentTokenIndex is the index of the next element of the Tokens[]
  1740. array that the lexer will fill in.
  1741. Tokens[] is the array of tokens the lexer has generated.
  1742. --*/
  1743. {
  1744. static int NestingLevel=0; // level of nesting of braces and parens
  1745. static BOOL fInlineSeen=FALSE; // TRUE while deleting __inline functions
  1746. static int ExternCLevel=0; // tracks the number of extern "C" blocks
  1747. static int InlineLevel=0; // NestingLevel for the outermost __inline
  1748. int Digit; // a digit in a numeric constant
  1749. int NumberBase = 10; // assume numbers are base-10
  1750. PTOKEN Token; // ptr to current token being lexed
  1751. //
  1752. // Assume the lexical analysis is not done
  1753. //
  1754. *pfLexDone = FALSE;
  1755. //
  1756. // Pick up analysis where we left off...
  1757. //
  1758. Token = &Tokens[CurrentTokenIndex];
  1759. InitializeToken(Token);
  1760. //
  1761. // Loop over all characters in the line, or until a complete lexical
  1762. // unit is done (depends on fStopAtStatement).
  1763. //
  1764. while (*p) {
  1765. switch (*p) {
  1766. case ' ':
  1767. case '\t':
  1768. case '\r':
  1769. case '\n':
  1770. case '\v':
  1771. case '\f':
  1772. case '\b':
  1773. case '\a':
  1774. case '\\': // line-continuation characters are ignored
  1775. p++;
  1776. continue;
  1777. case '#':
  1778. //
  1779. // HandlePreprocessorDirective() is implemented in the
  1780. // app which links to genmisc.c.
  1781. //
  1782. HandlePreprocessorDirective(p);
  1783. CurrentTokenIndex = (int)(Token - Tokens);
  1784. return NULL;
  1785. case '+':
  1786. Token->TokenType = TK_PLUS;
  1787. break;
  1788. case '-':
  1789. Token->TokenType = TK_MINUS;
  1790. break;
  1791. case ':':
  1792. Token->TokenType = TK_COLON;
  1793. break;
  1794. case '=':
  1795. Token->TokenType = TK_ASSIGN;
  1796. break;
  1797. case ';':
  1798. if (NestingLevel == 0 && fStopAtStatement) {
  1799. //
  1800. // Found a ';' at file-scope. This token marks the
  1801. // end of the C-language statement.
  1802. //
  1803. p++;
  1804. if (*p == '\n') {
  1805. //
  1806. // ';' is at EOL - consume it now.
  1807. //
  1808. p++;
  1809. }
  1810. Token->TokenType = TK_EOS;
  1811. *pfLexDone = TRUE;
  1812. CurrentTokenIndex = (int)(Token - Tokens + 1);
  1813. return p;
  1814. }
  1815. Token->TokenType = TK_SEMI;
  1816. break;
  1817. case '*':
  1818. Token->TokenType = TK_STAR;
  1819. break;
  1820. case '/':
  1821. Token->TokenType = TK_DIVIDE;
  1822. break;
  1823. case ',':
  1824. Token->TokenType = TK_COMMA;
  1825. break;
  1826. case '<':
  1827. if (p[1] == '<') {
  1828. Token->TokenType = TK_LSHIFT;
  1829. p++;
  1830. } else {
  1831. Token->TokenType = TK_LESS;
  1832. }
  1833. break;
  1834. case '>':
  1835. if (p[1] == '>') {
  1836. Token->TokenType = TK_RSHIFT;
  1837. p++;
  1838. } else {
  1839. Token->TokenType = TK_GREATER;
  1840. }
  1841. break;
  1842. case '&':
  1843. if (p[1] == '&') {
  1844. Token->TokenType = TK_LOGICAL_AND;
  1845. p++;
  1846. } else {
  1847. Token->TokenType = TK_BITWISE_AND;
  1848. }
  1849. break;
  1850. case '|':
  1851. if (p[1] == '|') {
  1852. Token->TokenType = TK_LOGICAL_OR;
  1853. p++;
  1854. } else {
  1855. Token->TokenType = TK_BITWISE_OR;
  1856. }
  1857. break;
  1858. case '%':
  1859. Token->TokenType = TK_MOD;
  1860. break;
  1861. case '^':
  1862. Token->TokenType = TK_XOR;
  1863. break;
  1864. case '!':
  1865. Token->TokenType = TK_NOT;
  1866. break;
  1867. case '~':
  1868. Token->TokenType = TK_TILDE;
  1869. break;
  1870. case '[':
  1871. Token->TokenType = TK_LSQUARE;
  1872. break;
  1873. case ']':
  1874. Token->TokenType = TK_RSQUARE;
  1875. break;
  1876. case '(':
  1877. NestingLevel++;
  1878. Token->TokenType = TK_LPAREN;
  1879. break;
  1880. case ')':
  1881. NestingLevel--;
  1882. if (NestingLevel == 0 && !fStopAtStatement) {
  1883. //
  1884. // Found a ')' at file-scope, and we're lexing
  1885. // the contents of an @-command in genthnk.
  1886. // Time to stop lexing.
  1887. //
  1888. p++;
  1889. Token->TokenType = TK_EOS;
  1890. *pfLexDone = TRUE;
  1891. CurrentTokenIndex = (int)(Token - Tokens + 1);
  1892. return p;
  1893. } else if (NestingLevel < 0) {
  1894. ExitErrMsg(FALSE, "Parse Error: mismatched nested '(' and ')'\n");
  1895. }
  1896. Token->TokenType = TK_RPAREN;
  1897. break;
  1898. case '{':
  1899. //check for a 'extern "C" {}' or 'extern "C++" {}'
  1900. if (Token - Tokens >= 2 &&
  1901. Token[-2].TokenType == TK_EXTERN &&
  1902. Token[-1].TokenType == TK_STRING &&
  1903. (strcmp(Token[- 1].Name, "C") == 0 || strcmp(Token[-1].Name, "C++") == 0)) {
  1904. if (NestingLevel == 0 && fInlineSeen) {
  1905. ExitErrMsg(FALSE, "Extern \"C\" blocks only supported at file scope\n");
  1906. }
  1907. ExternCLevel++;
  1908. //remove the last 2 tokens and skip this token
  1909. ReleaseToken(Token - 2);
  1910. ReleaseToken(Token - 1);
  1911. Token -= 2;
  1912. p++;
  1913. continue;
  1914. }
  1915. NestingLevel++;
  1916. Token->TokenType = TK_LBRACE;
  1917. break;
  1918. case '.':
  1919. if (p[1] == '.' && p[2] == '.') {
  1920. Token->TokenType = TK_VARGS;
  1921. p+=2;
  1922. } else {
  1923. Token->TokenType = TK_DOT;
  1924. }
  1925. break;
  1926. case '}':
  1927. if (NestingLevel == 0 && ExternCLevel > 0) {
  1928. //omit this token since it is the end of an extern "C" block
  1929. ExternCLevel--;
  1930. p++;
  1931. continue;
  1932. }
  1933. NestingLevel--;
  1934. if (NestingLevel < 0) {
  1935. ExitErrMsg(FALSE, "Parse Error: mismatched nested '{' and '}'\n");
  1936. }
  1937. else if (NestingLevel == InlineLevel && fInlineSeen) {
  1938. //
  1939. // Found the closing '}' for the end of an inline
  1940. // function. Advance past the '}' and start lexing
  1941. // again as if the __inline was never there.
  1942. //
  1943. fInlineSeen = FALSE;
  1944. p++;
  1945. continue;
  1946. }
  1947. else {
  1948. Token->TokenType = TK_RBRACE;
  1949. }
  1950. break;
  1951. case '0':
  1952. if (p[1] == 'x' || p[1] == 'X') {
  1953. //
  1954. // Found '0x' prefix - the token is a hex constant
  1955. //
  1956. Token->TokenType = TK_NUMBER;
  1957. for (p+=2; *p != '\0'; p++) {
  1958. if (isdigit(*p)) {
  1959. int i;
  1960. i = *p - '0';
  1961. Token->Value = Token->Value * 16 + i;
  1962. Token->dwValue = Token->dwValue * 16 + i;
  1963. } else {
  1964. char c = (char)toupper(*p);
  1965. if (c >= 'A' && c <= 'F') {
  1966. int i;
  1967. i = c - 'A' + 10;
  1968. Token->Value = Token->Value * 16 + i;
  1969. Token->dwValue = Token->dwValue * 16 + i;
  1970. } else if (c == 'L') {
  1971. //
  1972. // Numeric constant ending in 'L' is a long-integer
  1973. // type.
  1974. //
  1975. break;
  1976. } else if (isalpha(c)) {
  1977. DumpLexerOutput(0);
  1978. ExitErrMsg(FALSE, "Parse Error in hex constant.\n");
  1979. } else {
  1980. p--;
  1981. break;
  1982. }
  1983. }
  1984. }
  1985. break;
  1986. } else if (isdigit(p[1])) {
  1987. //
  1988. // Found '0' followed by a valid number - the token is
  1989. // an octal constant.
  1990. //
  1991. NumberBase = 8;
  1992. }
  1993. // fall into general number processing code
  1994. case '1':
  1995. case '2':
  1996. case '3':
  1997. case '4':
  1998. case '5':
  1999. case '6':
  2000. case '7':
  2001. case '8':
  2002. case '9':
  2003. Token->TokenType = TK_NUMBER;
  2004. for (; *p != '\0'; p++) {
  2005. Digit = *p - '0';
  2006. if (*p == 'l' || *p == 'L') {
  2007. //
  2008. // Numeric constant ending in 'l' is a long-integer
  2009. //
  2010. break;
  2011. } else if (Digit < 0 || Digit >= NumberBase) {
  2012. p--;
  2013. break;
  2014. }
  2015. Token->Value = Token->Value * NumberBase + Digit;
  2016. Token->dwValue = Token->dwValue * NumberBase + Digit;
  2017. }
  2018. break;
  2019. case '\'':
  2020. Token->TokenType = TK_NUMBER;
  2021. p++; //skip past beginning '
  2022. for(; *p != '\''; p++) {
  2023. if (*p == '\0') {
  2024. ExitErrMsg(FALSE, "\' without ending \'\n");
  2025. }
  2026. Token->Value = Token->Value << 8 | (UCHAR)*p;
  2027. Token->dwValue = Token->dwValue << 8 | (UCHAR)*p;
  2028. }
  2029. break;
  2030. case '"':
  2031. // A string literal. ie. char *p = "foo";
  2032. {
  2033. char *strStart;
  2034. Token->TokenType = TK_STRING;
  2035. strStart = ++p; //skip begining quote
  2036. //get a count of the number of characters
  2037. while (*p != '\0' && *p != '"') p++;
  2038. if ('\0' == *p || '\0' == *(p+1)) {
  2039. ExitErrMsg(FALSE, "String without ending quote\n");
  2040. }
  2041. p++; //skip past the ending quote
  2042. Token->Name = GenHeapAlloc(p - strStart); //1+strlen
  2043. if (Token->Name == NULL) {
  2044. ExitErrMsg(FALSE, "Out of memory in lexer\n");
  2045. }
  2046. memcpy(Token->Name, strStart, p-strStart-1);
  2047. Token->Name[p-strStart-1] = '\0';
  2048. p--;
  2049. ProcessEscapes(Token->Name);
  2050. }
  2051. break;
  2052. default:
  2053. if (*p == '_' || isalpha(*p)) {
  2054. //
  2055. // An identifier or keyword
  2056. //
  2057. char *IdStart = p;
  2058. Token->TokenType = TK_IDENTIFIER;
  2059. while (*p == '_' || isalpha(*p) || isdigit(*p)) {
  2060. p++;
  2061. }
  2062. Token->Name = GenHeapAlloc(p - IdStart + 1);
  2063. if (Token->Name == NULL) {
  2064. ExitErrMsg(FALSE, "Out of memory in lexer\n");
  2065. }
  2066. memcpy(Token->Name, IdStart, p-IdStart);
  2067. Token->Name[p-IdStart] = '\0';
  2068. CheckForKeyword(Token);
  2069. if (Token->TokenType == TK_TEMPLATE) {
  2070. fInlineSeen = TRUE;
  2071. InlineLevel = NestingLevel; // want to get back to the same scope
  2072. } else if (Token->TokenType == TK_INLINE) {
  2073. if (NestingLevel) {
  2074. //
  2075. // __inline keyword embedded inside {}. It's
  2076. // technically an error but we want to allow it
  2077. // during inclusion of ntcb.h.
  2078. //
  2079. continue;
  2080. }
  2081. fInlineSeen = TRUE;
  2082. InlineLevel = 0; // want to get back to file scope
  2083. } else if (Token->TokenType == TK_STATIC ||
  2084. Token->TokenType == TK_UNALIGNED ||
  2085. Token->TokenType == TK_RESTRICT ||
  2086. Token->TokenType == TK___W64) {
  2087. // filter out 'static', '__restrict', '__unaligned' and '__w64'
  2088. // keywords
  2089. continue;
  2090. }
  2091. p--;
  2092. } else if (fInlineSeen) {
  2093. //
  2094. // While processing __inline functions, the lexer is
  2095. // going to encounter all sorts of weird characters
  2096. // in __asm blocks, etc. Just ignore them and keep
  2097. // consuming input.
  2098. //
  2099. p++;
  2100. continue;
  2101. } else {
  2102. ExitErrMsg(FALSE, "Lexer: unexpected char '%c' (0x%x) found\n", *p, *p);
  2103. }
  2104. } // switch
  2105. p++;
  2106. if (!fInlineSeen) {
  2107. Token++;
  2108. if (Token == &Tokens[MAX_TOKENS_IN_STATEMENT]) {
  2109. ExitErrMsg(FALSE, "Lexer internal error - too many tokens in this statement.");
  2110. }
  2111. InitializeToken(Token);
  2112. }
  2113. } // while (*p)
  2114. //
  2115. // Hit end-of-line. Indicate this to the caller
  2116. //
  2117. Token->TokenType = TK_EOS;
  2118. CurrentTokenIndex = (int)(Token - Tokens);
  2119. return NULL;
  2120. }
  2121. void
  2122. CheckForKeyword(
  2123. PTOKEN Token
  2124. )
  2125. /*++
  2126. Routine Description:
  2127. Converts a TK_INDENTIFIER token into a C-language keyword token, if
  2128. the identifier is in the KeywordList[].
  2129. Arguments:
  2130. Token -- Token to convert
  2131. Return Value:
  2132. None. Token->TokenType and Token->Name may be changed.
  2133. --*/
  2134. {
  2135. int i;
  2136. int r;
  2137. for (i=0; KeywordList[i].MatchString; ++i) {
  2138. r = strcmp(Token->Name, KeywordList[i].MatchString);
  2139. if (r == 0) {
  2140. GenHeapFree(Token->Name);
  2141. Token->Name = NULL;
  2142. Token->TokenType = KeywordList[i].Tk;
  2143. return;
  2144. } else if (r < 0) {
  2145. return;
  2146. }
  2147. }
  2148. }
  2149. void
  2150. DumpLexerOutput(
  2151. int FirstToken
  2152. )
  2153. /*++
  2154. Routine Description:
  2155. Debug routine to dump out the Token list as human-readable text.
  2156. Arguments:
  2157. FirstToken -- Index of the first token to list back.
  2158. Return Value:
  2159. None.
  2160. --*/
  2161. {
  2162. int i;
  2163. for (i=0; i<FirstToken; ++i) {
  2164. if (Tokens[i].TokenType == TK_EOS) {
  2165. fprintf(stderr, "DumpLexerOutput: FirstToken %d is after EOS at %d\n", FirstToken, i);
  2166. return;
  2167. }
  2168. }
  2169. fprintf(stderr, "Lexer: ");
  2170. for (i=FirstToken; Tokens[i].TokenType != TK_EOS; ++i) {
  2171. switch (Tokens[i].TokenType) {
  2172. case TK_NUMBER:
  2173. fprintf(stderr, "0x%X ", Tokens[i].Value);
  2174. break;
  2175. case TK_IDENTIFIER:
  2176. case TK_STRING:
  2177. fprintf(stderr, "%s ", Tokens[i].Name);
  2178. break;
  2179. case TK_NONE:
  2180. fprintf(stderr, "<TK_NONE> ");
  2181. break;
  2182. default:
  2183. fprintf(stderr, "%s ", TokenString[(int)Tokens[i].TokenType]);
  2184. break;
  2185. }
  2186. }
  2187. fprintf(stderr, "<EOS>\n");
  2188. }
  2189. BOOL
  2190. UnlexToText(
  2191. char *dest,
  2192. int destlen,
  2193. int StartToken,
  2194. int EndToken
  2195. )
  2196. /*++
  2197. Routine Description:
  2198. Convert a sequence of Tokens back into human-readable text.
  2199. Arguments:
  2200. dest -- ptr to destination buffer
  2201. destlen -- length of destination buffer
  2202. StartToken -- index of first token to list back
  2203. EndToken -- index of last token (this token is *not* listed back)
  2204. Return Value:
  2205. TRUE if Unlex successful. FALSE if failure (ie. buffer overflow).
  2206. --*/
  2207. {
  2208. int i;
  2209. int len;
  2210. char buffer[16];
  2211. char *src;
  2212. if (bDebug) {
  2213. for (i=0; i<StartToken; ++i) {
  2214. if (Tokens[i].TokenType == TK_EOS) {
  2215. ErrMsg("UnlexToText: StartToken %d is after EOS %d\n", StartToken, i);
  2216. return FALSE;
  2217. }
  2218. }
  2219. }
  2220. for (i=StartToken; i<EndToken; ++i) {
  2221. switch (Tokens[i].TokenType) {
  2222. case TK_EOS:
  2223. return FALSE;
  2224. case TK_NUMBER:
  2225. sprintf(buffer, "%d", Tokens[i].Value);
  2226. src = buffer;
  2227. break;
  2228. case TK_IDENTIFIER:
  2229. case TK_STRING:
  2230. src = Tokens[i].Name;
  2231. break;
  2232. case TK_NONE:
  2233. src = "<TK_NONE>";
  2234. break;
  2235. default:
  2236. src = TokenString[(int)Tokens[i].TokenType];
  2237. break;
  2238. }
  2239. len = strlen(src);
  2240. if (len+1 > destlen) {
  2241. return FALSE;
  2242. }
  2243. strcpy(dest, src);
  2244. dest += len;
  2245. *dest = ' ';
  2246. dest++;
  2247. destlen -= len+1;
  2248. }
  2249. dest--; // back up over the trailing ' '
  2250. *dest = '\0'; // null-terminate
  2251. return TRUE;
  2252. }
  2253. PVOID
  2254. GenHeapAlloc(
  2255. INT_PTR Len
  2256. )
  2257. {
  2258. return RtlAllocateHeap(RtlProcessHeap(), 0, Len);
  2259. }
  2260. void
  2261. GenHeapFree(
  2262. PVOID pv
  2263. )
  2264. {
  2265. RtlFreeHeap(RtlProcessHeap(), 0, pv);
  2266. }
  2267. TOKENTYPE
  2268. ConsumeDirectionOpt(
  2269. void
  2270. )
  2271. /*++
  2272. Routine Description:
  2273. Comsumes a TK_IN or TK_OUT, if present in the lexer stream. TK_IN
  2274. followed by TK_OUT is converted to TK_INOUT.
  2275. Arguments:
  2276. None.
  2277. Return Value:
  2278. TK_IN, TK_OUT, TK_INOUT, or TK_NONE.
  2279. --*/
  2280. {
  2281. TOKENTYPE t = CurrentToken()->TokenType;
  2282. switch (t) {
  2283. case TK_IN:
  2284. ConsumeToken();
  2285. if (CurrentToken()->TokenType == TK_OUT) {
  2286. ConsumeToken();
  2287. t = TK_INOUT;
  2288. }
  2289. break;
  2290. case TK_OUT:
  2291. ConsumeToken();
  2292. if (CurrentToken()->TokenType == TK_IN) {
  2293. ConsumeToken();
  2294. t = TK_INOUT;
  2295. }
  2296. break;
  2297. default:
  2298. t = TK_NONE;
  2299. break;
  2300. }
  2301. return t;
  2302. }
  2303. TOKENTYPE
  2304. ConsumeConstVolatileOpt(
  2305. void
  2306. )
  2307. /*++
  2308. Routine Description:
  2309. Comsumes a TK_CONST or TK_VOLATILE, if present in the lexer stream.
  2310. Arguments:
  2311. None.
  2312. Return Value:
  2313. TK_CONST, TK_VOLATILE, or TK_NONE.
  2314. --*/
  2315. {
  2316. TOKENTYPE t = CurrentToken()->TokenType;
  2317. switch (t) {
  2318. case TK_CONST:
  2319. case TK_VOLATILE:
  2320. ConsumeToken();
  2321. break;
  2322. default:
  2323. t = TK_NONE;
  2324. break;
  2325. }
  2326. return t;
  2327. }
  2328. PMEMBERINFO
  2329. AllocMemInfoAndLink(
  2330. BUFALLOCINFO *pbufallocinfo,
  2331. PMEMBERINFO pmeminfo
  2332. )
  2333. /*++
  2334. Routine Description:
  2335. Allocates a new MEMBERINFO struct from the buffer
  2336. Arguments:
  2337. pbufallocinfo -- ptr to memory buffer to allocate from
  2338. pmeminfo -- ptr to list of MEMBERINFOs to link the new one into
  2339. Return Value:
  2340. Newly-allocated, initialized, linked-in MEMBERINFO struct (or NULL)
  2341. --*/
  2342. {
  2343. PMEMBERINFO pmeminfoNext;
  2344. pmeminfoNext = BufAllocate(pbufallocinfo, sizeof(MEMBERINFO));
  2345. if (pmeminfoNext) {
  2346. if (pmeminfo) {
  2347. pmeminfo->pmeminfoNext = pmeminfoNext;
  2348. }
  2349. memset(pmeminfoNext, 0, sizeof(MEMBERINFO));
  2350. }
  2351. return pmeminfoNext;
  2352. }
  2353. PFUNCINFO
  2354. AllocFuncInfoAndLink(
  2355. BUFALLOCINFO *bufallocinfo,
  2356. PFUNCINFO pfuncinfo
  2357. )
  2358. /*++
  2359. Routine Description:
  2360. Allocates a new FUNCINFO struct from the buffer
  2361. Arguments:
  2362. pbufallocinfo -- ptr to memory buffer to allocate from
  2363. pmeminfo -- ptr to list of FUNCINFOs to link the new one into
  2364. Return Value:
  2365. Newly-allocated, initialized, linked-in FUNCINFO struct (or NULL)
  2366. --*/
  2367. {
  2368. PFUNCINFO pfuncinfoNext;
  2369. pfuncinfoNext = BufAllocate(bufallocinfo, sizeof(FUNCINFO));
  2370. if ((pfuncinfoNext != NULL) && (pfuncinfo != NULL)) {
  2371. pfuncinfo->pfuncinfoNext = pfuncinfoNext;
  2372. pfuncinfoNext->sName = NULL;
  2373. pfuncinfoNext->sType = NULL;
  2374. }
  2375. return pfuncinfoNext;
  2376. }
  2377. DWORD
  2378. SizeOfMultiSz(
  2379. char *c
  2380. )
  2381. {
  2382. /*++
  2383. Routine Description:
  2384. Determines the number of bytes used by double '\0' terminated list.
  2385. Arguments:
  2386. c - [IN] ptr to the double '\0' termined list.
  2387. Return Value:
  2388. Bytes used.
  2389. --*/
  2390. DWORD dwSize = 1;
  2391. char cPrevChar = '\0'+1;
  2392. do {
  2393. dwSize++;
  2394. cPrevChar = *c;
  2395. } while(*++c != '\0' || cPrevChar != '\0');
  2396. return dwSize;
  2397. }
  2398. BOOL
  2399. CatMultiSz(
  2400. char *dest,
  2401. char *source,
  2402. DWORD dwMaxSize
  2403. )
  2404. {
  2405. /*++
  2406. Routine Description:
  2407. Concatinates two double '\0' terminated lists.
  2408. New list is stored at dest.
  2409. Arguments:
  2410. dest - [IN/OUT] ptr to the head double '\0' terminated list.
  2411. element - [IN] ptr to the head double '\0' terminated list.
  2412. dwMaxSize - [IN] max size of the new list in bytes.
  2413. Return Value:
  2414. TRUE - Success.
  2415. FALSE - Failure.
  2416. --*/
  2417. //Find end of MultiSz
  2418. DWORD dwLengthDest, dwLengthSource;
  2419. dwLengthDest = SizeOfMultiSz(dest);
  2420. if (2 == dwLengthDest) dwLengthDest = 0;
  2421. else dwLengthDest--;
  2422. dwLengthSource = SizeOfMultiSz(source);
  2423. if (dwLengthDest + dwLengthSource > dwMaxSize) return FALSE;
  2424. memcpy(dest + dwLengthDest, source, dwLengthSource);
  2425. return TRUE;
  2426. }
  2427. BOOL
  2428. AppendToMultiSz(
  2429. char *dest,
  2430. char *source,
  2431. DWORD dwMaxSize
  2432. )
  2433. {
  2434. /*++
  2435. Routine Description:
  2436. Adds a string to the end of a double '\0' terminated list.
  2437. Arguments:
  2438. dest - [IN/OUT] ptr to the double '\0' terminated list.
  2439. source - [IN] ptr to the string to add.
  2440. dwMaxSize - [IN] max number of bytes that can be used by the list.
  2441. Return Value:
  2442. TRUE - Success.
  2443. FALSE - Failure.
  2444. --*/
  2445. DWORD dwLengthDest, dwLengthSource;
  2446. dwLengthDest = SizeOfMultiSz(dest);
  2447. if (2 == dwLengthDest) dwLengthDest = 0;
  2448. else dwLengthDest--;
  2449. dwLengthSource = strlen(source) + 1;
  2450. if (dwLengthDest + dwLengthSource + 1 > dwMaxSize) return FALSE;
  2451. memcpy(dest + dwLengthDest, source, dwLengthSource);
  2452. *(dest + dwLengthDest + dwLengthSource) = '\0';
  2453. return TRUE;
  2454. }
  2455. BOOL IsInMultiSz(
  2456. const char *multisz,
  2457. const char *element
  2458. )
  2459. {
  2460. /*++
  2461. Routine Description:
  2462. Determines if a string exists in a double '\0' terminated list.
  2463. Arguments:
  2464. ppHead - [IN] ptr to the double '\0' terminated list.
  2465. element - [IN] ptr to the element to find.
  2466. Return Value:
  2467. TRUE - element is in the list.
  2468. FALSE - element is not in the list.
  2469. --*/
  2470. do {
  2471. if (strcmp(multisz, element) == 0) return TRUE;
  2472. //skip to end of string
  2473. while(*multisz++ != '\0');
  2474. } while(*multisz != '\0');
  2475. return FALSE;
  2476. }
  2477. BOOL
  2478. ConvertGuidCharToInt(
  2479. const char *pString,
  2480. DWORD *n,
  2481. unsigned short number
  2482. )
  2483. {
  2484. /*++
  2485. Routine Description:
  2486. Internal route to be called only from ConvertStringToGuid.
  2487. Converts segements of the GUID to numbers.
  2488. Arguments:
  2489. pString - [IN] ptr to the string segment to process.
  2490. n - [OUT] ptr to number representation of string segment.
  2491. number - [IN] size of string segment in characters.
  2492. Return Value:
  2493. TRUE - Success.
  2494. --*/
  2495. unsigned short base = 16; //guid numbers are in hex
  2496. *n = 0;
  2497. while(number-- > 0) {
  2498. int t;
  2499. if (*pString >= '0' && *pString <= '9') {
  2500. t = *pString++ - '0';
  2501. }
  2502. else if (*pString >= 'A' && *pString <= 'F') {
  2503. t = (*pString++ - 'A') + 10;
  2504. }
  2505. else if (*pString >= 'a' && *pString <= 'f') {
  2506. t = (*pString++ - 'a') + 10;
  2507. }
  2508. else return FALSE;
  2509. *n = (*n * base) + t;
  2510. }
  2511. return TRUE;
  2512. }
  2513. BOOL
  2514. ConvertStringToGuid(
  2515. const char *pString,
  2516. GUID *pGuid
  2517. )
  2518. {
  2519. /*++
  2520. Routine Description:
  2521. Converts a string in the form found in _declspec(uuid(GUID)) to a GUID.
  2522. Braces around guid are acceptable and are striped before processing.
  2523. Arguments:
  2524. pString - [IN] ptr to the string that represents the guid.
  2525. pGuid - [OUT] ptr to the new guid.
  2526. Return Value:
  2527. TRUE - Success.
  2528. --*/
  2529. DWORD t;
  2530. unsigned int c;
  2531. unsigned int guidlength = 36;
  2532. char tString[37]; //guidlength + 1
  2533. t = strlen(pString);
  2534. if (guidlength + 2 == t) {
  2535. //string is surounded with braces
  2536. //check for braces and chop
  2537. if (pString[0] != '{' || pString[guidlength + 1] != '}') return FALSE;
  2538. memcpy(tString, pString + 1, guidlength);
  2539. tString[guidlength] = '\0';
  2540. pString = tString;
  2541. }
  2542. else if (t != guidlength) return FALSE;
  2543. if (!ConvertGuidCharToInt(pString, &t, 8)) return FALSE;
  2544. pString += 8;
  2545. pGuid->Data1 = t;
  2546. if (*pString++ != '-') return FALSE;
  2547. if (!ConvertGuidCharToInt(pString, &t, 4)) return FALSE;
  2548. pString += 4;
  2549. pGuid->Data2 = (unsigned short)t;
  2550. if (*pString++ != '-') return FALSE;
  2551. if (!ConvertGuidCharToInt(pString, &t, 4)) return FALSE;
  2552. pString += 4;
  2553. pGuid->Data3 = (unsigned short)t;
  2554. if (*pString++ != '-') return FALSE;
  2555. for(c = 0; c < 8; c++) {
  2556. if (!ConvertGuidCharToInt(pString, &t, 2)) return FALSE;
  2557. pString += 2;
  2558. pGuid->Data4[c] = (unsigned char)t;
  2559. if (c == 1)
  2560. if (*pString++ != '-') return FALSE;
  2561. }
  2562. return TRUE;
  2563. }
  2564. BOOL
  2565. IsDefinedPointerDependent(
  2566. char *pName
  2567. )
  2568. {
  2569. /*++
  2570. Routine Description:
  2571. Determines if a typename is inharenty pointer size dependent.
  2572. The user is expected to check pointers and derived types.
  2573. Arguments:
  2574. pName - [IN] Type to check.
  2575. Return Value:
  2576. TRUE - Type is pointer size dependent.
  2577. --*/
  2578. if (NULL == pName) return FALSE;
  2579. if (strcmp(pName, "INT_PTR") == 0) return TRUE;
  2580. if (strcmp(pName, "UINT_PTR") == 0) return TRUE;
  2581. if (strcmp(pName, "HALF_PTR") == 0) return TRUE;
  2582. if (strcmp(pName, "UHALF_PTR") == 0) return TRUE;
  2583. if (strcmp(pName, "LONG_PTR") == 0) return TRUE;
  2584. if (strcmp(pName, "ULONG_PTR") == 0) return TRUE;
  2585. if (strcmp(pName, "__int64") == 0) return TRUE;
  2586. if (strcmp(pName, "_int64") == 0) return TRUE;
  2587. return FALSE;
  2588. }
  2589. PCHAR
  2590. IsDefinedPtrToPtrDependent(
  2591. IN char *pName
  2592. )
  2593. /*++
  2594. Routine Description:
  2595. Determines if a typename is inharenty a pointer to a pointer
  2596. dependent type. The user is expected to check pointers to pointers and derived types.
  2597. All of these types have an indirection level of 1.
  2598. Arguments:
  2599. pName - [IN] Type to check.
  2600. Return Value:
  2601. Pointer to the name of the indirection of this type.
  2602. --*/
  2603. {
  2604. if (*pName != 'P') return NULL;
  2605. if (strcmp(pName, "PINT_PTR") == 0) return "INT_PTR";
  2606. if (strcmp(pName, "PUINT_PTR") == 0) return "UINT_PTR";
  2607. if (strcmp(pName, "PHALF_PTR") == 0) return "HALF_PTR";
  2608. if (strcmp(pName, "PUHALF_PTR") == 0) return "UHALF_PTR";
  2609. if (strcmp(pName, "PLONG_PTR") == 0) return "LONG_PTR";
  2610. if (strcmp(pName, "PULONG_PTR") == 0) return "ULONG_PTR";
  2611. return NULL;
  2612. }
  2613. static HANDLE hFile = INVALID_HANDLE_VALUE;
  2614. static HANDLE hMapFile = NULL;
  2615. static void *pvMappedBase = NULL;
  2616. BOOL
  2617. ClosePpmFile(
  2618. BOOL bExitFailure
  2619. )
  2620. {
  2621. /*++
  2622. Routine Description:
  2623. Closes the opened ppm file.
  2624. Arguments:
  2625. bExitFailure - [IN] Terminate program on error
  2626. Return Value:
  2627. Error - FALSE
  2628. Success - TRUE
  2629. --*/
  2630. if (NULL != pvMappedBase) {
  2631. if(!UnmapViewOfFile(pvMappedBase)) {
  2632. if (bExitFailure) {
  2633. ErrMsg("ClosePpmFile: Unable to unmap ppm file, error %u\n", GetLastError());
  2634. ExitErrMsg(FALSE, _strerror(NULL));
  2635. }
  2636. return FALSE;
  2637. }
  2638. pvMappedBase = NULL;
  2639. }
  2640. if (NULL != hMapFile) {
  2641. if(!CloseHandle(hMapFile)) {
  2642. if (bExitFailure) {
  2643. ErrMsg("ClosePpmFile: Unable to close ppm file, error %u\n", GetLastError());
  2644. ExitErrMsg(FALSE, _strerror(NULL));
  2645. }
  2646. return FALSE;
  2647. }
  2648. hMapFile = NULL;
  2649. }
  2650. if (INVALID_HANDLE_VALUE != hFile) {
  2651. if(!CloseHandle(hFile)) {
  2652. if (bExitFailure) {
  2653. ErrMsg("ClosePpmFile: Unable to close ppm file, error %u\n", GetLastError());
  2654. ExitErrMsg(FALSE, _strerror(NULL));
  2655. }
  2656. return FALSE;
  2657. }
  2658. hFile = INVALID_HANDLE_VALUE;
  2659. }
  2660. return TRUE;
  2661. }
  2662. PCVMHEAPHEADER
  2663. MapPpmFile(
  2664. char *sPpmfile,
  2665. BOOL bExitFailure
  2666. )
  2667. {
  2668. /*++
  2669. Routine Description:
  2670. Opens a Ppm file and maps it.
  2671. Arguments:
  2672. pName - [IN] Name of the file to map.
  2673. bExitFailure - [IN] Terminate program on error
  2674. Return Value:
  2675. Error - NULL
  2676. Success - Pointer to the VCVMHEAPHEADER
  2677. --*/
  2678. void *pvBaseAddress;
  2679. DWORD dwBytesRead;
  2680. BOOL fSuccess;
  2681. ULONG Version;
  2682. DWORD dwErrorNo;
  2683. PCVMHEAPHEADER pHeader;
  2684. hFile = CreateFile(sPpmfile,
  2685. GENERIC_READ,
  2686. FILE_SHARE_READ,
  2687. NULL,
  2688. OPEN_EXISTING,
  2689. 0,
  2690. NULL
  2691. );
  2692. if (hFile == INVALID_HANDLE_VALUE) {
  2693. if (!bExitFailure) goto fail;
  2694. ErrMsg("MapPpmFile: Unable to open %s, error %u\n", sPpmfile, GetLastError());
  2695. ExitErrMsg(FALSE, _strerror(NULL));
  2696. }
  2697. fSuccess = ReadFile(hFile,
  2698. &Version,
  2699. sizeof(ULONG),
  2700. &dwBytesRead,
  2701. NULL
  2702. );
  2703. if (! fSuccess || dwBytesRead != sizeof(ULONG)) {
  2704. if (!bExitFailure) goto fail;
  2705. ErrMsg("MapPpmFile: Unable to read version for %s, error %u\n", sPpmfile, GetLastError());
  2706. ExitErrMsg(FALSE, _strerror(NULL));
  2707. }
  2708. if (Version != VM_TOOL_VERSION) {
  2709. //SetLastError(ERROR_BAD_DATABASE_VERSION);
  2710. if (!bExitFailure) goto fail;
  2711. ExitErrMsg(FALSE, "MapPpmFile: Ppm file file has version %x, expect %x\n", Version, VM_TOOL_VERSION);
  2712. }
  2713. #if _WIN64
  2714. // Read and skip the padding between the version and the base
  2715. fSuccess = ReadFile(hFile,
  2716. &Version,
  2717. sizeof(ULONG),
  2718. &dwBytesRead,
  2719. NULL
  2720. );
  2721. if (! fSuccess || dwBytesRead != sizeof(ULONG)) {
  2722. if (!bExitFailure) goto fail;
  2723. ErrMsg("MapPpmFile: Unable to read version for %s, error %u\n", sPpmfile, GetLastError());
  2724. ExitErrMsg(FALSE, _strerror(NULL));
  2725. }
  2726. #endif
  2727. fSuccess = ReadFile(hFile,
  2728. &pvBaseAddress,
  2729. sizeof(pvBaseAddress),
  2730. &dwBytesRead,
  2731. NULL
  2732. );
  2733. if (! fSuccess || dwBytesRead != sizeof(pvBaseAddress)) {
  2734. if (!bExitFailure) goto fail;
  2735. ExitErrMsg(FALSE, "MapPpmFile: Unable to read base address of ppm file %s, error %u\n", sPpmfile, GetLastError());
  2736. ExitErrMsg(FALSE, _strerror(NULL));
  2737. }
  2738. hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0,NULL);
  2739. if (!hMapFile) {
  2740. if (!bExitFailure) goto fail;
  2741. ExitErrMsg(FALSE, "MapPpmfile: Unable to map %s, error %u\n", sPpmfile, GetLastError());
  2742. ExitErrMsg(FALSE, _strerror(NULL));
  2743. }
  2744. pvMappedBase = MapViewOfFileEx(hMapFile, FILE_MAP_READ, 0, 0, 0, pvBaseAddress);
  2745. if (! pvMappedBase || pvMappedBase != pvBaseAddress) {
  2746. // If the file can't be mapped at the expected base, we must fail
  2747. // since the memory is chock full o' pointers.
  2748. if (!bExitFailure) goto fail;
  2749. ExitErrMsg(FALSE, "MapPpmFile: Unable to map view of %s, error %u\n", sPpmfile, GetLastError());
  2750. ExitErrMsg(FALSE, _strerror(NULL));
  2751. }
  2752. NIL = &((PCVMHEAPHEADER)pvMappedBase)->NIL;
  2753. return (PCVMHEAPHEADER)pvMappedBase;
  2754. fail:
  2755. dwErrorNo = GetLastError();
  2756. ClosePpmFile(FALSE);
  2757. SetLastError(dwErrorNo);
  2758. return NULL;
  2759. }
  2760. char szHOSTPTR32[] = "/* 64 bit ptr */ _int64";
  2761. char szHOSTPTR64[] = "/* 32 bit ptr */ _int32";
  2762. char *GetHostPointerName(BOOL bIsPtr64) {
  2763. if (bIsPtr64)
  2764. return szHOSTPTR32;
  2765. else
  2766. return szHOSTPTR64;
  2767. }
  2768. char szHOSTUSIZE8[] = "unsigned _int8";
  2769. char szHOSTUSIZE16[] = "unsigned _int16";
  2770. char szHOSTUSIZE32[] = "unsigned _int32";
  2771. char szHOSTUSIZE64[] = "unsigned _int64";
  2772. char szHOSTSIZE8[] = "_int8";
  2773. char szHOSTSIZE16[] = "_int16";
  2774. char szHOSTSIZE32[] = "_int32";
  2775. char szHOSTSIZE64[] = "_int64";
  2776. char szHOSTSIZEGUID[] = "struct _GUID";
  2777. char *GetHostBasicTypeName(PKNOWNTYPES pkt) {
  2778. DWORD dwSize;
  2779. if (pkt->Flags & BTI_ISARRAY)
  2780. dwSize = pkt->dwBaseSize;
  2781. else
  2782. dwSize = pkt->Size;
  2783. if (pkt->Flags & BTI_UNSIGNED) {
  2784. switch(pkt->Size) {
  2785. case 1:
  2786. return szHOSTUSIZE8;
  2787. case 2:
  2788. return szHOSTUSIZE16;
  2789. case 4:
  2790. return szHOSTUSIZE32;
  2791. case 8:
  2792. return szHOSTUSIZE64;
  2793. default:
  2794. ExitErrMsg(FALSE, "Unknown type size of %d for type %s.\n", pkt->Size, pkt->TypeName);
  2795. return 0;
  2796. }
  2797. }
  2798. else {
  2799. switch(pkt->Size) {
  2800. case 0:
  2801. return szVOID;
  2802. case 1:
  2803. return szHOSTSIZE8;
  2804. case 2:
  2805. return szHOSTSIZE16;
  2806. case 4:
  2807. return szHOSTSIZE32;
  2808. case 8:
  2809. return szHOSTSIZE64;
  2810. case 16:
  2811. return szHOSTSIZEGUID;
  2812. default:
  2813. ExitErrMsg(FALSE, "Unknown type size of %d for type %s.\n", pkt->Size, pkt->TypeName);
  2814. return 0;
  2815. }
  2816. }
  2817. }
  2818. char *GetHostTypeName(PKNOWNTYPES pkt, char *pBuffer) {
  2819. if (pkt->IndLevel > 0) {
  2820. strcpy(pBuffer, GetHostPointerName(pkt->Flags & BTI_PTR64));
  2821. }
  2822. else if(!(BTI_NOTDERIVED & pkt->Flags)) {
  2823. if (strcmp(pkt->BaseName, "enum") == 0) {
  2824. strcpy(pBuffer, szHOSTSIZE32);
  2825. }
  2826. else if (strcmp(pkt->BaseName, "union") == 0 ||
  2827. strcmp(pkt->BaseName, "struct") == 0) {
  2828. strcpy(pBuffer, pkt->BaseName);
  2829. strcat(pBuffer, " NT32");
  2830. strcat(pBuffer, pkt->TypeName);
  2831. }
  2832. else {
  2833. strcpy(pBuffer, "NT32");
  2834. strcat(pBuffer, pkt->TypeName);
  2835. }
  2836. }
  2837. else {
  2838. strcpy(pBuffer, GetHostBasicTypeName(pkt));
  2839. }
  2840. return pBuffer;
  2841. }