VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin/kDepIDB.c@ 2019

Last change on this file since 2019 was 2019, checked in by bird, 16 years ago

GPLv2 -> GPLv3. See Ticket #44 for clarifications. Fixes #44.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.5 KB
Line 
1/* $Id: kDepIDB.c 2019 2008-11-02 00:21:05Z bird $ */
2/** @file
3 * kDepIDB - Extract dependency information from a MS Visual C++ .idb file.
4 */
5
6/*
7 * Copyright (c) 2007-2008 knut st. osmundsen <[email protected]>
8 *
9 * This file is part of kBuild.
10 *
11 * kBuild is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * kBuild is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
23 *
24 */
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#include <stdio.h>
30#include <stdlib.h>
31#include <stddef.h>
32#include <string.h>
33#include <errno.h>
34#include <ctype.h>
35#if !defined(_MSC_VER)
36# include <stdint.h>
37#else
38# define USE_WIN_MMAP
39# include <io.h>
40# include <Windows.h>
41 typedef unsigned char uint8_t;
42 typedef unsigned short uint16_t;
43 typedef unsigned int uint32_t;
44#endif
45/*#include "kDep.h"*/
46#include "../../lib/kDep.h"
47#include "kmkbuiltin.h"
48
49#define OFFSETOF(type, member) ( (int)(size_t)(void *)&( ((type *)(void *)0)->member) )
50
51/*#define DEBUG*/
52#ifdef DEBUG
53# define dprintf(a) printf a
54# define dump(pb, cb, offBase) hexdump(pb,cb,offBase)
55#else
56# define dprintf(a) do {} while (0)
57# define dump(pb, cb, offBase) do {} while (0)
58#endif
59
60
61/*******************************************************************************
62* Global Variables *
63*******************************************************************************/
64/** the executable name. */
65static const char *argv0 = "";
66
67#ifdef DEBUG
68/**
69 * Performs a hexdump.
70 */
71static void hexdump(const uint8_t *pb, size_t cb, size_t offBase)
72{
73 static const char szHex[16] = "0123456789abcdef";
74
75 const unsigned cchWidth = 16;
76 size_t off = 0;
77 while (off < cb)
78 {
79 unsigned i;
80 printf("%s%0*x %04x:", off ? "\n" : "", sizeof(pb) * 2, offBase + off, off);
81 for (i = 0; i < cchWidth && off + i < cb ; i++)
82 printf(off + i < cb ? !(i & 7) && i ? "-%02x" : " %02x" : " ", pb[i]);
83
84 while (i++ < cchWidth)
85 printf(" ");
86 printf(" ");
87
88 for (i = 0; i < cchWidth && off + i < cb; i++)
89 {
90 const uint8_t u8 = pb[i];
91 printf("%c", u8 < 127 && u8 >= 32 ? u8 : '.', 1);
92 }
93 off += cchWidth;
94 pb += cchWidth;
95 }
96 printf("\n");
97}
98#endif
99
100/**
101 * Scans a stream (chunk of data really) for dependencies.
102 *
103 * @returns 0 on success.
104 * @returns !0 on failure.
105 * @param pbStream The stream bits.
106 * @param cbStream The size of the stream.
107 * @param pszPrefix The dependency prefix.
108 * @param cchPrefix The size of the prefix.
109 */
110static int ScanStream(uint8_t *pbStream, size_t cbStream, const char *pszPrefix, size_t cchPrefix)
111{
112 const uint8_t *pbCur = pbStream;
113 size_t cbLeft = cbStream;
114 register char chFirst = *pszPrefix;
115 while (cbLeft > cchPrefix + 2)
116 {
117 if ( *pbCur != chFirst
118 || memcmp(pbCur, pszPrefix, cchPrefix))
119 {
120 pbCur++;
121 cbLeft--;
122 }
123 else
124 {
125 size_t cchDep;
126 pbCur += cchPrefix;
127 cchDep = strlen((const char *)pbCur);
128 depAdd((const char *)pbCur, cchDep);
129 dprintf(("%05x: '%s'\n", pbCur - pbStream, pbCur));
130
131 pbCur += cchDep;
132 cbLeft -= cchDep + cchPrefix;
133 }
134 }
135
136 return 0;
137}
138
139
140#ifdef USE_WIN_MMAP
141/** Handle to the current file mapping object. */
142static HANDLE g_hMapObj = NULL;
143#endif
144
145
146/**
147 * Reads the file specified by the pInput file stream into memory.
148 * The size of the file is returned in *pcbFile if specified.
149 * The returned pointer should be freed by FreeFileMemory().
150 */
151void *ReadFileIntoMemory(FILE *pInput, size_t *pcbFile)
152{
153 void *pvFile;
154 long cbFile;
155 int rc = 0;
156
157 /*
158 * Figure out file size.
159 */
160#if defined(_MSC_VER)
161 cbFile = _filelength(fileno(pInput));
162 if (cbFile < 0)
163#else
164 if ( fseek(pInput, 0, SEEK_END) < 0
165 || (cbFile = ftell(pInput)) < 0
166 || fseek(pInput, 0, SEEK_SET))
167#endif
168 {
169 fprintf(stderr, "%s: error: Failed to determin file size.\n", argv0);
170 return NULL;
171 }
172 if (pcbFile)
173 *pcbFile = cbFile;
174
175 /*
176 * Try mmap first.
177 */
178#ifdef USE_WIN_MMAP
179 {
180 HANDLE hMapObj = CreateFileMapping((HANDLE)_get_osfhandle(fileno(pInput)),
181 NULL, PAGE_READONLY, 0, cbFile, NULL);
182 if (hMapObj != NULL)
183 {
184 pvFile = MapViewOfFile(hMapObj, FILE_MAP_READ, 0, 0, cbFile);
185 if (pvFile)
186 {
187 g_hMapObj = hMapObj;
188 return pvFile;
189 }
190 fprintf(stderr, "%s: warning: MapViewOfFile failed, %d.\n", argv0, GetLastError());
191 CloseHandle(hMapObj);
192 }
193 else
194 fprintf(stderr, "%s: warning: CreateFileMapping failed, %d.\n", argv0, GetLastError());
195 }
196
197#endif
198
199 /*
200 * Allocate memory and read the file.
201 */
202 pvFile = malloc(cbFile + 1);
203 if (pvFile)
204 {
205 if (fread(pvFile, cbFile, 1, pInput))
206 {
207 ((uint8_t *)pvFile)[cbFile] = '\0';
208 return pvFile;
209 }
210 fprintf(stderr, "%s: error: Failed to read %ld bytes.\n", argv0, cbFile);
211 free(pvFile);
212 }
213 else
214 fprintf(stderr, "%s: error: Failed to allocate %ld bytes (file mapping).\n", argv0, cbFile);
215 return NULL;
216}
217
218
219static void FreeFileMemory(void *pvFile)
220{
221#if defined(USE_WIN_MMAP)
222 if (g_hMapObj)
223 {
224 UnmapViewOfFile(pvFile);
225 CloseHandle(g_hMapObj);
226 return;
227 }
228#endif
229 free(pvFile);
230}
231
232
233///////////////////////////////////////////////////////////////////////////////
234//
235//
236// P D B 7 . 0
237//
238//
239///////////////////////////////////////////////////////////////////////////////
240
241/** A PDB 7.0 Page number. */
242typedef uint32_t PDB70PAGE;
243/** Pointer to a PDB 7.0 Page number. */
244typedef PDB70PAGE *PPDB70PAGE;
245
246/**
247 * A PDB 7.0 stream.
248 */
249typedef struct PDB70STREAM
250{
251 /** The size of the stream. */
252 uint32_t cbStream;
253} PDB70STREAM, *PPDB70STREAM;
254
255
256/** The PDB 7.00 signature. */
257#define PDB_SIGNATURE_700 "Microsoft C/C++ MSF 7.00\r\n\x1A" "DS\0\0"
258/**
259 * The PDB 7.0 header.
260 */
261typedef struct PDB70HDR
262{
263 /** The signature string. */
264 uint8_t szSignature[sizeof(PDB_SIGNATURE_700)];
265 /** The page size. */
266 uint32_t cbPage;
267 /** The start page. */
268 PDB70PAGE iStartPage;
269 /** The number of pages in the file. */
270 PDB70PAGE cPages;
271 /** The root stream directory. */
272 uint32_t cbRoot;
273 /** Unknown function, always 0. */
274 uint32_t u32Reserved;
275 /** The page index of the root page table. */
276 PDB70PAGE iRootPages;
277} PDB70HDR, *PPDB70HDR;
278
279/**
280 * The PDB 7.0 root directory.
281 */
282typedef struct PDB70ROOT
283{
284 /** The number of streams */
285 uint32_t cStreams;
286 /** Array of streams. */
287 PDB70STREAM aStreams[1];
288 /* uint32_t aiPages[] */
289} PDB70ROOT, *PPDB70ROOT;
290
291/**
292 * The PDB 7.0 name stream (#1) header.
293 */
294typedef struct PDB70NAMES
295{
296 /** The structure version. */
297 uint32_t Version;
298 /** Timestamp. */
299 uint32_t TimeStamp;
300 /** Unknown. */
301 uint32_t Unknown1;
302 /** GUID. */
303 uint32_t u32Guid[4];
304 /** The size of the following name table. */
305 uint32_t cbNames;
306 /** The name table. */
307 char szzNames[1];
308} PDB70NAMES, *PPDB70NAMES;
309
310/** The version / magic of the names structure. */
311#define PDB70NAMES_VERSION 20000404
312
313
314static int Pdb70ValidateHeader(PPDB70HDR pHdr, size_t cbFile)
315{
316 if (pHdr->cbPage * pHdr->cPages != cbFile)
317 {
318 fprintf(stderr, "%s: error: Bad PDB 2.0 header - cbPage * cPages != cbFile.\n", argv0);
319 return 1;
320 }
321 if (pHdr->iStartPage >= pHdr->cPages && pHdr->iStartPage <= 0)
322 {
323 fprintf(stderr, "%s: error: Bad PDB 2.0 header - iStartPage=%u cPages=%u.\n", argv0,
324 pHdr->iStartPage, pHdr->cPages);
325 return 1;
326 }
327 if (pHdr->iRootPages >= pHdr->cPages && pHdr->iRootPages <= 0)
328 {
329 fprintf(stderr, "%s: error: Bad PDB 2.0 header - iRootPages=%u cPage=%u.\n", argv0,
330 pHdr->iStartPage, pHdr->cPages);
331 return 1;
332 }
333 return 0;
334}
335
336static size_t Pdb70Align(PPDB70HDR pHdr, size_t cb)
337{
338 if (cb == ~(uint32_t)0 || !cb)
339 return 0;
340 return ((cb + pHdr->cbPage - 1) / pHdr->cbPage) * pHdr->cbPage;
341}
342
343static size_t Pdb70Pages(PPDB70HDR pHdr, size_t cb)
344{
345 if (cb == ~(uint32_t)0 || !cb)
346 return 0;
347 return (cb + pHdr->cbPage - 1) / pHdr->cbPage;
348}
349
350static void *Pdb70AllocAndRead(PPDB70HDR pHdr, size_t cb, PPDB70PAGE paiPageMap)
351{
352 const size_t cbPage = pHdr->cbPage;
353 size_t cPages = Pdb70Pages(pHdr, cb);
354 uint8_t *pbBuf = malloc(cPages * cbPage + 1);
355 if (pbBuf)
356 {
357 size_t iPage = 0;
358 while (iPage < cPages)
359 {
360 size_t off = paiPageMap[iPage];
361 if (off < pHdr->cPages)
362 {
363 off *= cbPage;
364 memcpy(pbBuf + iPage * cbPage, (uint8_t *)pHdr + off, cbPage);
365 dump(pbBuf + iPage * cbPage, iPage + 1 < cPages ? cbPage : cb % cbPage, off);
366 }
367 else
368 {
369 fprintf(stderr, "%s: warning: Invalid page index %u (max %u)!\n", argv0,
370 (unsigned)off, pHdr->cPages);
371 memset(pbBuf + iPage * cbPage, 0, cbPage);
372 }
373
374 iPage++;
375 }
376 pbBuf[cPages * cbPage] = '\0';
377 }
378 else
379 fprintf(stderr, "%s: error: failed to allocate %u bytes\n", argv0, cPages * cbPage + 1);
380 return pbBuf;
381}
382
383static PPDB70ROOT Pdb70AllocAndReadRoot(PPDB70HDR pHdr)
384{
385 /*
386 * The tricky bit here is to find the right length. Really?
387 * (Todo: Check if we can just use the stream #0 size..)
388 */
389 PPDB70PAGE piPageMap = (uint32_t *)((uint8_t *)pHdr + pHdr->iRootPages * pHdr->cbPage);
390 PPDB70ROOT pRoot = Pdb70AllocAndRead(pHdr, pHdr->cbRoot, piPageMap);
391 if (pRoot)
392 {
393#if 1
394 /* This stuff is probably unnecessary: */
395 /* size = stream header + array of stream. */
396 size_t cb = OFFSETOF(PDB70ROOT, aStreams[pRoot->cStreams]);
397 free(pRoot);
398 pRoot = Pdb70AllocAndRead(pHdr, cb, piPageMap);
399 if (pRoot)
400 {
401 /* size += page tables. */
402 unsigned iStream = pRoot->cStreams;
403 while (iStream-- > 0)
404 if (pRoot->aStreams[iStream].cbStream != ~(uint32_t)0)
405 cb += Pdb70Pages(pHdr, pRoot->aStreams[iStream].cbStream) * sizeof(PDB70PAGE);
406 free(pRoot);
407 pRoot = Pdb70AllocAndRead(pHdr, cb, piPageMap);
408 if (pRoot)
409 {
410 /* validate? */
411 return pRoot;
412 }
413 }
414#else
415 /* validate? */
416 return pRoot;
417#endif
418 }
419 return NULL;
420}
421
422static void *Pdb70AllocAndReadStream(PPDB70HDR pHdr, PPDB70ROOT pRoot, unsigned iStream, size_t *pcbStream)
423{
424 const size_t cbStream = pRoot->aStreams[iStream].cbStream;
425 PPDB70PAGE paiPageMap;
426 if ( iStream >= pRoot->cStreams
427 || cbStream == ~(uint32_t)0)
428 {
429 fprintf(stderr, "%s: error: Invalid stream %d\n", iStream);
430 return NULL;
431 }
432
433 paiPageMap = (PPDB70PAGE)&pRoot->aStreams[pRoot->cStreams];
434 while (iStream-- > 0)
435 if (pRoot->aStreams[iStream].cbStream != ~(uint32_t)0)
436 paiPageMap += Pdb70Pages(pHdr, pRoot->aStreams[iStream].cbStream);
437
438 if (pcbStream)
439 *pcbStream = cbStream;
440 return Pdb70AllocAndRead(pHdr, cbStream, paiPageMap);
441}
442
443static int Pdb70Process(uint8_t *pbFile, size_t cbFile)
444{
445 PPDB70HDR pHdr = (PPDB70HDR)pbFile;
446 PPDB70ROOT pRoot;
447 PPDB70NAMES pNames;
448 size_t cbStream;
449 unsigned fDone = 0;
450 unsigned iStream;
451 int rc = 0;
452 dprintf(("pdb70\n"));
453
454 /*
455 * Validate the header and read the root stream.
456 */
457 if (Pdb70ValidateHeader(pHdr, cbFile))
458 return 1;
459 pRoot = Pdb70AllocAndReadRoot(pHdr);
460 if (!pRoot)
461 return 1;
462
463 /*
464 * The names we want are usually all found in the 'Names' stream, that is #1.
465 */
466 dprintf(("Reading the names stream....\n"));
467 pNames = Pdb70AllocAndReadStream(pHdr, pRoot, 1, &cbStream);
468 if (pNames)
469 {
470 dprintf(("Names: Version=%u cbNames=%u (%#x)\n", pNames->Version, pNames->cbNames, pNames->cbNames));
471 if ( pNames->Version == PDB70NAMES_VERSION
472 && pNames->cbNames > 32
473 && pNames->cbNames + offsetof(PDB70NAMES, szzNames) <= pRoot->aStreams[1].cbStream)
474 {
475 /*
476 * Iterate the names and add the /mr/inversedeps/ ones to the dependency list.
477 */
478 const char *psz = &pNames->szzNames[0];
479 size_t cb = pNames->cbNames;
480 size_t off = 0;
481 dprintf(("0x0000 #0: %6d bytes [root / toc]\n", pRoot->aStreams[0].cbStream));
482 for (iStream = 1; cb > 0; iStream++)
483 {
484 int fAdded = 0;
485 size_t cch = strlen(psz);
486 if ( cch >= sizeof("/mr/inversedeps/")
487 && !memcmp(psz, "/mr/inversedeps/", sizeof("/mr/inversedeps/") - 1))
488 {
489 depAdd(psz + sizeof("/mr/inversedeps/") - 1, cch - (sizeof("/mr/inversedeps/") - 1));
490 fAdded = 1;
491 }
492 dprintf(("%#06x #%d: %6d bytes %s%s\n", off, iStream,
493 iStream < pRoot->cStreams ? pRoot->aStreams[iStream].cbStream : -1,
494 psz, fAdded ? " [dep]" : ""));
495 (void)fAdded;
496
497 /* next */
498 if (cch >= cb)
499 {
500 dprintf(("warning! cch=%d cb=%d\n", cch, cb));
501 cch = cb - 1;
502 }
503 cb -= cch + 1;
504 psz += cch + 1;
505 off += cch + 1;
506 }
507 rc = 0;
508 fDone = 1;
509 }
510 else
511 dprintf(("Unknown version or bad size: Version=%u cbNames=%d cbStream=%d\n",
512 pNames->Version, pNames->cbNames, cbStream));
513 free(pNames);
514 }
515
516 if (!fDone)
517 {
518 /*
519 * Iterate the streams in the root and scan their content for
520 * dependencies.
521 */
522 rc = 0;
523 for (iStream = 0; iStream < pRoot->cStreams && !rc; iStream++)
524 {
525 uint8_t *pbStream;
526 if ( pRoot->aStreams[iStream].cbStream == ~(uint32_t)0
527 || !pRoot->aStreams[iStream].cbStream)
528 continue;
529 dprintf(("Stream #%d: %#x bytes (%#x aligned)\n", iStream, pRoot->aStreams[iStream].cbStream,
530 Pdb70Align(pHdr, pRoot->aStreams[iStream].cbStream)));
531 pbStream = (uint8_t *)Pdb70AllocAndReadStream(pHdr, pRoot, iStream, &cbStream);
532 if (pbStream)
533 {
534 rc = ScanStream(pbStream, cbStream, "/mr/inversedeps/", sizeof("/mr/inversedeps/") - 1);
535 free(pbStream);
536 }
537 else
538 rc = 1;
539 }
540 }
541
542 free(pRoot);
543 return rc;
544}
545
546
547
548///////////////////////////////////////////////////////////////////////////////
549//
550//
551// P D B 2 . 0
552//
553//
554///////////////////////////////////////////////////////////////////////////////
555
556
557/** A PDB 2.0 Page number. */
558typedef uint16_t PDB20PAGE;
559/** Pointer to a PDB 2.0 Page number. */
560typedef PDB20PAGE *PPDB20PAGE;
561
562/**
563 * A PDB 2.0 stream.
564 */
565typedef struct PDB20STREAM
566{
567 /** The size of the stream. */
568 uint32_t cbStream;
569 /** Some unknown value. */
570 uint32_t u32Unknown;
571} PDB20STREAM, *PPDB20STREAM;
572
573/** The PDB 2.00 signature. */
574#define PDB_SIGNATURE_200 "Microsoft C/C++ program database 2.00\r\n\x1A" "JG\0"
575/**
576 * The PDB 2.0 header.
577 */
578typedef struct PDB20HDR
579{
580 /** The signature string. */
581 uint8_t szSignature[sizeof(PDB_SIGNATURE_200)];
582 /** The page size. */
583 uint32_t cbPage;
584 /** The start page - whatever that is... */
585 PDB20PAGE iStartPage;
586 /** The number of pages in the file. */
587 PDB20PAGE cPages;
588 /** The root stream directory. */
589 PDB20STREAM RootStream;
590 /** The root page table. */
591 PDB20PAGE aiRootPageMap[1];
592} PDB20HDR, *PPDB20HDR;
593
594/**
595 * The PDB 2.0 root directory.
596 */
597typedef struct PDB20ROOT
598{
599 /** The number of streams */
600 uint16_t cStreams;
601 /** Reserved or high part of cStreams. */
602 uint16_t u16Reserved;
603 /** Array of streams. */
604 PDB20STREAM aStreams[1];
605} PDB20ROOT, *PPDB20ROOT;
606
607
608static int Pdb20ValidateHeader(PPDB20HDR pHdr, size_t cbFile)
609{
610 if (pHdr->cbPage * pHdr->cPages != cbFile)
611 {
612 fprintf(stderr, "%s: error: Bad PDB 2.0 header - cbPage * cPages != cbFile.\n", argv0);
613 return 1;
614 }
615 if (pHdr->iStartPage >= pHdr->cPages && pHdr->iStartPage <= 0)
616 {
617 fprintf(stderr, "%s: error: Bad PDB 2.0 header - cbPage * cPages != cbFile.\n", argv0);
618 return 1;
619 }
620 return 0;
621}
622
623static size_t Pdb20Pages(PPDB20HDR pHdr, size_t cb)
624{
625 if (cb == ~(uint32_t)0 || !cb)
626 return 0;
627 return (cb + pHdr->cbPage - 1) / pHdr->cbPage;
628}
629
630static void *Pdb20AllocAndRead(PPDB20HDR pHdr, size_t cb, PPDB20PAGE paiPageMap)
631{
632 size_t cPages = Pdb20Pages(pHdr, cb);
633 uint8_t *pbBuf = malloc(cPages * pHdr->cbPage + 1);
634 if (pbBuf)
635 {
636 size_t iPage = 0;
637 while (iPage < cPages)
638 {
639 size_t off = paiPageMap[iPage];
640 off *= pHdr->cbPage;
641 memcpy(pbBuf + iPage * pHdr->cbPage, (uint8_t *)pHdr + off, pHdr->cbPage);
642 iPage++;
643 }
644 pbBuf[cPages * pHdr->cbPage] = '\0';
645 }
646 else
647 fprintf(stderr, "%s: error: failed to allocate %d bytes\n", argv0, cPages * pHdr->cbPage + 1);
648 return pbBuf;
649}
650
651static PPDB20ROOT Pdb20AllocAndReadRoot(PPDB20HDR pHdr)
652{
653 /*
654 * The tricky bit here is to find the right length.
655 * (Todo: Check if we can just use the stream size..)
656 */
657 PPDB20ROOT pRoot = Pdb20AllocAndRead(pHdr, sizeof(*pRoot), &pHdr->aiRootPageMap[0]);
658 if (pRoot)
659 {
660 /* size = stream header + array of stream. */
661 size_t cb = OFFSETOF(PDB20ROOT, aStreams[pRoot->cStreams]);
662 free(pRoot);
663 pRoot = Pdb20AllocAndRead(pHdr, cb, &pHdr->aiRootPageMap[0]);
664 if (pRoot)
665 {
666 /* size += page tables. */
667 unsigned iStream = pRoot->cStreams;
668 while (iStream-- > 0)
669 if (pRoot->aStreams[iStream].cbStream != ~(uint32_t)0)
670 cb += Pdb20Pages(pHdr, pRoot->aStreams[iStream].cbStream) * sizeof(PDB20PAGE);
671 free(pRoot);
672 pRoot = Pdb20AllocAndRead(pHdr, cb, &pHdr->aiRootPageMap[0]);
673 if (pRoot)
674 {
675 /* validate? */
676 return pRoot;
677 }
678 }
679 }
680 return NULL;
681
682}
683
684static void *Pdb20AllocAndReadStream(PPDB20HDR pHdr, PPDB20ROOT pRoot, unsigned iStream, size_t *pcbStream)
685{
686 size_t cbStream = pRoot->aStreams[iStream].cbStream;
687 PPDB20PAGE paiPageMap;
688 if ( iStream >= pRoot->cStreams
689 || cbStream == ~(uint32_t)0)
690 {
691 fprintf(stderr, "%s: error: Invalid stream %d\n", iStream);
692 return NULL;
693 }
694
695 paiPageMap = (PPDB20PAGE)&pRoot->aStreams[pRoot->cStreams];
696 while (iStream-- > 0)
697 if (pRoot->aStreams[iStream].cbStream != ~(uint32_t)0)
698 paiPageMap += Pdb20Pages(pHdr, pRoot->aStreams[iStream].cbStream);
699
700 if (pcbStream)
701 *pcbStream = cbStream;
702 return Pdb20AllocAndRead(pHdr, cbStream, paiPageMap);
703}
704
705static int Pdb20Process(uint8_t *pbFile, size_t cbFile)
706{
707 PPDB20HDR pHdr = (PPDB20HDR)pbFile;
708 PPDB20ROOT pRoot;
709 unsigned iStream;
710 int rc = 0;
711
712 /*
713 * Validate the header and read the root stream.
714 */
715 if (Pdb20ValidateHeader(pHdr, cbFile))
716 return 1;
717 pRoot = Pdb20AllocAndReadRoot(pHdr);
718 if (!pRoot)
719 return 1;
720
721 /*
722 * Iterate the streams in the root and scan their content for
723 * dependencies.
724 */
725 rc = 0;
726 for (iStream = 0; iStream < pRoot->cStreams && !rc; iStream++)
727 {
728 uint8_t *pbStream;
729 if (pRoot->aStreams[iStream].cbStream == ~(uint32_t)0)
730 continue;
731 pbStream = (uint8_t *)Pdb20AllocAndReadStream(pHdr, pRoot, iStream, NULL);
732 if (pbStream)
733 {
734 rc = ScanStream(pbStream, pRoot->aStreams[iStream].cbStream, "/ipm/header/", sizeof("/ipm/header/") - 1);
735 free(pbStream);
736 }
737 else
738 rc = 1;
739 }
740
741 free(pRoot);
742 return rc;
743}
744
745
746/**
747 * Make an attempt at parsing a Visual C++ IDB file.
748 */
749static int ProcessIDB(FILE *pInput)
750{
751 size_t cbFile;
752 uint8_t *pbFile;
753 int rc = 0;
754
755 /*
756 * Read the file into memory.
757 */
758 pbFile = (uint8_t *)ReadFileIntoMemory(pInput, &cbFile);
759 if (!pbFile)
760 return 1;
761
762 /*
763 * Figure out which parser to use.
764 */
765 if (!memcmp(pbFile, PDB_SIGNATURE_700, sizeof(PDB_SIGNATURE_700)))
766 rc = Pdb70Process(pbFile, cbFile);
767 else if (!memcmp(pbFile, PDB_SIGNATURE_200, sizeof(PDB_SIGNATURE_200)))
768 rc = Pdb20Process(pbFile, cbFile);
769 else
770 {
771 fprintf(stderr, "%s: error: Doesn't recognize the header of the Visual C++ IDB file.\n", argv0);
772 rc = 1;
773 }
774
775 FreeFileMemory(pbFile);
776 return rc;
777}
778
779
780static void usage(const char *argv0)
781{
782 printf("usage: %s -o <output> -t <target> [-f] [-s] <vc idb-file>\n"
783 " or: %s --help\n"
784 " or: %s --version\n",
785 argv0, argv0, argv0);
786}
787
788
789int kmk_builtin_kDepIDB(int argc, char *argv[], char **envp)
790{
791 int i;
792
793 /* Arguments. */
794 FILE *pOutput = NULL;
795 const char *pszOutput = NULL;
796 FILE *pInput = NULL;
797 const char *pszTarget = NULL;
798 int fStubs = 0;
799 int fFixCase = 0;
800 /* Argument parsing. */
801 int fInput = 0; /* set when we've found input argument. */
802
803 argv0 = argv[0];
804
805 /*
806 * Parse arguments.
807 */
808 if (argc <= 1)
809 {
810 usage(argv[0]);
811 return 1;
812 }
813 for (i = 1; i < argc; i++)
814 {
815 if (argv[i][0] == '-')
816 {
817 const char *psz = &argv[i][1];
818 if (*psz == '-')
819 {
820 if (!strcmp(psz, "-help"))
821 psz = "?";
822 else if (!strcmp(psz, "-version"))
823 psz = "v";
824 }
825
826 switch (*psz)
827 {
828 /*
829 * Output file.
830 */
831 case 'o':
832 {
833 pszOutput = &argv[i][2];
834 if (pOutput)
835 {
836 fprintf(stderr, "%s: syntax error: only one output file!\n", argv[0]);
837 return 1;
838 }
839 if (!*pszOutput)
840 {
841 if (++i >= argc)
842 {
843 fprintf(stderr, "%s: syntax error: The '-o' argument is missing the filename.\n", argv[0]);
844 return 1;
845 }
846 pszOutput = argv[i];
847 }
848 if (pszOutput[0] == '-' && !pszOutput[1])
849 pOutput = stdout;
850 else
851 pOutput = fopen(pszOutput, "w");
852 if (!pOutput)
853 {
854 fprintf(stderr, "%s: error: Failed to create output file '%s'.\n", argv[0], pszOutput);
855 return 1;
856 }
857 break;
858 }
859
860 /*
861 * Target name.
862 */
863 case 't':
864 {
865 if (pszTarget)
866 {
867 fprintf(stderr, "%s: syntax error: only one target!\n", argv[0]);
868 return 1;
869 }
870 pszTarget = &argv[i][2];
871 if (!*pszTarget)
872 {
873 if (++i >= argc)
874 {
875 fprintf(stderr, "%s: syntax error: The '-t' argument is missing the target name.\n", argv[0]);
876 return 1;
877 }
878 pszTarget = argv[i];
879 }
880 break;
881 }
882
883 /*
884 * Fix case.
885 */
886 case 'f':
887 {
888 fFixCase = 1;
889 break;
890 }
891
892 /*
893 * Generate stubs.
894 */
895 case 's':
896 {
897 fStubs = 1;
898 break;
899 }
900
901 /*
902 * The mandatory version & help.
903 */
904 case '?':
905 usage(argv[0]);
906 return 0;
907 case 'v':
908 return kbuild_version(argv[0]);
909
910 /*
911 * Invalid argument.
912 */
913 default:
914 fprintf(stderr, "%s: syntax error: Invalid argument '%s'.\n", argv[0], argv[i]);
915 usage(argv[0]);
916 return 1;
917 }
918 }
919 else
920 {
921 pInput = fopen(argv[i], "rb");
922 if (!pInput)
923 {
924 fprintf(stderr, "%s: error: Failed to open input file '%s'.\n", argv[0], argv[i]);
925 return 1;
926 }
927 fInput = 1;
928 }
929
930 /*
931 * End of the line?
932 */
933 if (fInput)
934 {
935 if (++i < argc)
936 {
937 fprintf(stderr, "%s: syntax error: No arguments shall follow the input spec.\n", argv[0]);
938 return 1;
939 }
940 break;
941 }
942 }
943
944 /*
945 * Got all we require?
946 */
947 if (!pInput)
948 {
949 fprintf(stderr, "%s: syntax error: No input!\n", argv[0]);
950 return 1;
951 }
952 if (!pOutput)
953 {
954 fprintf(stderr, "%s: syntax error: No output!\n", argv[0]);
955 return 1;
956 }
957 if (!pszTarget)
958 {
959 fprintf(stderr, "%s: syntax error: No target!\n", argv[0]);
960 return 1;
961 }
962
963 /*
964 * Do the parsing.
965 */
966 i = ProcessIDB(pInput);
967 fclose(pInput);
968
969 /*
970 * Write the dependecy file.
971 */
972 if (!i)
973 {
974 depOptimize(fFixCase);
975 fprintf(pOutput, "%s:", pszTarget);
976 depPrint(pOutput);
977 if (fStubs)
978 depPrintStubs(pOutput);
979 }
980
981 /*
982 * Close the output, delete output on failure.
983 */
984 if (!i && ferror(pOutput))
985 {
986 i = 1;
987 fprintf(stderr, "%s: error: Error writing to '%s'.\n", argv[0], pszOutput);
988 }
989 fclose(pOutput);
990 if (i)
991 {
992 if (unlink(pszOutput))
993 fprintf(stderr, "%s: warning: failed to remove output file '%s' on failure.\n", argv[0], pszOutput);
994 }
995
996 depCleanup();
997 return i;
998}
999
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