MakeAlternativeSource.cpp revision 7306565f20289efa418aa6d90ebaa82fd54f3958
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * MakeAlternative - Generate an Alternative BIOS Source that requires less tools.
c7814cf6e1240a519cbec0441e033d0e2470ed00vboxsync * Copyright (C) 2012 Oracle Corporation
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * available from http://www.virtualbox.org. This file is free software;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * General Public License (GPL) as published by the Free Software
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/*******************************************************************************
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync* Header Files *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync*******************************************************************************/
73ba84f95f918cc170be38908ad240fbb2f8f354vboxsync/*******************************************************************************
73ba84f95f918cc170be38908ad240fbb2f8f354vboxsync* Structures and Typedefs *
73ba84f95f918cc170be38908ad240fbb2f8f354vboxsync*******************************************************************************/
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * A BIOS segment.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsynctypedef struct BIOSSEG
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/** Pointer to a BIOS segment. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * A BIOS object file.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsynctypedef struct BIOSOBJFILE
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsync/** A BIOS object file. */
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsync * Pointer to a BIOS map parser handle.
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsynctypedef struct BIOSMAP
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsync /** The stream pointer. */
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsync /** The file name. */
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsync /** Set when EOF has been reached. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync /** The current line number (0 based).*/
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync /** The length of the current line. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync /** The offset of the first non-white character on the line. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync /** The line buffer. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/** Pointer to a BIOS map parser handle. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/*******************************************************************************
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync* Global Variables *
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync*******************************************************************************/
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/** The verbosity level.*/
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/** Pointer to the BIOS image. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/** The size of the BIOS image. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/** Debug module for the map file. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/** The number of BIOS segments found in the map file. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/** Array of BIOS segments from the map file. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/** List of BIOSOBJFILE. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/** The output stream. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/** The type of BIOS we're working on. */
4a9af9a8062589b741444d717d2dd1ed22b0f583vboxsync/** The flat ROM base address. */
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsyncstatic bool outputPrintfV(const char *pszFormat, va_list va)
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsync int rc = RTStrmPrintfV(g_hStrmOutput, pszFormat, va);
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsync return false;
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsync return true;
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsyncstatic bool outputPrintf(const char *pszFormat, ...)
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsync * Opens the output file for writing.
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsync * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsync * @param pszOutput Path to the output file.
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsyncstatic RTEXITCODE OpenOutputFile(const char *pszOutput)
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsync int rc = RTStrmOpen(pszOutput, "w", &g_hStrmOutput);
1c0d3d017f9a45748b4839bf6622b53e83a4f1f8vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to open output file '%s': %Rrc", pszOutput, rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Displays a disassembly error and returns @c false.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns @c false.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pszFormat The error format string.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param ... Format argument.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Output the disassembly file header.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns @c true on success,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool disFileHeader(void)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ";; @file\n"
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync "; Auto Generated source file. Do not edit.\n"
73ba84f95f918cc170be38908ad240fbb2f8f354vboxsync * List the header of each source file, up to and including the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * copyright notice.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTListForEach(&g_ObjList, pObjFile, BIOSOBJFILE, Node)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = RTStrmOpen(pObjFile->pszSource, "r", &hStrm);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync "; Source file: %Rbn\n"
bdbed0b8e7fb553d01417fdc976a76f3b287dbe2vboxsync while ((rc = RTStrmGetLine(hStrm, szLine, sizeof(szLine))) == VINF_SUCCESS)
7b4ea63789001468ec3662bdfcd6432bf89095dfvboxsync /* Check if we're done. */
46737b2c6b2da473108a7670c3682d88474bd8b9vboxsync /* Strip comment suffix. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cch >= 2 && psz[cch - 1] == '/' && psz[cch - 2] == '*')
1389294d44ac76b0a25f5655756c9d39855a73efvboxsync /* Skip line prefix. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Skip the doxygen file tag line. */
bdbed0b8e7fb553d01417fdc976a76f3b287dbe2vboxsync if (!strcmp(psz, "* @file") || !strcmp(psz, "@file"))
bdbed0b8e7fb553d01417fdc976a76f3b287dbe2vboxsync /* Detect copyright section. */
bdbed0b8e7fb553d01417fdc976a76f3b287dbe2vboxsync return disError("Error reading '%s': rc=%Rrc iLine=%u", pObjFile->pszSource, rc, iLine);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Set the org.
bdbed0b8e7fb553d01417fdc976a76f3b287dbe2vboxsync * Checks if a byte sequence could be a string litteral.
bdbed0b8e7fb553d01417fdc976a76f3b287dbe2vboxsync * @returns @c true if it is, @c false if it isn't.
bdbed0b8e7fb553d01417fdc976a76f3b287dbe2vboxsync * @param uFlatAddr The address of the byte sequence.
bdbed0b8e7fb553d01417fdc976a76f3b287dbe2vboxsync * @param cb The length of the sequence.
bdbed0b8e7fb553d01417fdc976a76f3b287dbe2vboxsyncstatic bool disIsString(uint32_t uFlatAddr, uint32_t cb)
bdbed0b8e7fb553d01417fdc976a76f3b287dbe2vboxsync return false;
bdbed0b8e7fb553d01417fdc976a76f3b287dbe2vboxsync uint8_t const *pb = &g_pbImg[uFlatAddr - g_uBiosFlatBase];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync while (cb > 0)
bdbed0b8e7fb553d01417fdc976a76f3b287dbe2vboxsync return cb == 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
73ba84f95f918cc170be38908ad240fbb2f8f354vboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Checks if a dword could be a far 16:16 BIOS address.
1389294d44ac76b0a25f5655756c9d39855a73efvboxsync * @returns @c true if it is, @c false if it isn't.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param uFlatAddr The address of the dword.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint16_t const *pu16 = (uint16_t const *)&g_pbImg[uFlatAddr - g_uBiosFlatBase];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t uFlatAddr2 = (uint32_t)(pu16[1] << 4) | pu16[0];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool disByteData(uint32_t uFlatAddr, uint32_t cb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t const *pb = &g_pbImg[uFlatAddr - g_uBiosFlatBase];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync while (cb-- > 0)
359416647a711739d1b14addbf399178949a1a60vboxsync return false;
359416647a711739d1b14addbf399178949a1a60vboxsyncstatic bool disWordData(uint32_t uFlatAddr, uint32_t cb)
359416647a711739d1b14addbf399178949a1a60vboxsync return disError("disWordData expects word aligned size: cb=%#x uFlatAddr=%#x", uFlatAddr, cb);
359416647a711739d1b14addbf399178949a1a60vboxsync uint16_t const *pu16 = (uint16_t const *)&g_pbImg[uFlatAddr - g_uBiosFlatBase];
359416647a711739d1b14addbf399178949a1a60vboxsync while (cb > 0)
359416647a711739d1b14addbf399178949a1a60vboxsync return false;
359416647a711739d1b14addbf399178949a1a60vboxsyncstatic bool disDWordData(uint32_t uFlatAddr, uint32_t cb)
ad290511521ce8388a9926b165241ecf83c330a7vboxsync return disError("disWordData expects dword aligned size: cb=%#x uFlatAddr=%#x", uFlatAddr, cb);
359416647a711739d1b14addbf399178949a1a60vboxsync uint32_t const *pu32 = (uint32_t const *)&g_pbImg[uFlatAddr - g_uBiosFlatBase];
359416647a711739d1b14addbf399178949a1a60vboxsync while (cb > 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool disStringData(uint32_t uFlatAddr, uint32_t cb)
329df9696e709dc71611f504a4774f323545be0avboxsync uint8_t const *pb = &g_pbImg[uFlatAddr - g_uBiosFlatBase];
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync while (cb > 0)
359416647a711739d1b14addbf399178949a1a60vboxsync /* Line endings and beginnings. */
329df9696e709dc71611f504a4774f323545be0avboxsync return false;
359416647a711739d1b14addbf399178949a1a60vboxsync return false;
359416647a711739d1b14addbf399178949a1a60vboxsync /* See how many printable character we've got. */
359416647a711739d1b14addbf399178949a1a60vboxsync bool fRc = true;
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync return false;
359416647a711739d1b14addbf399178949a1a60vboxsync * For dumping a portion of a string table.
359416647a711739d1b14addbf399178949a1a60vboxsync * @returns @c true on success, @c false on failure.
359416647a711739d1b14addbf399178949a1a60vboxsync * @param uFlatAddr The start address.
359416647a711739d1b14addbf399178949a1a60vboxsync * @param cb The size of the string table.
359416647a711739d1b14addbf399178949a1a60vboxsyncstatic bool disStringsData(uint32_t uFlatAddr, uint32_t cb)
359416647a711739d1b14addbf399178949a1a60vboxsync uint8_t const *pb = &g_pbImg[uFlatAddr - g_uBiosFlatBase];
359416647a711739d1b14addbf399178949a1a60vboxsync while (cb > 0)
359416647a711739d1b14addbf399178949a1a60vboxsync /* Line endings and beginnings. */
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync return false;
359416647a711739d1b14addbf399178949a1a60vboxsync return false;
359416647a711739d1b14addbf399178949a1a60vboxsync /* See how many printable character we've got. */
359416647a711739d1b14addbf399178949a1a60vboxsync bool fRc = true;
359416647a711739d1b14addbf399178949a1a60vboxsync return false;
359416647a711739d1b14addbf399178949a1a60vboxsync * Minds the gap between two segments.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * Gaps should generally be zero filled.
359416647a711739d1b14addbf399178949a1a60vboxsync * @returns @c true on success, @c false on failure.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * @param uFlatAddr The address of the gap.
359416647a711739d1b14addbf399178949a1a60vboxsync * @param cbPadding The size of the gap.
09f4b412099acda62997fd82c8608075c453b3ebvboxsyncstatic bool disCopySegmentGap(uint32_t uFlatAddr, uint32_t cbPadding)
359416647a711739d1b14addbf399178949a1a60vboxsync " ; Padding %#x bytes at %#x\n", cbPadding, uFlatAddr);
359416647a711739d1b14addbf399178949a1a60vboxsync uint8_t const *pb = &g_pbImg[uFlatAddr - g_uBiosFlatBase];
359416647a711739d1b14addbf399178949a1a60vboxsync return outputPrintf(" times %u db 0\n", cbPadding);
359416647a711739d1b14addbf399178949a1a60vboxsync * Worker for disGetNextSymbol that only does the looking up, no RTDBSYMBOL::cb
359416647a711739d1b14addbf399178949a1a60vboxsync * @param uFlatAddr The address to start searching at.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * @param cbMax The size of the search range.
359416647a711739d1b14addbf399178949a1a60vboxsync * @param poff Where to return the offset between the symbol
359416647a711739d1b14addbf399178949a1a60vboxsync * and @a uFlatAddr.
359416647a711739d1b14addbf399178949a1a60vboxsync * @param pSym Where to return the symbol data.
359416647a711739d1b14addbf399178949a1a60vboxsyncstatic void disGetNextSymbolWorker(uint32_t uFlatAddr, uint32_t cbMax, uint32_t *poff, PRTDBGSYMBOL pSym)
359416647a711739d1b14addbf399178949a1a60vboxsync int rc = RTDbgModSymbolByAddr(g_hMapMod, RTDBGSEGIDX_RVA, uFlatAddr, RTDBGSYMADDR_FLAGS_GREATER_OR_EQUAL, &off, pSym);
359416647a711739d1b14addbf399178949a1a60vboxsync /* negative offset, indicates beyond. */
359416647a711739d1b14addbf399178949a1a60vboxsync outputPrintf(" ; !! RTDbgModSymbolByAddr(,,%#x,,) -> off=%RTptr cb=%RTptr uValue=%RTptr '%s'\n",
359416647a711739d1b14addbf399178949a1a60vboxsync uFlatAddr, off, pSym->cb, pSym->Value, pSym->szName);
359416647a711739d1b14addbf399178949a1a60vboxsync outputPrintf(" ; !! RTDbgModSymbolByAddr(,,%#x,,) -> %Rrc\n", uFlatAddr, rc);
359416647a711739d1b14addbf399178949a1a60vboxsync RTStrPrintf(pSym->szName, sizeof(pSym->szName), "_dummy_addr_%#x", uFlatAddr + cbMax);
359416647a711739d1b14addbf399178949a1a60vboxsync * Gets the symbol at or after the given address.
359416647a711739d1b14addbf399178949a1a60vboxsync * If there are no symbols in the specified range, @a pSym and @a poff will be
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * set up to indicate a symbol at the first byte after the range.
359416647a711739d1b14addbf399178949a1a60vboxsync * @param uFlatAddr The address to start searching at.
359416647a711739d1b14addbf399178949a1a60vboxsync * @param cbMax The size of the search range.
359416647a711739d1b14addbf399178949a1a60vboxsync * @param poff Where to return the offset between the symbol
359416647a711739d1b14addbf399178949a1a60vboxsync * and @a uFlatAddr.
359416647a711739d1b14addbf399178949a1a60vboxsync * @param pSym Where to return the symbol data.
359416647a711739d1b14addbf399178949a1a60vboxsyncstatic void disGetNextSymbol(uint32_t uFlatAddr, uint32_t cbMax, uint32_t *poff, PRTDBGSYMBOL pSym)
09f4b412099acda62997fd82c8608075c453b3ebvboxsync disGetNextSymbolWorker(uFlatAddr, cbMax, poff, pSym);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync disGetNextSymbolWorker(uFlatAddr + *poff + 1, cbMax - *poff - 1, &off2, &Sym2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync outputPrintf(" ; disGetNextSymbol %#x LB %#x -> off=%#x cb=%RTptr uValue=%RTptr '%s'\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uFlatAddr, cbMax, *poff, pSym->cb, pSym->Value, pSym->szName);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * For dealing with the const segment (string constants).
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync * @returns @c true on success, @c false on failure.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param iSeg The segment.
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync while (cb > 0)
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fRc = outputPrintf("%s: %*s; %#x LB %#x\n", Sym.szName, cchName < 41 - 2 ? cchName - 41 - 2 : 0, "", uFlatAddr, Sym.cb);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync while (cb > 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fRc = outputPrintf("%s: %*s; %#x LB %#x\n", Sym.szName, cchName < 41 - 2 ? cchName - 41 - 2 : 0, "", uFlatAddr, Sym.cb);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync //else if (Sym.cb == 4 && disIsFarBiosAddr(uFlatAddr))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync // fRc = disDWordData(uFlatAddr, 4);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool disIsCodeAndAdjustSize(uint32_t uFlatAddr, PRTDBGSYMBOL pSym, PBIOSSEG pSeg)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This is for the PC BIOS.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || !strcmp(pSym->szName, "pci_routing_table_structure")
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This is for the VGA BIOS.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Deals with instructions that YASM will assemble differently than WASM/WCC.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic size_t disHandleYasmDifferences(PDISCPUSTATE pCpuState, uint32_t uFlatAddr, uint32_t cbInstr,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fDifferent = DISFormatYasmIsOddEncoding(pCpuState);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t const *pb = &g_pbImg[uFlatAddr - g_uBiosFlatBase];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Disassembler bugs.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo Group 1a and 11 seems to be disassembled incorrectly when
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * modrm.reg != 0. Those encodings should be invalid AFAICT. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || pCpuState->bOpCode == 0xc6 /* group 11 - not verified */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Check these out and consider adding them to DISFormatYasmIsOddEncoding.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fDifferent = true; /* rep insd - prefix switched. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fDifferent = true; /* mov ch, 0bah - yasm uses a short sequence: 0xb5 0xba. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Handle different stuff.
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync * @callback_method_impl{FNDISREADBYTES}
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync * @remarks @a uSrcAddr is the flat address.
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsyncstatic DECLCALLBACK(int) disReadOpcodeBytes(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync RTUINTPTR offBios = pDis->uInstrAddr + offInstr - g_uBiosFlatBase;
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync memcpy(&pDis->abInstr[offInstr], &g_pbImg[offBios], cbToRead);
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync * Disassembles code.
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync * @returns @c true on success, @c false on failure.
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync * @param uFlatAddr The address where the code starts.
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync * @param cb The amount of code to disassemble.
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync * @param fIs16Bit Is is 16-bit (@c true) or 32-bit (@c false).
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsyncstatic bool disCode(uint32_t uFlatAddr, uint32_t cb, bool fIs16Bit)
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync uint8_t const *pb = &g_pbImg[uFlatAddr - g_uBiosFlatBase];
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync while (cb > 0)
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync /* Trailing zero padding detection. */
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync uint32_t cbZeros = pv ? (uint32_t)((uint8_t const *)pv - pb) : cb;
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync return false;
ad290511521ce8388a9926b165241ecf83c330a7vboxsync /* Work arounds for switch tables and such (disas assertions). */
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync int rc = DISInstrWithReader(uFlatAddr, fIs16Bit ? DISCPUMODE_16BIT : DISCPUMODE_32BIT,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync size_t cch = DISFormatYasmEx(&CpuState, szTmp, sizeof(szTmp),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync | DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_COMMENT | DIS_FMT_FLAGS_BYTES_SPACED,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cch = disHandleYasmDifferences(&CpuState, uFlatAddr, cbInstr, szTmp, sizeof(szTmp), cch);
00ef464add2ac67ce0d698c9d02f720ef9e9a372vboxsync RTStrPrintf(&szTmp[cch], sizeof(szTmp) - cch, "; %#x", uFlatAddr);
00ef464add2ac67ce0d698c9d02f720ef9e9a372vboxsync return false;
00ef464add2ac67ce0d698c9d02f720ef9e9a372vboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync while (cb > 0)
2721dfb0e330d57ba888311520f5a343c64e7cefvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fRc = outputPrintf("%s: %*s; %#x LB %#x\n", Sym.szName, cchName < 41 - 2 ? cchName - 41 - 2 : 0, "", uFlatAddr, Sym.cb);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (disIsCodeAndAdjustSize(uFlatAddr, &Sym, &g_aSegs[iSeg]))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fRc = disCode(uFlatAddr, Sym.cb, disIs16BitCode(Sym.szName));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Work the image segment by segment.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fRc = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t iSeg = 0; iSeg < g_cSegs && fRc; iSeg++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Is there a gap between the segments? */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fRc = disCopySegmentGap(uFlatAddr, g_aSegs[iSeg].uFlatAddr - uFlatAddr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Overlapping segments: %u and %u; uFlatAddr=%#x\n", iSeg - 1, iSeg, uFlatAddr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Disassemble the segment. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync "section %s progbits vstart=%#x align=1 ; size=%#x class=%s group=%s\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync g_aSegs[iSeg].szName, g_aSegs[iSeg].uFlatAddr - g_uBiosFlatBase,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync g_aSegs[iSeg].cb, g_aSegs[iSeg].szClass, g_aSegs[iSeg].szGroup);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Advance. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Final gap. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fRc = disCopySegmentGap(uFlatAddr, g_uBiosFlatBase + g_cbImg - uFlatAddr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Last segment spills beyond 1MB; uFlatAddr=%#x\n", uFlatAddr);
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync * Parses the symbol file for the BIOS.
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync * This is in ELF/DWARF format.
f068575233c08526611dbe29684bee5f2cbe7144vboxsync * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
f068575233c08526611dbe29684bee5f2cbe7144vboxsync * @param pszBiosSym Path to the sym file.
f068575233c08526611dbe29684bee5f2cbe7144vboxsyncstatic RTEXITCODE ParseSymFile(const char *pszBiosSym)
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync /** @todo use RTDbg* later. (Just checking for existance currently.) */
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening '%s': %Rrc", pszBiosSym, rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = RTDbgModCreateFromImage(&hDbgMod, pszBiosSym, "VBoxBios", 0 /*fFlags*/);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTMsgInfo("RTDbgModCreateFromImage -> %Rrc\n", rc);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync * Display an error with the mapfile name and current line, return false.
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync * @returns @c false.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pMap The map file handle.
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync * @param pszFormat The format string.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param ... Format arguments.
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsyncstatic bool mapError(PBIOSMAP pMap, const char *pszFormat, ...)
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync RTMsgError("%s:%d: %N", pMap->pszMapFile, pMap->iLine, pszFormat, va);
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync return false;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * Reads a line from the file.
67b8a5a52c43a79ea7e159dbbeec99687fb9cd3bvboxsync * @returns @c true on success, @c false + msg on failure, @c false on eof.
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync * @param pMap The map file handle.
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync int rc = RTStrmGetLine(pMap->hStrm, pMap->szLine, sizeof(pMap->szLine));
67b8a5a52c43a79ea7e159dbbeec99687fb9cd3bvboxsync RTMsgError("%s:%d: Read error %Rrc", pMap->pszMapFile, pMap->iLine + 1, rc);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync return false;
7b6926b2bf44f326f40e1d9d1ce33a4dff0a2c67vboxsync /* Check out leading white space. */
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync return true;
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync * Checks if it is an empty line.
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync * @returns @c true if empty, @c false if not.
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync * @param pMap The map file handle.
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync * Reads ahead in the map file until a non-empty line or EOF is encountered.
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync * @returns @c true on success, @c false + msg on failure, @c false on eof.
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync * @param pMap The map file handle.
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync return false;
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync return true;
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync * Reads ahead in the map file until an empty line or EOF is encountered.
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync * @returns @c true on success, @c false + msg on failure, @c false on eof.
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync * @param pMap The map file handle.
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync return false;
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync return true;
6b2a50fc09aa4f7ce2082284f082d97a2c738321vboxsync * Strips the current line.
73ba84f95f918cc170be38908ad240fbb2f8f354vboxsync * The string length may change.
5159c4c6485473c77871b515c15b59c3caa60b46vboxsync * @returns Pointer to the first non-space character.
5159c4c6485473c77871b515c15b59c3caa60b46vboxsync * @param pMap The map file handle.
5159c4c6485473c77871b515c15b59c3caa60b46vboxsync * @param pcch Where to return the length of the unstripped
5159c4c6485473c77871b515c15b59c3caa60b46vboxsync * part. Optional.
5159c4c6485473c77871b515c15b59c3caa60b46vboxsyncstatic char *mapStripCurrentLine(PBIOSMAP pMap, size_t *pcch)
5159c4c6485473c77871b515c15b59c3caa60b46vboxsync * Reads a line from the file and right strips it.
5159c4c6485473c77871b515c15b59c3caa60b46vboxsync * @returns Pointer to szLine on success, @c NULL + msg on failure, @c NULL on
73ba84f95f918cc170be38908ad240fbb2f8f354vboxsync * @param pMap The map file handle.
6b2a50fc09aa4f7ce2082284f082d97a2c738321vboxsync * @param pcch Where to return the length of the unstripped
6b2a50fc09aa4f7ce2082284f082d97a2c738321vboxsync * part. Optional.
6b2a50fc09aa4f7ce2082284f082d97a2c738321vboxsyncstatic char *mapReadLineStripRight(PBIOSMAP pMap, size_t *pcch)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * mapReadLine() + mapStripCurrentLine().
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns Pointer to the first non-space character in the new line. NULL on
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * read error (bitched already) or end of file.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pMap The map file handle.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcch Where to return the length of the unstripped
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * part. Optional.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic char *mapReadLineStrip(PBIOSMAP pMap, size_t *pcch)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Parses a word, copying it into the supplied buffer, and skipping any spaces
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * following it.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns @c true on success, @c false on failure.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param ppszCursor Pointer to the cursor variable.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pszBuf The output buffer.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cbBuf The size of the output buffer.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool mapParseWord(char **ppszCursor, char *pszBuf, size_t cbBuf)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Check that we start on a non-blank. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Find the end of the word. */
dfa8f8fe70f68c12b11d4b15354571131dc75becvboxsync /* Copy it. */
dfa8f8fe70f68c12b11d4b15354571131dc75becvboxsync size_t cchWord = (uintptr_t)psz - (uintptr_t)pszStart;
67b8a5a52c43a79ea7e159dbbeec99687fb9cd3bvboxsync return false;
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync /* Skip blanks following it. */
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync return true;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * Parses an 16:16 address.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @returns @c true on success, @c false on failure.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param ppszCursor Pointer to the cursor variable.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pAddr Where to return the address.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool mapParseAddress(char **ppszCursor, PRTFAR16 pAddr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!mapParseWord(ppszCursor, szWord, sizeof(szWord)))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* An address is at least 16:16 format. It may be 16:32. It may also be flagged. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Drop flag if present. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Convert it. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc1 = RTStrToUInt16Full(szWord, 16, &pAddr->sel);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc2 = RTStrToUInt16Full(szWord + 5, 16, &pAddr->off);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Parses a size.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns @c true on success, @c false on failure.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param ppszCursor Pointer to the cursor variable.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pcb Where to return the size.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool mapParseSize(char **ppszCursor, uint32_t *pcb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!mapParseWord(ppszCursor, szWord, sizeof(szWord)))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Parses a section box and the following column header.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns @c true on success, @c false + msg on failure, @c false on eof.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pMap Map file handle.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pszSectionNm The expected section name.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cColumns The number of columns.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param ... The column names.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool mapSkipThruColumnHeadings(PBIOSMAP pMap, const char *pszSectionNm, uint32_t cColumns, ...)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* +------------+ */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTMsgError("%s:%d: Expected section box: +-----...", pMap->pszMapFile, pMap->iLine);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync /* | pszSectionNm | */
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync return false;
fdb57e5580007400346665b64c0e14ca1d149019vboxsync RTMsgError("%s:%d: Expected section box: | %s |", pMap->pszMapFile, pMap->iLine, pszSectionNm);
fdb57e5580007400346665b64c0e14ca1d149019vboxsync return false;
fdb57e5580007400346665b64c0e14ca1d149019vboxsync /* +------------+ */
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync return false;
29e87957eab05faee4ca07215447062bd927ce67vboxsync RTMsgError("%s:%d: Expected section box: +-----...", pMap->pszMapFile, pMap->iLine);
29e87957eab05faee4ca07215447062bd927ce67vboxsync return false;
29e87957eab05faee4ca07215447062bd927ce67vboxsync /* There may be a few lines describing the table notation now, surrounded by blank lines. */
fdb57e5580007400346665b64c0e14ca1d149019vboxsync return false;
fdb57e5580007400346665b64c0e14ca1d149019vboxsync /* Should have the column heading now. */
fdb57e5580007400346665b64c0e14ca1d149019vboxsync RTMsgError("%s:%d: Expected column '%s' found '%s'", pMap->pszMapFile, pMap->iLine, pszColumn, psz);
fdb57e5580007400346665b64c0e14ca1d149019vboxsync return false;
fdb57e5580007400346665b64c0e14ca1d149019vboxsync /* The next line is the underlining. */
fdb57e5580007400346665b64c0e14ca1d149019vboxsync return false;
fdb57e5580007400346665b64c0e14ca1d149019vboxsync RTMsgError("%s:%d: Expected column header underlining", pMap->pszMapFile, pMap->iLine);
fdb57e5580007400346665b64c0e14ca1d149019vboxsync return false;
fdb57e5580007400346665b64c0e14ca1d149019vboxsync /* Skip one blank line. */
fdb57e5580007400346665b64c0e14ca1d149019vboxsync return false;
fdb57e5580007400346665b64c0e14ca1d149019vboxsync RTMsgError("%s:%d: Expected blank line beneath the column headers", pMap->pszMapFile, pMap->iLine);
fdb57e5580007400346665b64c0e14ca1d149019vboxsync return false;
fdb57e5580007400346665b64c0e14ca1d149019vboxsync return true;
fdb57e5580007400346665b64c0e14ca1d149019vboxsync * Parses a segment list.
fdb57e5580007400346665b64c0e14ca1d149019vboxsync * @returns @c true on success, @c false + msg on failure, @c false on eof.
fdb57e5580007400346665b64c0e14ca1d149019vboxsync * @param pMap The map file handle.
fdb57e5580007400346665b64c0e14ca1d149019vboxsync return false;
fdb57e5580007400346665b64c0e14ca1d149019vboxsync /* The end? The line should be empty. Expectes segment name to not
fdb57e5580007400346665b64c0e14ca1d149019vboxsync start with a space. */
fdb57e5580007400346665b64c0e14ca1d149019vboxsync if (!pMap->szLine[0] || RT_C_IS_SPACE(pMap->szLine[0]))
fdb57e5580007400346665b64c0e14ca1d149019vboxsync return true;
1389294d44ac76b0a25f5655756c9d39855a73efvboxsync RTMsgError("%s:%u: Malformed segment line", pMap->pszMapFile, pMap->iLine);
1389294d44ac76b0a25f5655756c9d39855a73efvboxsync return false;
fdb57e5580007400346665b64c0e14ca1d149019vboxsync /* Parse the segment line. */
fdb57e5580007400346665b64c0e14ca1d149019vboxsync RTMsgError("%s:%u: Too many segments", pMap->pszMapFile, pMap->iLine);
fdb57e5580007400346665b64c0e14ca1d149019vboxsync return false;
fdb57e5580007400346665b64c0e14ca1d149019vboxsync if (!mapParseWord(&psz, g_aSegs[iSeg].szName, sizeof(g_aSegs[iSeg].szName)))
fdb57e5580007400346665b64c0e14ca1d149019vboxsync RTMsgError("%s:%u: Segment name parser error", pMap->pszMapFile, pMap->iLine);
fdb57e5580007400346665b64c0e14ca1d149019vboxsync else if (!mapParseWord(&psz, g_aSegs[iSeg].szClass, sizeof(g_aSegs[iSeg].szClass)))
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync RTMsgError("%s:%u: Segment class parser error", pMap->pszMapFile, pMap->iLine);
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync else if (!mapParseWord(&psz, g_aSegs[iSeg].szGroup, sizeof(g_aSegs[iSeg].szGroup)))
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync RTMsgError("%s:%u: Segment group parser error", pMap->pszMapFile, pMap->iLine);
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync else if (!mapParseAddress(&psz, &g_aSegs[iSeg].Address))
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync RTMsgError("%s:%u: Segment address parser error", pMap->pszMapFile, pMap->iLine);
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync RTMsgError("%s:%u: Segment size parser error", pMap->pszMapFile, pMap->iLine);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync g_aSegs[iSeg].uFlatAddr = ((uint32_t)g_aSegs[iSeg].Address.sel << 4) + g_aSegs[iSeg].Address.off;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTStrmPrintf(g_pStdErr, "read segment at %08x / %04x:%04x LB %04x %s / %s / %s\n",
e6ad2e18e663b076aeabfec994947514566a7accvboxsync RTMsgError("%s:%u: Junk at end of line", pMap->pszMapFile, pMap->iLine);
e6ad2e18e663b076aeabfec994947514566a7accvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Sorts the segment array by flat address and adds them to the debug module.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns @c true on success, @c false + msg on failure, @c false on eof.
3ea1dbf096240fc221aea99352a74c17a367a9b6vboxsyncstatic bool mapSortAndAddSegments(void)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTStrmPrintf(g_pStdErr, "segment at %08x / %04x:%04x LB %04x %s / %s / %s\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = RTDbgModSegmentAdd(g_hMapMod, g_aSegs[i].uFlatAddr, g_aSegs[i].cb, g_aSegs[i].szName, 0 /*fFlags*/, &idx);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTMsgError("RTDbgModSegmentAdd failed on %s: %Rrc", g_aSegs[i].szName);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Parses a segment list.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns @c true on success, @c false + msg on failure, @c false on eof.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pMap The map file handle.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The end? The line should be empty. Expectes segment name to not
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync start with a space. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pMap->szLine[0] || RT_C_IS_SPACE(pMap->szLine[0]))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!strncmp(pMap->szLine, RT_STR_TUPLE("Module: ")))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Parse the module line. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync while ((ch = pMap->szLine[offSrc]) != '(' && ch != '\0')
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync while ((ch = pMap->szLine[cchSrc]) != ')' && ch != '\0')
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return mapError(pMap, "Symbol/Module line parse error");
e6ad2e18e663b076aeabfec994947514566a7accvboxsync PBIOSOBJFILE pObjFile = (PBIOSOBJFILE)RTMemAllocZ(sizeof(*pObjFile) + cchSrc + cchObj + 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Parse the segment line. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return mapError(pMap, "Symbol address parser error");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t uFlatAddr = ((uint32_t)Addr.sel << 4) + Addr.off;
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync int rc = RTDbgModSymbolAdd(g_hMapMod, szName, RTDBGSEGIDX_RVA, uFlatAddr, 0 /*cb*/, 0 /*fFlags*/, NULL);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync if (RT_FAILURE(rc) && rc != VERR_DBG_ADDRESS_CONFLICT)
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync /* HACK ALERT! For dealing with lables at segment size. */ /** @todo fix end labels. */
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync rc = RTDbgModSymbolAdd(g_hMapMod, szName, RTDBGSEGIDX_RVA, uFlatAddr - 1, 0 /*cb*/, 0 /*fFlags*/, NULL);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync if (RT_FAILURE(rc) && rc != VERR_DBG_ADDRESS_CONFLICT)
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync return mapError(pMap, "RTDbgModSymbolAdd failed: %Rrc", rc);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync RTStrmPrintf(g_pStdErr, "read symbol - %08x %s\n", uFlatAddr, szName);
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync * Parses the given map file.
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync * @returns RTEXITCODE_SUCCESS and lots of globals, or RTEXITCODE_FAILURE and a
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync * error message.
105b1a31b6037dbe14acb8d09e60da540885202bvboxsync * @param pMap The map file handle.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = RTDbgModCreate(&g_hMapMod, "VBoxBios", 0 /*cbSeg*/, 0 /*fFlags*/);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDbgModCreate failed: %Rrc", rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Read the header.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (strncmp(pMap->szLine, RT_STR_TUPLE("Open Watcom Linker Version")))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Unexpected map-file header: '%s'", pMap->szLine);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Skip groups.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!mapSkipThruColumnHeadings(pMap, "Groups", 3, "Group", "Address", "Size", NULL))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Parse segments.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!mapSkipThruColumnHeadings(pMap, "Segments", 5, "Segment", "Class", "Group", "Address", "Size"))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Parse symbols.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!mapSkipThruColumnHeadings(pMap, "Memory Map", 2, "Address", "Symbol"))
423b1ce7f19ff0687e825ddc42d8bc6c68a4c9cdvboxsync /* Ignore the rest of the file. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Parses the linker map file for the BIOS.
423b1ce7f19ff0687e825ddc42d8bc6c68a4c9cdvboxsync * This is generated by the Watcom linker.
ad290511521ce8388a9926b165241ecf83c330a7vboxsync * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
423b1ce7f19ff0687e825ddc42d8bc6c68a4c9cdvboxsync * @param pszBiosMap Path to the map file.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic RTEXITCODE ParseMapFile(const char *pszBiosMap)
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening '%s': %Rrc", pszBiosMap, rc);
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync * Reads the BIOS image into memory (g_pbImg and g_cbImg).
cb0578a5309e1fc264e5a4acc30543bea075be43vboxsync * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
fdb57e5580007400346665b64c0e14ca1d149019vboxsync * @param pszBiosImg Path to the image file.
fdb57e5580007400346665b64c0e14ca1d149019vboxsyncstatic RTEXITCODE ReadBiosImage(const char *pszBiosImg)
fdb57e5580007400346665b64c0e14ca1d149019vboxsync int rc = RTFileReadAll(pszBiosImg, &pvImg, &cbImg);
fdb57e5580007400346665b64c0e14ca1d149019vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error reading '%s': %Rrc", pszBiosImg, rc);
fdb57e5580007400346665b64c0e14ca1d149019vboxsync default: cbImgExpect = 0; break;
fdb57e5580007400346665b64c0e14ca1d149019vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "The BIOS image %u bytes intead of %u bytes", cbImg, cbImgExpect);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Option config.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = RTGetOptInit(&GetOptState, argc, argv, &s_aOpts[0], RT_ELEMENTS(s_aOpts), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
e6ad2e18e663b076aeabfec994947514566a7accvboxsync * Process the options.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync while ((rc = RTGetOpt(&GetOptState, &ValueUnion)) != 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--bios-image is given more than once");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--bios-map is given more than once");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--bios-sym is given more than once");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--output is given more than once");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown bios type '%s'", ValueUnion.psz);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTPrintf("usage: %Rbn --bios-image <file.img> --bios-map <file.map> [--output <file.asm>]\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The following is assuming that svn does it's job here. */
635c83753ed04cf3637e019af0e15ba40e07f2fevboxsync * Got it all?
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--bios-image is required");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--bios-map is required");
3fa7a7e633f46a212052b510cdb8cee41f279a67vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--bios-sym is required");
635c83753ed04cf3637e019af0e15ba40e07f2fevboxsync * Do the job.