VirtualBox

source: kBuild/trunk/src/kDepIDB/kDepIDB.c@ 866

Last change on this file since 866 was 866, checked in by bird, 18 years ago

damn, left debug on.

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