OLD | NEW |
(Empty) | |
| 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." DE
SC_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* i
nLine) |
| 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(sectionSt
ring, "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 != sectionInd
ex1) |
| 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.mCurrentObjec
t->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 sectio
n 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.mCur
rentObject->mSections, sizeof(MSDump_Section) * sectionIndex1); |
| 503 if(NULL != moved) |
| 504 { |
| 505 unsigned oldCount = inContainer->mReadSt
ate.mCurrentObject->mSectionCount; |
| 506 |
| 507 inContainer->mReadState.mCurrentObject->
mSections = (MSDump_Section*)moved; |
| 508 inContainer->mReadState.mCurrentObject->
mSectionCount = sectionIndex1; |
| 509 memset(&inContainer->mReadState.mCurrent
Object->mSections[oldCount], 0, sizeof(MSDump_Section) * (sectionIndex1 - oldCou
nt)); |
| 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 leng
th 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 dup
licate type."); |
| 534 } |
| 535 } |
| 536 else |
| 537 { |
| 538 retval = __LINE__; |
| 539 ERROR_REPORT(retval, inLine, "Unable to determin
e 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 l
ist 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 (si
ze). |
| 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 s
ection. |
| 595 */ |
| 596 moved = realloc(inContainer->mReadState.mCur
rentObject->mSections[sectionIndex].mSymbols, sizeof(MSDump_Symbol) * (inContain
er->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 o
rder for their section (size calc depends on it). |
| 604 */ |
| 605 symIndex = inContainer->mReadState.mCurr
entObject->mSections[sectionIndex].mSymbolCount; |
| 606 inContainer->mReadState.mCurrentObject->
mSections[sectionIndex].mSymbolCount++; |
| 607 inContainer->mReadState.mCurrentObject->
mSections[sectionIndex].mSymbols = (MSDump_Symbol*)moved; |
| 608 memset(&inContainer->mReadState.mCurrent
Object->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.mCurr
entObject->mSections[sectionIndex].mSymbols[symIndex].mName) |
| 617 { |
| 618 char* trim = NULL; |
| 619 |
| 620 trim = (char*)skipNonWhite(inContain
er->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 conv
ert offset to a number."); |
| 642 } |
| 643 } |
| 644 } |
| 645 } |
| 646 else |
| 647 { |
| 648 retval = __LINE__; |
| 649 ERROR_REPORT(retval, inLine, "Unable to determine sectio
n 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].mSe
ctionCount; sectionLoop++) |
| 682 { |
| 683 for(symbolLoop = 0; symbolLoop < inContainer->mObjects[objectLoop].m
Sections[sectionLoop].mSymbolCount; symbolLoop++) |
| 684 { |
| 685 CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop]
.mSymbols[symbolLoop].mName); |
| 686 } |
| 687 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCoun
t = 0; |
| 688 CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mSy
mbols); |
| 689 CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mTy
pe); |
| 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; o
bjectLoop++) |
| 738 { |
| 739 for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[
objectLoop].mSectionCount; sectionLoop++) |
| 740 { |
| 741 qsort( |
| 742 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbol
s, |
| 743 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbol
Count, |
| 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; o
bjectLoop++) |
| 755 { |
| 756 for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[
objectLoop].mSectionCount; sectionLoop++) |
| 757 { |
| 758 for(symbolLoop = 0; 0 == retval && symbolLoop < inContainer->mObject
s[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++) |
| 759 { |
| 760 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbol
s[symbolLoop].mSize = |
| 761 inContainer->mObjects[objectLoop].mSections[sectionLoop].mLe
ngth - |
| 762 inContainer->mObjects[objectLoop].mSections[sectionLoop].mUs
ed - |
| 763 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSy
mbols[symbolLoop].mOffset; |
| 764 |
| 765 inContainer->mObjects[objectLoop].mSections[sectionLoop].mUsed +
= |
| 766 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSy
mbols[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; o
bjectLoop++) |
| 789 { |
| 790 for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[
objectLoop].mSectionCount; sectionLoop++) |
| 791 { |
| 792 for(symbolLoop = 0; 0 == retval && symbolLoop < inContainer->mObject
s[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].mSy
mbols[symbolLoop].mName, |
| 796 inContainer->mObjects[objectLoop].mSections[sectionLoop].mTy
pe, |
| 797 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSy
mbols[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 writ
e 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 v
alue."); |
| 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 simp
le\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 |
OLD | NEW |