VirtualBox

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

最後變更 在這個檔案從2115是 2115,由 bird 提交於 16 年 前

kDepIDB: warnings.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette