1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * 3 * ***** BEGIN LICENSE BLOCK ***** 4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 5 * 6 * The contents of this file are subject to the Mozilla Public License Version 7 * 1.1 (the "License"); you may not use this file except in compliance with 8 * the License. You may obtain a copy of the License at 9 * http://www.mozilla.org/MPL/ 10 * 11 * Software distributed under the License is distributed on an "AS IS" basis, 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 13 * for the specific language governing rights and limitations under the 14 * License. 15 * 16 * The Original Code is msdump2symdb.c code, released 17 * Jan 16, 2003. 18 * 19 * The Initial Developer of the Original Code is 20 * Netscape Communications Corporation. 21 * Portions created by the Initial Developer are Copyright (C) 2002 22 * the Initial Developer. All Rights Reserved. 23 * 24 * Contributor(s): 25 * Garrett Arch Blythe, 16-January-2003 26 * 27 * Alternatively, the contents of this file may be used under the terms of 28 * either the GNU General Public License Version 2 or later (the "GPL"), or 29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 30 * in which case the provisions of the GPL or the LGPL are applicable instead 31 * of those above. If you wish to allow use of your version of this file only 32 * under the terms of either the GPL or the LGPL, and not to allow others to 33 * use your version of this file under the terms of the MPL, indicate your 34 * decision by deleting the provisions above and replace them with the notice 35 * and other provisions required by the GPL or the LGPL. If you do not delete 36 * the provisions above, a recipient may use your version of this file under 37 * the terms of any one of the MPL, the GPL or the LGPL. 38 * 39 * ***** END LICENSE BLOCK ***** */ 40 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <time.h> 45 #include <ctype.h> 46 #include <errno.h> 47 48 #define ERROR_REPORT(num, val, msg) fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg)); 49 #define CLEANUP(ptr) do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0) 50 51 52 typedef struct __struct_Options 53 /* 54 ** Options to control how we perform. 55 ** 56 ** mProgramName Used in help text. 57 ** mInput File to read for input. 58 ** Default is stdin. 59 ** mInputName Name of the file. 60 ** mOutput Output file, append. 61 ** Default is stdout. 62 ** mOutputName Name of the file. 63 ** mHelp Whether or not help should be shown. 64 */ 65 { 66 const char* mProgramName; 67 FILE* mInput; 68 char* mInputName; 69 FILE* mOutput; 70 char* mOutputName; 71 int mHelp; 72 } 73 Options; 74 75 76 typedef struct __struct_Switch 77 /* 78 ** Command line options. 79 */ 80 { 81 const char* mLongName; 82 const char* mShortName; 83 int mHasValue; 84 const char* mValue; 85 const char* mDescription; 86 } 87 Switch; 88 89 #define DESC_NEWLINE "\n\t\t" 90 91 static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."}; 92 static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."}; 93 static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."}; 94 95 static Switch* gSwitches[] = { 96 &gInputSwitch, 97 &gOutputSwitch, 98 &gHelpSwitch 99 }; 100 101 102 typedef struct __struct_MSDump_Symbol 103 /* 104 ** Struct to hold infomration on a symbol. 105 ** 106 ** mSize Size of the symbol once all work is complete. 107 ** mOffset Offset of the symbol in the section. 108 ** mName Symbolic name. 109 */ 110 { 111 unsigned mSize; 112 unsigned mOffset; 113 char* mName; 114 } 115 MSDump_Symbol; 116 117 118 typedef struct __struct_MSDump_Section 119 /* 120 ** Struct for holding information on a section. 121 ** 122 ** mLength Length of the section in bytes. 123 ** mUsed Number of bytes used in the section thus far. 124 ** Should eventually match mLength after work is done. 125 ** mType Type of section, as string (.data, .text, et. al.) 126 ** mSymbols Symbols found inside the section. 127 ** mSymbolCount Number of symbols in array. 128 */ 129 { 130 unsigned mLength; 131 unsigned mUsed; 132 char* mType; 133 134 MSDump_Symbol* mSymbols; 135 unsigned mSymbolCount; 136 } 137 MSDump_Section; 138 139 140 typedef struct __struct_MSDump_Object 141 /* 142 ** Struct for holding object's data. 143 */ 144 { 145 char* mObject; 146 147 MSDump_Section* mSections; 148 unsigned mSectionCount; 149 } 150 MSDump_Object; 151 152 153 typedef struct __struct_MSDump_ReadState 154 /* 155 ** State flags while reading the input gives us hints on what to do. 156 ** 157 ** mSkipLines Number of lines to skip without parsing. 158 ** mSectionDetails Section information next, like line length. 159 ** mCurrentObject Object file we are dealing with. 160 */ 161 { 162 unsigned mSkipLines; 163 unsigned mSectionDetails; 164 MSDump_Object* mCurrentObject; 165 } 166 MSDump_ReadState; 167 168 169 typedef struct __struct_MSDump_Container 170 /* 171 ** Umbrella container for all data encountered. 172 */ 173 { 174 MSDump_ReadState mReadState; 175 176 MSDump_Object* mObjects; 177 unsigned mObjectCount; 178 } 179 MSDump_Container; 180 181 182 void trimWhite(char* inString) 183 /* 184 ** Remove any whitespace from the end of the string. 185 */ 186 { 187 int len = strlen(inString); 188 189 while(len) 190 { 191 len--; 192 193 if(isspace(*(inString + len))) 194 { 195 *(inString + len) = '\0'; 196 } 197 else 198 { 199 break; 200 } 201 } 202 } 203 204 205 const char* skipWhite(const char* inString) 206 /* 207 ** Return pointer to first non white space character. 208 */ 209 { 210 const char* retval = inString; 211 212 while('\0' != *retval && isspace(*retval)) 213 { 214 retval++; 215 } 216 217 return retval; 218 } 219 220 221 const char* skipNonWhite(const char* inString) 222 /* 223 ** Return pointer to first white space character. 224 */ 225 { 226 const char* retval = inString; 227 228 while('\0' != *retval && !isspace(*retval)) 229 { 230 retval++; 231 } 232 233 return retval; 234 } 235 236 237 void slash2bs(char* inString) 238 /* 239 ** Change any forward slash to a backslash. 240 */ 241 { 242 char* slash = inString; 243 244 while(NULL != (slash = strchr(slash, '/'))) 245 { 246 *slash = '\\'; 247 slash++; 248 } 249 } 250 251 252 const char* skipToArg(const char* inString, unsigned inArgIndex) 253 /* 254 ** Return pointer either to the arg or NULL. 255 ** 1 indexed. 256 */ 257 { 258 const char* retval = NULL; 259 260 while(0 != inArgIndex && '\0' != *inString) 261 { 262 inArgIndex--; 263 264 inString = skipWhite(inString); 265 if(0 != inArgIndex) 266 { 267 inString = skipNonWhite(inString); 268 } 269 } 270 271 if('\0' != *inString) 272 { 273 retval = inString; 274 } 275 276 return retval; 277 } 278 279 280 const char* getLastArg(const char* inString) 281 /* 282 ** Return pointer to last arg in string. 283 */ 284 { 285 const char* retval = NULL; 286 int length = 0; 287 int sawString = 0; 288 289 length = strlen(inString); 290 while(0 != length) 291 { 292 length--; 293 294 if(0 == sawString) 295 { 296 if(0 == isspace(inString[length])) 297 { 298 sawString = __LINE__; 299 } 300 } 301 else 302 { 303 if(0 != isspace(inString[length])) 304 { 305 retval = inString + length + 1; 306 } 307 } 308 } 309 310 return retval; 311 } 312 313 314 int processLine(Options* inOptions, MSDump_Container* inContainer, const char* inLine) 315 /* 316 ** Handle one line at a time. 317 ** Looking for several different types of lines. 318 ** Ignore all other lines. 319 ** The container is the state machine. 320 ** returns 0 on no error. 321 */ 322 { 323 int retval = 0; 324 325 /* 326 ** Check to see if we were expecting section details. 327 */ 328 if(0 != inContainer->mReadState.mSectionDetails) 329 { 330 const char* length = NULL; 331 unsigned sectionIndex = 0; 332 333 /* 334 ** Detail is a 1 based index.... 335 ** Reset. 336 */ 337 sectionIndex = inContainer->mReadState.mSectionDetails - 1; 338 inContainer->mReadState.mSectionDetails = 0; 339 340 if(0 == strncmp(" Section length", inLine, 18)) 341 { 342 const char* sectionLength = NULL; 343 unsigned numericLength = 0; 344 char* endScan = NULL; 345 346 sectionLength = skipWhite(inLine + 18); 347 348 errno = 0; 349 numericLength = strtoul(sectionLength, &endScan, 16); 350 if(0 == errno && endScan != sectionLength) 351 { 352 inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mLength = numericLength; 353 } 354 else 355 { 356 retval = __LINE__; 357 ERROR_REPORT(retval, inLine, "Cannot scan for section length."); 358 } 359 } 360 else 361 { 362 retval = __LINE__; 363 ERROR_REPORT(retval, inLine, "Cannot parse section line."); 364 } 365 } 366 /* 367 ** Check for switching object file symbols. 368 */ 369 else if(0 == strncmp("Dump of file ", inLine, 13)) 370 { 371 const char* dupMe = inLine + 13; 372 char* dup = NULL; 373 374 dup = strdup(dupMe); 375 if(NULL != dup) 376 { 377 void* growth = NULL; 378 379 trimWhite(dup); 380 slash2bs(dup); 381 382 383 growth = realloc(inContainer->mObjects, (inContainer->mObjectCount + 1) * sizeof(MSDump_Object)); 384 if(NULL != growth) 385 { 386 unsigned int index = inContainer->mObjectCount; 387 388 inContainer->mObjectCount++; 389 inContainer->mObjects = growth; 390 memset(inContainer->mObjects + index, 0, sizeof(MSDump_Object)); 391 392 inContainer->mObjects[index].mObject = dup; 393 394 /* 395 ** Reset the read state for this new object. 396 */ 397 memset(&inContainer->mReadState, 0, sizeof(MSDump_ReadState)); 398 399 /* 400 ** Record our current object file. 401 */ 402 inContainer->mReadState.mCurrentObject = inContainer->mObjects + index; 403 404 /* 405 ** We can skip a few lines. 406 */ 407 inContainer->mReadState.mSkipLines = 4; 408 } 409 else 410 { 411 retval = __LINE__; 412 ERROR_REPORT(retval, dup, "Unable to grow object array."); 413 free(dup); 414 } 415 } 416 else 417 { 418 retval = __LINE__; 419 ERROR_REPORT(retval, dupMe, "Unable to copy string."); 420 421 } 422 } 423 /* 424 ** Check for a symbol dump or a section header. 425 */ 426 else if(isxdigit(*inLine) && isxdigit(*(inLine + 1)) && isxdigit(*(inLine + 2))) 427 { 428 const char* sectionString = NULL; 429 430 /* 431 ** Determine the section for this line. 432 ** Ignore DEBUG sections. 433 */ 434 sectionString = skipToArg(inLine, 3); 435 if(NULL != sectionString) 436 { 437 if(0 != strncmp(sectionString, "DEBUG", 5) && 0 != strncmp(sectionString, "ABS", 3) && 0 != strncmp(sectionString, "UNDEF", 5)) 438 { 439 /* 440 ** MUST start with "SECT" 441 */ 442 if(0 == strncmp(sectionString, "SECT", 4)) 443 { 444 unsigned sectionIndex1 = 0; 445 446 char *endScan = NULL; 447 448 sectionString += 4; 449 450 /* 451 ** Convert the remaining string to an index. 452 ** It will be 1 based. 453 */ 454 errno = 0; 455 sectionIndex1 = strtoul(sectionString, &endScan, 16); 456 if(0 == errno && endScan != sectionString && 0 != sectionIndex1) 457 { 458 unsigned sectionIndex = sectionIndex1 - 1; 459 460 /* 461 ** Is this a new section? Assumed to be ascending. 462 ** Or is this a symbol in the section? 463 */ 464 if(sectionIndex1 > inContainer->mReadState.mCurrentObject->mSectionCount) 465 { 466 const char* typeArg = NULL; 467 468 /* 469 ** New Section, figure out the type. 470 */ 471 typeArg = skipToArg(sectionString, 5); 472 if(NULL != typeArg) 473 { 474 char* typeDup = NULL; 475 476 /* 477 ** Skip the leading period before duping. 478 */ 479 if('.' == *typeArg) 480 { 481 typeArg++; 482 } 483 typeDup = strdup(typeArg); 484 485 if(NULL != typeDup) 486 { 487 void* moved = NULL; 488 char* nonWhite = NULL; 489 490 /* 491 ** Terminate the duplicate after the section type. 492 */ 493 nonWhite = (char*)skipNonWhite(typeDup); 494 if(NULL != nonWhite) 495 { 496 *nonWhite = '\0'; 497 } 498 499 /* 500 ** Create more space for the section in the object... 501 */ 502 moved = realloc(inContainer->mReadState.mCurrentObject->mSections, sizeof(MSDump_Section) * sectionIndex1); 503 if(NULL != moved) 504 { 505 unsigned oldCount = inContainer->mReadState.mCurrentObject->mSectionCount; 506 507 inContainer->mReadState.mCurrentObject->mSections = (MSDump_Section*)moved; 508 inContainer->mReadState.mCurrentObject->mSectionCount = sectionIndex1; 509 memset(&inContainer->mReadState.mCurrentObject->mSections[oldCount], 0, sizeof(MSDump_Section) * (sectionIndex1 - oldCount)); 510 511 /* 512 ** Other section details. 513 */ 514 inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mType = typeDup; 515 516 517 /* 518 ** Mark it so that we look for the length on the next line. 519 ** This happens on next entry into the read state. 520 */ 521 inContainer->mReadState.mSectionDetails = sectionIndex1; 522 } 523 else 524 { 525 retval = __LINE__; 526 ERROR_REPORT(retval, inLine, "Unable to grow for new section."); 527 free(typeDup); 528 } 529 } 530 else 531 { 532 retval = __LINE__; 533 ERROR_REPORT(retval, typeArg, "Unable to duplicate type."); 534 } 535 } 536 else 537 { 538 retval = __LINE__; 539 ERROR_REPORT(retval, inLine, "Unable to determine section type."); 540 } 541 542 } 543 else 544 { 545 const char* offsetArg = NULL; 546 const char* classArg = NULL; 547 unsigned classWords = 1; 548 const char* symbolArg = NULL; 549 550 /* 551 ** This is an section we've seen before, and must list a symbol. 552 ** Figure out the things we want to know about the symbol, e.g. size. 553 ** We will ignore particular classes of symbols. 554 */ 555 556 offsetArg = skipToArg(inLine, 2); 557 558 classArg = skipToArg(offsetArg, 4); 559 if(0 == strncmp(classArg, "()", 2)) 560 { 561 classArg = skipToArg(classArg, 2); 562 } 563 if(0 == strncmp(classArg, ".bf or.ef", 9)) 564 { 565 classWords = 2; 566 } 567 568 symbolArg = skipToArg(classArg, 3 + (classWords - 1)); 569 570 /* 571 ** Skip particular lines/items. 572 */ 573 if( 574 0 != strncmp(classArg, "Label", 5) && 575 0 != strncmp(symbolArg, ".bf", 3) && 576 0 != strncmp(symbolArg, ".lf", 3) && 577 0 != strncmp(symbolArg, ".ef", 3) 578 ) 579 { 580 char* endOffsetArg = NULL; 581 unsigned offset = 0; 582 583 /* 584 ** Convert the offset to something meaninful (size). 585 */ 586 errno = 0; 587 offset = strtoul(offsetArg, &endOffsetArg, 16); 588 if(0 == errno && endOffsetArg != offsetArg) 589 { 590 void* moved = NULL; 591 592 /* 593 ** Increase the size of the symbol array in the section. 594 ** Assumed symbols are unique within each section. 595 */ 596 moved = realloc(inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols, sizeof(MSDump_Symbol) * (inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount + 1)); 597 if(NULL != moved) 598 { 599 unsigned symIndex = 0; 600 601 /* 602 ** Record symbol details. 603 ** Assumed symbols are encountered in order for their section (size calc depends on it). 604 */ 605 symIndex = inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount; 606 inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount++; 607 inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols = (MSDump_Symbol*)moved; 608 memset(&inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex], 0, sizeof(MSDump_Symbol)); 609 610 inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mOffset = offset; 611 612 /* 613 ** We could allocate smarter here if it ever mattered. 614 */ 615 inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName = strdup(symbolArg); 616 if(NULL != inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName) 617 { 618 char* trim = NULL; 619 620 trim = (char*)skipNonWhite(inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName); 621 if(NULL != trim) 622 { 623 *trim = '\0'; 624 } 625 } 626 else 627 { 628 retval = __LINE__; 629 ERROR_REPORT(retval, inLine, "Unable to duplicate symbol name."); 630 } 631 } 632 else 633 { 634 retval = __LINE__; 635 ERROR_REPORT(retval, inLine, "Unable to grow symbol array for section."); 636 } 637 } 638 else 639 { 640 retval = __LINE__; 641 ERROR_REPORT(retval, inLine, "Unable to convert offset to a number."); 642 } 643 } 644 } 645 } 646 else 647 { 648 retval = __LINE__; 649 ERROR_REPORT(retval, inLine, "Unable to determine section index."); 650 } 651 } 652 else 653 { 654 retval = __LINE__; 655 ERROR_REPORT(retval, inLine, "No match for section prefix."); 656 } 657 } 658 } 659 else 660 { 661 retval = __LINE__; 662 ERROR_REPORT(retval, inLine, "Unable to scan for section."); 663 } 664 } 665 666 return retval; 667 } 668 669 670 void dumpCleanup(MSDump_Container* inContainer) 671 /* 672 ** Attempt to be nice and free up what we have allocated. 673 */ 674 { 675 unsigned objectLoop = 0; 676 unsigned sectionLoop = 0; 677 unsigned symbolLoop = 0; 678 679 for(objectLoop = 0; objectLoop < inContainer->mObjectCount; objectLoop++) 680 { 681 for(sectionLoop = 0; sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++) 682 { 683 for(symbolLoop = 0; symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++) 684 { 685 CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mName); 686 } 687 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount = 0; 688 CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols); 689 CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mType); 690 } 691 inContainer->mObjects[objectLoop].mSectionCount = 0; 692 CLEANUP(inContainer->mObjects[objectLoop].mSections); 693 } 694 CLEANUP(inContainer->mObjects); 695 inContainer->mObjectCount = 0; 696 } 697 698 699 int qsortSymOffset(const void* in1, const void* in2) 700 /* 701 ** qsort callback to sort the symbols by their offset. 702 */ 703 { 704 MSDump_Symbol* sym1 = (MSDump_Symbol*)in1; 705 MSDump_Symbol* sym2 = (MSDump_Symbol*)in2; 706 int retval = 0; 707 708 if(sym1->mOffset < sym2->mOffset) 709 { 710 retval = 1; 711 } 712 else if(sym1->mOffset > sym2->mOffset) 713 { 714 retval = -1; 715 } 716 717 return retval; 718 } 719 720 721 int calcContainer(Options* inOptions, MSDump_Container* inContainer) 722 /* 723 ** Resposible for doing any size calculations based on the offsets known. 724 ** After this calculation, each sections mUsed will match mSize. 725 ** After this calculation, all symbols should know how big they are. 726 */ 727 { 728 int retval = 0; 729 unsigned objectLoop = 0; 730 unsigned sectionLoop = 0; 731 unsigned symbolLoop = 0; 732 733 734 /* 735 ** Need to sort all symbols by their offsets. 736 */ 737 for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++) 738 { 739 for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++) 740 { 741 qsort( 742 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols, 743 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount, 744 sizeof(MSDump_Symbol), 745 qsortSymOffset 746 ); 747 } 748 } 749 750 751 /* 752 ** Need to go through all symbols and calculate their size. 753 */ 754 for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++) 755 { 756 for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++) 757 { 758 for(symbolLoop = 0; 0 == retval && symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++) 759 { 760 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize = 761 inContainer->mObjects[objectLoop].mSections[sectionLoop].mLength - 762 inContainer->mObjects[objectLoop].mSections[sectionLoop].mUsed - 763 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mOffset; 764 765 inContainer->mObjects[objectLoop].mSections[sectionLoop].mUsed += 766 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize; 767 } 768 } 769 } 770 771 772 return retval; 773 } 774 775 776 int reportContainer(Options* inOptions, MSDump_Container* inContainer) 777 /* 778 ** Display all symbols and their data. 779 ** We'll use a tsv format. 780 */ 781 { 782 int retval = 0; 783 unsigned objectLoop = 0; 784 unsigned sectionLoop = 0; 785 unsigned symbolLoop = 0; 786 int printRes = 0; 787 788 for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++) 789 { 790 for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++) 791 { 792 for(symbolLoop = 0; 0 == retval && symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++) 793 { 794 printRes = fprintf(inOptions->mOutput, "%s\t%s\t%.8X\t%s\n", 795 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mName, 796 inContainer->mObjects[objectLoop].mSections[sectionLoop].mType, 797 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize, 798 inContainer->mObjects[objectLoop].mObject 799 ); 800 801 if(0 > printRes) 802 { 803 retval = __LINE__; 804 ERROR_REPORT(retval, inOptions->mOutputName, "Unable to write to file."); 805 } 806 } 807 } 808 } 809 810 return retval; 811 } 812 813 814 int dump2symdb(Options* inOptions) 815 /* 816 ** Convert the input into the output, respecting the options. 817 ** Returns 0 on success. 818 */ 819 { 820 int retval = 0; 821 char lineBuffer[0x800]; 822 MSDump_Container container; 823 824 memset(&container, 0, sizeof(container)); 825 826 /* 827 ** Read the file line by line. 828 */ 829 while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput)) 830 { 831 if(0 != container.mReadState.mSkipLines) 832 { 833 container.mReadState.mSkipLines--; 834 continue; 835 } 836 retval = processLine(inOptions, &container, lineBuffer); 837 } 838 839 /* 840 ** Perform whatever calculations desired. 841 */ 842 if(0 == retval) 843 { 844 retval = calcContainer(inOptions, &container); 845 } 846 847 /* 848 ** Output what we know. 849 */ 850 if(0 == retval) 851 { 852 retval = reportContainer(inOptions, &container); 853 } 854 855 /* 856 ** Cleanup what we've done. 857 */ 858 dumpCleanup(&container); 859 860 return retval; 861 } 862 863 864 int initOptions(Options* outOptions, int inArgc, char** inArgv) 865 /* 866 ** returns int 0 if successful. 867 */ 868 { 869 int retval = 0; 870 int loop = 0; 871 int switchLoop = 0; 872 int match = 0; 873 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]); 874 Switch* current = NULL; 875 876 /* 877 ** Set any defaults. 878 */ 879 memset(outOptions, 0, sizeof(Options)); 880 outOptions->mProgramName = inArgv[0]; 881 outOptions->mInput = stdin; 882 outOptions->mInputName = strdup("stdin"); 883 outOptions->mOutput = stdout; 884 outOptions->mOutputName = strdup("stdout"); 885 886 if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName) 887 { 888 retval = __LINE__; 889 ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup."); 890 } 891 892 /* 893 ** Go through and attempt to do the right thing. 894 */ 895 for(loop = 1; loop < inArgc && 0 == retval; loop++) 896 { 897 match = 0; 898 current = NULL; 899 900 for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++) 901 { 902 if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop])) 903 { 904 match = __LINE__; 905 } 906 else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop])) 907 { 908 match = __LINE__; 909 } 910 911 if(match) 912 { 913 if(gSwitches[switchLoop]->mHasValue) 914 { 915 /* 916 ** Attempt to absorb next option to fullfill value. 917 */ 918 if(loop + 1 < inArgc) 919 { 920 loop++; 921 922 current = gSwitches[switchLoop]; 923 current->mValue = inArgv[loop]; 924 } 925 } 926 else 927 { 928 current = gSwitches[switchLoop]; 929 } 930 931 break; 932 } 933 } 934 935 if(0 == match) 936 { 937 outOptions->mHelp = __LINE__; 938 retval = __LINE__; 939 ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch."); 940 } 941 else if(NULL == current) 942 { 943 outOptions->mHelp = __LINE__; 944 retval = __LINE__; 945 ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value."); 946 } 947 else 948 { 949 /* 950 ** Do something based on address/swtich. 951 */ 952 if(current == &gInputSwitch) 953 { 954 CLEANUP(outOptions->mInputName); 955 if(NULL != outOptions->mInput && stdin != outOptions->mInput) 956 { 957 fclose(outOptions->mInput); 958 outOptions->mInput = NULL; 959 } 960 961 outOptions->mInput = fopen(current->mValue, "r"); 962 if(NULL == outOptions->mInput) 963 { 964 retval = __LINE__; 965 ERROR_REPORT(retval, current->mValue, "Unable to open input file."); 966 } 967 else 968 { 969 outOptions->mInputName = strdup(current->mValue); 970 if(NULL == outOptions->mInputName) 971 { 972 retval = __LINE__; 973 ERROR_REPORT(retval, current->mValue, "Unable to strdup."); 974 } 975 } 976 } 977 else if(current == &gOutputSwitch) 978 { 979 CLEANUP(outOptions->mOutputName); 980 if(NULL != outOptions->mOutput && stdout != outOptions->mOutput) 981 { 982 fclose(outOptions->mOutput); 983 outOptions->mOutput = NULL; 984 } 985 986 outOptions->mOutput = fopen(current->mValue, "a"); 987 if(NULL == outOptions->mOutput) 988 { 989 retval = __LINE__; 990 ERROR_REPORT(retval, current->mValue, "Unable to open output file."); 991 } 992 else 993 { 994 outOptions->mOutputName = strdup(current->mValue); 995 if(NULL == outOptions->mOutputName) 996 { 997 retval = __LINE__; 998 ERROR_REPORT(retval, current->mValue, "Unable to strdup."); 999 } 1000 } 1001 } 1002 else if(current == &gHelpSwitch) 1003 { 1004 outOptions->mHelp = __LINE__; 1005 } 1006 else 1007 { 1008 retval = __LINE__; 1009 ERROR_REPORT(retval, current->mLongName, "No handler for command line switch."); 1010 } 1011 } 1012 } 1013 1014 return retval; 1015 } 1016 1017 1018 void cleanOptions(Options* inOptions) 1019 /* 1020 ** Clean up any open handles. 1021 */ 1022 { 1023 CLEANUP(inOptions->mInputName); 1024 if(NULL != inOptions->mInput && stdin != inOptions->mInput) 1025 { 1026 fclose(inOptions->mInput); 1027 } 1028 CLEANUP(inOptions->mOutputName); 1029 if(NULL != inOptions->mOutput && stdout != inOptions->mOutput) 1030 { 1031 fclose(inOptions->mOutput); 1032 } 1033 1034 memset(inOptions, 0, sizeof(Options)); 1035 } 1036 1037 1038 void showHelp(Options* inOptions) 1039 /* 1040 ** Show some simple help text on usage. 1041 */ 1042 { 1043 int loop = 0; 1044 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]); 1045 const char* valueText = NULL; 1046 1047 printf("usage:\t%s [arguments]\n", inOptions->mProgramName); 1048 printf("\n"); 1049 printf("arguments:\n"); 1050 1051 for(loop = 0; loop < switchCount; loop++) 1052 { 1053 if(gSwitches[loop]->mHasValue) 1054 { 1055 valueText = " <value>"; 1056 } 1057 else 1058 { 1059 valueText = ""; 1060 } 1061 1062 printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText); 1063 printf("\t %s%s", gSwitches[loop]->mShortName, valueText); 1064 printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription); 1065 } 1066 1067 printf("This tool takes the output of \"dumpbin /symbols\" to produce a simple\n"); 1068 printf("tsv db file of symbols and their respective attributes, like size.\n"); 1069 } 1070 1071 1072 int main(int inArgc, char** inArgv) 1073 { 1074 int retval = 0; 1075 Options options; 1076 1077 retval = initOptions(&options, inArgc, inArgv); 1078 if(options.mHelp) 1079 { 1080 showHelp(&options); 1081 } 1082 else if(0 == retval) 1083 { 1084 retval = dump2symdb(&options); 1085 } 1086 1087 cleanOptions(&options); 1088 return retval; 1089 } 1090 1091