VirtualBox

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

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

kmkbuiltin: include config.h

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

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