VirtualBox

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

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

Bad idea to use read(fileno()) on a stream after searching it because (1) it might already be buffered and (2) the fseek might not be synced to the file handle yet.

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