VirtualBox

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

Last change on this file since 1223 was 1183, checked in by bird, 17 years ago

Added --version and --help to all builtins.

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