VirtualBox

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

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

Working on the 64-bit probe argument issue for 32-bit hosts...

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