VirtualBox

source: kBuild/trunk/src/kLibTweaker/kLibTweaker.c@ 2962

Last change on this file since 2962 was 2791, checked in by bird, 9 years ago

kLibTweaker: New tool for playing with Microsoft import libraries (currently).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.0 KB
Line 
1/* $Id: kLibTweaker.c 2791 2015-09-15 22:57:44Z bird $ */
2/** @file
3 * kLibTweaker - Import library tweaker for windows.
4 */
5
6/*
7 * Copyright (c) 2007-2015 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#if 0
30# define ELECTRIC_HEAP
31# include "../kmk/electric.h"
32# include "../kmk/electric.c"
33#endif
34#include <ctype.h>
35#include <string.h>
36#include <stdlib.h>
37#include <stdarg.h>
38#include <stdio.h>
39#include <errno.h>
40#include <assert.h>
41
42#include "k/kLdrFmts/pe.h"
43
44
45/*********************************************************************************************************************************
46* Structures and Typedefs *
47*********************************************************************************************************************************/
48/**
49 * Microsoft import library archive header.
50 *
51 * This has the same size as a COFF header, which is probably not a coincidence.
52 */
53typedef struct COFFIMPLIBHDR
54{
55 KU16 uSig1; /* 0 */
56 KU16 uSig2; /* 0xffff */
57 KU16 uVersion; /* 0 */
58 KU16 uMachine; /* IMAGE_FILE_MACHINE_I386, ... */
59 KU32 uTimeDateStamp;
60 KU32 cbData;
61 KU16 uOrdinalOrHint;
62 KU16 uFlags;
63} COFFIMPLIBHDR;
64
65/**
66 * COFF symbol.
67 *
68 * This one has an odd size and will cause misaligned accesses on platforms
69 * which cares about such.
70 */
71#pragma pack(1)
72typedef struct COFFSYMBOL
73{
74 union
75 {
76 char e_name[8];
77 struct
78 {
79 KU32 e_zeros; /**< Zero to distinguish it from ascii name. */
80 KU32 e_offset; /**< String table offset. */
81 } e;
82 } e;
83 KU32 e_value;
84 KI16 e_scnum;
85 KU16 e_type;
86 KU8 e_sclass;
87 KU8 e_numaux;
88} COFFSYMBOL;
89#pragma pack()
90
91/**
92 * Archive file header.
93 */
94typedef struct ARCHFILEHDR
95{
96 char achName[16];
97 char achModtime[12];
98 char achOwnerId[6];
99 char achGroupId[6];
100 char achMode[8];
101 char achSize[10];
102 char achMagic[2];
103} ARCHFILEHDR;
104
105
106/*********************************************************************************************************************************
107* Global Variables *
108*********************************************************************************************************************************/
109/** Whether verbose output is enabled. */
110static unsigned g_cVerbosityLevel = 0;
111/** What to prefix the errors with. */
112static char g_szErrorPrefix[128];
113
114
115void FatalMsg(const char *pszFormat, ...)
116{
117 va_list va;
118
119 if (g_szErrorPrefix[0])
120 fprintf(stderr, "%s - fatal error: ", g_szErrorPrefix);
121 else
122 fprintf(stderr, "fatal error: ");
123
124 va_start(va, pszFormat);
125 vfprintf(stderr, pszFormat, va);
126 va_end(va);
127}
128
129
130void FatalDie(const char *pszFormat, ...)
131{
132 va_list va;
133
134 if (g_szErrorPrefix[0])
135 fprintf(stderr, "%s - fatal error: ", g_szErrorPrefix);
136 else
137 fprintf(stderr, "fatal error: ");
138
139 va_start(va, pszFormat);
140 vfprintf(stderr, pszFormat, va);
141 va_end(va);
142
143 exit(1);
144}
145
146
147static int ErrorMsg(const char *pszFormat, ...)
148{
149 va_list va;
150
151 if (g_szErrorPrefix[0])
152 fprintf(stderr, "%s - error: ", g_szErrorPrefix);
153 else
154 fprintf(stderr, "error: ");
155
156 va_start(va, pszFormat);
157 vfprintf(stderr, pszFormat, va);
158 va_end(va);
159
160 return 1;
161}
162
163
164static void InfoMsg(unsigned uLevel, const char *pszFormat, ...)
165{
166 if (uLevel <= g_cVerbosityLevel)
167 {
168 va_list va;
169
170 if (g_szErrorPrefix[0])
171 fprintf(stderr, "%s - info: ", g_szErrorPrefix);
172 else
173 fprintf(stderr, "info: ");
174
175 va_start(va, pszFormat);
176 vfprintf(stderr, pszFormat, va);
177 va_end(va);
178 }
179}
180
181
182static void SetErrorPrefix(const char *pszPrefix, ...)
183{
184 int cch;
185 va_list va;
186
187 va_start(va, pszPrefix);
188#if defined(_MSC_VER) || defined(__sun__)
189 cch = vsprintf(g_szErrorPrefix, pszPrefix, va);
190 if (cch >= sizeof(g_szErrorPrefix))
191 FatalDie("Buffer overflow setting error prefix!\n");
192#else
193 vsnprintf(g_szErrorPrefix, sizeof(g_szErrorPrefix), pszPrefix, va);
194#endif
195 va_end(va);
196 (void)cch;
197}
198
199#ifndef ELECTRIC_HEAP
200void *xmalloc(size_t cb)
201{
202 void *pv = malloc(cb);
203 if (!pv)
204 FatalDie("out of memory (%d)\n", (int)cb);
205 return pv;
206}
207
208
209void *xrealloc(void *pvOld, size_t cb)
210{
211 void *pv = realloc(pvOld, cb);
212 if (!pv)
213 FatalDie("out of memory (%d)\n", (int)cb);
214 return pv;
215}
216
217
218char *xstrdup(const char *pszIn)
219{
220 char *psz;
221 if (pszIn)
222 {
223 psz = strdup(pszIn);
224 if (!psz)
225 FatalDie("out of memory (%d)\n", (int)strlen(pszIn));
226 }
227 else
228 psz = NULL;
229 return psz;
230}
231#endif
232
233
234void *xmallocz(size_t cb)
235{
236 void *pv = xmalloc(cb);
237 memset(pv, 0, cb);
238 return pv;
239}
240
241
242/**
243 * Adds the arguments found in the pszCmdLine string to argument vector.
244 *
245 * The parsing of the pszCmdLine string isn't very sophisticated, no
246 * escaping or quotes.
247 *
248 * @param pcArgs Pointer to the argument counter.
249 * @param ppapszArgs Pointer to the argument vector pointer.
250 * @param pszCmdLine The command line to parse and append.
251 * @param pszWedgeArg Argument to put infront of anything found in pszCmdLine.
252 */
253static void AppendArgs(int *pcArgs, char ***ppapszArgs, const char *pszCmdLine, const char *pszWedgeArg)
254{
255 int i;
256 int cExtraArgs;
257 const char *psz;
258 char **papszArgs;
259
260 /*
261 * Count the new arguments.
262 */
263 cExtraArgs = 0;
264 psz = pszCmdLine;
265 while (*psz)
266 {
267 while (isspace(*psz))
268 psz++;
269 if (!psz)
270 break;
271 cExtraArgs++;
272 while (!isspace(*psz) && *psz)
273 psz++;
274 }
275 if (!cExtraArgs)
276 return;
277
278 /*
279 * Allocate a new vector that can hold the arguments.
280 * (Reallocating might not work since the argv might not be allocated
281 * from the heap but off the stack or somewhere... )
282 */
283 i = *pcArgs;
284 *pcArgs = i + cExtraArgs + !!pszWedgeArg;
285 papszArgs = xmalloc((*pcArgs + 1) * sizeof(char *));
286 *ppapszArgs = memcpy(papszArgs, *ppapszArgs, i * sizeof(char *));
287
288 if (pszWedgeArg)
289 papszArgs[i++] = xstrdup(pszWedgeArg);
290
291 psz = pszCmdLine;
292 while (*psz)
293 {
294 size_t cch;
295 const char *pszEnd;
296 while (isspace(*psz))
297 psz++;
298 if (!psz)
299 break;
300 pszEnd = psz;
301 while (!isspace(*pszEnd) && *pszEnd)
302 pszEnd++;
303
304 cch = pszEnd - psz;
305 papszArgs[i] = xmalloc(cch + 1);
306 memcpy(papszArgs[i], psz, cch);
307 papszArgs[i][cch] = '\0';
308
309 i++;
310 psz = pszEnd;
311 }
312
313 papszArgs[i] = NULL;
314}
315
316
317
318
319static fpos_t kLibTweakerAsciiToSize(const char *pch, size_t cch)
320{
321 fpos_t cb = 0;
322
323 /* strip leading spaces. */
324 while (cch > 0 && (*pch == ' ' || *pch == '\t'))
325 cch--, pch++;
326
327 /* Convert decimal to binary. */
328 while (cch-- > 0)
329 {
330 char ch = *pch++;
331 if (ch >= '0' && ch <= '9')
332 {
333 cb *= 10;
334 cb += ch - '0';
335 }
336 else
337 break;
338 }
339
340 return cb;
341}
342
343
344static int kLibMyReadAt(FILE *pFile, void *pv, size_t cb, fpos_t off, int fEofOk)
345{
346 if (fsetpos(pFile, &off) == 0)
347 {
348 size_t cbActual = fread(pv, 1, cb, pFile);
349 if (cbActual == cb)
350 return 0;
351 if (!fEofOk || !feof(pFile))
352 ErrorMsg("fread returned %#lx, expected %#lx!\n", (unsigned long)cbActual, (unsigned long)cb);
353 }
354 else
355 ErrorMsg("seek error!\n");
356 return 1;
357}
358
359
360static int kLibMyWriteAt(FILE *pFile, const void *pv, size_t cb, fpos_t off)
361{
362 if (fsetpos(pFile, &off) == 0)
363 {
364 size_t cbActual = fwrite(pv, 1, cb, pFile);
365 if (cbActual == cb)
366 return 0;
367 ErrorMsg("fwrite returned %#lx, expected %#lx!\n", (unsigned long)cbActual, (unsigned long)cb);
368 }
369 else
370 ErrorMsg("seek error!\n");
371 return 1;
372}
373
374
375static int kLibFillNullThunkData(FILE *pFile, fpos_t cbFile, fpos_t offFileBytes)
376{
377 size_t off;
378 IMAGE_FILE_HEADER CoffHdr;
379 IMAGE_SECTION_HEADER SecHdr;
380 unsigned iSecHdr;
381 fpos_t offCur;
382 unsigned cbMachineWord;
383 KU32 cbStrTab;
384 COFFSYMBOL *paSymbols;
385 int rcRet = 0;
386
387 /*
388 * Read the COFF file header and filter out unlikly files based on
389 * section and symbol counts.
390 */
391 if (cbFile <= sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_SECTION_HEADER) * 2 + 4)
392 return 0;
393 if (kLibMyReadAt(pFile, &CoffHdr, sizeof(CoffHdr), offFileBytes, 0) != 0)
394 return 1;
395 if ( CoffHdr.Machine != IMAGE_FILE_MACHINE_I386
396 && CoffHdr.Machine != IMAGE_FILE_MACHINE_AMD64)
397 return 0;
398 cbMachineWord = CoffHdr.Machine == IMAGE_FILE_MACHINE_I386 ? 4 : 8;
399 if ( CoffHdr.NumberOfSections == 0
400 || CoffHdr.NumberOfSymbols == 0)
401 return 0;
402 off = sizeof(IMAGE_FILE_HEADER) + CoffHdr.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
403 if ((fpos_t)off >= cbFile)
404 return 0;
405 if ( CoffHdr.PointerToSymbolTable >= (KU64)cbFile
406 || CoffHdr.PointerToSymbolTable < off)
407 return 0;
408
409 /*
410 * Search for the .idata$5 section which the thunk data is usually found in.
411 */
412 offCur = offFileBytes + sizeof(CoffHdr);
413 for (iSecHdr = 0; iSecHdr < CoffHdr.NumberOfSections; iSecHdr++)
414 {
415 if (kLibMyReadAt(pFile, &SecHdr, sizeof(SecHdr), offCur, 0) != 0)
416 return 1;
417 InfoMsg(2, "#2: %.8s VirtualSize=%#lx\n", SecHdr.Name, SecHdr.SizeOfRawData);
418 if ( !memcmp(SecHdr.Name, ".idata$5", 8)
419 && SecHdr.SizeOfRawData == cbMachineWord)
420 break;
421 offCur += sizeof(SecHdr);
422 }
423 if (iSecHdr == CoffHdr.NumberOfSections)
424 return 0;
425
426 /*
427 * Read in the symbo and string tables.
428 */
429 off = CoffHdr.PointerToSymbolTable + CoffHdr.NumberOfSymbols * sizeof(COFFSYMBOL);
430 if (kLibMyReadAt(pFile, &cbStrTab, sizeof(cbStrTab), offFileBytes + off, 0) != 0)
431 return 1;
432 InfoMsg(2, "#2: Found COFF file header, cbStrTab=%#x; off=%#lx NumberOfSymbols=%#x PointerToSymbolTable=%#x\n",
433 cbStrTab, (long)off, CoffHdr.NumberOfSymbols, CoffHdr.PointerToSymbolTable);
434 if ( cbStrTab <= 4U
435 || cbStrTab >= 16*1024*1024U /* 16MB */
436 || (fpos_t)off + cbStrTab > cbFile)
437 return 0;
438 paSymbols = xmalloc(CoffHdr.NumberOfSymbols * sizeof(COFFSYMBOL) + cbStrTab + 1);
439 if (kLibMyReadAt(pFile, paSymbols, CoffHdr.NumberOfSymbols * sizeof(COFFSYMBOL) + cbStrTab,
440 offFileBytes + CoffHdr.PointerToSymbolTable, 0) == 0)
441 {
442 char *pchStrTab = (char *)&paSymbols[CoffHdr.NumberOfSymbols];
443 unsigned iSym;
444
445 pchStrTab[cbStrTab] = '\0';
446 pchStrTab[0] = '\0';
447 pchStrTab[1] = '\0';
448 pchStrTab[2] = '\0';
449 pchStrTab[3] = '\0';
450
451 for (iSym = 0; iSym < CoffHdr.NumberOfSymbols; iSym++)
452 {
453 static char const s_szSuffix[] = "NULL_THUNK_DATA";
454 const char *pchName;
455 size_t cchName;
456 if (paSymbols[iSym].e.e.e_zeros != 0)
457 {
458 pchName = &paSymbols[iSym].e.e_name[0];
459 cchName = (char *)memchr(pchName, '\0', sizeof(paSymbols[iSym].e.e_name)) - pchName;
460 if (cchName > sizeof(paSymbols[iSym].e.e_name))
461 cchName = sizeof(paSymbols[iSym].e.e_name);
462 }
463 else if ( paSymbols[iSym].e.e.e_offset == 0
464 || paSymbols[iSym].e.e.e_offset >= cbStrTab)
465 continue;
466 else
467 {
468 pchName = &pchStrTab[paSymbols[iSym].e.e.e_offset];
469 cchName = strlen(pchName);
470 }
471
472 if ( *pchName == 0x7f
473 && cchName >= sizeof(s_szSuffix)
474 && memcmp(&pchName[cchName - sizeof(s_szSuffix) + 1], s_szSuffix, sizeof(s_szSuffix) - 1) == 0)
475 {
476 if (pchName[cchName] == '\0')
477 InfoMsg(1, "#2: Found '%s': value=%#lx\n", pchName, paSymbols[iSym].e_value);
478 else
479 InfoMsg(1, "#2: Found '%.8s': value=%#lx\n", pchName, paSymbols[iSym].e_value);
480 if ( paSymbols[iSym].e_scnum > 0
481 && paSymbols[iSym].e_scnum <= CoffHdr.NumberOfSections)
482 {
483 if (paSymbols[iSym].e_scnum != iSecHdr + 1)
484 InfoMsg(0, "#2: '%s' in section %u, expected %u\n", pchName, paSymbols[iSym].e_scnum, iSecHdr);
485 else if (paSymbols[iSym].e_value != 0)
486 InfoMsg(0, "#2: '%s' in value %#xu, expected 0x0\n", pchName, paSymbols[iSym].e_value);
487 else if ( SecHdr.PointerToRawData < sizeof(CoffHdr) + CoffHdr.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
488 || (fpos_t)SecHdr.PointerToRawData + cbMachineWord > cbFile)
489 InfoMsg(0, "#2: Unexpected PointerToRawData value: %#x\n", SecHdr.PointerToRawData);
490 else
491 {
492 union
493 {
494 KU8 ab[8];
495 KU32 u32;
496 KU64 u64;
497 } uBuf;
498 uBuf.u64 = 0;
499 off = offFileBytes + SecHdr.PointerToRawData;
500 if (kLibMyReadAt(pFile, &uBuf, cbMachineWord, off, 0) == 0)
501 {
502 static const KU8 s_abGarbage[8] = { 0xaa, 0x99, 0x88, 0xbb, 0xbb, 0xaa, 0x88, 0x99 };
503 static const KU8 s_abZero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
504 if (memcmp(&uBuf, s_abZero,cbMachineWord) == 0)
505 {
506 rcRet = kLibMyWriteAt(pFile, s_abGarbage, cbMachineWord, off);
507 if (!rcRet)
508 InfoMsg(1, "#2: Updated '%s'\n", pchName);
509 }
510 else if (memcmp(&uBuf, s_abGarbage, cbMachineWord) == 0)
511 {
512 InfoMsg(1, "#2: Already modified '%s'\n", pchName);
513 rcRet = 0;
514 }
515 else
516 rcRet = ErrorMsg(0, "#2: Unexpected '%s' data: %02x %02x %02x %02x %02x %02x %02x %02x\n",
517 pchName,
518 uBuf.ab[0], uBuf.ab[1], uBuf.ab[2], uBuf.ab[3],
519 uBuf.ab[4], uBuf.ab[5], uBuf.ab[6], uBuf.ab[7]);
520 }
521 break;
522 }
523 }
524 }
525 }
526
527 }
528 else
529 rcRet = 1;
530 free(paSymbols);
531 return rcRet;
532}
533
534
535/**
536 * Clears timestamps to avoid rebuilding stuff just because the internal
537 * timestamps changed in an import library.
538 */
539static int kLibClearTimestamps(FILE *pFile, fpos_t offFileHdr, ARCHFILEHDR *pFileHdr, fpos_t cbFile, fpos_t offFileBytes)
540{
541 union
542 {
543 IMAGE_FILE_HEADER CoffHdr;
544 COFFIMPLIBHDR ImpLibHdr;
545 } u;
546 if (sizeof(u.CoffHdr) != sizeof(u.ImpLibHdr))
547 FatalDie("Oops!");
548
549 /*
550 * Clear the timestamp in the library file header.
551 */
552 memset(pFileHdr->achModtime, '0', sizeof(pFileHdr->achModtime));
553 if (kLibMyWriteAt(pFile, pFileHdr, sizeof(*pFileHdr), offFileHdr) != 0)
554 return 1;
555
556 /*
557 * Clear the timestamp in the COFF header, if we find one.
558 */
559 if (cbFile <= sizeof(IMAGE_FILE_HEADER))
560 return 0;
561 if (kLibMyReadAt(pFile, &u.CoffHdr, sizeof(u.CoffHdr), offFileBytes, 0) != 0)
562 return 1;
563
564 if ( ( u.CoffHdr.Machine == IMAGE_FILE_MACHINE_I386
565 || u.CoffHdr.Machine == IMAGE_FILE_MACHINE_AMD64)
566 && sizeof(IMAGE_FILE_HEADER)
567 + u.CoffHdr.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
568 <= (KU64)cbFile
569 && u.CoffHdr.PointerToSymbolTable <= (KU64)cbFile)
570 {
571 InfoMsg(1, "Found COFF file header\n");
572 if (u.CoffHdr.TimeDateStamp != 0)
573 {
574 u.CoffHdr.TimeDateStamp = 0;
575 return kLibMyWriteAt(pFile, &u.CoffHdr, sizeof(u.CoffHdr), offFileBytes);
576 }
577 }
578 else if ( u.ImpLibHdr.uSig1 == 0
579 && u.ImpLibHdr.uSig2 == 0xffff
580 && u.ImpLibHdr.uVersion == 0
581 && ( u.ImpLibHdr.uMachine == IMAGE_FILE_MACHINE_I386
582 || u.ImpLibHdr.uMachine == IMAGE_FILE_MACHINE_AMD64)
583 && u.ImpLibHdr.cbData <= cbFile)
584 {
585 InfoMsg(1, "Found COFF import library header\n");
586 if (u.ImpLibHdr.uTimeDateStamp)
587 {
588 u.ImpLibHdr.uTimeDateStamp = 0;
589 return kLibMyWriteAt(pFile, &u.ImpLibHdr, sizeof(u.ImpLibHdr), offFileBytes);
590 }
591 }
592 else
593 InfoMsg(1, "CoffHdr.Machine=%#x ImpLibHdr.Machine=%#x\n", u.CoffHdr.Machine, u.ImpLibHdr.uMachine);
594
595 return 0;
596}
597
598
599static int kLibTweakerDoIt(const char *pszLib, int fClearTimestamps, int fFillNullThunkData)
600{
601 int rcRet = 0;
602 FILE *pFile = fopen(pszLib, "r+b");
603 if (pFile)
604 {
605 /*
606 * Read the header.
607 */
608 static char s_szMagic[] = "!<arch>\n";
609 union
610 {
611 char ab[1024];
612 IMAGE_FILE_HEADER CoffHdr;
613 } uBuf;
614 if ( fread(uBuf.ab, 1, sizeof(s_szMagic) - 1, pFile) == sizeof(s_szMagic) - 1
615 && memcmp(uBuf.ab, s_szMagic, sizeof(s_szMagic) - 1) == 0)
616 {
617 fpos_t offFileHdr = sizeof(s_szMagic) - 1;
618 while (!feof(pFile))
619 {
620 ARCHFILEHDR FileHdr;
621 if (kLibMyReadAt(pFile, &FileHdr, sizeof(FileHdr), offFileHdr, 1) != 0)
622 {
623 if (feof(pFile))
624 break;
625 rcRet = ErrorMsg("failed reading the file header (offset %ld)\n", (long)offFileHdr);
626 break;
627 }
628 if ( FileHdr.achMagic[0] == 0x60
629 && FileHdr.achMagic[1] == 0x0a)
630 {
631 fpos_t const offFileBytes = offFileHdr + sizeof(FileHdr);
632
633 /*
634 * Convert the size from decimal to binary as we need it to skip to
635 * the next file header.
636 */
637 fpos_t const cb = kLibTweakerAsciiToSize(FileHdr.achSize, sizeof(FileHdr.achSize));
638 InfoMsg(1, "Found header at %#lx: cbFile=%#lx, bytes at %#lx\n",
639 (unsigned long)offFileHdr, (unsigned long)cb, (unsigned long)offFileBytes);
640
641 /*
642 * Make the requested changes.
643 */
644 if (fClearTimestamps)
645 rcRet |= kLibClearTimestamps(pFile, offFileHdr, &FileHdr, cb, offFileBytes);
646
647 if (fFillNullThunkData)
648 rcRet |= kLibFillNullThunkData(pFile, cb, offFileBytes);
649
650 /*
651 * Skip to the next header.
652 */
653 offFileHdr = offFileBytes + ((cb + 1) & ~(fpos_t)1);
654 }
655 else
656 rcRet = ErrorMsg("invalid file header magic (offset %ld)\n", (long)offFileHdr);
657 }
658 }
659 else
660 rcRet = ErrorMsg("Didn't find '!<arch>\\n' magic in '%s' (or read error)\n", pszLib);
661
662 if (fclose(pFile) != 0)
663 rcRet = ErrorMsg("Error closing '%s'\n");
664 }
665 else
666 rcRet = ErrorMsg("Failed to open '%s' for read+write\n", pszLib);
667 return rcRet;
668}
669
670
671/**
672 * Prints a syntax error and returns the appropriate exit code
673 *
674 * @returns approriate exit code.
675 * @param pszFormat The syntax error message.
676 * @param ... Message args.
677 */
678static int SyntaxError(const char *pszFormat, ...)
679{
680 va_list va;
681 fprintf(stderr, "kObjCache: syntax error: ");
682 va_start(va, pszFormat);
683 vfprintf(stderr, pszFormat, va);
684 va_end(va);
685 return 1;
686}
687
688
689/**
690 * Prints the usage.
691 * @returns 0.
692 */
693static int usage(FILE *pOut)
694{
695 fprintf(pOut,
696 "syntax: kLibTweaker [-v|--verbose] [--clear-timestamps] <lib>\n"
697 "\n");
698 return 0;
699}
700
701
702int main(int argc, char **argv)
703{
704 char *psz;
705 int i;
706
707 int fClearTimestamps = 0;
708 int fFillNullThunkData = 0;
709 const char *pszLib = NULL;
710
711 SetErrorPrefix("kLibTweaker");
712
713 /*
714 * Arguments passed in the environmnet?
715 */
716 psz = getenv("KLIBTWEAKER_OPTS");
717 if (psz)
718 AppendArgs(&argc, &argv, psz, NULL);
719
720/** @todo Add the capability to produce import/stub libraries from ELF shared
721 * objects that we can use while linking and break up linking dependencies
722 * (i.e. not relink everything just because something in VBoxRT change that
723 * didn't make any difference to the symbols it exports). */
724
725 /*
726 * Parse the arguments.
727 */
728 if (argc <= 1)
729 return usage(stderr) + 1;
730 for (i = 1; i < argc; i++)
731 {
732 if (!strcmp(argv[i], "--clear-timestamps"))
733 fClearTimestamps = 1;
734 else if (!strcmp(argv[i], "--fill-null_thunk_data"))
735 fFillNullThunkData = 1;
736 /* Standard stuff: */
737 else if (!strcmp(argv[i], "--help"))
738 return usage(stderr);
739 else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose"))
740 g_cVerbosityLevel++;
741 else if (!strcmp(argv[i], "-q") || !strcmp(argv[i], "--quiet"))
742 g_cVerbosityLevel = 0;
743 else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-?")
744 || !strcmp(argv[i], "/h") || !strcmp(argv[i], "/?") || !strcmp(argv[i], "/help"))
745 return usage(stdout);
746 else if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version"))
747 {
748 printf("kLibTweaker - kBuild version %d.%d.%d ($Revision: 2791 $)\n"
749 "Copyright (c) 2007-2015 knut st. osmundsen\n",
750 KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH);
751 return 0;
752 }
753 else if (!strcmp(argv[i], "--"))
754 {
755 i++;
756 if (i == argc)
757 return SyntaxError("No library given!\n");
758 if (i + 1 != argc || pszLib)
759 return SyntaxError("Only one library can be tweaked at a time!\n");
760 pszLib = argv[i];
761 break;
762 }
763 else if (argv[i][0] == '-')
764 return SyntaxError("Doesn't grok '%s'!\n", argv[i]);
765 else if (!pszLib)
766 pszLib = argv[i];
767 else
768 return SyntaxError("Only one library can be tweaked at a time!\n");
769 }
770 if (!pszLib)
771 return SyntaxError("No library given!\n");
772
773 return kLibTweakerDoIt(pszLib, fClearTimestamps, fFillNullThunkData);
774}
775
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