VirtualBox

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

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

kmk: make sure alloca.h gets included (Solaris again).

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