VBoxTpG.cpp revision 49a6b09abb20015b0af3e618a1f92b7e26785e90
/* $Id$ */
/** @file
* IPRT Testcase / Tool - VBox Tracepoint Compiler.
*/
/*
* Copyright (C) 2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/initterm.h>
#include <iprt/strcache.h>
#include "scmstream.h"
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
typedef struct VTGARG
{
const char *pszName;
const char *pszType;
} VTGARG;
typedef struct VTGPROBE
{
const char *pszName;
} VTGPROBE;
typedef struct VTGPROVIDER
{
const char *pszName;
} VTGPROVIDER;
typedef VTGPROVIDER *PVTGPROVIDER;
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** String cache used for storing strings when parsing. */
/** List of providers created by the parser. */
static RTLISTANCHOR g_ProviderHead;
/** @name Options
* @{ */
static enum
{
static bool g_fApplyCpp = false;
static uint32_t g_cVerbosity = 0;
static const char *g_pszOutput = NULL;
static const char *g_pszScript = NULL;
static const char *g_pszTempAsm = NULL;
#ifdef RT_OS_DARWIN
static const char *g_pszAssembler = "yasm";
static const char *g_pszAssemblerFmtOpt = "--oformat";
static const char g_szAssemblerFmtVal32[] = "macho32";
static const char g_szAssemblerFmtVal64[] = "macho64";
static const char *pszAssembler = "nasm.exe";
static const char *pszAssemblerFmtOpt = "-f";
static const char g_szAssemblerFmtVal32[] = "obj";
static const char g_szAssemblerFmtVal64[] = "elf64";
#elif defined(RT_OS_WINDOWS)
static const char *g_pszAssembler = "yasm.exe";
static const char *g_pszAssemblerFmtOpt = "--oformat";
static const char g_szAssemblerFmtVal32[] = "win32";
static const char g_szAssemblerFmtVal64[] = "win64";
#else
static const char *g_pszAssembler = "yasm";
static const char *g_pszAssemblerFmtOpt = "--oformat";
static const char g_szAssemblerFmtVal32[] = "elf32";
static const char g_szAssemblerFmtVal64[] = "elf64";
#endif
static const char *g_pszAssemblerOutputOpt = "-o";
static unsigned g_cAssemblerOptions = 0;
static const char *g_apszAssemblerOptions[32];
/** @} */
{
RTPrintf("Todo invoke the assembler\n");
return RTEXITCODE_SKIPPED;
}
{
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "ScmStreamInitForWriting returned %Rrc when generating the %s file",
if (rcExit == RTEXITCODE_SUCCESS)
{
if (RT_FAILURE(rc))
rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "ScmStreamWriteToFile returned %Rrc when writing '%s' (%s)",
if (rcExit == RTEXITCODE_SUCCESS)
{
if (g_cVerbosity > 0)
if (g_cVerbosity > 1)
{
const char *pszLine;
}
}
}
return rcExit;
}
{
if (g_cVerbosity > 0)
RTMsgInfo("Generating assembly code...");
RTPrintf("Todo generate the assembly code\n");
return RTEXITCODE_SUCCESS;
}
{
if (!pszTempAsm)
{
pszTempAsm = psz;
}
if (rcExit == RTEXITCODE_SUCCESS)
return rcExit;
}
{
RTPrintf("Todo generate the header\n");
return RTEXITCODE_SUCCESS;
}
{
}
/**
* If the given C word is at off - 1, return @c true and skip beyond it,
* otherwise return @c false.
*
* @retval true if the given C-word is at the current position minus one char.
* The stream position changes.
* @retval false if not. The stream position is unchanged.
*
* @param pStream The stream.
* @param cchWord The length of the word.
* @param pszWord The word.
*/
{
/* Check stream state. */
/* Sufficient chars left on the line? */
size_t const cchLeft = pStream->paLines[iLine].cch + pStream->paLines[iLine].off - (pStream->off - 1);
return false;
/* Do they match? */
return false;
/* Is it the end of a C word? */
{
return false;
}
/* Skip ahead. */
return true;
}
/**
* Get's the C word starting at the current position.
*
* @returns Pointer to the word on success and the stream position advanced to
* the end of it.
* NULL on failure, stream position normally unchanged.
* @param pStream The stream to get the C word from.
* @param pcchWord Where to return the word length.
*/
{
/* Check stream state. */
/* Get the number of chars left on the line and locate the current char. */
/* Is it a leading C character. */
return NULL;
/* Find the end of the word. */
char ch;
|| RT_C_IS_ALNUM(ch)))
off++;
return psz;
}
/**
* Parser error with line and position.
*
* @returns RTEXITCODE_FAILURE.
* @param pStrm The stream.
* @param cb The offset from the current position to the
* point of failure.
* @param pszMsg The message to display.
*/
{
if (pszLine)
RTPrintf(" %.*s\n"
" %*s^\n",
return RTEXITCODE_FAILURE;
}
/**
* Parser error with line and position.
*
* @returns RTEXITCODE_FAILURE.
* @param pStrm The stream.
* @param cb The offset from the current position to the
* point of failure.
* @param pszMsg The message to display.
*/
{
}
/**
* Handles a C++ one line comment.
*
* @returns Exit code.
* @param pStrm The stream.
*/
{
return RTEXITCODE_SUCCESS;
}
/**
* Handles a multi-line C/C++ comment.
*
* @returns Exit code.
* @param pStrm The stream.
*/
{
unsigned ch;
{
if (ch == '*')
{
do
while (ch == '*');
if (ch == '/')
return RTEXITCODE_SUCCESS;
}
}
return RTEXITCODE_FAILURE;
}
/**
* Skips spaces and comments.
*
* @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE.
* @param pStrm The stream..
*/
{
unsigned ch;
{
return RTEXITCODE_SUCCESS;
AssertBreak(ch != ~(unsigned)0);
if (ch == '/')
{
if (ch == '*')
else if (ch == '/')
else
if (rcExit != RTEXITCODE_SUCCESS)
return rcExit;
}
}
}
/**
* Skips spaces and comments, returning the next character.
*
* @returns Next non-space-non-comment character. ~(unsigned)0 on EOF or
* failure.
* @param pStrm The stream.
*/
{
unsigned ch;
{
return ch;
if (ch == '/')
{
if (ch == '*')
else if (ch == '/')
else
if (rcExit != RTEXITCODE_SUCCESS)
return ~(unsigned)0;
}
}
return ~(unsigned)0;
}
{
/*
* Next up is a name followed by a curly bracket. Ignore comment.s
*/
if (rcExit != RTEXITCODE_SUCCESS)
if (!pszName)
if (ch != '{')
/*
* Create a provider instance.
*/
if (!pProv)
/*
* Parse loop.
*/
for (;;)
{
switch (ch)
{
case 'p':
else
break;
case '}':
{
if (ch != ';')
return RTEXITCODE_SUCCESS;
}
case ~(unsigned)0:
default:
}
}
}
{
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to open & read '%s' into memory: %Rrc", pszScript, rc);
if (g_cVerbosity > 0)
unsigned ch;
{
if (RT_C_IS_SPACE(ch))
continue;
switch (ch)
{
case '/':
if (ch == '*')
else if (ch == '/')
else
break;
case 'p':
else
break;
case '#':
break;
default:
break;
}
if (rcExit != RTEXITCODE_SUCCESS)
return rcExit;
}
return rcExit;
}
/**
* Parses the arguments.
*/
{
enum
{
kVBoxTpGOpt_32Bit = 1000,
};
static RTGETOPTDEF const s_aOpts[] =
{
/* dtrace w/ long options */
/* out stuff */
};
int rc = RTGetOptInit(&GetOptState, argc, argv, &s_aOpts[0], RT_ELEMENTS(s_aOpts), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
{
switch (rc)
{
/*
* DTrace compatible options.
*/
case kVBoxTpGOpt_32Bit:
g_cBits = 32;
break;
case kVBoxTpGOpt_64Bit:
g_cBits = 64;
break;
case 'C':
g_fApplyCpp = true;
RTMsgWarning("Ignoring the -C option - no preprocessing of the D script will be performed");
break;
case 'G':
if ( g_enmAction != kVBoxTpGAction_Nothing
break;
case 'h':
{
if ( g_enmAction != kVBoxTpGAction_Nothing
}
else
{
/* --help or similar */
RTPrintf("VirtualBox Tracepoint Generator\n"
"\n"
"Usage: %s [options]\n"
"\n"
"Options:\n", RTProcShortName());
else
return RTEXITCODE_SUCCESS;
}
break;
case 'o':
if (g_pszOutput)
break;
case 's':
if (g_pszScript)
break;
case 'v':
g_cVerbosity++;
break;
case 'V':
{
/* The following is assuming that svn does it's job here. */
static const char s_szRev[] = "$Revision$";
return RTEXITCODE_SUCCESS;
}
case VINF_GETOPT_NOT_OPTION:
break; /* object files, ignore them. */
/*
* Out options.
*/
case kVBoxTpGOpt_Assembler:
break;
break;
break;
break;
return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many assembly options (max %u)", RT_ELEMENTS(g_apszAssemblerOptions));
break;
/*
* Errors and bugs.
*/
default:
}
}
/*
* Check that we've got all we need.
*/
if (g_enmAction == kVBoxTpGAction_Nothing)
if (!g_pszScript)
if (!g_pszOutput)
return RTEXITCODE_SUCCESS;
}
{
if (RT_FAILURE(rc))
return 1;
if (rcExit == RTEXITCODE_SUCCESS)
{
/*
* Parse the script.
*/
if (RT_SUCCESS(rc))
{
if (rcExit == RTEXITCODE_SUCCESS)
{
/*
* Take action.
*/
else
}
}
}
return rcExit;
}