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.

3644 lines
89 KiB

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