VirtualBox

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

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

VBoxTpG,SUPDrv,VBoxVMM: Working on static user land probes for the non-native platforms.

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