VirtualBox

source: vbox/trunk/src/VBox/Devices/BiosCommonCode/MakeAlternativeSource.cpp@ 59890

Last change on this file since 59890 was 59747, checked in by vboxsync, 9 years ago

iprt/asm.h: Cleaned up the ASMMemIsAll8/U32 mess and implmeneted the former in assembly. (Found inverted usage due to bad naming in copyUtf8Block, but it is fortunately an unused method.) Replaces the complicated ASMBitFirstSet based scanning in RTSgBufIsZero with a simple call to the new ASMMemIsZero function.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 60.9 KB
Line 
1/* $Id: MakeAlternativeSource.cpp 59747 2016-02-19 23:18:18Z vboxsync $ */
2/** @file
3 * MakeAlternative - Generate an Alternative BIOS Source that requires less tools.
4 */
5
6/*
7 * Copyright (C) 2012-2015 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 <iprt/asm.h>
23#include <iprt/buildconfig.h>
24#include <iprt/ctype.h>
25#include <iprt/dbg.h>
26#include <iprt/file.h>
27#include <iprt/getopt.h>
28#include <iprt/initterm.h>
29#include <iprt/list.h>
30#include <iprt/mem.h>
31#include <iprt/message.h>
32#include <iprt/string.h>
33#include <iprt/stream.h>
34#include <iprt/x86.h>
35
36#include <VBox/dis.h>
37
38
39/*********************************************************************************************************************************
40* Structures and Typedefs *
41*********************************************************************************************************************************/
42/**
43 * A BIOS segment.
44 */
45typedef struct BIOSSEG
46{
47 char szName[32];
48 char szClass[32];
49 char szGroup[32];
50 RTFAR16 Address;
51 uint32_t uFlatAddr;
52 uint32_t cb;
53} BIOSSEG;
54/** Pointer to a BIOS segment. */
55typedef BIOSSEG *PBIOSSEG;
56
57
58/**
59 * A BIOS object file.
60 */
61typedef struct BIOSOBJFILE
62{
63 RTLISTNODE Node;
64 char *pszSource;
65 char *pszObject;
66} BIOSOBJFILE;
67/** A BIOS object file. */
68typedef BIOSOBJFILE *PBIOSOBJFILE;
69
70
71/**
72 * Pointer to a BIOS map parser handle.
73 */
74typedef struct BIOSMAP
75{
76 /** The stream pointer. */
77 PRTSTREAM hStrm;
78 /** The file name. */
79 const char *pszMapFile;
80 /** Set when EOF has been reached. */
81 bool fEof;
82 /** The current line number (0 based).*/
83 uint32_t iLine;
84 /** The length of the current line. */
85 uint32_t cch;
86 /** The offset of the first non-white character on the line. */
87 uint32_t offNW;
88 /** The line buffer. */
89 char szLine[16384];
90} BIOSMAP;
91/** Pointer to a BIOS map parser handle. */
92typedef BIOSMAP *PBIOSMAP;
93
94
95/*********************************************************************************************************************************
96* Global Variables *
97*********************************************************************************************************************************/
98/** The verbosity level.*/
99static unsigned g_cVerbose = 1 /*0*/;
100/** Pointer to the BIOS image. */
101static uint8_t const *g_pbImg;
102/** The size of the BIOS image. */
103static size_t g_cbImg;
104
105/** Debug module for the map file. */
106static RTDBGMOD g_hMapMod = NIL_RTDBGMOD;
107/** The number of BIOS segments found in the map file. */
108static uint32_t g_cSegs = 0;
109/** Array of BIOS segments from the map file. */
110static BIOSSEG g_aSegs[32];
111/** List of BIOSOBJFILE. */
112static RTLISTANCHOR g_ObjList;
113
114/** The output stream. */
115static PRTSTREAM g_hStrmOutput = NULL;
116
117/** The type of BIOS we're working on. */
118static enum BIOSTYPE
119{
120 kBiosType_System = 0,
121 kBiosType_Vga
122} g_enmBiosType = kBiosType_System;
123/** The flat ROM base address. */
124static uint32_t g_uBiosFlatBase = 0xf0000;
125
126
127static bool outputPrintfV(const char *pszFormat, va_list va)
128{
129 int rc = RTStrmPrintfV(g_hStrmOutput, pszFormat, va);
130 if (RT_FAILURE(rc))
131 {
132 RTMsgError("Output error: %Rrc\n", rc);
133 return false;
134 }
135 return true;
136}
137
138
139static bool outputPrintf(const char *pszFormat, ...)
140{
141 va_list va;
142 va_start(va, pszFormat);
143 bool fRc = outputPrintfV(pszFormat, va);
144 va_end(va);
145 return fRc;
146}
147
148
149/**
150 * Opens the output file for writing.
151 *
152 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
153 * @param pszOutput Path to the output file.
154 */
155static RTEXITCODE OpenOutputFile(const char *pszOutput)
156{
157 if (!pszOutput)
158 g_hStrmOutput = g_pStdOut;
159 else
160 {
161 int rc = RTStrmOpen(pszOutput, "w", &g_hStrmOutput);
162 if (RT_FAILURE(rc))
163 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to open output file '%s': %Rrc", pszOutput, rc);
164 }
165 return RTEXITCODE_SUCCESS;
166}
167
168
169/**
170 * Displays a disassembly error and returns @c false.
171 *
172 * @returns @c false.
173 * @param pszFormat The error format string.
174 * @param ... Format argument.
175 */
176static bool disError(const char *pszFormat, ...)
177{
178 va_list va;
179 va_start(va, pszFormat);
180 RTMsgErrorV(pszFormat, va);
181 va_end(va);
182 return false;
183}
184
185
186/**
187 * Output the disassembly file header.
188 *
189 * @returns @c true on success,
190 */
191static bool disFileHeader(void)
192{
193 bool fRc;
194 fRc = outputPrintf("; $Id: MakeAlternativeSource.cpp 59747 2016-02-19 23:18:18Z vboxsync $ \n"
195 ";; @file\n"
196 "; Auto Generated source file. Do not edit.\n"
197 ";\n"
198 );
199 if (!fRc)
200 return fRc;
201
202 /*
203 * List the header of each source file, up to and including the
204 * copyright notice.
205 */
206 bool fNeedLgplDisclaimer = false;
207 PBIOSOBJFILE pObjFile;
208 RTListForEach(&g_ObjList, pObjFile, BIOSOBJFILE, Node)
209 {
210 PRTSTREAM hStrm;
211 int rc = RTStrmOpen(pObjFile->pszSource, "r", &hStrm);
212 if (RT_SUCCESS(rc))
213 {
214 fRc = outputPrintf("\n"
215 ";\n"
216 "; Source file: %Rbn\n"
217 ";\n"
218 , pObjFile->pszSource);
219 uint32_t iLine = 0;
220 bool fSeenCopyright = false;
221 char szLine[4096];
222 while ((rc = RTStrmGetLine(hStrm, szLine, sizeof(szLine))) == VINF_SUCCESS)
223 {
224 iLine++;
225
226 /* Check if we're done. */
227 char *psz = RTStrStrip(szLine);
228 if ( fSeenCopyright
229 && ( (psz[0] == '*' && psz[1] == '/')
230 || psz[0] == '\0') )
231 break;
232
233 /* Strip comment suffix. */
234 size_t cch = strlen(psz);
235 if (cch >= 2 && psz[cch - 1] == '/' && psz[cch - 2] == '*')
236 {
237 psz[cch - 2] = '\0';
238 RTStrStripR(psz);
239 }
240
241 /* Skip line prefix. */
242 if (psz[0] == '/' && psz[1] == '*')
243 psz += 2;
244 else if (psz[0] == '*')
245 psz += 1;
246 else
247 while (*psz == ';')
248 psz++;
249 if (RT_C_IS_SPACE(*psz))
250 psz++;
251
252 /* Skip the doxygen file tag line. */
253 if (!strcmp(psz, "* @file") || !strcmp(psz, "@file"))
254 continue;
255
256 /* Detect copyright section. */
257 if ( !fSeenCopyright
258 && ( strstr(psz, "Copyright")
259 || strstr(psz, "copyright")) )
260 fSeenCopyright = true;
261
262 /* Detect LGPL. */
263 if (strstr(psz, "LGPL"))
264 fNeedLgplDisclaimer = true;
265
266 fRc = outputPrintf("; %s\n", psz) && fRc;
267 }
268
269 RTStrmClose(hStrm);
270 if (rc != VINF_SUCCESS)
271 return disError("Error reading '%s': rc=%Rrc iLine=%u", pObjFile->pszSource, rc, iLine);
272 }
273 }
274
275 /*
276 * Add Oracle LGPL disclaimer.
277 */
278 if (fNeedLgplDisclaimer)
279 outputPrintf("\n"
280 ";\n"
281 "; Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice\n"
282 "; other than GPL or LGPL is available it will apply instead, Oracle elects to use only\n"
283 "; the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where\n"
284 "; a choice of LGPL license versions is made available with the language indicating\n"
285 "; that LGPLv2 or any later version may be used, or where a choice of which version\n"
286 "; of the LGPL is applied is otherwise unspecified.\n"
287 ";\n"
288 "\n");
289
290 /*
291 * Set the org.
292 */
293 fRc = outputPrintf("\n"
294 "\n"
295 "\n"
296 ) && fRc;
297 return fRc;
298}
299
300
301/**
302 * Checks if a byte sequence could be a string litteral.
303 *
304 * @returns @c true if it is, @c false if it isn't.
305 * @param uFlatAddr The address of the byte sequence.
306 * @param cb The length of the sequence.
307 */
308static bool disIsString(uint32_t uFlatAddr, uint32_t cb)
309{
310 if (cb < 6)
311 return false;
312
313 uint8_t const *pb = &g_pbImg[uFlatAddr - g_uBiosFlatBase];
314 while (cb > 0)
315 {
316 if ( !RT_C_IS_PRINT(*pb)
317 && *pb != '\r'
318 && *pb != '\n'
319 && *pb != '\t')
320 {
321 if (*pb == '\0')
322 {
323 do
324 {
325 pb++;
326 cb--;
327 } while (cb > 0 && *pb == '\0');
328 return cb == 0;
329 }
330 return false;
331 }
332 pb++;
333 cb--;
334 }
335
336 return true;
337}
338
339
340/**
341 * Checks if a dword could be a far 16:16 BIOS address.
342 *
343 * @returns @c true if it is, @c false if it isn't.
344 * @param uFlatAddr The address of the dword.
345 */
346static bool disIsFarBiosAddr(uint32_t uFlatAddr)
347{
348 uint16_t const *pu16 = (uint16_t const *)&g_pbImg[uFlatAddr - g_uBiosFlatBase];
349 if (pu16[1] < 0xf000)
350 return false;
351 if (pu16[1] > 0xfff0)
352 return false;
353 uint32_t uFlatAddr2 = (uint32_t)(pu16[1] << 4) | pu16[0];
354 if (uFlatAddr2 >= g_uBiosFlatBase + g_cbImg)
355 return false;
356 return true;
357}
358
359
360static bool disByteData(uint32_t uFlatAddr, uint32_t cb)
361{
362 uint8_t const *pb = &g_pbImg[uFlatAddr - g_uBiosFlatBase];
363 size_t cbOnLine = 0;
364 while (cb-- > 0)
365 {
366 bool fRc;
367 if (cbOnLine >= 16)
368 {
369 fRc = outputPrintf("\n"
370 " db 0%02xh", *pb);
371 cbOnLine = 1;
372 }
373 else if (!cbOnLine)
374 {
375 fRc = outputPrintf(" db 0%02xh", *pb);
376 cbOnLine = 1;
377 }
378 else
379 {
380 fRc = outputPrintf(", 0%02xh", *pb);
381 cbOnLine++;
382 }
383 if (!fRc)
384 return false;
385 pb++;
386 }
387 return outputPrintf("\n");
388}
389
390
391static bool disWordData(uint32_t uFlatAddr, uint32_t cb)
392{
393 if (cb & 1)
394 return disError("disWordData expects word aligned size: cb=%#x uFlatAddr=%#x", uFlatAddr, cb);
395
396 uint16_t const *pu16 = (uint16_t const *)&g_pbImg[uFlatAddr - g_uBiosFlatBase];
397 size_t cbOnLine = 0;
398 while (cb > 0)
399 {
400 bool fRc;
401 if (cbOnLine >= 16)
402 {
403 fRc = outputPrintf("\n"
404 " dw 0%04xh", *pu16);
405 cbOnLine = 2;
406 }
407 else if (!cbOnLine)
408 {
409 fRc = outputPrintf(" dw 0%04xh", *pu16);
410 cbOnLine = 2;
411 }
412 else
413 {
414 fRc = outputPrintf(", 0%04xh", *pu16);
415 cbOnLine += 2;
416 }
417 if (!fRc)
418 return false;
419 pu16++;
420 cb -= 2;
421 }
422 return outputPrintf("\n");
423}
424
425
426static bool disDWordData(uint32_t uFlatAddr, uint32_t cb)
427{
428 if (cb & 3)
429 return disError("disWordData expects dword aligned size: cb=%#x uFlatAddr=%#x", uFlatAddr, cb);
430
431 uint32_t const *pu32 = (uint32_t const *)&g_pbImg[uFlatAddr - g_uBiosFlatBase];
432 size_t cbOnLine = 0;
433 while (cb > 0)
434 {
435 bool fRc;
436 if (cbOnLine >= 16)
437 {
438 fRc = outputPrintf("\n"
439 " dd 0%08xh", *pu32);
440 cbOnLine = 4;
441 }
442 else if (!cbOnLine)
443 {
444 fRc = outputPrintf(" dd 0%08xh", *pu32);
445 cbOnLine = 4;
446 }
447 else
448 {
449 fRc = outputPrintf(", 0%08xh", *pu32);
450 cbOnLine += 4;
451 }
452 if (!fRc)
453 return false;
454 pu32++;
455 cb -= 4;
456 }
457 return outputPrintf("\n");
458}
459
460
461static bool disStringData(uint32_t uFlatAddr, uint32_t cb)
462{
463 uint8_t const *pb = &g_pbImg[uFlatAddr - g_uBiosFlatBase];
464 uint32_t cchOnLine = 0;
465 while (cb > 0)
466 {
467 /* Line endings and beginnings. */
468 if (cchOnLine >= 72)
469 {
470 if (!outputPrintf("\n"))
471 return false;
472 cchOnLine = 0;
473 }
474 if ( !cchOnLine
475 && !outputPrintf(" db "))
476 return false;
477
478 /* See how many printable character we've got. */
479 uint32_t cchPrintable = 0;
480 while ( cchPrintable < cb
481 && RT_C_IS_PRINT(pb[cchPrintable])
482 && pb[cchPrintable] != '\'')
483 cchPrintable++;
484
485 bool fRc = true;
486 if (cchPrintable)
487 {
488 if (cchPrintable + cchOnLine > 72)
489 cchPrintable = 72 - cchOnLine;
490 if (cchOnLine)
491 {
492 fRc = outputPrintf(", '%.*s'", cchPrintable, pb);
493 cchOnLine += 4 + cchPrintable;
494 }
495 else
496 {
497 fRc = outputPrintf("'%.*s'", cchPrintable, pb);
498 cchOnLine += 2 + cchPrintable;
499 }
500 pb += cchPrintable;
501 cb -= cchPrintable;
502 }
503 else
504 {
505 if (cchOnLine)
506 {
507 fRc = outputPrintf(", 0%02xh", *pb);
508 cchOnLine += 6;
509 }
510 else
511 {
512 fRc = outputPrintf("0%02xh", *pb);
513 cchOnLine += 4;
514 }
515 pb++;
516 cb--;
517 }
518 if (!fRc)
519 return false;
520 }
521 return outputPrintf("\n");
522}
523
524
525/**
526 * For dumping a portion of a string table.
527 *
528 * @returns @c true on success, @c false on failure.
529 * @param uFlatAddr The start address.
530 * @param cb The size of the string table.
531 */
532static bool disStringsData(uint32_t uFlatAddr, uint32_t cb)
533{
534 uint8_t const *pb = &g_pbImg[uFlatAddr - g_uBiosFlatBase];
535 uint32_t cchOnLine = 0;
536 uint8_t bPrev = 255;
537 while (cb > 0)
538 {
539 /* Line endings and beginnings. */
540 if ( cchOnLine >= 72
541 || (bPrev == '\0' && *pb != '\0'))
542 {
543 if (!outputPrintf("\n"))
544 return false;
545 cchOnLine = 0;
546 }
547 if ( !cchOnLine
548 && !outputPrintf(" db "))
549 return false;
550
551 /* See how many printable character we've got. */
552 uint32_t cchPrintable = 0;
553 while ( cchPrintable < cb
554 && RT_C_IS_PRINT(pb[cchPrintable])
555 && pb[cchPrintable] != '\'')
556 cchPrintable++;
557
558 bool fRc = true;
559 if (cchPrintable)
560 {
561 if (cchPrintable + cchOnLine > 72)
562 cchPrintable = 72 - cchOnLine;
563 if (cchOnLine)
564 {
565 fRc = outputPrintf(", '%.*s'", cchPrintable, pb);
566 cchOnLine += 4 + cchPrintable;
567 }
568 else
569 {
570 fRc = outputPrintf("'%.*s'", cchPrintable, pb);
571 cchOnLine += 2 + cchPrintable;
572 }
573 pb += cchPrintable;
574 cb -= cchPrintable;
575 }
576 else
577 {
578 if (cchOnLine)
579 {
580 fRc = outputPrintf(", 0%02xh", *pb);
581 cchOnLine += 6;
582 }
583 else
584 {
585 fRc = outputPrintf("0%02xh", *pb);
586 cchOnLine += 4;
587 }
588 pb++;
589 cb--;
590 }
591 if (!fRc)
592 return false;
593 bPrev = pb[-1];
594 }
595 return outputPrintf("\n");
596}
597
598
599/**
600 * Minds the gap between two segments.
601 *
602 * Gaps should generally be zero filled.
603 *
604 * @returns @c true on success, @c false on failure.
605 * @param uFlatAddr The address of the gap.
606 * @param cbPadding The size of the gap.
607 */
608static bool disCopySegmentGap(uint32_t uFlatAddr, uint32_t cbPadding)
609{
610 if (g_cVerbose > 0)
611 outputPrintf("\n"
612 " ; Padding %#x bytes at %#x\n", cbPadding, uFlatAddr);
613 uint8_t const *pb = &g_pbImg[uFlatAddr - g_uBiosFlatBase];
614 if (ASMMemIsZero(pb, cbPadding))
615 return outputPrintf(" times %u db 0\n", cbPadding);
616
617 return disByteData(uFlatAddr, cbPadding);
618}
619
620
621/**
622 * Worker for disGetNextSymbol that only does the looking up, no RTDBSYMBOL::cb
623 * calc.
624 *
625 * @param uFlatAddr The address to start searching at.
626 * @param cbMax The size of the search range.
627 * @param poff Where to return the offset between the symbol
628 * and @a uFlatAddr.
629 * @param pSym Where to return the symbol data.
630 */
631static void disGetNextSymbolWorker(uint32_t uFlatAddr, uint32_t cbMax, uint32_t *poff, PRTDBGSYMBOL pSym)
632{
633 RTINTPTR off = 0;
634 int rc = RTDbgModSymbolByAddr(g_hMapMod, RTDBGSEGIDX_RVA, uFlatAddr, RTDBGSYMADDR_FLAGS_GREATER_OR_EQUAL, &off, pSym);
635 if (RT_SUCCESS(rc))
636 {
637 /* negative offset, indicates beyond. */
638 if (off <= 0)
639 {
640 *poff = (uint32_t)-off;
641 return;
642 }
643
644 outputPrintf(" ; !! RTDbgModSymbolByAddr(,,%#x,,) -> off=%RTptr cb=%RTptr uValue=%RTptr '%s'\n",
645 uFlatAddr, off, pSym->cb, pSym->Value, pSym->szName);
646 }
647 else if (rc != VERR_SYMBOL_NOT_FOUND)
648 outputPrintf(" ; !! RTDbgModSymbolByAddr(,,%#x,,) -> %Rrc\n", uFlatAddr, rc);
649
650 RTStrPrintf(pSym->szName, sizeof(pSym->szName), "_dummy_addr_%#x", uFlatAddr + cbMax);
651 pSym->Value = uFlatAddr + cbMax;
652 pSym->cb = 0;
653 pSym->offSeg = uFlatAddr + cbMax;
654 pSym->iSeg = RTDBGSEGIDX_RVA;
655 pSym->iOrdinal = 0;
656 pSym->fFlags = 0;
657 *poff = cbMax;
658}
659
660
661/**
662 * Gets the symbol at or after the given address.
663 *
664 * If there are no symbols in the specified range, @a pSym and @a poff will be
665 * set up to indicate a symbol at the first byte after the range.
666 *
667 * @param uFlatAddr The address to start searching at.
668 * @param cbMax The size of the search range.
669 * @param poff Where to return the offset between the symbol
670 * and @a uFlatAddr.
671 * @param pSym Where to return the symbol data.
672 */
673static void disGetNextSymbol(uint32_t uFlatAddr, uint32_t cbMax, uint32_t *poff, PRTDBGSYMBOL pSym)
674{
675 disGetNextSymbolWorker(uFlatAddr, cbMax, poff, pSym);
676 if ( *poff < cbMax
677 && pSym->cb == 0)
678 {
679 if (*poff + 1 < cbMax)
680 {
681 uint32_t off2;
682 RTDBGSYMBOL Sym2;
683 disGetNextSymbolWorker(uFlatAddr + *poff + 1, cbMax - *poff - 1, &off2, &Sym2);
684 pSym->cb = off2 + 1;
685 }
686 else
687 pSym->cb = 1;
688 }
689 if (pSym->cb > cbMax - *poff)
690 pSym->cb = cbMax - *poff;
691
692 if (g_cVerbose > 1)
693 outputPrintf(" ; disGetNextSymbol %#x LB %#x -> off=%#x cb=%RTptr uValue=%RTptr '%s'\n",
694 uFlatAddr, cbMax, *poff, pSym->cb, pSym->Value, pSym->szName);
695
696}
697
698
699/**
700 * For dealing with the const segment (string constants).
701 *
702 * @returns @c true on success, @c false on failure.
703 * @param iSeg The segment.
704 */
705static bool disConstSegment(uint32_t iSeg)
706{
707 uint32_t uFlatAddr = g_aSegs[iSeg].uFlatAddr;
708 uint32_t cb = g_aSegs[iSeg].cb;
709
710 while (cb > 0)
711 {
712 uint32_t off;
713 RTDBGSYMBOL Sym;
714 disGetNextSymbol(uFlatAddr, cb, &off, &Sym);
715
716 if (off > 0)
717 {
718 if (!disStringsData(uFlatAddr, off))
719 return false;
720 cb -= off;
721 uFlatAddr += off;
722 off = 0;
723 if (!cb)
724 break;
725 }
726
727 bool fRc;
728 if (off == 0)
729 {
730 size_t cchName = strlen(Sym.szName);
731 fRc = outputPrintf("%s: %*s; %#x LB %#x\n", Sym.szName, cchName < 41 - 2 ? cchName - 41 - 2 : 0, "", uFlatAddr, Sym.cb);
732 if (!fRc)
733 return false;
734 fRc = disStringsData(uFlatAddr, Sym.cb);
735 uFlatAddr += Sym.cb;
736 cb -= Sym.cb;
737 }
738 else
739 {
740 fRc = disStringsData(uFlatAddr, Sym.cb);
741 uFlatAddr += cb;
742 cb = 0;
743 }
744 if (!fRc)
745 return false;
746 }
747
748 return true;
749}
750
751
752
753static bool disDataSegment(uint32_t iSeg)
754{
755 uint32_t uFlatAddr = g_aSegs[iSeg].uFlatAddr;
756 uint32_t cb = g_aSegs[iSeg].cb;
757
758 while (cb > 0)
759 {
760 uint32_t off;
761 RTDBGSYMBOL Sym;
762 disGetNextSymbol(uFlatAddr, cb, &off, &Sym);
763
764 if (off > 0)
765 {
766 if (!disByteData(uFlatAddr, off))
767 return false;
768 cb -= off;
769 uFlatAddr += off;
770 off = 0;
771 if (!cb)
772 break;
773 }
774
775 bool fRc;
776 if (off == 0)
777 {
778 size_t cchName = strlen(Sym.szName);
779 fRc = outputPrintf("%s: %*s; %#x LB %#x\n", Sym.szName, cchName < 41 - 2 ? cchName - 41 - 2 : 0, "", uFlatAddr, Sym.cb);
780 if (!fRc)
781 return false;
782
783 if (Sym.cb == 2)
784 fRc = disWordData(uFlatAddr, 2);
785 //else if (Sym.cb == 4 && disIsFarBiosAddr(uFlatAddr))
786 // fRc = disDWordData(uFlatAddr, 4);
787 else if (Sym.cb == 4)
788 fRc = disDWordData(uFlatAddr, 4);
789 else if (disIsString(uFlatAddr, Sym.cb))
790 fRc = disStringData(uFlatAddr, Sym.cb);
791 else
792 fRc = disByteData(uFlatAddr, Sym.cb);
793
794 uFlatAddr += Sym.cb;
795 cb -= Sym.cb;
796 }
797 else
798 {
799 fRc = disByteData(uFlatAddr, cb);
800 uFlatAddr += cb;
801 cb = 0;
802 }
803 if (!fRc)
804 return false;
805 }
806
807 return true;
808}
809
810
811static bool disIsCodeAndAdjustSize(uint32_t uFlatAddr, PRTDBGSYMBOL pSym, PBIOSSEG pSeg)
812{
813 switch (g_enmBiosType)
814 {
815 /*
816 * This is for the PC BIOS.
817 */
818 case kBiosType_System:
819 if (!strcmp(pSeg->szName, "BIOSSEG"))
820 {
821 if ( !strcmp(pSym->szName, "rom_fdpt")
822 || !strcmp(pSym->szName, "pmbios_gdt")
823 || !strcmp(pSym->szName, "pmbios_gdt_desc")
824 || !strcmp(pSym->szName, "_pmode_IDT")
825 || !strcmp(pSym->szName, "_rmode_IDT")
826 || !strncmp(pSym->szName, RT_STR_TUPLE("font"))
827 || !strcmp(pSym->szName, "bios_string")
828 || !strcmp(pSym->szName, "vector_table")
829 || !strcmp(pSym->szName, "pci_routing_table_structure")
830 || !strcmp(pSym->szName, "_pci_routing_table")
831 )
832 return false;
833 }
834
835 if (!strcmp(pSym->szName, "cpu_reset"))
836 pSym->cb = RT_MIN(pSym->cb, 5);
837 else if (!strcmp(pSym->szName, "pci_init_end"))
838 pSym->cb = RT_MIN(pSym->cb, 3);
839 break;
840
841 /*
842 * This is for the VGA BIOS.
843 */
844 case kBiosType_Vga:
845 break;
846 }
847
848 return true;
849}
850
851
852static bool disIs16BitCode(const char *pszSymbol)
853{
854 return true;
855}
856
857
858/**
859 * Deals with instructions that YASM will assemble differently than WASM/WCC.
860 */
861static size_t disHandleYasmDifferences(PDISCPUSTATE pCpuState, uint32_t uFlatAddr, uint32_t cbInstr,
862 char *pszBuf, size_t cbBuf, size_t cchUsed)
863{
864 bool fDifferent = DISFormatYasmIsOddEncoding(pCpuState);
865 uint8_t const *pb = &g_pbImg[uFlatAddr - g_uBiosFlatBase];
866
867 /*
868 * Disassembler bugs.
869 */
870 /** @todo Group 1a and 11 seems to be disassembled incorrectly when
871 * modrm.reg != 0. Those encodings should be invalid AFAICT. */
872
873 if ( ( pCpuState->bOpCode == 0x8f /* group 1a */
874 || pCpuState->bOpCode == 0xc7 /* group 11 */
875 || pCpuState->bOpCode == 0xc6 /* group 11 - not verified */
876 )
877 && pCpuState->ModRM.Bits.Reg != 0)
878 fDifferent = true;
879 /*
880 * Check these out and consider adding them to DISFormatYasmIsOddEncoding.
881 */
882 else if ( pb[0] == 0xf3
883 && pb[1] == 0x66
884 && pb[2] == 0x6d)
885 fDifferent = true; /* rep insd - prefix switched. */
886 else if ( pb[0] == 0xc6
887 && pb[1] == 0xc5
888 && pb[2] == 0xba)
889 fDifferent = true; /* mov ch, 0bah - yasm uses a short sequence: 0xb5 0xba. */
890
891 /*
892 * 32-bit retf.
893 */
894 else if ( pb[0] == 0x66
895 && pb[1] == 0xcb)
896 fDifferent = true;
897
898 /*
899 * Handle different stuff.
900 */
901 if (fDifferent)
902 {
903 disByteData(uFlatAddr, cbInstr); /* lazy bird. */
904
905 if (cchUsed + 2 < cbBuf)
906 {
907 memmove(pszBuf + 2, pszBuf, cchUsed + 1); /* include terminating \0 */
908 cchUsed += 2;
909 }
910
911 pszBuf[0] = ';';
912 pszBuf[1] = ' ';
913 }
914
915 return cchUsed;
916}
917
918
919/**
920 * @callback_method_impl{FNDISREADBYTES}
921 *
922 * @remarks @a uSrcAddr is the flat address.
923 */
924static DECLCALLBACK(int) disReadOpcodeBytes(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
925{
926 RTUINTPTR offBios = pDis->uInstrAddr + offInstr - g_uBiosFlatBase;
927 size_t cbToRead = cbMaxRead;
928 if (offBios + cbToRead > g_cbImg)
929 {
930 if (offBios >= g_cbImg)
931 cbToRead = 0;
932 else
933 cbToRead = g_cbImg - offBios;
934 }
935 memcpy(&pDis->abInstr[offInstr], &g_pbImg[offBios], cbToRead);
936 pDis->cbCachedInstr = (uint8_t)(offInstr + cbToRead);
937 return VINF_SUCCESS;
938}
939
940
941/**
942 * Disassembles code.
943 *
944 * @returns @c true on success, @c false on failure.
945 * @param uFlatAddr The address where the code starts.
946 * @param cb The amount of code to disassemble.
947 * @param fIs16Bit Is is 16-bit (@c true) or 32-bit (@c false).
948 */
949static bool disCode(uint32_t uFlatAddr, uint32_t cb, bool fIs16Bit)
950{
951 uint8_t const *pb = &g_pbImg[uFlatAddr - g_uBiosFlatBase];
952
953 while (cb > 0)
954 {
955 /* Trailing zero padding detection. */
956 if ( *pb == '\0'
957 && ASMMemIsZero(pb, RT_MIN(cb, 8)))
958 {
959 void *pv = ASMMemFirstNonZero(pb, cb);
960 uint32_t cbZeros = pv ? (uint32_t)((uint8_t const *)pv - pb) : cb;
961 if (!outputPrintf(" times %#x db 0\n", cbZeros))
962 return false;
963 cb -= cbZeros;
964 pb += cbZeros;
965 uFlatAddr += cbZeros;
966 if ( cb == 2
967 && pb[0] == 'X'
968 && pb[1] == 'M')
969 return disStringData(uFlatAddr, cb);
970 }
971 /* Work arounds for switch tables and such (disas assertions). */
972 else if ( 0
973 || ( pb[0] == 0x50 /* int13_cdemu switch */
974 && pb[1] == 0x4e
975 && pb[2] == 0x49
976 && pb[3] == 0x48
977 && pb[4] == 0x47
978 )
979 || ( pb[0] == 0x67 /* _pci16_function switch */
980 && pb[1] == 0x92
981 && pb[2] == 0x81
982 && pb[3] == 0x92
983 && pb[4] == 0x94
984 && pb[5] == 0x92
985 )
986 || ( pb[0] == 0xa3 /* _int1a_function switch */
987 && pb[1] == 0x67
988 && pb[2] == 0xca
989 && pb[3] == 0x67
990 && pb[4] == 0xef
991 && pb[5] == 0x67
992 )
993 || ( pb[0] == 0x0b /* _ahci_init byte table */
994 && pb[1] == 0x05
995 && pb[2] == 0x04
996 && pb[3] == 0x03
997 && pb[4] == 0x02
998 && pb[5] == 0x01
999 )
1000 || ( pb[0] == 0x8c /* bytes after apm_out_str_ */
1001 && pb[1] == 0x2f
1002 && pb[2] == 0x8d
1003 && pb[3] == 0xbb
1004 && pb[4] == 0x8c
1005 && pb[5] == 0x2f)
1006 || ( pb[0] == 0xec /* _int15_function switch */
1007 && pb[1] == 0xe9
1008 && pb[2] == 0xd8
1009 && pb[3] == 0xc1
1010 && pb[4] == 0xc0
1011 && pb[5] == 0xbf)
1012 || ( pb[0] == 0x21 /* _int15_function32 switch */
1013 && pb[1] == 0x66
1014 && pb[2] == 0x43
1015 && pb[3] == 0x66
1016 && pb[4] == 0x66
1017 && pb[5] == 0x66)
1018 || 0
1019 )
1020 return disByteData(uFlatAddr, cb);
1021 else
1022 {
1023 unsigned cbInstr;
1024 DISCPUSTATE CpuState;
1025 int rc = DISInstrWithReader(uFlatAddr, fIs16Bit ? DISCPUMODE_16BIT : DISCPUMODE_32BIT,
1026 disReadOpcodeBytes, NULL, &CpuState, &cbInstr);
1027 if ( RT_SUCCESS(rc)
1028 && cbInstr <= cb
1029 && CpuState.pCurInstr
1030 && CpuState.pCurInstr->uOpcode != OP_INVALID)
1031 {
1032 char szTmp[4096];
1033 size_t cch = DISFormatYasmEx(&CpuState, szTmp, sizeof(szTmp),
1034 DIS_FMT_FLAGS_STRICT
1035 | DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_COMMENT | DIS_FMT_FLAGS_BYTES_SPACED,
1036 NULL, NULL);
1037 cch = disHandleYasmDifferences(&CpuState, uFlatAddr, cbInstr, szTmp, sizeof(szTmp), cch);
1038 Assert(cch < sizeof(szTmp));
1039
1040 if (g_cVerbose > 1)
1041 {
1042 while (cch < 72)
1043 szTmp[cch++] = ' ';
1044 RTStrPrintf(&szTmp[cch], sizeof(szTmp) - cch, "; %#x", uFlatAddr);
1045 }
1046
1047 if (!outputPrintf(" %s\n", szTmp))
1048 return false;
1049 cb -= cbInstr;
1050 pb += cbInstr;
1051 uFlatAddr += cbInstr;
1052 }
1053 else
1054 {
1055 if (!disByteData(uFlatAddr, 1))
1056 return false;
1057 cb--;
1058 pb++;
1059 uFlatAddr++;
1060 }
1061 }
1062 }
1063 return true;
1064}
1065
1066
1067static bool disCodeSegment(uint32_t iSeg)
1068{
1069 uint32_t uFlatAddr = g_aSegs[iSeg].uFlatAddr;
1070 uint32_t cb = g_aSegs[iSeg].cb;
1071
1072 while (cb > 0)
1073 {
1074 uint32_t off;
1075 RTDBGSYMBOL Sym;
1076 disGetNextSymbol(uFlatAddr, cb, &off, &Sym);
1077
1078 if (off > 0)
1079 {
1080 if (!disByteData(uFlatAddr, off))
1081 return false;
1082 cb -= off;
1083 uFlatAddr += off;
1084 off = 0;
1085 if (!cb)
1086 break;
1087 }
1088
1089 bool fRc;
1090 if (off == 0)
1091 {
1092 size_t cchName = strlen(Sym.szName);
1093 fRc = outputPrintf("%s: %*s; %#x LB %#x\n", Sym.szName, cchName < 41 - 2 ? cchName - 41 - 2 : 0, "", uFlatAddr, Sym.cb);
1094 if (!fRc)
1095 return false;
1096
1097 if (disIsCodeAndAdjustSize(uFlatAddr, &Sym, &g_aSegs[iSeg]))
1098 fRc = disCode(uFlatAddr, Sym.cb, disIs16BitCode(Sym.szName));
1099 else
1100 fRc = disByteData(uFlatAddr, Sym.cb);
1101
1102 uFlatAddr += Sym.cb;
1103 cb -= Sym.cb;
1104 }
1105 else
1106 {
1107 fRc = disByteData(uFlatAddr, cb);
1108 uFlatAddr += cb;
1109 cb = 0;
1110 }
1111 if (!fRc)
1112 return false;
1113 }
1114
1115 return true;
1116}
1117
1118
1119static RTEXITCODE DisassembleBiosImage(void)
1120{
1121 if (!disFileHeader())
1122 return RTEXITCODE_FAILURE;
1123
1124 /*
1125 * Work the image segment by segment.
1126 */
1127 bool fRc = true;
1128 uint32_t uFlatAddr = g_uBiosFlatBase;
1129 for (uint32_t iSeg = 0; iSeg < g_cSegs && fRc; iSeg++)
1130 {
1131 /* Is there a gap between the segments? */
1132 if (uFlatAddr < g_aSegs[iSeg].uFlatAddr)
1133 {
1134 fRc = disCopySegmentGap(uFlatAddr, g_aSegs[iSeg].uFlatAddr - uFlatAddr);
1135 if (!fRc)
1136 break;
1137 uFlatAddr = g_aSegs[iSeg].uFlatAddr;
1138 }
1139 else if (uFlatAddr > g_aSegs[iSeg].uFlatAddr)
1140 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Overlapping segments: %u and %u; uFlatAddr=%#x\n", iSeg - 1, iSeg, uFlatAddr);
1141
1142 /* Disassemble the segment. */
1143 fRc = outputPrintf("\n"
1144 "section %s progbits vstart=%#x align=1 ; size=%#x class=%s group=%s\n",
1145 g_aSegs[iSeg].szName, g_aSegs[iSeg].uFlatAddr - g_uBiosFlatBase,
1146 g_aSegs[iSeg].cb, g_aSegs[iSeg].szClass, g_aSegs[iSeg].szGroup);
1147 if (!fRc)
1148 return RTEXITCODE_FAILURE;
1149 if (!strcmp(g_aSegs[iSeg].szName, "CONST"))
1150 fRc = disConstSegment(iSeg);
1151 else if (!strcmp(g_aSegs[iSeg].szClass, "DATA"))
1152 fRc = disDataSegment(iSeg);
1153 else
1154 fRc = disCodeSegment(iSeg);
1155
1156 /* Advance. */
1157 uFlatAddr += g_aSegs[iSeg].cb;
1158 }
1159
1160 /* Final gap. */
1161 if (uFlatAddr < g_uBiosFlatBase + g_cbImg)
1162 fRc = disCopySegmentGap(uFlatAddr, (uint32_t)(g_uBiosFlatBase + g_cbImg - uFlatAddr));
1163 else if (uFlatAddr > g_uBiosFlatBase + g_cbImg)
1164 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Last segment spills beyond 1MB; uFlatAddr=%#x\n", uFlatAddr);
1165
1166 if (!fRc)
1167 return RTEXITCODE_FAILURE;
1168 return RTEXITCODE_SUCCESS;
1169}
1170
1171
1172
1173/**
1174 * Parses the symbol file for the BIOS.
1175 *
1176 * This is in ELF/DWARF format.
1177 *
1178 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
1179 * @param pszBiosSym Path to the sym file.
1180 */
1181static RTEXITCODE ParseSymFile(const char *pszBiosSym)
1182{
1183#if 1
1184 /** @todo use RTDbg* later. (Just checking for existance currently.) */
1185 PRTSTREAM hStrm;
1186 int rc = RTStrmOpen(pszBiosSym, "rb", &hStrm);
1187 if (RT_FAILURE(rc))
1188 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening '%s': %Rrc", pszBiosSym, rc);
1189 RTStrmClose(hStrm);
1190#else
1191 RTDBGMOD hDbgMod;
1192 int rc = RTDbgModCreateFromImage(&hDbgMod, pszBiosSym, "VBoxBios", 0 /*fFlags*/);
1193 RTMsgInfo("RTDbgModCreateFromImage -> %Rrc\n", rc);
1194#endif
1195 return RTEXITCODE_SUCCESS;
1196}
1197
1198
1199/**
1200 * Display an error with the mapfile name and current line, return false.
1201 *
1202 * @returns @c false.
1203 * @param pMap The map file handle.
1204 * @param pszFormat The format string.
1205 * @param ... Format arguments.
1206 */
1207static bool mapError(PBIOSMAP pMap, const char *pszFormat, ...)
1208{
1209 va_list va;
1210 va_start(va, pszFormat);
1211 RTMsgError("%s:%d: %N", pMap->pszMapFile, pMap->iLine, pszFormat, va);
1212 va_end(va);
1213 return false;
1214}
1215
1216
1217/**
1218 * Reads a line from the file.
1219 *
1220 * @returns @c true on success, @c false + msg on failure, @c false on eof.
1221 * @param pMap The map file handle.
1222 */
1223static bool mapReadLine(PBIOSMAP pMap)
1224{
1225 int rc = RTStrmGetLine(pMap->hStrm, pMap->szLine, sizeof(pMap->szLine));
1226 if (RT_FAILURE(rc))
1227 {
1228 if (rc == VERR_EOF)
1229 {
1230 pMap->fEof = true;
1231 pMap->cch = 0;
1232 pMap->offNW = 0;
1233 pMap->szLine[0] = '\0';
1234 }
1235 else
1236 RTMsgError("%s:%d: Read error %Rrc", pMap->pszMapFile, pMap->iLine + 1, rc);
1237 return false;
1238 }
1239 pMap->iLine++;
1240 pMap->cch = (uint32_t)strlen(pMap->szLine);
1241
1242 /* Check out leading white space. */
1243 if (!RT_C_IS_SPACE(pMap->szLine[0]))
1244 pMap->offNW = 0;
1245 else
1246 {
1247 uint32_t off = 1;
1248 while (RT_C_IS_SPACE(pMap->szLine[off]))
1249 off++;
1250 pMap->offNW = off;
1251 }
1252
1253 return true;
1254}
1255
1256
1257/**
1258 * Checks if it is an empty line.
1259 * @returns @c true if empty, @c false if not.
1260 * @param pMap The map file handle.
1261 */
1262static bool mapIsEmptyLine(PBIOSMAP pMap)
1263{
1264 Assert(pMap->offNW <= pMap->cch);
1265 return pMap->offNW == pMap->cch;
1266}
1267
1268
1269/**
1270 * Reads ahead in the map file until a non-empty line or EOF is encountered.
1271 *
1272 * @returns @c true on success, @c false + msg on failure, @c false on eof.
1273 * @param pMap The map file handle.
1274 */
1275static bool mapSkipEmptyLines(PBIOSMAP pMap)
1276{
1277 for (;;)
1278 {
1279 if (!mapReadLine(pMap))
1280 return false;
1281 if (pMap->offNW < pMap->cch)
1282 return true;
1283 }
1284}
1285
1286
1287/**
1288 * Reads ahead in the map file until an empty line or EOF is encountered.
1289 *
1290 * @returns @c true on success, @c false + msg on failure, @c false on eof.
1291 * @param pMap The map file handle.
1292 */
1293static bool mapSkipNonEmptyLines(PBIOSMAP pMap)
1294{
1295 for (;;)
1296 {
1297 if (!mapReadLine(pMap))
1298 return false;
1299 if (pMap->offNW == pMap->cch)
1300 return true;
1301 }
1302}
1303
1304
1305/**
1306 * Strips the current line.
1307 *
1308 * The string length may change.
1309 *
1310 * @returns Pointer to the first non-space character.
1311 * @param pMap The map file handle.
1312 * @param pcch Where to return the length of the unstripped
1313 * part. Optional.
1314 */
1315static char *mapStripCurrentLine(PBIOSMAP pMap, size_t *pcch)
1316{
1317 char *psz = &pMap->szLine[pMap->offNW];
1318 char *pszEnd = &pMap->szLine[pMap->cch];
1319 while ( (uintptr_t)pszEnd > (uintptr_t)psz
1320 && RT_C_IS_SPACE(pszEnd[-1]))
1321 {
1322 *--pszEnd = '\0';
1323 pMap->cch--;
1324 }
1325 if (pcch)
1326 *pcch = pszEnd - psz;
1327 return psz;
1328}
1329
1330
1331/**
1332 * Reads a line from the file and right strips it.
1333 *
1334 * @returns Pointer to szLine on success, @c NULL + msg on failure, @c NULL on
1335 * EOF.
1336 * @param pMap The map file handle.
1337 * @param pcch Where to return the length of the unstripped
1338 * part. Optional.
1339 */
1340static char *mapReadLineStripRight(PBIOSMAP pMap, size_t *pcch)
1341{
1342 if (!mapReadLine(pMap))
1343 return NULL;
1344 mapStripCurrentLine(pMap, NULL);
1345 if (pcch)
1346 *pcch = pMap->cch;
1347 return pMap->szLine;
1348}
1349
1350
1351/**
1352 * mapReadLine() + mapStripCurrentLine().
1353 *
1354 * @returns Pointer to the first non-space character in the new line. NULL on
1355 * read error (bitched already) or end of file.
1356 * @param pMap The map file handle.
1357 * @param pcch Where to return the length of the unstripped
1358 * part. Optional.
1359 */
1360static char *mapReadLineStrip(PBIOSMAP pMap, size_t *pcch)
1361{
1362 if (!mapReadLine(pMap))
1363 return NULL;
1364 return mapStripCurrentLine(pMap, pcch);
1365}
1366
1367
1368/**
1369 * Parses a word, copying it into the supplied buffer, and skipping any spaces
1370 * following it.
1371 *
1372 * @returns @c true on success, @c false on failure.
1373 * @param ppszCursor Pointer to the cursor variable.
1374 * @param pszBuf The output buffer.
1375 * @param cbBuf The size of the output buffer.
1376 */
1377static bool mapParseWord(char **ppszCursor, char *pszBuf, size_t cbBuf)
1378{
1379 /* Check that we start on a non-blank. */
1380 char *pszStart = *ppszCursor;
1381 if (!*pszStart || RT_C_IS_SPACE(*pszStart))
1382 return false;
1383
1384 /* Find the end of the word. */
1385 char *psz = pszStart + 1;
1386 while (*psz && !RT_C_IS_SPACE(*psz))
1387 psz++;
1388
1389 /* Copy it. */
1390 size_t cchWord = (uintptr_t)psz - (uintptr_t)pszStart;
1391 if (cchWord >= cbBuf)
1392 return false;
1393 memcpy(pszBuf, pszStart, cchWord);
1394 pszBuf[cchWord] = '\0';
1395
1396 /* Skip blanks following it. */
1397 while (RT_C_IS_SPACE(*psz))
1398 psz++;
1399 *ppszCursor = psz;
1400 return true;
1401}
1402
1403
1404/**
1405 * Parses an 16:16 address.
1406 *
1407 * @returns @c true on success, @c false on failure.
1408 * @param ppszCursor Pointer to the cursor variable.
1409 * @param pAddr Where to return the address.
1410 */
1411static bool mapParseAddress(char **ppszCursor, PRTFAR16 pAddr)
1412{
1413 char szWord[32];
1414 if (!mapParseWord(ppszCursor, szWord, sizeof(szWord)))
1415 return false;
1416 size_t cchWord = strlen(szWord);
1417
1418 /* An address is at least 16:16 format. It may be 16:32. It may also be flagged. */
1419 size_t cchAddr = 4 + 1 + 4;
1420 if (cchWord < cchAddr)
1421 return false;
1422 if ( !RT_C_IS_XDIGIT(szWord[0])
1423 || !RT_C_IS_XDIGIT(szWord[1])
1424 || !RT_C_IS_XDIGIT(szWord[2])
1425 || !RT_C_IS_XDIGIT(szWord[3])
1426 || szWord[4] != ':'
1427 || !RT_C_IS_XDIGIT(szWord[5])
1428 || !RT_C_IS_XDIGIT(szWord[6])
1429 || !RT_C_IS_XDIGIT(szWord[7])
1430 || !RT_C_IS_XDIGIT(szWord[8])
1431 )
1432 return false;
1433 if ( cchWord > cchAddr
1434 && RT_C_IS_XDIGIT(szWord[9])
1435 && RT_C_IS_XDIGIT(szWord[10])
1436 && RT_C_IS_XDIGIT(szWord[11])
1437 && RT_C_IS_XDIGIT(szWord[12]))
1438 cchAddr += 4;
1439
1440 /* Drop flag if present. */
1441 if (cchWord > cchAddr)
1442 {
1443 if (RT_C_IS_XDIGIT(szWord[cchAddr]))
1444 return false;
1445 szWord[cchAddr] = '\0';
1446 cchWord = cchAddr;
1447 }
1448
1449 /* Convert it. */
1450 szWord[4] = '\0';
1451 int rc1 = RTStrToUInt16Full(szWord, 16, &pAddr->sel);
1452 if (rc1 != VINF_SUCCESS)
1453 return false;
1454
1455 int rc2 = RTStrToUInt16Full(szWord + 5, 16, &pAddr->off);
1456 if (rc2 != VINF_SUCCESS)
1457 return false;
1458 return true;
1459}
1460
1461
1462/**
1463 * Parses a size.
1464 *
1465 * @returns @c true on success, @c false on failure.
1466 * @param ppszCursor Pointer to the cursor variable.
1467 * @param pcb Where to return the size.
1468 */
1469static bool mapParseSize(char **ppszCursor, uint32_t *pcb)
1470{
1471 char szWord[32];
1472 if (!mapParseWord(ppszCursor, szWord, sizeof(szWord)))
1473 return false;
1474 size_t cchWord = strlen(szWord);
1475 if (cchWord != 8)
1476 return false;
1477
1478 int rc = RTStrToUInt32Full(szWord, 16, pcb);
1479 if (rc != VINF_SUCCESS)
1480 return false;
1481 return true;
1482}
1483
1484
1485/**
1486 * Parses a section box and the following column header.
1487 *
1488 * @returns @c true on success, @c false + msg on failure, @c false on eof.
1489 * @param pMap Map file handle.
1490 * @param pszSectionNm The expected section name.
1491 * @param cColumns The number of columns.
1492 * @param ... The column names.
1493 */
1494static bool mapSkipThruColumnHeadings(PBIOSMAP pMap, const char *pszSectionNm, uint32_t cColumns, ...)
1495{
1496 if ( mapIsEmptyLine(pMap)
1497 && !mapSkipEmptyLines(pMap))
1498 return false;
1499
1500 /* +------------+ */
1501 size_t cch;
1502 char *psz = mapStripCurrentLine(pMap, &cch);
1503 if (!psz)
1504 return false;
1505
1506 if ( psz[0] != '+'
1507 || psz[1] != '-'
1508 || psz[2] != '-'
1509 || psz[3] != '-'
1510 || psz[cch - 4] != '-'
1511 || psz[cch - 3] != '-'
1512 || psz[cch - 2] != '-'
1513 || psz[cch - 1] != '+'
1514 )
1515 {
1516 RTMsgError("%s:%d: Expected section box: +-----...", pMap->pszMapFile, pMap->iLine);
1517 return false;
1518 }
1519
1520 /* | pszSectionNm | */
1521 psz = mapReadLineStrip(pMap, &cch);
1522 if (!psz)
1523 return false;
1524
1525 size_t cchSectionNm = strlen(pszSectionNm);
1526 if ( psz[0] != '|'
1527 || psz[1] != ' '
1528 || psz[2] != ' '
1529 || psz[3] != ' '
1530 || psz[cch - 4] != ' '
1531 || psz[cch - 3] != ' '
1532 || psz[cch - 2] != ' '
1533 || psz[cch - 1] != '|'
1534 || cch != 1 + 3 + cchSectionNm + 3 + 1
1535 || strncmp(&psz[4], pszSectionNm, cchSectionNm)
1536 )
1537 {
1538 RTMsgError("%s:%d: Expected section box: | %s |", pMap->pszMapFile, pMap->iLine, pszSectionNm);
1539 return false;
1540 }
1541
1542 /* +------------+ */
1543 psz = mapReadLineStrip(pMap, &cch);
1544 if (!psz)
1545 return false;
1546 if ( psz[0] != '+'
1547 || psz[1] != '-'
1548 || psz[2] != '-'
1549 || psz[3] != '-'
1550 || psz[cch - 4] != '-'
1551 || psz[cch - 3] != '-'
1552 || psz[cch - 2] != '-'
1553 || psz[cch - 1] != '+'
1554 )
1555 {
1556 RTMsgError("%s:%d: Expected section box: +-----...", pMap->pszMapFile, pMap->iLine);
1557 return false;
1558 }
1559
1560 /* There may be a few lines describing the table notation now, surrounded by blank lines. */
1561 do
1562 {
1563 psz = mapReadLineStripRight(pMap, &cch);
1564 if (!psz)
1565 return false;
1566 } while ( *psz == '\0'
1567 || ( !RT_C_IS_SPACE(psz[0])
1568 && RT_C_IS_SPACE(psz[1])
1569 && psz[2] == '='
1570 && RT_C_IS_SPACE(psz[3]))
1571 );
1572
1573 /* Should have the column heading now. */
1574 va_list va;
1575 va_start(va, cColumns);
1576 for (uint32_t i = 0; i < cColumns; i++)
1577 {
1578 const char *pszColumn = va_arg(va, const char *);
1579 size_t cchColumn = strlen(pszColumn);
1580 if ( strncmp(psz, pszColumn, cchColumn)
1581 || ( psz[cchColumn] != '\0'
1582 && !RT_C_IS_SPACE(psz[cchColumn])))
1583 {
1584 va_end(va);
1585 RTMsgError("%s:%d: Expected column '%s' found '%s'", pMap->pszMapFile, pMap->iLine, pszColumn, psz);
1586 return false;
1587 }
1588 psz += cchColumn;
1589 while (RT_C_IS_SPACE(*psz))
1590 psz++;
1591 }
1592 va_end(va);
1593
1594 /* The next line is the underlining. */
1595 psz = mapReadLineStripRight(pMap, &cch);
1596 if (!psz)
1597 return false;
1598 if (*psz != '=' || psz[cch - 1] != '=')
1599 {
1600 RTMsgError("%s:%d: Expected column header underlining", pMap->pszMapFile, pMap->iLine);
1601 return false;
1602 }
1603
1604 /* Skip one blank line. */
1605 psz = mapReadLineStripRight(pMap, &cch);
1606 if (!psz)
1607 return false;
1608 if (*psz)
1609 {
1610 RTMsgError("%s:%d: Expected blank line beneath the column headers", pMap->pszMapFile, pMap->iLine);
1611 return false;
1612 }
1613
1614 return true;
1615}
1616
1617
1618/**
1619 * Parses a segment list.
1620 *
1621 * @returns @c true on success, @c false + msg on failure, @c false on eof.
1622 * @param pMap The map file handle.
1623 */
1624static bool mapParseSegments(PBIOSMAP pMap)
1625{
1626 for (;;)
1627 {
1628 if (!mapReadLineStripRight(pMap, NULL))
1629 return false;
1630
1631 /* The end? The line should be empty. Expectes segment name to not
1632 start with a space. */
1633 if (!pMap->szLine[0] || RT_C_IS_SPACE(pMap->szLine[0]))
1634 {
1635 if (!pMap->szLine[0])
1636 return true;
1637 RTMsgError("%s:%u: Malformed segment line", pMap->pszMapFile, pMap->iLine);
1638 return false;
1639 }
1640
1641 /* Parse the segment line. */
1642 uint32_t iSeg = g_cSegs;
1643 if (iSeg >= RT_ELEMENTS(g_aSegs))
1644 {
1645 RTMsgError("%s:%u: Too many segments", pMap->pszMapFile, pMap->iLine);
1646 return false;
1647 }
1648
1649 char *psz = pMap->szLine;
1650 if (!mapParseWord(&psz, g_aSegs[iSeg].szName, sizeof(g_aSegs[iSeg].szName)))
1651 RTMsgError("%s:%u: Segment name parser error", pMap->pszMapFile, pMap->iLine);
1652 else if (!mapParseWord(&psz, g_aSegs[iSeg].szClass, sizeof(g_aSegs[iSeg].szClass)))
1653 RTMsgError("%s:%u: Segment class parser error", pMap->pszMapFile, pMap->iLine);
1654 else if (!mapParseWord(&psz, g_aSegs[iSeg].szGroup, sizeof(g_aSegs[iSeg].szGroup)))
1655 RTMsgError("%s:%u: Segment group parser error", pMap->pszMapFile, pMap->iLine);
1656 else if (!mapParseAddress(&psz, &g_aSegs[iSeg].Address))
1657 RTMsgError("%s:%u: Segment address parser error", pMap->pszMapFile, pMap->iLine);
1658 else if (!mapParseSize(&psz, &g_aSegs[iSeg].cb))
1659 RTMsgError("%s:%u: Segment size parser error", pMap->pszMapFile, pMap->iLine);
1660 else
1661 {
1662 g_aSegs[iSeg].uFlatAddr = ((uint32_t)g_aSegs[iSeg].Address.sel << 4) + g_aSegs[iSeg].Address.off;
1663 g_cSegs++;
1664 if (g_cVerbose > 2)
1665 RTStrmPrintf(g_pStdErr, "read segment at %08x / %04x:%04x LB %04x %s / %s / %s\n",
1666 g_aSegs[iSeg].uFlatAddr,
1667 g_aSegs[iSeg].Address.sel,
1668 g_aSegs[iSeg].Address.off,
1669 g_aSegs[iSeg].cb,
1670 g_aSegs[iSeg].szName,
1671 g_aSegs[iSeg].szClass,
1672 g_aSegs[iSeg].szGroup);
1673
1674 while (RT_C_IS_SPACE(*psz))
1675 psz++;
1676 if (!*psz)
1677 continue;
1678 RTMsgError("%s:%u: Junk at end of line", pMap->pszMapFile, pMap->iLine);
1679 }
1680 return false;
1681 }
1682}
1683
1684
1685/**
1686 * Sorts the segment array by flat address and adds them to the debug module.
1687 *
1688 * @returns @c true on success, @c false + msg on failure, @c false on eof.
1689 */
1690static bool mapSortAndAddSegments(void)
1691{
1692 for (uint32_t i = 0; i < g_cSegs; i++)
1693 {
1694 for (uint32_t j = i + 1; j < g_cSegs; j++)
1695 if (g_aSegs[j].uFlatAddr < g_aSegs[i].uFlatAddr)
1696 {
1697 BIOSSEG Tmp = g_aSegs[i];
1698 g_aSegs[i] = g_aSegs[j];
1699 g_aSegs[j] = Tmp;
1700 }
1701 if (g_cVerbose > 0)
1702 RTStrmPrintf(g_pStdErr, "segment at %08x / %04x:%04x LB %04x %s / %s / %s\n",
1703 g_aSegs[i].uFlatAddr,
1704 g_aSegs[i].Address.sel,
1705 g_aSegs[i].Address.off,
1706 g_aSegs[i].cb,
1707 g_aSegs[i].szName,
1708 g_aSegs[i].szClass,
1709 g_aSegs[i].szGroup);
1710
1711 RTDBGSEGIDX idx = i;
1712 int rc = RTDbgModSegmentAdd(g_hMapMod, g_aSegs[i].uFlatAddr, g_aSegs[i].cb, g_aSegs[i].szName, 0 /*fFlags*/, &idx);
1713 if (RT_FAILURE(rc))
1714 {
1715 RTMsgError("RTDbgModSegmentAdd failed on %s: %Rrc", g_aSegs[i].szName);
1716 return false;
1717 }
1718 }
1719 return true;
1720}
1721
1722
1723/**
1724 * Parses a segment list.
1725 *
1726 * @returns @c true on success, @c false + msg on failure, @c false on eof.
1727 * @param pMap The map file handle.
1728 */
1729static bool mapParseSymbols(PBIOSMAP pMap)
1730{
1731 for (;;)
1732 {
1733 if (!mapReadLineStripRight(pMap, NULL))
1734 return false;
1735
1736 /* The end? The line should be empty. Expectes segment name to not
1737 start with a space. */
1738 if (!pMap->szLine[0] || RT_C_IS_SPACE(pMap->szLine[0]))
1739 {
1740 if (!pMap->szLine[0])
1741 return true;
1742 return mapError(pMap, "Malformed symbol line");
1743 }
1744
1745 if (!strncmp(pMap->szLine, RT_STR_TUPLE("Module: ")))
1746 {
1747 /* Parse the module line. */
1748 size_t offObj = sizeof("Module: ") - 1;
1749 while (RT_C_IS_SPACE(pMap->szLine[offObj]))
1750 offObj++;
1751 size_t offSrc = offObj;
1752 char ch;
1753 while ((ch = pMap->szLine[offSrc]) != '(' && ch != '\0')
1754 offSrc++;
1755 size_t cchObj = offSrc - offObj;
1756
1757 offSrc++;
1758 size_t cchSrc = offSrc;
1759 while ((ch = pMap->szLine[cchSrc]) != ')' && ch != '\0')
1760 cchSrc++;
1761 cchSrc -= offSrc;
1762 if (ch != ')')
1763 return mapError(pMap, "Symbol/Module line parse error");
1764
1765 PBIOSOBJFILE pObjFile = (PBIOSOBJFILE)RTMemAllocZ(sizeof(*pObjFile) + cchSrc + cchObj + 2);
1766 if (!pObjFile)
1767 return mapError(pMap, "Out of memory");
1768 char *psz = (char *)(pObjFile + 1);
1769 pObjFile->pszObject = psz;
1770 memcpy(psz, &pMap->szLine[offObj], cchObj);
1771 psz += cchObj;
1772 *psz++ = '\0';
1773 pObjFile->pszSource = psz;
1774 memcpy(psz, &pMap->szLine[offSrc], cchSrc);
1775 psz[cchSrc] = '\0';
1776 RTListAppend(&g_ObjList, &pObjFile->Node);
1777 }
1778 else
1779 {
1780 /* Parse the segment line. */
1781 RTFAR16 Addr;
1782 char *psz = pMap->szLine;
1783 if (!mapParseAddress(&psz, &Addr))
1784 return mapError(pMap, "Symbol address parser error");
1785
1786 char szName[4096];
1787 if (!mapParseWord(&psz, szName, sizeof(szName)))
1788 return mapError(pMap, "Symbol name parser error");
1789
1790 uint32_t uFlatAddr = ((uint32_t)Addr.sel << 4) + Addr.off;
1791 if (uFlatAddr != 0)
1792 {
1793 int rc = RTDbgModSymbolAdd(g_hMapMod, szName, RTDBGSEGIDX_RVA, uFlatAddr, 0 /*cb*/, 0 /*fFlags*/, NULL);
1794 if (RT_FAILURE(rc) && rc != VERR_DBG_ADDRESS_CONFLICT)
1795 {
1796 /* HACK ALERT! For dealing with lables at segment size. */ /** @todo fix end labels. */
1797 rc = RTDbgModSymbolAdd(g_hMapMod, szName, RTDBGSEGIDX_RVA, uFlatAddr - 1, 0 /*cb*/, 0 /*fFlags*/, NULL);
1798 if (RT_FAILURE(rc) && rc != VERR_DBG_ADDRESS_CONFLICT)
1799 return mapError(pMap, "RTDbgModSymbolAdd failed: %Rrc", rc);
1800 }
1801
1802 if (g_cVerbose > 2)
1803 RTStrmPrintf(g_pStdErr, "read symbol - %08x %s\n", uFlatAddr, szName);
1804 while (RT_C_IS_SPACE(*psz))
1805 psz++;
1806 if (*psz)
1807 return mapError(pMap, "Junk at end of line");
1808 }
1809
1810 }
1811 }
1812}
1813
1814
1815/**
1816 * Parses the given map file.
1817 *
1818 * @returns RTEXITCODE_SUCCESS and lots of globals, or RTEXITCODE_FAILURE and a
1819 * error message.
1820 * @param pMap The map file handle.
1821 */
1822static RTEXITCODE mapParseFile(PBIOSMAP pMap)
1823{
1824 int rc = RTDbgModCreate(&g_hMapMod, "VBoxBios", 0 /*cbSeg*/, 0 /*fFlags*/);
1825 if (RT_FAILURE(rc))
1826 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDbgModCreate failed: %Rrc", rc);
1827
1828 /*
1829 * Read the header.
1830 */
1831 if (!mapReadLine(pMap))
1832 return RTEXITCODE_FAILURE;
1833 if (strncmp(pMap->szLine, RT_STR_TUPLE("Open Watcom Linker Version")))
1834 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Unexpected map-file header: '%s'", pMap->szLine);
1835 if ( !mapSkipNonEmptyLines(pMap)
1836 || !mapSkipEmptyLines(pMap))
1837 return RTEXITCODE_FAILURE;
1838
1839 /*
1840 * Skip groups.
1841 */
1842 if (!mapSkipThruColumnHeadings(pMap, "Groups", 3, "Group", "Address", "Size", NULL))
1843 return RTEXITCODE_FAILURE;
1844 if (!mapSkipNonEmptyLines(pMap))
1845 return RTEXITCODE_FAILURE;
1846
1847 /*
1848 * Parse segments.
1849 */
1850 if (!mapSkipThruColumnHeadings(pMap, "Segments", 5, "Segment", "Class", "Group", "Address", "Size"))
1851 return RTEXITCODE_FAILURE;
1852 if (!mapParseSegments(pMap))
1853 return RTEXITCODE_FAILURE;
1854 if (!mapSortAndAddSegments())
1855 return RTEXITCODE_FAILURE;
1856
1857 /*
1858 * Parse symbols.
1859 */
1860 if (!mapSkipThruColumnHeadings(pMap, "Memory Map", 2, "Address", "Symbol"))
1861 return RTEXITCODE_FAILURE;
1862 if (!mapParseSymbols(pMap))
1863 return RTEXITCODE_FAILURE;
1864
1865 /* Ignore the rest of the file. */
1866 return RTEXITCODE_SUCCESS;
1867}
1868
1869
1870/**
1871 * Parses the linker map file for the BIOS.
1872 *
1873 * This is generated by the Watcom linker.
1874 *
1875 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
1876 * @param pszBiosMap Path to the map file.
1877 */
1878static RTEXITCODE ParseMapFile(const char *pszBiosMap)
1879{
1880 BIOSMAP Map;
1881 Map.pszMapFile = pszBiosMap;
1882 Map.hStrm = NULL;
1883 Map.iLine = 0;
1884 Map.fEof = false;
1885 Map.cch = 0;
1886 Map.offNW = 0;
1887 int rc = RTStrmOpen(pszBiosMap, "r", &Map.hStrm);
1888 if (RT_FAILURE(rc))
1889 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening '%s': %Rrc", pszBiosMap, rc);
1890 RTEXITCODE rcExit = mapParseFile(&Map);
1891 RTStrmClose(Map.hStrm);
1892 return rcExit;
1893}
1894
1895
1896/**
1897 * Reads the BIOS image into memory (g_pbImg and g_cbImg).
1898 *
1899 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
1900 * @param pszBiosImg Path to the image file.
1901 */
1902static RTEXITCODE ReadBiosImage(const char *pszBiosImg)
1903{
1904 void *pvImg;
1905 size_t cbImg;
1906 int rc = RTFileReadAll(pszBiosImg, &pvImg, &cbImg);
1907 if (RT_FAILURE(rc))
1908 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error reading '%s': %Rrc", pszBiosImg, rc);
1909
1910 size_t cbImgExpect;
1911 switch (g_enmBiosType)
1912 {
1913 case kBiosType_System: cbImgExpect = _64K; break;
1914 case kBiosType_Vga: cbImgExpect = _32K; break;
1915 default: cbImgExpect = 0; break;
1916 }
1917 if (cbImg != cbImgExpect)
1918 {
1919 RTFileReadAllFree(pvImg, cbImg);
1920 return RTMsgErrorExit(RTEXITCODE_FAILURE, "The BIOS image %u bytes intead of %u bytes", cbImg, cbImgExpect);
1921 }
1922
1923 g_pbImg = (uint8_t *)pvImg;
1924 g_cbImg = cbImg;
1925 return RTEXITCODE_SUCCESS;
1926}
1927
1928
1929int main(int argc, char **argv)
1930{
1931 int rc = RTR3InitExe(argc, &argv, 0);
1932 if (RT_FAILURE(rc))
1933 return RTMsgInitFailure(rc);
1934
1935 RTListInit(&g_ObjList);
1936
1937 /*
1938 * Option config.
1939 */
1940 static RTGETOPTDEF const s_aOpts[] =
1941 {
1942 { "--bios-image", 'i', RTGETOPT_REQ_STRING },
1943 { "--bios-map", 'm', RTGETOPT_REQ_STRING },
1944 { "--bios-sym", 's', RTGETOPT_REQ_STRING },
1945 { "--bios-type", 't', RTGETOPT_REQ_STRING },
1946 { "--output", 'o', RTGETOPT_REQ_STRING },
1947 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
1948 { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
1949 };
1950
1951 const char *pszBiosMap = NULL;
1952 const char *pszBiosSym = NULL;
1953 const char *pszBiosImg = NULL;
1954 const char *pszOutput = NULL;
1955
1956 RTGETOPTUNION ValueUnion;
1957 RTGETOPTSTATE GetOptState;
1958 rc = RTGetOptInit(&GetOptState, argc, argv, &s_aOpts[0], RT_ELEMENTS(s_aOpts), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
1959 AssertReleaseRCReturn(rc, RTEXITCODE_FAILURE);
1960
1961 /*
1962 * Process the options.
1963 */
1964 while ((rc = RTGetOpt(&GetOptState, &ValueUnion)) != 0)
1965 {
1966 switch (rc)
1967 {
1968 case 'i':
1969 if (pszBiosImg)
1970 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--bios-image is given more than once");
1971 pszBiosImg = ValueUnion.psz;
1972 break;
1973
1974 case 'm':
1975 if (pszBiosMap)
1976 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--bios-map is given more than once");
1977 pszBiosMap = ValueUnion.psz;
1978 break;
1979
1980 case 's':
1981 if (pszBiosSym)
1982 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--bios-sym is given more than once");
1983 pszBiosSym = ValueUnion.psz;
1984 break;
1985
1986 case 'o':
1987 if (pszOutput)
1988 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--output is given more than once");
1989 pszOutput = ValueUnion.psz;
1990 break;
1991
1992 case 't':
1993 if (!strcmp(ValueUnion.psz, "system"))
1994 {
1995 g_enmBiosType = kBiosType_System;
1996 g_uBiosFlatBase = 0xf0000;
1997 }
1998 else if (!strcmp(ValueUnion.psz, "vga"))
1999 {
2000 g_enmBiosType = kBiosType_Vga;
2001 g_uBiosFlatBase = 0xc0000;
2002 }
2003 else
2004 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown bios type '%s'", ValueUnion.psz);
2005 break;
2006
2007 case 'v':
2008 g_cVerbose++;
2009 break;
2010
2011 case 'q':
2012 g_cVerbose = 0;
2013 break;
2014
2015 case 'H':
2016 RTPrintf("usage: %Rbn --bios-image <file.img> --bios-map <file.map> [--output <file.asm>]\n",
2017 argv[0]);
2018 return RTEXITCODE_SUCCESS;
2019
2020 case 'V':
2021 {
2022 /* The following is assuming that svn does it's job here. */
2023 RTPrintf("r%u\n", RTBldCfgRevision());
2024 return RTEXITCODE_SUCCESS;
2025 }
2026
2027 default:
2028 return RTGetOptPrintError(rc, &ValueUnion);
2029 }
2030 }
2031
2032 /*
2033 * Got it all?
2034 */
2035 if (!pszBiosImg)
2036 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--bios-image is required");
2037 if (!pszBiosMap)
2038 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--bios-map is required");
2039 if (!pszBiosSym)
2040 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--bios-sym is required");
2041
2042 /*
2043 * Do the job.
2044 */
2045 RTEXITCODE rcExit;
2046 rcExit = ReadBiosImage(pszBiosImg);
2047 if (rcExit == RTEXITCODE_SUCCESS)
2048 rcExit = ParseMapFile(pszBiosMap);
2049 if (rcExit == RTEXITCODE_SUCCESS)
2050 rcExit = ParseSymFile(pszBiosSym);
2051 if (rcExit == RTEXITCODE_SUCCESS)
2052 rcExit = OpenOutputFile(pszOutput);
2053 if (rcExit == RTEXITCODE_SUCCESS)
2054 rcExit = DisassembleBiosImage();
2055
2056 return rcExit;
2057}
2058
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