VirtualBox

source: vbox/trunk/src/bldprogs/VBoxTpG.cpp@ 41117

Last change on this file since 41117 was 41117, checked in by vboxsync, 13 years ago

SUP,VBoxTpG,++: Initial implementation of generic user module tracepoints. (disabled)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 85.6 KB
Line 
1/* $Id: VBoxTpG.cpp 41117 2012-05-02 14:22:29Z vboxsync $ */
2/** @file
3 * VBox Build Tool - VBox Tracepoint Generator.
4 */
5
6/*
7 * Copyright (C) 2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <VBox/VBoxTpG.h>
23
24#include <iprt/alloca.h>
25#include <iprt/assert.h>
26#include <iprt/ctype.h>
27#include <iprt/env.h>
28#include <iprt/err.h>
29#include <iprt/file.h>
30#include <iprt/getopt.h>
31#include <iprt/initterm.h>
32#include <iprt/list.h>
33#include <iprt/mem.h>
34#include <iprt/message.h>
35#include <iprt/path.h>
36#include <iprt/process.h>
37#include <iprt/stream.h>
38#include <iprt/string.h>
39#include <iprt/uuid.h>
40
41#include "scmstream.h"
42
43
44/*******************************************************************************
45* Structures and Typedefs *
46*******************************************************************************/
47
48typedef struct VTGATTRS
49{
50 kVTGStability enmCode;
51 kVTGStability enmData;
52 kVTGClass enmDataDep;
53} VTGATTRS;
54typedef VTGATTRS *PVTGATTRS;
55
56
57typedef struct VTGARG
58{
59 RTLISTNODE ListEntry;
60 char *pszName;
61 const char *pszType;
62 uint32_t fType;
63} VTGARG;
64typedef VTGARG *PVTGARG;
65
66typedef struct VTGPROBE
67{
68 RTLISTNODE ListEntry;
69 char *pszMangledName;
70 const char *pszUnmangledName;
71 RTLISTANCHOR ArgHead;
72 uint32_t cArgs;
73 bool fHaveLargeArgs;
74 uint32_t offArgList;
75 uint32_t iProbe;
76} VTGPROBE;
77typedef VTGPROBE *PVTGPROBE;
78
79typedef struct VTGPROVIDER
80{
81 RTLISTNODE ListEntry;
82 const char *pszName;
83
84 uint16_t iFirstProbe;
85 uint16_t cProbes;
86
87 VTGATTRS AttrSelf;
88 VTGATTRS AttrModules;
89 VTGATTRS AttrFunctions;
90 VTGATTRS AttrName;
91 VTGATTRS AttrArguments;
92
93 RTLISTANCHOR ProbeHead;
94} VTGPROVIDER;
95typedef VTGPROVIDER *PVTGPROVIDER;
96
97/**
98 * A string table string.
99 */
100typedef struct VTGSTRING
101{
102 /** The string space core. */
103 RTSTRSPACECORE Core;
104 /** The string table offset. */
105 uint32_t offStrTab;
106 /** The actual string. */
107 char szString[1];
108} VTGSTRING;
109typedef VTGSTRING *PVTGSTRING;
110
111
112/*******************************************************************************
113* Global Variables *
114*******************************************************************************/
115/** The string space organizing the string table strings. Each node is a VTGSTRING. */
116static RTSTRSPACE g_StrSpace = NULL;
117/** Used by the string table enumerator to set VTGSTRING::offStrTab. */
118static uint32_t g_offStrTab;
119/** List of providers created by the parser. */
120static RTLISTANCHOR g_ProviderHead;
121
122/** The number of type errors. */
123static uint32_t g_cTypeErrors = 0;
124
125/** @name Options
126 * @{ */
127static enum
128{
129 kVBoxTpGAction_Nothing,
130 kVBoxTpGAction_GenerateHeader,
131 kVBoxTpGAction_GenerateObject
132} g_enmAction = kVBoxTpGAction_Nothing;
133static uint32_t g_cBits = ARCH_BITS;
134static bool g_fApplyCpp = false;
135static uint32_t g_cVerbosity = 0;
136static const char *g_pszOutput = NULL;
137static const char *g_pszScript = NULL;
138static const char *g_pszTempAsm = NULL;
139#ifdef RT_OS_DARWIN
140static const char *g_pszAssembler = "yasm";
141static const char *g_pszAssemblerFmtOpt = "-f";
142static const char g_szAssemblerFmtVal32[] = "macho32";
143static const char g_szAssemblerFmtVal64[] = "macho64";
144static const char g_szAssemblerOsDef[] = "RT_OS_DARWIN";
145#elif defined(RT_OS_OS2)
146static const char *pszAssembler = "nasm.exe";
147static const char *pszAssemblerFmtOpt = "-f";
148static const char g_szAssemblerFmtVal32[] = "obj";
149static const char g_szAssemblerFmtVal64[] = "elf64";
150static const char g_szAssemblerOsDef[] = "RT_OS_OS2";
151#elif defined(RT_OS_WINDOWS)
152static const char *g_pszAssembler = "yasm.exe";
153static const char *g_pszAssemblerFmtOpt = "-f";
154static const char g_szAssemblerFmtVal32[] = "win32";
155static const char g_szAssemblerFmtVal64[] = "win64";
156static const char g_szAssemblerOsDef[] = "RT_OS_WINDOWS";
157#else
158static const char *g_pszAssembler = "yasm";
159static const char *g_pszAssemblerFmtOpt = "-f";
160static const char g_szAssemblerFmtVal32[] = "elf32";
161static const char g_szAssemblerFmtVal64[] = "elf64";
162# ifdef RT_OS_FREEBSD
163static const char g_szAssemblerOsDef[] = "RT_OS_FREEBSD";
164# elif defined(RT_OS_NETBSD)
165static const char g_szAssemblerOsDef[] = "RT_OS_NETBSD";
166# elif defined(RT_OS_OPENBSD)
167static const char g_szAssemblerOsDef[] = "RT_OS_OPENBSD";
168# elif defined(RT_OS_LINUX)
169static const char g_szAssemblerOsDef[] = "RT_OS_LINUX";
170# elif defined(RT_OS_SOLARIS)
171static const char g_szAssemblerOsDef[] = "RT_OS_SOLARIS";
172# else
173# error "Port me!"
174# endif
175#endif
176static const char *g_pszAssemblerFmtVal = RT_CONCAT(g_szAssemblerFmtVal, ARCH_BITS);
177static const char *g_pszAssemblerDefOpt = "-D";
178static const char *g_pszAssemblerIncOpt = "-I";
179static char g_szAssemblerIncVal[RTPATH_MAX];
180static const char *g_pszAssemblerIncVal = __FILE__ "/../../../include/";
181static const char *g_pszAssemblerOutputOpt = "-o";
182static unsigned g_cAssemblerOptions = 0;
183static const char *g_apszAssemblerOptions[32];
184static const char *g_pszProbeFnName = "SUPR0TracerFireProbe";
185static bool g_fProbeFnImported = true;
186static bool g_fPic = false;
187/** @} */
188
189
190
191
192/**
193 * Inserts a string into the string table, reusing any matching existing string
194 * if possible.
195 *
196 * @returns Read only string.
197 * @param pch The string to insert (need not be terminated).
198 * @param cch The length of the string.
199 */
200static const char *strtabInsertN(const char *pch, size_t cch)
201{
202 PVTGSTRING pStr = (PVTGSTRING)RTStrSpaceGetN(&g_StrSpace, pch, cch);
203 if (pStr)
204 return pStr->szString;
205
206 /*
207 * Create a new entry.
208 */
209 pStr = (PVTGSTRING)RTMemAlloc(RT_OFFSETOF(VTGSTRING, szString[cch + 1]));
210 if (!pStr)
211 return NULL;
212
213 pStr->Core.pszString = pStr->szString;
214 memcpy(pStr->szString, pch, cch);
215 pStr->szString[cch] = '\0';
216 pStr->offStrTab = UINT32_MAX;
217
218 bool fRc = RTStrSpaceInsert(&g_StrSpace, &pStr->Core);
219 Assert(fRc); NOREF(fRc);
220 return pStr->szString;
221}
222
223
224/**
225 * Retrieves the string table offset of the given string table string.
226 *
227 * @returns String table offset.
228 * @param pszStrTabString The string table string.
229 */
230static uint32_t strtabGetOff(const char *pszStrTabString)
231{
232 PVTGSTRING pStr = RT_FROM_MEMBER(pszStrTabString, VTGSTRING, szString[0]);
233 Assert(pStr->Core.pszString == pszStrTabString);
234 return pStr->offStrTab;
235}
236
237
238/**
239 * Invokes the assembler.
240 *
241 * @returns Exit code.
242 * @param pszOutput The output file.
243 * @param pszTempAsm The source file.
244 */
245static RTEXITCODE generateInvokeAssembler(const char *pszOutput, const char *pszTempAsm)
246{
247 const char *apszArgs[64];
248 unsigned iArg = 0;
249
250 apszArgs[iArg++] = g_pszAssembler;
251 apszArgs[iArg++] = g_pszAssemblerFmtOpt;
252 apszArgs[iArg++] = g_pszAssemblerFmtVal;
253 apszArgs[iArg++] = g_pszAssemblerDefOpt;
254 if (!strcmp(g_pszAssemblerFmtVal, "macho32") || !strcmp(g_pszAssemblerFmtVal, "macho64"))
255 apszArgs[iArg++] = "ASM_FORMAT_MACHO";
256 else if (!strcmp(g_pszAssemblerFmtVal, "obj") || !strcmp(g_pszAssemblerFmtVal, "omf"))
257 apszArgs[iArg++] = "ASM_FORMAT_OMF";
258 else if ( !strcmp(g_pszAssemblerFmtVal, "win32")
259 || !strcmp(g_pszAssemblerFmtVal, "win64")
260 || !strcmp(g_pszAssemblerFmtVal, "pe32")
261 || !strcmp(g_pszAssemblerFmtVal, "pe64")
262 || !strcmp(g_pszAssemblerFmtVal, "pe") )
263 apszArgs[iArg++] = "ASM_FORMAT_PE";
264 else if ( !strcmp(g_pszAssemblerFmtVal, "elf32")
265 || !strcmp(g_pszAssemblerFmtVal, "elf64")
266 || !strcmp(g_pszAssemblerFmtVal, "elf"))
267 apszArgs[iArg++] = "ASM_FORMAT_ELF";
268 else
269 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Unknown assembler format '%s'", g_pszAssemblerFmtVal);
270 apszArgs[iArg++] = g_pszAssemblerDefOpt;
271 if (g_cBits == 32)
272 apszArgs[iArg++] = "ARCH_BITS=32";
273 else
274 apszArgs[iArg++] = "ARCH_BITS=64";
275 apszArgs[iArg++] = g_pszAssemblerDefOpt;
276 if (g_cBits == 32)
277 apszArgs[iArg++] = "RT_ARCH_X86";
278 else
279 apszArgs[iArg++] = "RT_ARCH_AMD64";
280 if (g_szAssemblerOsDef[0])
281 {
282 apszArgs[iArg++] = g_pszAssemblerDefOpt;
283 apszArgs[iArg++] = g_szAssemblerOsDef;
284 }
285 apszArgs[iArg++] = g_pszAssemblerIncOpt;
286 apszArgs[iArg++] = g_pszAssemblerIncVal;
287 apszArgs[iArg++] = g_pszAssemblerOutputOpt;
288 apszArgs[iArg++] = pszOutput;
289 for (unsigned i = 0; i < g_cAssemblerOptions; i++)
290 apszArgs[iArg++] = g_apszAssemblerOptions[i];
291 apszArgs[iArg++] = pszTempAsm;
292 apszArgs[iArg] = NULL;
293
294 if (g_cVerbosity > 1)
295 {
296 RTMsgInfo("Starting assmbler '%s' with arguments:\n", g_pszAssembler);
297 for (unsigned i = 0; i < iArg; i++)
298 RTMsgInfo(" #%02u: '%s'\n", i, apszArgs[i]);
299 }
300
301 RTPROCESS hProc;
302 int rc = RTProcCreate(apszArgs[0], apszArgs, RTENV_DEFAULT, RTPROC_FLAGS_SEARCH_PATH, &hProc);
303 if (RT_FAILURE(rc))
304 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to start '%s' (assembler): %Rrc", apszArgs[0], rc);
305
306 RTPROCSTATUS Status;
307 rc = RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &Status);
308 if (RT_FAILURE(rc))
309 {
310 RTProcTerminate(hProc);
311 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTProcWait failed: %Rrc", rc);
312 }
313 if (Status.enmReason == RTPROCEXITREASON_SIGNAL)
314 return RTMsgErrorExit(RTEXITCODE_FAILURE, "The assembler failed: signal %d", Status.iStatus);
315 if (Status.enmReason != RTPROCEXITREASON_NORMAL)
316 return RTMsgErrorExit(RTEXITCODE_FAILURE, "The assembler failed: abend");
317 if (Status.iStatus != 0)
318 return RTMsgErrorExit((RTEXITCODE)Status.iStatus, "The assembler failed: exit code %d", Status.iStatus);
319
320 return RTEXITCODE_SUCCESS;
321}
322
323
324/**
325 * Worker that does the boring bits when generating a file.
326 *
327 * @returns Exit code.
328 * @param pszOutput The name of the output file.
329 * @param pszWhat What kind of file it is.
330 * @param pfnGenerator The callback function that provides the contents
331 * of the file.
332 */
333static RTEXITCODE generateFile(const char *pszOutput, const char *pszWhat,
334 RTEXITCODE (*pfnGenerator)(PSCMSTREAM))
335{
336 SCMSTREAM Strm;
337 int rc = ScmStreamInitForWriting(&Strm, NULL);
338 if (RT_FAILURE(rc))
339 return RTMsgErrorExit(RTEXITCODE_FAILURE, "ScmStreamInitForWriting returned %Rrc when generating the %s file",
340 rc, pszWhat);
341
342 RTEXITCODE rcExit = pfnGenerator(&Strm);
343 if (RT_FAILURE(ScmStreamGetStatus(&Strm)))
344 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Stream error %Rrc generating the %s file",
345 ScmStreamGetStatus(&Strm), pszWhat);
346 if (rcExit == RTEXITCODE_SUCCESS)
347 {
348 rc = ScmStreamWriteToFile(&Strm, "%s", pszOutput);
349 if (RT_FAILURE(rc))
350 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "ScmStreamWriteToFile returned %Rrc when writing '%s' (%s)",
351 rc, pszOutput, pszWhat);
352 if (rcExit == RTEXITCODE_SUCCESS)
353 {
354 if (g_cVerbosity > 0)
355 RTMsgInfo("Successfully generated '%s'.", pszOutput);
356 if (g_cVerbosity > 1)
357 {
358 RTMsgInfo("================ %s - start ================", pszWhat);
359 ScmStreamRewindForReading(&Strm);
360 const char *pszLine;
361 size_t cchLine;
362 SCMEOL enmEol;
363 while ((pszLine = ScmStreamGetLine(&Strm, &cchLine, &enmEol)) != NULL)
364 RTPrintf("%.*s\n", cchLine, pszLine);
365 RTMsgInfo("================ %s - end ================", pszWhat);
366 }
367 }
368 }
369 ScmStreamDelete(&Strm);
370 return rcExit;
371}
372
373
374/**
375 * Formats a string and writes it to the SCM stream.
376 *
377 * @returns The number of bytes written (>= 0). Negative value are IPRT error
378 * status codes.
379 * @param pStream The stream to write to.
380 * @param pszFormat The format string.
381 * @param va The arguments to format.
382 */
383static ssize_t ScmStreamPrintfV(PSCMSTREAM pStream, const char *pszFormat, va_list va)
384{
385 char *psz;
386 ssize_t cch = RTStrAPrintfV(&psz, pszFormat, va);
387 if (cch)
388 {
389 int rc = ScmStreamWrite(pStream, psz, cch);
390 RTStrFree(psz);
391 if (RT_FAILURE(rc))
392 cch = rc;
393 }
394 return cch;
395}
396
397
398/**
399 * Formats a string and writes it to the SCM stream.
400 *
401 * @returns The number of bytes written (>= 0). Negative value are IPRT error
402 * status codes.
403 * @param pStream The stream to write to.
404 * @param pszFormat The format string.
405 * @param ... The arguments to format.
406 */
407static ssize_t ScmStreamPrintf(PSCMSTREAM pStream, const char *pszFormat, ...)
408{
409 va_list va;
410 va_start(va, pszFormat);
411 ssize_t cch = ScmStreamPrintfV(pStream, pszFormat, va);
412 va_end(va);
413 return cch;
414}
415
416
417/**
418 * @callback_method_impl{FNRTSTRSPACECALLBACK, Writes the string table strings.}
419 */
420static DECLCALLBACK(int) generateAssemblyStrTabCallback(PRTSTRSPACECORE pStr, void *pvUser)
421{
422 PVTGSTRING pVtgStr = (PVTGSTRING)pStr;
423 PSCMSTREAM pStrm = (PSCMSTREAM)pvUser;
424
425 pVtgStr->offStrTab = g_offStrTab;
426 g_offStrTab += (uint32_t)pVtgStr->Core.cchString + 1;
427
428 ScmStreamPrintf(pStrm,
429 " db '%s', 0 ; off=%u len=%zu\n",
430 pVtgStr->szString, pVtgStr->offStrTab, pVtgStr->Core.cchString);
431 return VINF_SUCCESS;
432}
433
434
435/**
436 * Generate assembly source that can be turned into an object file.
437 *
438 * (This is a generateFile callback.)
439 *
440 * @returns Exit code.
441 * @param pStrm The output stream.
442 */
443static RTEXITCODE generateAssembly(PSCMSTREAM pStrm)
444{
445 PVTGPROVIDER pProvider;
446 PVTGPROBE pProbe;
447 PVTGARG pArg;
448
449
450 if (g_cVerbosity > 0)
451 RTMsgInfo("Generating assembly code...");
452
453 /*
454 * Write the file header.
455 */
456 ScmStreamPrintf(pStrm,
457 "; $Id: VBoxTpG.cpp 41117 2012-05-02 14:22:29Z vboxsync $ \n"
458 ";; @file\n"
459 "; Automatically generated from %s. Do NOT edit!\n"
460 ";\n"
461 "\n"
462 "%%include \"iprt/asmdefs.mac\"\n"
463 "\n"
464 "\n"
465 ";"
466 "; We put all the data in a dedicated section / segment.\n"
467 ";\n"
468 "; In order to find the probe location specifiers, we do the necessary\n"
469 "; trickery here, ASSUMING that this object comes in first in the link\n"
470 "; editing process.\n"
471 ";\n"
472 "%%ifdef ASM_FORMAT_OMF\n"
473 " %%macro VTG_GLOBAL 2\n"
474 " global NAME(%%1)\n"
475 " NAME(%%1):\n"
476 " %%endmacro\n"
477 " segment VTG.Obj public CLASS=VTG align=4096 use32\n"
478 "\n"
479 "%%elifdef ASM_FORMAT_MACHO\n"
480 " %%macro VTG_GLOBAL 2\n"
481 " global NAME(%%1)\n"
482 " NAME(%%1):\n"
483 " %%endmacro\n"
484 " [section __VTG __VTGObj align=64]\n"
485 "\n"
486 "%%elifdef ASM_FORMAT_PE\n"
487 " %%macro VTG_GLOBAL 2\n"
488 " global NAME(%%1)\n"
489 " NAME(%%1):\n"
490 " %%endmacro\n"
491 " [section VTGPrLc.Begin data align=64]\n"
492 /*" times 16 db 0xcc\n"*/
493 "VTG_GLOBAL g_aVTGPrLc, data\n"
494 " [section VTGPrLc.Data data align=4]\n"
495 " [section VTGPrLc.End data align=4]\n"
496 "VTG_GLOBAL g_aVTGPrLc_End, data\n"
497 /*" times 16 db 0xcc\n"*/
498 " [section VTGObj data align=32]\n"
499 "\n"
500 "%%elifdef ASM_FORMAT_ELF\n"
501 " %%macro VTG_GLOBAL 2\n"
502 " global NAME(%%1):%%2 hidden\n"
503 " NAME(%%1):\n"
504 " %%endmacro\n"
505 " [section .VTGData progbits alloc noexec write align=4096]\n"
506 " [section .VTGPrLc.Begin progbits alloc noexec write align=32]\n"
507 " dd 0,0,0,0, 0,0,0,0\n"
508 "VTG_GLOBAL g_aVTGPrLc, data\n"
509 " [section .VTGPrLc progbits alloc noexec write align=1]\n"
510 " [section .VTGPrLc.End progbits alloc noexec write align=1]\n"
511 "VTG_GLOBAL g_aVTGPrLc_End, data\n"
512 " dd 0,0,0,0, 0,0,0,0\n"
513 " [section .VTGData progbits alloc noexec write align=4096]\n"
514 "\n"
515 "%%else\n"
516 " %%error \"ASM_FORMAT_XXX is not defined\"\n"
517 "%%endif\n"
518 "\n"
519 "\n"
520 "VTG_GLOBAL g_VTGObjHeader, data\n"
521 " ;0 1 2 3\n"
522 " ;012345678901234567890123456789012\n"
523 " db 'VTG Object Header v1.5', 0, 0\n"
524 " dd %u\n"
525 " dd NAME(g_acVTGProbeEnabled_End) - NAME(g_VTGObjHeader)\n"
526 " dd NAME(g_achVTGStringTable) - NAME(g_VTGObjHeader)\n"
527 " dd NAME(g_achVTGStringTable_End) - NAME(g_achVTGStringTable)\n"
528 " dd NAME(g_aVTGArgLists) - NAME(g_VTGObjHeader)\n"
529 " dd NAME(g_aVTGArgLists_End) - NAME(g_aVTGArgLists)\n"
530 " dd NAME(g_aVTGProbes) - NAME(g_VTGObjHeader)\n"
531 " dd NAME(g_aVTGProbes_End) - NAME(g_aVTGProbes)\n"
532 " dd NAME(g_aVTGProviders) - NAME(g_VTGObjHeader)\n"
533 " dd NAME(g_aVTGProviders_End) - NAME(g_aVTGProviders)\n"
534 " dd NAME(g_acVTGProbeEnabled) - NAME(g_VTGObjHeader)\n"
535 " dd NAME(g_acVTGProbeEnabled_End) - NAME(g_acVTGProbeEnabled)\n"
536 " dd 0\n"
537 " dd 0\n"
538 "%%ifdef ASM_FORMAT_MACHO ; Apple has a real decent linker!\n"
539 "extern section$start$__VTG$__VTGPrLc\n"
540 " RTCCPTR_DEF section$start$__VTG$__VTGPrLc\n"
541 " %%if ARCH_BITS == 32\n"
542 " dd 0\n"
543 " %%endif\n"
544 "extern section$end$__VTG$__VTGPrLc\n"
545 " RTCCPTR_DEF section$end$__VTG$__VTGPrLc\n"
546 " %%if ARCH_BITS == 32\n"
547 " dd 0\n"
548 " %%endif\n"
549 "%%else\n"
550 " RTCCPTR_DEF NAME(g_aVTGPrLc)\n"
551 " %%if ARCH_BITS == 32\n"
552 " dd 0\n"
553 " %%endif\n"
554 " RTCCPTR_DEF NAME(g_aVTGPrLc_End)\n"
555 " %%if ARCH_BITS == 32\n"
556 " dd 0\n"
557 " %%endif\n"
558 "%%endif\n"
559 ,
560 g_pszScript, g_cBits);
561 RTUUID Uuid;
562 int rc = RTUuidCreate(&Uuid);
563 if (RT_FAILURE(rc))
564 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTUuidCreate failed: %Rrc", rc);
565 ScmStreamPrintf(pStrm,
566 " dd 0%08xh, 0%08xh, 0%08xh, 0%08xh\n"
567 " dd 0, 0, 0, 0\n"
568 , Uuid.au32[0], Uuid.au32[1], Uuid.au32[2], Uuid.au32[3]);
569
570 /*
571 * Dump the string table before we start using the strings.
572 */
573 ScmStreamPrintf(pStrm,
574 "\n"
575 ";\n"
576 "; The string table.\n"
577 ";\n"
578 "VTG_GLOBAL g_achVTGStringTable, data\n");
579 g_offStrTab = 0;
580 RTStrSpaceEnumerate(&g_StrSpace, generateAssemblyStrTabCallback, pStrm);
581 ScmStreamPrintf(pStrm,
582 "VTG_GLOBAL g_achVTGStringTable_End, data\n");
583
584 /*
585 * Write out the argument lists before we use them.
586 */
587 ScmStreamPrintf(pStrm,
588 "\n"
589 ";\n"
590 "; The argument lists.\n"
591 ";\n"
592 "ALIGNDATA(16)\n"
593 "VTG_GLOBAL g_aVTGArgLists, data\n");
594 uint32_t off = 0;
595 RTListForEach(&g_ProviderHead, pProvider, VTGPROVIDER, ListEntry)
596 {
597 RTListForEach(&pProvider->ProbeHead, pProbe, VTGPROBE, ListEntry)
598 {
599 if (pProbe->offArgList != UINT32_MAX)
600 continue;
601
602 /* Write it. */
603 pProbe->offArgList = off;
604 ScmStreamPrintf(pStrm,
605 " ; off=%u\n"
606 " db %2u ; Argument count\n"
607 " db %u ; fHaveLargeArgs\n"
608 " db 0, 0 ; Reserved\n"
609 , off, pProbe->cArgs, (int)pProbe->fHaveLargeArgs);
610 off += 4;
611 RTListForEach(&pProbe->ArgHead, pArg, VTGARG, ListEntry)
612 {
613 ScmStreamPrintf(pStrm,
614 " dd %8u ; type '%s' (name '%s')\n"
615 " dd 0%08xh ; type flags\n",
616 strtabGetOff(pArg->pszType), pArg->pszType, pArg->pszName,
617 pArg->fType);
618 off += 8;
619 }
620
621 /* Look for matching argument lists (lazy bird walks the whole list). */
622 PVTGPROVIDER pProv2;
623 RTListForEach(&g_ProviderHead, pProv2, VTGPROVIDER, ListEntry)
624 {
625 PVTGPROBE pProbe2;
626 RTListForEach(&pProvider->ProbeHead, pProbe2, VTGPROBE, ListEntry)
627 {
628 if (pProbe2->offArgList != UINT32_MAX)
629 continue;
630 if (pProbe2->cArgs != pProbe->cArgs)
631 continue;
632
633 PVTGARG pArg2;
634 pArg = RTListNodeGetNext(&pProbe->ArgHead, VTGARG, ListEntry);
635 pArg2 = RTListNodeGetNext(&pProbe2->ArgHead, VTGARG, ListEntry);
636 int32_t cArgs = pProbe->cArgs;
637 while ( cArgs-- > 0
638 && pArg2->pszType == pArg->pszType
639 && pArg2->fType == pArg->fType)
640 {
641 pArg = RTListNodeGetNext(&pArg->ListEntry, VTGARG, ListEntry);
642 pArg2 = RTListNodeGetNext(&pArg2->ListEntry, VTGARG, ListEntry);
643 }
644 if (cArgs >= 0)
645 continue;
646 pProbe2->offArgList = pProbe->offArgList;
647 }
648 }
649 }
650 }
651 ScmStreamPrintf(pStrm,
652 "VTG_GLOBAL g_aVTGArgLists_End, data\n");
653
654
655 /*
656 * Probe definitions.
657 */
658 ScmStreamPrintf(pStrm,
659 "\n"
660 ";\n"
661 "; Prob definitions.\n"
662 ";\n"
663 "ALIGNDATA(16)\n"
664 "VTG_GLOBAL g_aVTGProbes, data\n"
665 "\n");
666 uint32_t iProvider = 0;
667 uint32_t iProbe = 0;
668 RTListForEach(&g_ProviderHead, pProvider, VTGPROVIDER, ListEntry)
669 {
670 pProvider->iFirstProbe = iProbe;
671 RTListForEach(&pProvider->ProbeHead, pProbe, VTGPROBE, ListEntry)
672 {
673 ScmStreamPrintf(pStrm,
674 "VTG_GLOBAL g_VTGProbeData_%s_%s, data ; idx=#%4u\n"
675 " dd %6u ; offName\n"
676 " dd %6u ; offArgList\n"
677 " dw (NAME(g_cVTGProbeEnabled_%s_%s) - NAME(g_acVTGProbeEnabled)) / 4 ; idxEnabled\n"
678 " dw %6u ; idxProvider\n"
679 " dd NAME(g_VTGObjHeader) - NAME(g_VTGProbeData_%s_%s) ; offObjHdr\n"
680 ,
681 pProvider->pszName, pProbe->pszMangledName, iProbe,
682 strtabGetOff(pProbe->pszUnmangledName),
683 pProbe->offArgList,
684 pProvider->pszName, pProbe->pszMangledName,
685 iProvider,
686 pProvider->pszName, pProbe->pszMangledName
687 );
688 pProbe->iProbe = iProbe;
689 iProbe++;
690 }
691 pProvider->cProbes = iProbe - pProvider->iFirstProbe;
692 iProvider++;
693 }
694 ScmStreamPrintf(pStrm, "VTG_GLOBAL g_aVTGProbes_End, data\n");
695
696 /*
697 * The provider data.
698 */
699 ScmStreamPrintf(pStrm,
700 "\n"
701 ";\n"
702 "; Provider data.\n"
703 ";\n"
704 "ALIGNDATA(16)\n"
705 "VTG_GLOBAL g_aVTGProviders, data\n");
706 iProvider = 0;
707 RTListForEach(&g_ProviderHead, pProvider, VTGPROVIDER, ListEntry)
708 {
709 ScmStreamPrintf(pStrm,
710 " ; idx=#%4u - %s\n"
711 " dd %6u ; name\n"
712 " dw %6u ; index of first probe\n"
713 " dw %6u ; count of probes\n"
714 " db %d, %d, %d ; AttrSelf\n"
715 " db %d, %d, %d ; AttrModules\n"
716 " db %d, %d, %d ; AttrFunctions\n"
717 " db %d, %d, %d ; AttrName\n"
718 " db %d, %d, %d ; AttrArguments\n"
719 " db 0 ; reserved\n"
720 ,
721 iProvider, pProvider->pszName,
722 strtabGetOff(pProvider->pszName),
723 pProvider->iFirstProbe,
724 pProvider->cProbes,
725 pProvider->AttrSelf.enmCode, pProvider->AttrSelf.enmData, pProvider->AttrSelf.enmDataDep,
726 pProvider->AttrModules.enmCode, pProvider->AttrModules.enmData, pProvider->AttrModules.enmDataDep,
727 pProvider->AttrFunctions.enmCode, pProvider->AttrFunctions.enmData, pProvider->AttrFunctions.enmDataDep,
728 pProvider->AttrName.enmCode, pProvider->AttrName.enmData, pProvider->AttrName.enmDataDep,
729 pProvider->AttrArguments.enmCode, pProvider->AttrArguments.enmData, pProvider->AttrArguments.enmDataDep);
730 iProvider++;
731 }
732 ScmStreamPrintf(pStrm, "VTG_GLOBAL g_aVTGProviders_End, data\n");
733
734 /*
735 * Declare the probe enable flags.
736 *
737 * These must be placed at the end so they'll end up adjacent to the probe
738 * locations. This is important for reducing the amount of memory we need
739 * to lock down for user mode modules.
740 */
741 ScmStreamPrintf(pStrm,
742 ";\n"
743 "; Probe enabled flags.\n"
744 ";\n"
745 "ALIGNDATA(16)\n"
746 "VTG_GLOBAL g_acVTGProbeEnabled, data\n"
747 );
748 uint32_t cProbes = 0;
749 RTListForEach(&g_ProviderHead, pProvider, VTGPROVIDER, ListEntry)
750 {
751 RTListForEach(&pProvider->ProbeHead, pProbe, VTGPROBE, ListEntry)
752 {
753 ScmStreamPrintf(pStrm,
754 "VTG_GLOBAL g_cVTGProbeEnabled_%s_%s, data\n"
755 " dd 0\n",
756 pProvider->pszName, pProbe->pszMangledName);
757 cProbes++;
758 }
759 }
760 ScmStreamPrintf(pStrm, "VTG_GLOBAL g_acVTGProbeEnabled_End, data\n");
761 if (cProbes >= _32K)
762 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Too many probes: %u (max %u)", cProbes, _32K - 1);
763
764
765 /*
766 * Emit code for the stub functions.
767 */
768 bool const fWin64 = g_cBits == 64 && (!strcmp(g_pszAssemblerFmtVal, "win64") || !strcmp(g_pszAssemblerFmtVal, "pe64"));
769 bool const fMachO64 = g_cBits == 64 && !strcmp(g_pszAssemblerFmtVal, "macho64");
770 bool const fMachO32 = g_cBits == 32 && !strcmp(g_pszAssemblerFmtVal, "macho32");
771 ScmStreamPrintf(pStrm,
772 "\n"
773 ";\n"
774 "; Prob stubs.\n"
775 ";\n"
776 "BEGINCODE\n"
777 "extern %sNAME(%s)\n",
778 g_fProbeFnImported ? "IMP" : "",
779 g_pszProbeFnName);
780 if (fMachO64 && g_fProbeFnImported && !g_fPic)
781 ScmStreamPrintf(pStrm,
782 "g_pfnVtgProbeFn:\n"
783 " dq NAME(%s)\n",
784 g_pszProbeFnName);
785
786 RTListForEach(&g_ProviderHead, pProvider, VTGPROVIDER, ListEntry)
787 {
788 RTListForEach(&pProvider->ProbeHead, pProbe, VTGPROBE, ListEntry)
789 {
790 ScmStreamPrintf(pStrm,
791 "\n"
792 "VTG_GLOBAL VTGProbeStub_%s_%s, function; (VBOXTPGPROBELOC pVTGProbeLoc",
793 pProvider->pszName, pProbe->pszMangledName);
794 RTListForEach(&pProbe->ArgHead, pArg, VTGARG, ListEntry)
795 {
796 ScmStreamPrintf(pStrm, ", %s %s", pArg->pszType, pArg->pszName);
797 }
798 ScmStreamPrintf(pStrm,
799 ");\n");
800
801 /*
802 * Check if the probe in question is enabled.
803 */
804 if (g_cBits == 32)
805 ScmStreamPrintf(pStrm,
806 " mov eax, [esp + 4]\n"
807 " test byte [eax+3], 0x80 ; fEnabled == true?\n"
808 " jz .return ; jump on false\n");
809 else if (fWin64)
810 ScmStreamPrintf(pStrm,
811 " test byte [rcx+3], 0x80 ; fEnabled == true?\n"
812 " jz .return ; jump on false\n");
813 else
814 ScmStreamPrintf(pStrm,
815 " test byte [rdi+3], 0x80 ; fEnabled == true?\n"
816 " jz .return ; jump on false\n");
817
818 /*
819 * Jump to the fire-probe function.
820 */
821 if (g_cBits == 32)
822 ScmStreamPrintf(pStrm, g_fPic ?
823 " call .mov_ecx_eip_plus_5\n"
824 ".got_eip:\n"
825 " add ecx, _GLOBAL_OFFSET_TABLE + ($$ - .got_eip) wrt ..gotpc\n"
826 " mov ecx, [%s@GOT + ecx]\n"
827 " jmp ecx\n"
828 ".mov_ecx_eip_plus_5:\n"
829 " pop ecx\n"
830 " jmp ecx\n"
831 : g_fProbeFnImported ?
832 " mov ecx, IMP2(%s)\n"
833 " jmp ecx\n"
834 :
835 " jmp NAME(%s)\n"
836 , g_pszProbeFnName);
837 else if (fWin64)
838 ScmStreamPrintf(pStrm, g_fProbeFnImported ?
839 " mov rax, IMP2(%s)\n"
840 " jmp rax\n"
841 :
842 " jmp NAME(%s)\n"
843 , g_pszProbeFnName);
844 else if (fMachO64 && g_fProbeFnImported)
845 ScmStreamPrintf(pStrm,
846 " jmp [g_pfnVtgProbeFn wrt rip]\n");
847 else
848 ScmStreamPrintf(pStrm, g_fPic ?
849 " jmp [rel %s wrt ..got]\n"
850 : g_fProbeFnImported ?
851 " lea rax, [IMP2(%s)]\n"
852 " jmp rax\n"
853 :
854 " jmp NAME(%s)\n"
855 , g_pszProbeFnName);
856
857 ScmStreamPrintf(pStrm,
858 ".return:\n"
859 " ret ; The probe was disabled, return\n"
860 "\n");
861 }
862 }
863
864 return RTEXITCODE_SUCCESS;
865}
866
867
868static RTEXITCODE generateObject(const char *pszOutput, const char *pszTempAsm)
869{
870 if (!pszTempAsm)
871 {
872 size_t cch = strlen(pszOutput);
873 char *psz = (char *)alloca(cch + sizeof(".asm"));
874 memcpy(psz, pszOutput, cch);
875 memcpy(psz + cch, ".asm", sizeof(".asm"));
876 pszTempAsm = psz;
877 }
878
879 RTEXITCODE rcExit = generateFile(pszTempAsm, "assembly", generateAssembly);
880 if (rcExit == RTEXITCODE_SUCCESS)
881 rcExit = generateInvokeAssembler(pszOutput, pszTempAsm);
882 RTFileDelete(pszTempAsm);
883 return rcExit;
884}
885
886
887static RTEXITCODE generateProbeDefineName(char *pszBuf, size_t cbBuf, const char *pszProvider, const char *pszProbe)
888{
889 size_t cbMax = strlen(pszProvider) + 1 + strlen(pszProbe) + 1;
890 if (cbMax > cbBuf || cbMax > 80)
891 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Probe '%s' in provider '%s' ends up with a too long defined\n", pszProbe, pszProvider);
892
893 while (*pszProvider)
894 *pszBuf++ = RT_C_TO_UPPER(*pszProvider++);
895
896 *pszBuf++ = '_';
897
898 while (*pszProbe)
899 {
900 if (pszProbe[0] == '_' && pszProbe[1] == '_')
901 pszProbe++;
902 *pszBuf++ = RT_C_TO_UPPER(*pszProbe++);
903 }
904
905 *pszBuf = '\0';
906 return RTEXITCODE_SUCCESS;
907}
908
909static RTEXITCODE generateHeaderInner(PSCMSTREAM pStrm)
910{
911 /*
912 * Calc the double inclusion blocker define and then write the file header.
913 */
914 char szTmp[4096];
915 const char *pszName = RTPathFilename(g_pszScript);
916 size_t cchName = strlen(pszName);
917 if (cchName >= sizeof(szTmp) - 64)
918 return RTMsgErrorExit(RTEXITCODE_FAILURE, "File name is too long '%s'", pszName);
919 szTmp[0] = '_';
920 szTmp[1] = '_';
921 szTmp[2] = '_';
922 memcpy(&szTmp[3], pszName, cchName);
923 szTmp[3 + cchName + 0] = '_';
924 szTmp[3 + cchName + 1] = '_';
925 szTmp[3 + cchName + 2] = '_';
926 szTmp[3 + cchName + 3] = '\0';
927 char *psz = &szTmp[3];
928 while (*psz)
929 {
930 if (!RT_C_IS_ALNUM(*psz) && *psz != '_')
931 *psz = '_';
932 psz++;
933 }
934
935 ScmStreamPrintf(pStrm,
936 "/* $Id: VBoxTpG.cpp 41117 2012-05-02 14:22:29Z vboxsync $ */\n"
937 "/** @file\n"
938 " * Automatically generated from %s. Do NOT edit!\n"
939 " */\n"
940 "\n"
941 "#ifndef %s\n"
942 "#define %s\n"
943 "\n"
944 "#include <VBox/VBoxTpG.h>\n"
945 "\n"
946 "RT_C_DECLS_BEGIN\n"
947 "\n"
948 "#ifdef VBOX_WITH_DTRACE\n"
949 "\n"
950 "# ifdef _MSC_VER\n"
951 "# pragma data_seg(VTG_LOC_SECT)\n"
952 "# pragma data_seg()\n"
953 "# endif\n"
954 "\n"
955 ,
956 g_pszScript,
957 szTmp,
958 szTmp);
959
960 /*
961 * Declare data, code and macros for each probe.
962 */
963 PVTGPROVIDER pProv;
964 PVTGPROBE pProbe;
965 PVTGARG pArg;
966 RTListForEach(&g_ProviderHead, pProv, VTGPROVIDER, ListEntry)
967 {
968 RTListForEach(&pProv->ProbeHead, pProbe, VTGPROBE, ListEntry)
969 {
970 ScmStreamPrintf(pStrm,
971 "extern uint32_t g_cVTGProbeEnabled_%s_%s;\n"
972 "extern uint8_t g_VTGProbeData_%s_%s;\n"
973 "DECLASM(void) VTGProbeStub_%s_%s(PVTGPROBELOC",
974 pProv->pszName, pProbe->pszMangledName,
975 pProv->pszName, pProbe->pszMangledName,
976 pProv->pszName, pProbe->pszMangledName);
977 RTListForEach(&pProbe->ArgHead, pArg, VTGARG, ListEntry)
978 {
979 ScmStreamPrintf(pStrm, ", %s", pArg->pszType);
980 }
981 generateProbeDefineName(szTmp, sizeof(szTmp), pProv->pszName, pProbe->pszMangledName);
982 ScmStreamPrintf(pStrm,
983 ");\n"
984 "# define %s_ENABLED() \\\n"
985 " (RT_UNLIKELY(g_cVTGProbeEnabled_%s_%s)) \n"
986 "# define %s("
987 , szTmp,
988 pProv->pszName, pProbe->pszMangledName,
989 szTmp);
990 RTListForEach(&pProbe->ArgHead, pArg, VTGARG, ListEntry)
991 {
992 if (RTListNodeIsFirst(&pProbe->ArgHead, &pArg->ListEntry))
993 ScmStreamPrintf(pStrm, "%s", pArg->pszName);
994 else
995 ScmStreamPrintf(pStrm, ", %s", pArg->pszName);
996 }
997 ScmStreamPrintf(pStrm,
998 ") \\\n"
999 " do { \\\n"
1000 " if (RT_UNLIKELY(g_cVTGProbeEnabled_%s_%s)) \\\n"
1001 " { \\\n"
1002 " VTG_DECL_VTGPROBELOC(s_VTGProbeLoc) = \\\n"
1003 " { __LINE__, 0, 0, __FUNCTION__, &g_VTGProbeData_%s_%s }; \\\n"
1004 " VTGProbeStub_%s_%s(&s_VTGProbeLoc",
1005 pProv->pszName, pProbe->pszMangledName,
1006 pProv->pszName, pProbe->pszMangledName,
1007 pProv->pszName, pProbe->pszMangledName);
1008 RTListForEach(&pProbe->ArgHead, pArg, VTGARG, ListEntry)
1009 {
1010 ScmStreamPrintf(pStrm, ", %s", pArg->pszName);
1011 }
1012 ScmStreamPrintf(pStrm,
1013 "); \\\n"
1014 " } \\\n"
1015 " { \\\n" );
1016 uint32_t iArg = 0;
1017 RTListForEach(&pProbe->ArgHead, pArg, VTGARG, ListEntry)
1018 {
1019 if (pArg->fType & VTG_TYPE_FIXED_SIZED)
1020 ScmStreamPrintf(pStrm,
1021 " AssertCompile(sizeof(%s) == %u); \\\n"
1022 " AssertCompile(sizeof(%s) <= %u); \\\n",
1023 pArg->pszType, pArg->fType & VTG_TYPE_SIZE_MASK,
1024 pArg->pszName, pArg->fType & VTG_TYPE_SIZE_MASK);
1025 else if (pArg->fType & (VTG_TYPE_POINTER | VTG_TYPE_HC_ARCH_SIZED))
1026 ScmStreamPrintf(pStrm,
1027 " AssertCompile(sizeof(%s) <= sizeof(uintptr_t)); \\\n"
1028 " AssertCompile(sizeof(%s) <= sizeof(uintptr_t)); \\\n",
1029 pArg->pszName,
1030 pArg->pszType);
1031 iArg++;
1032 }
1033 ScmStreamPrintf(pStrm,
1034 " } \\\n"
1035 " } while (0)\n"
1036 "\n");
1037 }
1038 }
1039
1040 ScmStreamPrintf(pStrm,
1041 "\n"
1042 "#else\n"
1043 "\n");
1044 RTListForEach(&g_ProviderHead, pProv, VTGPROVIDER, ListEntry)
1045 {
1046 RTListForEach(&pProv->ProbeHead, pProbe, VTGPROBE, ListEntry)
1047 {
1048 generateProbeDefineName(szTmp, sizeof(szTmp), pProv->pszName, pProbe->pszMangledName);
1049 ScmStreamPrintf(pStrm,
1050 "# define %s_ENABLED() (false)\n"
1051 "# define %s("
1052 , szTmp, szTmp);
1053 RTListForEach(&pProbe->ArgHead, pArg, VTGARG, ListEntry)
1054 {
1055 if (RTListNodeIsFirst(&pProbe->ArgHead, &pArg->ListEntry))
1056 ScmStreamPrintf(pStrm, "%s", pArg->pszName);
1057 else
1058 ScmStreamPrintf(pStrm, ", %s", pArg->pszName);
1059 }
1060 ScmStreamPrintf(pStrm,
1061 ") do { } while (0)\n");
1062 }
1063 }
1064
1065 ScmStreamWrite(pStrm, RT_STR_TUPLE("\n"
1066 "#endif\n"
1067 "\n"
1068 "RT_C_DECLS_END\n"
1069 "#endif\n"));
1070 return RTEXITCODE_SUCCESS;
1071}
1072
1073
1074static RTEXITCODE generateHeader(const char *pszHeader)
1075{
1076 return generateFile(pszHeader, "header", generateHeaderInner);
1077}
1078
1079/**
1080 * If the given C word is at off - 1, return @c true and skip beyond it,
1081 * otherwise return @c false.
1082 *
1083 * @retval true if the given C-word is at the current position minus one char.
1084 * The stream position changes.
1085 * @retval false if not. The stream position is unchanged.
1086 *
1087 * @param pStream The stream.
1088 * @param cchWord The length of the word.
1089 * @param pszWord The word.
1090 */
1091bool ScmStreamCMatchingWordM1(PSCMSTREAM pStream, const char *pszWord, size_t cchWord)
1092{
1093 /* Check stream state. */
1094 AssertReturn(!pStream->fWriteOrRead, false);
1095 AssertReturn(RT_SUCCESS(pStream->rc), false);
1096 AssertReturn(pStream->fFullyLineated, false);
1097
1098 /* Sufficient chars left on the line? */
1099 size_t const iLine = pStream->iLine;
1100 AssertReturn(pStream->off > pStream->paLines[iLine].off, false);
1101 size_t const cchLeft = pStream->paLines[iLine].cch + pStream->paLines[iLine].off - (pStream->off - 1);
1102 if (cchWord > cchLeft)
1103 return false;
1104
1105 /* Do they match? */
1106 const char *psz = &pStream->pch[pStream->off - 1];
1107 if (memcmp(psz, pszWord, cchWord))
1108 return false;
1109
1110 /* Is it the end of a C word? */
1111 if (cchWord < cchLeft)
1112 {
1113 psz += cchWord;
1114 if (RT_C_IS_ALNUM(*psz) || *psz == '_')
1115 return false;
1116 }
1117
1118 /* Skip ahead. */
1119 pStream->off += cchWord - 1;
1120 return true;
1121}
1122
1123/**
1124 * Get's the C word starting at the current position.
1125 *
1126 * @returns Pointer to the word on success and the stream position advanced to
1127 * the end of it.
1128 * NULL on failure, stream position normally unchanged.
1129 * @param pStream The stream to get the C word from.
1130 * @param pcchWord Where to return the word length.
1131 */
1132const char *ScmStreamCGetWord(PSCMSTREAM pStream, size_t *pcchWord)
1133{
1134 /* Check stream state. */
1135 AssertReturn(!pStream->fWriteOrRead, NULL);
1136 AssertReturn(RT_SUCCESS(pStream->rc), NULL);
1137 AssertReturn(pStream->fFullyLineated, NULL);
1138
1139 /* Get the number of chars left on the line and locate the current char. */
1140 size_t const iLine = pStream->iLine;
1141 size_t const cchLeft = pStream->paLines[iLine].cch + pStream->paLines[iLine].off - pStream->off;
1142 const char *psz = &pStream->pch[pStream->off];
1143
1144 /* Is it a leading C character. */
1145 if (!RT_C_IS_ALPHA(*psz) && *psz == '_')
1146 return NULL;
1147
1148 /* Find the end of the word. */
1149 char ch;
1150 size_t off = 1;
1151 while ( off < cchLeft
1152 && ( (ch = psz[off]) == '_'
1153 || RT_C_IS_ALNUM(ch)))
1154 off++;
1155
1156 pStream->off += off;
1157 *pcchWord = off;
1158 return psz;
1159}
1160
1161
1162/**
1163 * Get's the C word starting at the current position minus one.
1164 *
1165 * @returns Pointer to the word on success and the stream position advanced to
1166 * the end of it.
1167 * NULL on failure, stream position normally unchanged.
1168 * @param pStream The stream to get the C word from.
1169 * @param pcchWord Where to return the word length.
1170 */
1171const char *ScmStreamCGetWordM1(PSCMSTREAM pStream, size_t *pcchWord)
1172{
1173 /* Check stream state. */
1174 AssertReturn(!pStream->fWriteOrRead, NULL);
1175 AssertReturn(RT_SUCCESS(pStream->rc), NULL);
1176 AssertReturn(pStream->fFullyLineated, NULL);
1177
1178 /* Get the number of chars left on the line and locate the current char. */
1179 size_t const iLine = pStream->iLine;
1180 size_t const cchLeft = pStream->paLines[iLine].cch + pStream->paLines[iLine].off - (pStream->off - 1);
1181 const char *psz = &pStream->pch[pStream->off - 1];
1182
1183 /* Is it a leading C character. */
1184 if (!RT_C_IS_ALPHA(*psz) && *psz == '_')
1185 return NULL;
1186
1187 /* Find the end of the word. */
1188 char ch;
1189 size_t off = 1;
1190 while ( off < cchLeft
1191 && ( (ch = psz[off]) == '_'
1192 || RT_C_IS_ALNUM(ch)))
1193 off++;
1194
1195 pStream->off += off - 1;
1196 *pcchWord = off;
1197 return psz;
1198}
1199
1200
1201/**
1202 * Parser error with line and position.
1203 *
1204 * @returns RTEXITCODE_FAILURE.
1205 * @param pStrm The stream.
1206 * @param cb The offset from the current position to the
1207 * point of failure.
1208 * @param pszMsg The message to display.
1209 */
1210static RTEXITCODE parseError(PSCMSTREAM pStrm, size_t cb, const char *pszMsg)
1211{
1212 if (cb)
1213 ScmStreamSeekRelative(pStrm, -(ssize_t)cb);
1214 size_t const off = ScmStreamTell(pStrm);
1215 size_t const iLine = ScmStreamTellLine(pStrm);
1216 ScmStreamSeekByLine(pStrm, iLine);
1217 size_t const offLine = ScmStreamTell(pStrm);
1218
1219 RTPrintf("%s:%d:%zd: error: %s.\n", g_pszScript, iLine + 1, off - offLine + 1, pszMsg);
1220
1221 size_t cchLine;
1222 SCMEOL enmEof;
1223 const char *pszLine = ScmStreamGetLineByNo(pStrm, iLine, &cchLine, &enmEof);
1224 if (pszLine)
1225 RTPrintf(" %.*s\n"
1226 " %*s^\n",
1227 cchLine, pszLine, off - offLine, "");
1228 return RTEXITCODE_FAILURE;
1229}
1230
1231
1232/**
1233 * Parser error with line and position.
1234 *
1235 * @returns RTEXITCODE_FAILURE.
1236 * @param pStrm The stream.
1237 * @param cb The offset from the current position to the
1238 * point of failure.
1239 * @param pszMsg The message to display.
1240 */
1241static RTEXITCODE parseErrorAbs(PSCMSTREAM pStrm, size_t off, const char *pszMsg)
1242{
1243 ScmStreamSeekAbsolute(pStrm, off);
1244 return parseError(pStrm, 0, pszMsg);
1245}
1246
1247/**
1248 * Handles a C++ one line comment.
1249 *
1250 * @returns Exit code.
1251 * @param pStrm The stream.
1252 */
1253static RTEXITCODE parseOneLineComment(PSCMSTREAM pStrm)
1254{
1255 ScmStreamSeekByLine(pStrm, ScmStreamTellLine(pStrm) + 1);
1256 return RTEXITCODE_SUCCESS;
1257}
1258
1259/**
1260 * Handles a multi-line C/C++ comment.
1261 *
1262 * @returns Exit code.
1263 * @param pStrm The stream.
1264 */
1265static RTEXITCODE parseMultiLineComment(PSCMSTREAM pStrm)
1266{
1267 unsigned ch;
1268 while ((ch = ScmStreamGetCh(pStrm)) != ~(unsigned)0)
1269 {
1270 if (ch == '*')
1271 {
1272 do
1273 ch = ScmStreamGetCh(pStrm);
1274 while (ch == '*');
1275 if (ch == '/')
1276 return RTEXITCODE_SUCCESS;
1277 }
1278 }
1279
1280 parseError(pStrm, 1, "Expected end of comment, got end of file");
1281 return RTEXITCODE_FAILURE;
1282}
1283
1284
1285/**
1286 * Skips spaces and comments.
1287 *
1288 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE.
1289 * @param pStrm The stream..
1290 */
1291static RTEXITCODE parseSkipSpacesAndComments(PSCMSTREAM pStrm)
1292{
1293 unsigned ch;
1294 while ((ch = ScmStreamPeekCh(pStrm)) != ~(unsigned)0)
1295 {
1296 if (!RT_C_IS_SPACE(ch) && ch != '/')
1297 return RTEXITCODE_SUCCESS;
1298 unsigned ch2 = ScmStreamGetCh(pStrm); AssertBreak(ch == ch2); NOREF(ch2);
1299 if (ch == '/')
1300 {
1301 ch = ScmStreamGetCh(pStrm);
1302 RTEXITCODE rcExit;
1303 if (ch == '*')
1304 rcExit = parseMultiLineComment(pStrm);
1305 else if (ch == '/')
1306 rcExit = parseOneLineComment(pStrm);
1307 else
1308 rcExit = parseError(pStrm, 2, "Unexpected character");
1309 if (rcExit != RTEXITCODE_SUCCESS)
1310 return rcExit;
1311 }
1312 }
1313
1314 return parseError(pStrm, 0, "Unexpected end of file");
1315}
1316
1317
1318/**
1319 * Skips spaces and comments, returning the next character.
1320 *
1321 * @returns Next non-space-non-comment character. ~(unsigned)0 on EOF or
1322 * failure.
1323 * @param pStrm The stream.
1324 */
1325static unsigned parseGetNextNonSpaceNonCommentCh(PSCMSTREAM pStrm)
1326{
1327 unsigned ch;
1328 while ((ch = ScmStreamGetCh(pStrm)) != ~(unsigned)0)
1329 {
1330 if (!RT_C_IS_SPACE(ch) && ch != '/')
1331 return ch;
1332 if (ch == '/')
1333 {
1334 ch = ScmStreamGetCh(pStrm);
1335 RTEXITCODE rcExit;
1336 if (ch == '*')
1337 rcExit = parseMultiLineComment(pStrm);
1338 else if (ch == '/')
1339 rcExit = parseOneLineComment(pStrm);
1340 else
1341 rcExit = parseError(pStrm, 2, "Unexpected character");
1342 if (rcExit != RTEXITCODE_SUCCESS)
1343 return ~(unsigned)0;
1344 }
1345 }
1346
1347 parseError(pStrm, 0, "Unexpected end of file");
1348 return ~(unsigned)0;
1349}
1350
1351
1352/**
1353 * Get the next non-space-non-comment character on a preprocessor line.
1354 *
1355 * @returns The next character. On error message and ~(unsigned)0.
1356 * @param pStrm The stream.
1357 */
1358static unsigned parseGetNextNonSpaceNonCommentChOnPpLine(PSCMSTREAM pStrm)
1359{
1360 size_t off = ScmStreamTell(pStrm) - 1;
1361 unsigned ch;
1362 while ((ch = ScmStreamGetCh(pStrm)) != ~(unsigned)0)
1363 {
1364 if (RT_C_IS_SPACE(ch))
1365 {
1366 if (ch == '\n' || ch == '\r')
1367 {
1368 parseErrorAbs(pStrm, off, "Invalid preprocessor statement");
1369 break;
1370 }
1371 }
1372 else if (ch == '\\')
1373 {
1374 size_t off2 = ScmStreamTell(pStrm) - 1;
1375 ch = ScmStreamGetCh(pStrm);
1376 if (ch == '\r')
1377 ch = ScmStreamGetCh(pStrm);
1378 if (ch != '\n')
1379 {
1380 parseErrorAbs(pStrm, off2, "Expected new line");
1381 break;
1382 }
1383 }
1384 else
1385 return ch;
1386 }
1387 return ~(unsigned)0;
1388}
1389
1390
1391
1392/**
1393 * Skips spaces and comments.
1394 *
1395 * @returns Same as ScmStreamCGetWord
1396 * @param pStrm The stream..
1397 * @param pcchWord Where to return the length.
1398 */
1399static const char *parseGetNextCWord(PSCMSTREAM pStrm, size_t *pcchWord)
1400{
1401 if (parseSkipSpacesAndComments(pStrm) != RTEXITCODE_SUCCESS)
1402 return NULL;
1403 return ScmStreamCGetWord(pStrm, pcchWord);
1404}
1405
1406
1407
1408/**
1409 * Parses interface stability.
1410 *
1411 * @returns Interface stability if parsed correctly, otherwise error message and
1412 * kVTGStability_Invalid.
1413 * @param pStrm The stream.
1414 * @param ch The first character in the stability spec.
1415 */
1416static kVTGStability parseStability(PSCMSTREAM pStrm, unsigned ch)
1417{
1418 switch (ch)
1419 {
1420 case 'E':
1421 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("External")))
1422 return kVTGStability_External;
1423 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("Evolving")))
1424 return kVTGStability_Evolving;
1425 break;
1426 case 'I':
1427 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("Internal")))
1428 return kVTGStability_Internal;
1429 break;
1430 case 'O':
1431 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("Obsolete")))
1432 return kVTGStability_Obsolete;
1433 break;
1434 case 'P':
1435 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("Private")))
1436 return kVTGStability_Private;
1437 break;
1438 case 'S':
1439 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("Stable")))
1440 return kVTGStability_Stable;
1441 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("Standard")))
1442 return kVTGStability_Standard;
1443 break;
1444 case 'U':
1445 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("Unstable")))
1446 return kVTGStability_Unstable;
1447 break;
1448 }
1449 parseError(pStrm, 1, "Unknown stability specifier");
1450 return kVTGStability_Invalid;
1451}
1452
1453
1454/**
1455 * Parses data depndency class.
1456 *
1457 * @returns Data dependency class if parsed correctly, otherwise error message
1458 * and kVTGClass_Invalid.
1459 * @param pStrm The stream.
1460 * @param ch The first character in the stability spec.
1461 */
1462static kVTGClass parseDataDepClass(PSCMSTREAM pStrm, unsigned ch)
1463{
1464 switch (ch)
1465 {
1466 case 'C':
1467 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("Common")))
1468 return kVTGClass_Common;
1469 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("Cpu")))
1470 return kVTGClass_Cpu;
1471 break;
1472 case 'G':
1473 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("Group")))
1474 return kVTGClass_Group;
1475 break;
1476 case 'I':
1477 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("Isa")))
1478 return kVTGClass_Isa;
1479 break;
1480 case 'P':
1481 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("Platform")))
1482 return kVTGClass_Platform;
1483 break;
1484 case 'U':
1485 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("Unknown")))
1486 return kVTGClass_Unknown;
1487 break;
1488 }
1489 parseError(pStrm, 1, "Unknown data dependency class specifier");
1490 return kVTGClass_Invalid;
1491}
1492
1493/**
1494 * Parses a pragma D attributes statement.
1495 *
1496 * @returns Suitable exit code, errors message already written on failure.
1497 * @param pStrm The stream.
1498 */
1499static RTEXITCODE parsePragmaDAttributes(PSCMSTREAM pStrm)
1500{
1501 /*
1502 * "CodeStability/DataStability/DataDepClass" - no spaces allowed.
1503 */
1504 unsigned ch = parseGetNextNonSpaceNonCommentChOnPpLine(pStrm);
1505 if (ch == ~(unsigned)0)
1506 return RTEXITCODE_FAILURE;
1507
1508 kVTGStability enmCode = parseStability(pStrm, ch);
1509 if (enmCode == kVTGStability_Invalid)
1510 return RTEXITCODE_FAILURE;
1511 ch = ScmStreamGetCh(pStrm);
1512 if (ch != '/')
1513 return parseError(pStrm, 1, "Expected '/' following the code stability specifier");
1514
1515 kVTGStability enmData = parseStability(pStrm, ScmStreamGetCh(pStrm));
1516 if (enmData == kVTGStability_Invalid)
1517 return RTEXITCODE_FAILURE;
1518 ch = ScmStreamGetCh(pStrm);
1519 if (ch != '/')
1520 return parseError(pStrm, 1, "Expected '/' following the data stability specifier");
1521
1522 kVTGClass enmDataDep = parseDataDepClass(pStrm, ScmStreamGetCh(pStrm));
1523 if (enmDataDep == kVTGClass_Invalid)
1524 return RTEXITCODE_FAILURE;
1525
1526 /*
1527 * Expecting 'provider' followed by the name of an provider defined earlier.
1528 */
1529 ch = parseGetNextNonSpaceNonCommentChOnPpLine(pStrm);
1530 if (ch == ~(unsigned)0)
1531 return RTEXITCODE_FAILURE;
1532 if (ch != 'p' || !ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("provider")))
1533 return parseError(pStrm, 1, "Expected 'provider'");
1534
1535 size_t cchName;
1536 const char *pszName = parseGetNextCWord(pStrm, &cchName);
1537 if (!pszName)
1538 return parseError(pStrm, 1, "Expected provider name");
1539
1540 PVTGPROVIDER pProv;
1541 RTListForEach(&g_ProviderHead, pProv, VTGPROVIDER, ListEntry)
1542 {
1543 if ( !strncmp(pProv->pszName, pszName, cchName)
1544 && pProv->pszName[cchName] == '\0')
1545 break;
1546 }
1547 if (RTListNodeIsDummy(&g_ProviderHead, pProv, VTGPROVIDER, ListEntry))
1548 return parseError(pStrm, cchName, "Provider not found");
1549
1550 /*
1551 * Which aspect of the provider?
1552 */
1553 size_t cchAspect;
1554 const char *pszAspect = parseGetNextCWord(pStrm, &cchAspect);
1555 if (!pszAspect)
1556 return parseError(pStrm, 1, "Expected provider aspect");
1557
1558 PVTGATTRS pAttrs;
1559 if (cchAspect == 8 && !memcmp(pszAspect, "provider", 8))
1560 pAttrs = &pProv->AttrSelf;
1561 else if (cchAspect == 8 && !memcmp(pszAspect, "function", 8))
1562 pAttrs = &pProv->AttrFunctions;
1563 else if (cchAspect == 6 && !memcmp(pszAspect, "module", 6))
1564 pAttrs = &pProv->AttrModules;
1565 else if (cchAspect == 4 && !memcmp(pszAspect, "name", 4))
1566 pAttrs = &pProv->AttrName;
1567 else if (cchAspect == 4 && !memcmp(pszAspect, "args", 4))
1568 pAttrs = &pProv->AttrArguments;
1569 else
1570 return parseError(pStrm, cchAspect, "Unknown aspect");
1571
1572 if (pAttrs->enmCode != kVTGStability_Invalid)
1573 return parseError(pStrm, cchAspect, "You have already specified these attributes");
1574
1575 pAttrs->enmCode = enmCode;
1576 pAttrs->enmData = enmData;
1577 pAttrs->enmDataDep = enmDataDep;
1578 return RTEXITCODE_SUCCESS;
1579}
1580
1581/**
1582 * Parses a D pragma statement.
1583 *
1584 * @returns Suitable exit code, errors message already written on failure.
1585 * @param pStrm The stream.
1586 */
1587static RTEXITCODE parsePragma(PSCMSTREAM pStrm)
1588{
1589 RTEXITCODE rcExit;
1590 unsigned ch = parseGetNextNonSpaceNonCommentChOnPpLine(pStrm);
1591 if (ch == ~(unsigned)0)
1592 rcExit = RTEXITCODE_FAILURE;
1593 else if (ch == 'D' && ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("D")))
1594 {
1595 ch = parseGetNextNonSpaceNonCommentChOnPpLine(pStrm);
1596 if (ch == ~(unsigned)0)
1597 rcExit = RTEXITCODE_FAILURE;
1598 else if (ch == 'a' && ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("attributes")))
1599 rcExit = parsePragmaDAttributes(pStrm);
1600 else
1601 rcExit = parseError(pStrm, 1, "Unknown pragma D");
1602 }
1603 else
1604 rcExit = parseError(pStrm, 1, "Unknown pragma");
1605 return rcExit;
1606}
1607
1608
1609/**
1610 * Classifies the given type expression.
1611 *
1612 * @return Type flags.
1613 * @param pszType The type expression.
1614 */
1615static uint32_t parseTypeExpression(const char *pszType)
1616{
1617 size_t cchType = strlen(pszType);
1618#define MY_STRMATCH(a_sz) (cchType == sizeof(a_sz) - 1 && !memcmp(a_sz, pszType, sizeof(a_sz) - 1))
1619
1620 /*
1621 * Try detect pointers.
1622 */
1623 if (pszType[cchType - 1] == '*') return VTG_TYPE_POINTER;
1624 if (pszType[cchType - 1] == '&')
1625 {
1626 RTMsgWarning("Please avoid using references like '%s' for probe arguments!", pszType);
1627 return VTG_TYPE_POINTER;
1628 }
1629
1630 /*
1631 * Standard integer types and IPRT variants.
1632 * It's important that we catch all types larger than 32-bit here or we'll
1633 * screw up the probe argument handling.
1634 */
1635 if (MY_STRMATCH("int")) return VTG_TYPE_FIXED_SIZED | sizeof(int) | VTG_TYPE_SIGNED;
1636 if (MY_STRMATCH("uintptr_t")) return VTG_TYPE_HC_ARCH_SIZED | VTG_TYPE_UNSIGNED;
1637 if (MY_STRMATCH("intptr_t")) return VTG_TYPE_HC_ARCH_SIZED | VTG_TYPE_SIGNED;
1638
1639 //if (MY_STRMATCH("uint128_t")) return VTG_TYPE_FIXED_SIZED | sizeof(uint128_t) | VTG_TYPE_UNSIGNED;
1640 if (MY_STRMATCH("uint64_t")) return VTG_TYPE_FIXED_SIZED | sizeof(uint64_t) | VTG_TYPE_UNSIGNED;
1641 if (MY_STRMATCH("uint32_t")) return VTG_TYPE_FIXED_SIZED | sizeof(uint32_t) | VTG_TYPE_UNSIGNED;
1642 if (MY_STRMATCH("uint16_t")) return VTG_TYPE_FIXED_SIZED | sizeof(uint16_t) | VTG_TYPE_UNSIGNED;
1643 if (MY_STRMATCH("uint8_t")) return VTG_TYPE_FIXED_SIZED | sizeof(uint8_t) | VTG_TYPE_UNSIGNED;
1644
1645 //if (MY_STRMATCH("int128_t")) return VTG_TYPE_FIXED_SIZED | sizeof(int128_t) | VTG_TYPE_SIGNED;
1646 if (MY_STRMATCH("int64_t")) return VTG_TYPE_FIXED_SIZED | sizeof(int64_t) | VTG_TYPE_SIGNED;
1647 if (MY_STRMATCH("int32_t")) return VTG_TYPE_FIXED_SIZED | sizeof(int32_t) | VTG_TYPE_SIGNED;
1648 if (MY_STRMATCH("int16_t")) return VTG_TYPE_FIXED_SIZED | sizeof(int16_t) | VTG_TYPE_SIGNED;
1649 if (MY_STRMATCH("int8_t")) return VTG_TYPE_FIXED_SIZED | sizeof(int8_t) | VTG_TYPE_SIGNED;
1650
1651 if (MY_STRMATCH("RTUINT64U")) return VTG_TYPE_FIXED_SIZED | sizeof(uint64_t) | VTG_TYPE_UNSIGNED;
1652 if (MY_STRMATCH("RTUINT32U")) return VTG_TYPE_FIXED_SIZED | sizeof(uint32_t) | VTG_TYPE_UNSIGNED;
1653 if (MY_STRMATCH("RTUINT16U")) return VTG_TYPE_FIXED_SIZED | sizeof(uint16_t) | VTG_TYPE_UNSIGNED;
1654
1655 if (MY_STRMATCH("RTMSINTERVAL")) return VTG_TYPE_FIXED_SIZED | sizeof(RTMSINTERVAL) | VTG_TYPE_UNSIGNED;
1656 if (MY_STRMATCH("RTTIMESPEC")) return VTG_TYPE_FIXED_SIZED | sizeof(RTTIMESPEC) | VTG_TYPE_SIGNED;
1657 if (MY_STRMATCH("RTPROCESS")) return VTG_TYPE_FIXED_SIZED | sizeof(RTPROCESS) | VTG_TYPE_UNSIGNED;
1658 if (MY_STRMATCH("RTHCPHYS")) return VTG_TYPE_FIXED_SIZED | sizeof(RTHCPHYS) | VTG_TYPE_UNSIGNED | VTG_TYPE_PHYS;
1659
1660 if (MY_STRMATCH("RTR3PTR")) return VTG_TYPE_CTX_POINTER | VTG_TYPE_CTX_R3;
1661 if (MY_STRMATCH("RTR0PTR")) return VTG_TYPE_CTX_POINTER | VTG_TYPE_CTX_R0;
1662 if (MY_STRMATCH("RTRCPTR")) return VTG_TYPE_CTX_POINTER | VTG_TYPE_CTX_RC;
1663 if (MY_STRMATCH("RTHCPTR")) return VTG_TYPE_CTX_POINTER | VTG_TYPE_CTX_R3 | VTG_TYPE_CTX_R0;
1664
1665 if (MY_STRMATCH("RTR3UINTPTR")) return VTG_TYPE_CTX_POINTER | VTG_TYPE_CTX_R3 | VTG_TYPE_UNSIGNED;
1666 if (MY_STRMATCH("RTR0UINTPTR")) return VTG_TYPE_CTX_POINTER | VTG_TYPE_CTX_R0 | VTG_TYPE_UNSIGNED;
1667 if (MY_STRMATCH("RTRCUINTPTR")) return VTG_TYPE_CTX_POINTER | VTG_TYPE_CTX_RC | VTG_TYPE_UNSIGNED;
1668 if (MY_STRMATCH("RTHCUINTPTR")) return VTG_TYPE_CTX_POINTER | VTG_TYPE_CTX_R3 | VTG_TYPE_CTX_R0 | VTG_TYPE_UNSIGNED;
1669
1670 if (MY_STRMATCH("RTR3INTPTR")) return VTG_TYPE_CTX_POINTER | VTG_TYPE_CTX_R3 | VTG_TYPE_SIGNED;
1671 if (MY_STRMATCH("RTR0INTPTR")) return VTG_TYPE_CTX_POINTER | VTG_TYPE_CTX_R0 | VTG_TYPE_SIGNED;
1672 if (MY_STRMATCH("RTRCINTPTR")) return VTG_TYPE_CTX_POINTER | VTG_TYPE_CTX_RC | VTG_TYPE_SIGNED;
1673 if (MY_STRMATCH("RTHCINTPTR")) return VTG_TYPE_CTX_POINTER | VTG_TYPE_CTX_R3 | VTG_TYPE_CTX_R0 | VTG_TYPE_SIGNED;
1674
1675 if (MY_STRMATCH("RTUINTPTR")) return VTG_TYPE_CTX_POINTER | VTG_TYPE_CTX_R3 | VTG_TYPE_CTX_R0 | VTG_TYPE_CTX_RC | VTG_TYPE_UNSIGNED;
1676 if (MY_STRMATCH("RTINTPTR")) return VTG_TYPE_CTX_POINTER | VTG_TYPE_CTX_R3 | VTG_TYPE_CTX_R0 | VTG_TYPE_CTX_RC | VTG_TYPE_SIGNED;
1677
1678 if (MY_STRMATCH("RTHCUINTREG")) return VTG_TYPE_HC_ARCH_SIZED | VTG_TYPE_CTX_R3 | VTG_TYPE_CTX_R0 | VTG_TYPE_UNSIGNED;
1679 if (MY_STRMATCH("RTR3UINTREG")) return VTG_TYPE_HC_ARCH_SIZED | VTG_TYPE_CTX_R3 | VTG_TYPE_UNSIGNED;
1680 if (MY_STRMATCH("RTR0UINTREG")) return VTG_TYPE_HC_ARCH_SIZED | VTG_TYPE_CTX_R3 | VTG_TYPE_UNSIGNED;
1681
1682 if (MY_STRMATCH("RTGCUINTREG")) return VTG_TYPE_FIXED_SIZED | sizeof(RTGCUINTREG) | VTG_TYPE_UNSIGNED | VTG_TYPE_CTX_GST;
1683 if (MY_STRMATCH("RTGCPTR")) return VTG_TYPE_FIXED_SIZED | sizeof(RTGCPTR) | VTG_TYPE_UNSIGNED | VTG_TYPE_CTX_GST;
1684 if (MY_STRMATCH("RTGCINTPTR")) return VTG_TYPE_FIXED_SIZED | sizeof(RTGCUINTPTR) | VTG_TYPE_SIGNED | VTG_TYPE_CTX_GST;
1685 if (MY_STRMATCH("RTGCPTR32")) return VTG_TYPE_FIXED_SIZED | sizeof(RTGCPTR32) | VTG_TYPE_SIGNED | VTG_TYPE_CTX_GST;
1686 if (MY_STRMATCH("RTGCPTR64")) return VTG_TYPE_FIXED_SIZED | sizeof(RTGCPTR64) | VTG_TYPE_SIGNED | VTG_TYPE_CTX_GST;
1687 if (MY_STRMATCH("RTGCPHYS")) return VTG_TYPE_FIXED_SIZED | sizeof(RTGCPHYS) | VTG_TYPE_UNSIGNED | VTG_TYPE_PHYS | VTG_TYPE_CTX_GST;
1688 if (MY_STRMATCH("RTGCPHYS32")) return VTG_TYPE_FIXED_SIZED | sizeof(RTGCPHYS32) | VTG_TYPE_UNSIGNED | VTG_TYPE_PHYS | VTG_TYPE_CTX_GST;
1689 if (MY_STRMATCH("RTGCPHYS64")) return VTG_TYPE_FIXED_SIZED | sizeof(RTGCPHYS64) | VTG_TYPE_UNSIGNED | VTG_TYPE_PHYS | VTG_TYPE_CTX_GST;
1690
1691 /*
1692 * The special VBox types.
1693 */
1694 if (MY_STRMATCH("PVM")) return VTG_TYPE_CTX_POINTER;
1695 if (MY_STRMATCH("PVMCPU")) return VTG_TYPE_CTX_POINTER;
1696
1697 /*
1698 * Preaching time.
1699 */
1700 if ( MY_STRMATCH("unsigned long")
1701 || MY_STRMATCH("unsigned long long")
1702 || MY_STRMATCH("signed long")
1703 || MY_STRMATCH("signed long long")
1704 || MY_STRMATCH("long")
1705 || MY_STRMATCH("long long")
1706 || MY_STRMATCH("char")
1707 || MY_STRMATCH("signed char")
1708 || MY_STRMATCH("unsigned char")
1709 || MY_STRMATCH("double")
1710 || MY_STRMATCH("long double")
1711 || MY_STRMATCH("float")
1712 )
1713 {
1714 RTMsgError("Please do NOT use the type '%s' for probe arguments!", pszType);
1715 g_cTypeErrors++;
1716 return 0;
1717 }
1718
1719 if ( MY_STRMATCH("unsigned")
1720 || MY_STRMATCH("signed")
1721 || MY_STRMATCH("signed int")
1722 || MY_STRMATCH("unsigned int")
1723 || MY_STRMATCH("short")
1724 || MY_STRMATCH("signed short")
1725 || MY_STRMATCH("unsigned short")
1726 )
1727 RTMsgWarning("Please avoid using the type '%s' for probe arguments!", pszType);
1728 if (MY_STRMATCH("unsigned")) return VTG_TYPE_FIXED_SIZED | sizeof(int) | VTG_TYPE_UNSIGNED;
1729 if (MY_STRMATCH("unsigned int")) return VTG_TYPE_FIXED_SIZED | sizeof(int) | VTG_TYPE_UNSIGNED;
1730 if (MY_STRMATCH("signed")) return VTG_TYPE_FIXED_SIZED | sizeof(int) | VTG_TYPE_SIGNED;
1731 if (MY_STRMATCH("signed int")) return VTG_TYPE_FIXED_SIZED | sizeof(int) | VTG_TYPE_SIGNED;
1732 if (MY_STRMATCH("short")) return VTG_TYPE_FIXED_SIZED | sizeof(short) | VTG_TYPE_SIGNED;
1733 if (MY_STRMATCH("signed short")) return VTG_TYPE_FIXED_SIZED | sizeof(short) | VTG_TYPE_SIGNED;
1734 if (MY_STRMATCH("unsigned short")) return VTG_TYPE_FIXED_SIZED | sizeof(short) | VTG_TYPE_UNSIGNED;
1735
1736 /*
1737 * What we haven't caught by now is either unknown to us or wrong.
1738 */
1739 if (pszType[0] == 'P')
1740 {
1741 RTMsgError("Type '%s' looks like a pointer typedef, please do NOT use those "
1742 "but rather the non-pointer typedef or struct with '*'",
1743 pszType);
1744 g_cTypeErrors++;
1745 return VTG_TYPE_POINTER;
1746 }
1747
1748 RTMsgError("Don't know '%s' - please change or fix VBoxTpG", pszType);
1749 g_cTypeErrors++;
1750
1751#undef MY_STRCMP
1752 return 0;
1753}
1754
1755
1756/**
1757 * Unmangles the probe name.
1758 *
1759 * This involves translating double underscore to dash.
1760 *
1761 * @returns Pointer to the unmangled name in the string table.
1762 * @param pszMangled The mangled name.
1763 */
1764static const char *parseUnmangleProbeName(const char *pszMangled)
1765{
1766 size_t cchMangled = strlen(pszMangled);
1767 char *pszTmp = (char *)alloca(cchMangled + 2);
1768 const char *pszSrc = pszMangled;
1769 char *pszDst = pszTmp;
1770
1771 while (*pszSrc)
1772 {
1773 if (pszSrc[0] == '_' && pszSrc[1] == '_' && pszSrc[2] != '_')
1774 {
1775 *pszDst++ = '-';
1776 pszSrc += 2;
1777 }
1778 else
1779 *pszDst++ = *pszSrc++;
1780 }
1781 *pszDst = '\0';
1782
1783 return strtabInsertN(pszTmp, pszDst - pszTmp);
1784}
1785
1786
1787/**
1788 * Parses a D probe statement.
1789 *
1790 * @returns Suitable exit code, errors message already written on failure.
1791 * @param pStrm The stream.
1792 * @param pProv The provider being parsed.
1793 */
1794static RTEXITCODE parseProbe(PSCMSTREAM pStrm, PVTGPROVIDER pProv)
1795{
1796 /*
1797 * Next up is a name followed by an opening parenthesis.
1798 */
1799 size_t cchProbe;
1800 const char *pszProbe = parseGetNextCWord(pStrm, &cchProbe);
1801 if (!pszProbe)
1802 return parseError(pStrm, 1, "Expected a probe name starting with an alphabetical character");
1803 unsigned ch = parseGetNextNonSpaceNonCommentCh(pStrm);
1804 if (ch != '(')
1805 return parseError(pStrm, 1, "Expected '(' after the probe name");
1806
1807 /*
1808 * Create a probe instance.
1809 */
1810 PVTGPROBE pProbe = (PVTGPROBE)RTMemAllocZ(sizeof(*pProbe));
1811 if (!pProbe)
1812 return parseError(pStrm, 0, "Out of memory");
1813 RTListInit(&pProbe->ArgHead);
1814 RTListAppend(&pProv->ProbeHead, &pProbe->ListEntry);
1815 pProbe->offArgList = UINT32_MAX;
1816 pProbe->pszMangledName = RTStrDupN(pszProbe, cchProbe);
1817 if (!pProbe->pszMangledName)
1818 return parseError(pStrm, 0, "Out of memory");
1819 pProbe->pszUnmangledName = parseUnmangleProbeName(pProbe->pszMangledName);
1820 if (!pProbe->pszUnmangledName)
1821 return parseError(pStrm, 0, "Out of memory");
1822
1823 /*
1824 * Parse loop for the argument.
1825 */
1826 PVTGARG pArg = NULL;
1827 size_t cchName = 0;
1828 size_t cchArg = 0;
1829 char szArg[4096];
1830 for (;;)
1831 {
1832 ch = parseGetNextNonSpaceNonCommentCh(pStrm);
1833 switch (ch)
1834 {
1835 case ')':
1836 case ',':
1837 {
1838 /* commit the argument */
1839 if (pArg)
1840 {
1841 if (!cchName)
1842 return parseError(pStrm, 1, "Argument has no name");
1843 if (cchArg - cchName - 1 >= 128)
1844 return parseError(pStrm, 1, "Argument type too long");
1845 pArg->pszType = strtabInsertN(szArg, cchArg - cchName - 1);
1846 pArg->pszName = RTStrDupN(&szArg[cchArg - cchName], cchName);
1847 if (!pArg->pszType || !pArg->pszName)
1848 return parseError(pStrm, 1, "Out of memory");
1849 pArg->fType = parseTypeExpression(pArg->pszType);
1850 if (VTG_TYPE_IS_LARGE(pArg->fType))
1851 pProbe->fHaveLargeArgs = true;
1852
1853 pArg = NULL;
1854 cchName = cchArg = 0;
1855 }
1856 if (ch == ')')
1857 {
1858 size_t off = ScmStreamTell(pStrm);
1859 ch = parseGetNextNonSpaceNonCommentCh(pStrm);
1860 if (ch != ';')
1861 return parseErrorAbs(pStrm, off, "Expected ';'");
1862 return RTEXITCODE_SUCCESS;
1863 }
1864 break;
1865 }
1866
1867 default:
1868 {
1869 size_t cchWord;
1870 const char *pszWord = ScmStreamCGetWordM1(pStrm, &cchWord);
1871 if (!pszWord)
1872 return parseError(pStrm, 0, "Expected argument");
1873 if (!pArg)
1874 {
1875 pArg = (PVTGARG)RTMemAllocZ(sizeof(*pArg));
1876 if (!pArg)
1877 return parseError(pStrm, 1, "Out of memory");
1878 RTListAppend(&pProbe->ArgHead, &pArg->ListEntry);
1879 pProbe->cArgs++;
1880
1881 if (cchWord + 1 > sizeof(szArg))
1882 return parseError(pStrm, 1, "Too long parameter declaration");
1883 memcpy(szArg, pszWord, cchWord);
1884 szArg[cchWord] = '\0';
1885 cchArg = cchWord;
1886 cchName = 0;
1887 }
1888 else
1889 {
1890 if (cchArg + 1 + cchWord + 1 > sizeof(szArg))
1891 return parseError(pStrm, 1, "Too long parameter declaration");
1892
1893 szArg[cchArg++] = ' ';
1894 memcpy(&szArg[cchArg], pszWord, cchWord);
1895 cchArg += cchWord;
1896 szArg[cchArg] = '\0';
1897 cchName = cchWord;
1898 }
1899 break;
1900 }
1901
1902 case '*':
1903 {
1904 if (!pArg)
1905 return parseError(pStrm, 1, "A parameter type does not start with an asterix");
1906 if (cchArg + sizeof(" *") >= sizeof(szArg))
1907 return parseError(pStrm, 1, "Too long parameter declaration");
1908 szArg[cchArg++] = ' ';
1909 szArg[cchArg++] = '*';
1910 szArg[cchArg ] = '\0';
1911 cchName = 0;
1912 break;
1913 }
1914
1915 case ~(unsigned)0:
1916 return parseError(pStrm, 0, "Missing closing ')' on probe");
1917 }
1918 }
1919}
1920
1921/**
1922 * Parses a D provider statement.
1923 *
1924 * @returns Suitable exit code, errors message already written on failure.
1925 * @param pStrm The stream.
1926 */
1927static RTEXITCODE parseProvider(PSCMSTREAM pStrm)
1928{
1929 /*
1930 * Next up is a name followed by a curly bracket. Ignore comments.
1931 */
1932 RTEXITCODE rcExit = parseSkipSpacesAndComments(pStrm);
1933 if (rcExit != RTEXITCODE_SUCCESS)
1934 return parseError(pStrm, 1, "Expected a provider name starting with an alphabetical character");
1935 size_t cchName;
1936 const char *pszName = ScmStreamCGetWord(pStrm, &cchName);
1937 if (!pszName)
1938 return parseError(pStrm, 0, "Bad provider name");
1939 if (RT_C_IS_DIGIT(pszName[cchName - 1]))
1940 return parseError(pStrm, 1, "A provider name cannot end with digit");
1941
1942 unsigned ch = parseGetNextNonSpaceNonCommentCh(pStrm);
1943 if (ch != '{')
1944 return parseError(pStrm, 1, "Expected '{' after the provider name");
1945
1946 /*
1947 * Create a provider instance.
1948 */
1949 PVTGPROVIDER pProv = (PVTGPROVIDER)RTMemAllocZ(sizeof(*pProv));
1950 if (!pProv)
1951 return parseError(pStrm, 0, "Out of memory");
1952 RTListInit(&pProv->ProbeHead);
1953 RTListAppend(&g_ProviderHead, &pProv->ListEntry);
1954 pProv->pszName = strtabInsertN(pszName, cchName);
1955 if (!pProv->pszName)
1956 return parseError(pStrm, 0, "Out of memory");
1957
1958 /*
1959 * Parse loop.
1960 */
1961 for (;;)
1962 {
1963 ch = parseGetNextNonSpaceNonCommentCh(pStrm);
1964 switch (ch)
1965 {
1966 case 'p':
1967 if (ScmStreamCMatchingWordM1(pStrm, RT_STR_TUPLE("probe")))
1968 rcExit = parseProbe(pStrm, pProv);
1969 else
1970 rcExit = parseError(pStrm, 1, "Unexpected character");
1971 break;
1972
1973 case '}':
1974 {
1975 size_t off = ScmStreamTell(pStrm);
1976 ch = parseGetNextNonSpaceNonCommentCh(pStrm);
1977 if (ch == ';')
1978 return RTEXITCODE_SUCCESS;
1979 rcExit = parseErrorAbs(pStrm, off, "Expected ';'");
1980 break;
1981 }
1982
1983 case ~(unsigned)0:
1984 rcExit = parseError(pStrm, 0, "Missing closing '}' on provider");
1985 break;
1986
1987 default:
1988 rcExit = parseError(pStrm, 1, "Unexpected character");
1989 break;
1990 }
1991 if (rcExit != RTEXITCODE_SUCCESS)
1992 return rcExit;
1993 }
1994}
1995
1996
1997static RTEXITCODE parseScript(const char *pszScript)
1998{
1999 SCMSTREAM Strm;
2000 int rc = ScmStreamInitForReading(&Strm, pszScript);
2001 if (RT_FAILURE(rc))
2002 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to open & read '%s' into memory: %Rrc", pszScript, rc);
2003 if (g_cVerbosity > 0)
2004 RTMsgInfo("Parsing '%s'...", pszScript);
2005
2006 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
2007 unsigned ch;
2008 while ((ch = ScmStreamGetCh(&Strm)) != ~(unsigned)0)
2009 {
2010 if (RT_C_IS_SPACE(ch))
2011 continue;
2012 switch (ch)
2013 {
2014 case '/':
2015 ch = ScmStreamGetCh(&Strm);
2016 if (ch == '*')
2017 rcExit = parseMultiLineComment(&Strm);
2018 else if (ch == '/')
2019 rcExit = parseOneLineComment(&Strm);
2020 else
2021 rcExit = parseError(&Strm, 2, "Unexpected character");
2022 break;
2023
2024 case 'p':
2025 if (ScmStreamCMatchingWordM1(&Strm, RT_STR_TUPLE("provider")))
2026 rcExit = parseProvider(&Strm);
2027 else
2028 rcExit = parseError(&Strm, 1, "Unexpected character");
2029 break;
2030
2031 case '#':
2032 {
2033 ch = parseGetNextNonSpaceNonCommentChOnPpLine(&Strm);
2034 if (ch == ~(unsigned)0)
2035 rcExit = RTEXITCODE_FAILURE;
2036 else if (ch == 'p' && ScmStreamCMatchingWordM1(&Strm, RT_STR_TUPLE("pragma")))
2037 rcExit = parsePragma(&Strm);
2038 else
2039 rcExit = parseError(&Strm, 1, "Unsupported preprocessor directive");
2040 break;
2041 }
2042
2043 default:
2044 rcExit = parseError(&Strm, 1, "Unexpected character");
2045 break;
2046 }
2047 if (rcExit != RTEXITCODE_SUCCESS)
2048 return rcExit;
2049 }
2050
2051 ScmStreamDelete(&Strm);
2052 if (g_cVerbosity > 0 && rcExit == RTEXITCODE_SUCCESS)
2053 RTMsgInfo("Successfully parsed '%s'.", pszScript);
2054 return rcExit;
2055}
2056
2057
2058/**
2059 * Parses the arguments.
2060 */
2061static RTEXITCODE parseArguments(int argc, char **argv)
2062{
2063 /*
2064 * Set / Adjust defaults.
2065 */
2066 int rc = RTPathAbs(g_pszAssemblerIncVal, g_szAssemblerIncVal, sizeof(g_szAssemblerIncVal) - 1);
2067 if (RT_FAILURE(rc))
2068 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs failed: %Rrc", rc);
2069 strcat(g_szAssemblerIncVal, "/");
2070 g_pszAssemblerIncVal = g_szAssemblerIncVal;
2071
2072 /*
2073 * Option config.
2074 */
2075 enum
2076 {
2077 kVBoxTpGOpt_32Bit = 1000,
2078 kVBoxTpGOpt_64Bit,
2079 kVBoxTpGOpt_Assembler,
2080 kVBoxTpGOpt_AssemblerFmtOpt,
2081 kVBoxTpGOpt_AssemblerFmtVal,
2082 kVBoxTpGOpt_AssemblerOutputOpt,
2083 kVBoxTpGOpt_AssemblerOption,
2084 kVBoxTpGOpt_Pic,
2085 kVBoxTpGOpt_ProbeFnName,
2086 kVBoxTpGOpt_ProbeFnImported,
2087 kVBoxTpGOpt_ProbeFnNotImported,
2088 kVBoxTpGOpt_End
2089 };
2090
2091 static RTGETOPTDEF const s_aOpts[] =
2092 {
2093 /* dtrace w/ long options */
2094 { "-32", kVBoxTpGOpt_32Bit, RTGETOPT_REQ_NOTHING },
2095 { "-64", kVBoxTpGOpt_64Bit, RTGETOPT_REQ_NOTHING },
2096 { "--apply-cpp", 'C', RTGETOPT_REQ_NOTHING },
2097 { "--generate-obj", 'G', RTGETOPT_REQ_NOTHING },
2098 { "--generate-header", 'h', RTGETOPT_REQ_NOTHING },
2099 { "--output", 'o', RTGETOPT_REQ_STRING },
2100 { "--script", 's', RTGETOPT_REQ_STRING },
2101 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
2102 /* out stuff */
2103 { "--assembler", kVBoxTpGOpt_Assembler, RTGETOPT_REQ_STRING },
2104 { "--assembler-fmt-opt", kVBoxTpGOpt_AssemblerFmtOpt, RTGETOPT_REQ_STRING },
2105 { "--assembler-fmt-val", kVBoxTpGOpt_AssemblerFmtVal, RTGETOPT_REQ_STRING },
2106 { "--assembler-output-opt", kVBoxTpGOpt_AssemblerOutputOpt, RTGETOPT_REQ_STRING },
2107 { "--assembler-option", kVBoxTpGOpt_AssemblerOption, RTGETOPT_REQ_STRING },
2108 { "--pic", kVBoxTpGOpt_Pic, RTGETOPT_REQ_NOTHING },
2109 { "--probe-fn-name", kVBoxTpGOpt_ProbeFnName, RTGETOPT_REQ_STRING },
2110 { "--probe-fn-imported", kVBoxTpGOpt_ProbeFnImported, RTGETOPT_REQ_NOTHING },
2111 { "--probe-fn-not-imported", kVBoxTpGOpt_ProbeFnNotImported, RTGETOPT_REQ_NOTHING },
2112 /** @todo We're missing a bunch of assembler options! */
2113 };
2114
2115 RTGETOPTUNION ValueUnion;
2116 RTGETOPTSTATE GetOptState;
2117 rc = RTGetOptInit(&GetOptState, argc, argv, &s_aOpts[0], RT_ELEMENTS(s_aOpts), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
2118 AssertReleaseRCReturn(rc, RTEXITCODE_FAILURE);
2119
2120 /*
2121 * Process \the options.
2122 */
2123 while ((rc = RTGetOpt(&GetOptState, &ValueUnion)) != 0)
2124 {
2125 switch (rc)
2126 {
2127 /*
2128 * DTrace compatible options.
2129 */
2130 case kVBoxTpGOpt_32Bit:
2131 g_cBits = 32;
2132 g_pszAssemblerFmtVal = g_szAssemblerFmtVal32;
2133 break;
2134
2135 case kVBoxTpGOpt_64Bit:
2136 g_cBits = 64;
2137 g_pszAssemblerFmtVal = g_szAssemblerFmtVal64;
2138 break;
2139
2140 case 'C':
2141 g_fApplyCpp = true;
2142 RTMsgWarning("Ignoring the -C option - no preprocessing of the D script will be performed");
2143 break;
2144
2145 case 'G':
2146 if ( g_enmAction != kVBoxTpGAction_Nothing
2147 && g_enmAction != kVBoxTpGAction_GenerateObject)
2148 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "-G and -h does not mix");
2149 g_enmAction = kVBoxTpGAction_GenerateObject;
2150 break;
2151
2152 case 'h':
2153 if (!strcmp(GetOptState.pDef->pszLong, "--generate-header"))
2154 {
2155 if ( g_enmAction != kVBoxTpGAction_Nothing
2156 && g_enmAction != kVBoxTpGAction_GenerateHeader)
2157 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "-h and -G does not mix");
2158 g_enmAction = kVBoxTpGAction_GenerateHeader;
2159 }
2160 else
2161 {
2162 /* --help or similar */
2163 RTPrintf("VirtualBox Tracepoint Generator\n"
2164 "\n"
2165 "Usage: %s [options]\n"
2166 "\n"
2167 "Options:\n", RTProcShortName());
2168 for (size_t i = 0; i < RT_ELEMENTS(s_aOpts); i++)
2169 if ((unsigned)s_aOpts[i].iShort < 128)
2170 RTPrintf(" -%c,%s\n", s_aOpts[i].iShort, s_aOpts[i].pszLong);
2171 else
2172 RTPrintf(" %s\n", s_aOpts[i].pszLong);
2173 return RTEXITCODE_SUCCESS;
2174 }
2175 break;
2176
2177 case 'o':
2178 if (g_pszOutput)
2179 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Output file is already set to '%s'", g_pszOutput);
2180 g_pszOutput = ValueUnion.psz;
2181 break;
2182
2183 case 's':
2184 if (g_pszScript)
2185 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Script file is already set to '%s'", g_pszScript);
2186 g_pszScript = ValueUnion.psz;
2187 break;
2188
2189 case 'v':
2190 g_cVerbosity++;
2191 break;
2192
2193 case 'V':
2194 {
2195 /* The following is assuming that svn does it's job here. */
2196 static const char s_szRev[] = "$Revision: 41117 $";
2197 const char *psz = RTStrStripL(strchr(s_szRev, ' '));
2198 RTPrintf("r%.*s\n", strchr(psz, ' ') - psz, psz);
2199 return RTEXITCODE_SUCCESS;
2200 }
2201
2202 case VINF_GETOPT_NOT_OPTION:
2203 if (g_enmAction == kVBoxTpGAction_GenerateObject)
2204 break; /* object files, ignore them. */
2205 return RTGetOptPrintError(rc, &ValueUnion);
2206
2207
2208 /*
2209 * Our options.
2210 */
2211 case kVBoxTpGOpt_Assembler:
2212 g_pszAssembler = ValueUnion.psz;
2213 break;
2214
2215 case kVBoxTpGOpt_AssemblerFmtOpt:
2216 g_pszAssemblerFmtOpt = ValueUnion.psz;
2217 break;
2218
2219 case kVBoxTpGOpt_AssemblerFmtVal:
2220 g_pszAssemblerFmtVal = ValueUnion.psz;
2221 break;
2222
2223 case kVBoxTpGOpt_AssemblerOutputOpt:
2224 g_pszAssemblerOutputOpt = ValueUnion.psz;
2225 break;
2226
2227 case kVBoxTpGOpt_AssemblerOption:
2228 if (g_cAssemblerOptions >= RT_ELEMENTS(g_apszAssemblerOptions))
2229 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many assembly options (max %u)", RT_ELEMENTS(g_apszAssemblerOptions));
2230 g_apszAssemblerOptions[g_cAssemblerOptions] = ValueUnion.psz;
2231 g_cAssemblerOptions++;
2232 break;
2233
2234 case kVBoxTpGOpt_Pic:
2235 g_fPic = true;
2236 break;
2237
2238 case kVBoxTpGOpt_ProbeFnName:
2239 g_pszProbeFnName = ValueUnion.psz;
2240 break;
2241
2242 case kVBoxTpGOpt_ProbeFnImported:
2243 g_fProbeFnImported = true;
2244 break;
2245
2246 case kVBoxTpGOpt_ProbeFnNotImported:
2247 g_fProbeFnImported = false;
2248 break;
2249
2250 /*
2251 * Errors and bugs.
2252 */
2253 default:
2254 return RTGetOptPrintError(rc, &ValueUnion);
2255 }
2256 }
2257
2258 /*
2259 * Check that we've got all we need.
2260 */
2261 if (g_enmAction == kVBoxTpGAction_Nothing)
2262 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No action specified (-h or -G)");
2263 if (!g_pszScript)
2264 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No script file specified (-s)");
2265 if (!g_pszOutput)
2266 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No output file specified (-o)");
2267
2268 return RTEXITCODE_SUCCESS;
2269}
2270
2271
2272int main(int argc, char **argv)
2273{
2274 int rc = RTR3InitExe(argc, &argv, 0);
2275 if (RT_FAILURE(rc))
2276 return 1;
2277
2278 RTEXITCODE rcExit = parseArguments(argc, argv);
2279 if (rcExit == RTEXITCODE_SUCCESS)
2280 {
2281 /*
2282 * Parse the script.
2283 */
2284 RTListInit(&g_ProviderHead);
2285 rcExit = parseScript(g_pszScript);
2286 if (rcExit == RTEXITCODE_SUCCESS)
2287 {
2288 /*
2289 * Take action.
2290 */
2291 if (g_enmAction == kVBoxTpGAction_GenerateHeader)
2292 rcExit = generateHeader(g_pszOutput);
2293 else
2294 rcExit = generateObject(g_pszOutput, g_pszTempAsm);
2295 }
2296 }
2297
2298 if (rcExit == RTEXITCODE_SUCCESS && g_cTypeErrors > 0)
2299 rcExit = RTEXITCODE_FAILURE;
2300 return rcExit;
2301}
2302
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette