VirtualBox

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

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

proto.

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