|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1992 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: cvcommon.c ! 8: ! 9: Abstract: ! 10: ! 11: This file contians a set of common routines which are used in ! 12: doing symbol conversions from one type of symbols to CodeView ! 13: symbols. ! 14: ! 15: Author: ! 16: ! 17: Jim Schaad (jimsch) 22 May 1993 ! 18: ! 19: --*/ ! 20: ! 21: #include <windows.h> ! 22: #include <stdlib.h> ! 23: #include "cv.h" ! 24: #include "symcvt.h" ! 25: #include "cvcommon.h" ! 26: ! 27: typedef struct tagSYMHASH { ! 28: DWORD dwHashVal; // hash value for the symbol ! 29: DWORD dwHashBucket; // hash bucket number ! 30: DATASYM16 * dataSym; // pointer to the symbol info ! 31: } SYMHASH; ! 32: ! 33: typedef struct tagOFFSETSORT { ! 34: DWORD dwOffset; // offset for the symbol ! 35: DWORD dwSection; // section number of the symbol ! 36: DATASYM16 * dataSym; // pointer to the symbol info ! 37: } OFFSETSORT; ! 38: ! 39: ! 40: int _CRTAPI1 SymHashCompare( const void *arg1, const void *arg2 ); ! 41: int _CRTAPI1 OffsetSortCompare( const void *arg1, const void *arg2 ); ! 42: ! 43: ! 44: DWORD ! 45: CreateSignature( PPOINTERS p ) ! 46: ! 47: /*++ ! 48: ! 49: Routine Description: ! 50: ! 51: Creates the CODEVIEW signature record. Currently this converter only ! 52: generates NB08 data (MS C/C++ 7.0). ! 53: ! 54: ! 55: Arguments: ! 56: ! 57: p - pointer to a POINTERS structure (see cofftocv.h) ! 58: ! 59: ! 60: Return Value: ! 61: ! 62: number of records generates, this is always 1. ! 63: ! 64: --*/ ! 65: ! 66: { ! 67: OMFSignature *omfSig; ! 68: ! 69: omfSig = (OMFSignature *) p->pCvCurr; ! 70: strcpy( omfSig->Signature, "NB08" ); ! 71: omfSig->filepos = 0; ! 72: p->pCvStart.size += sizeof(OMFSignature); ! 73: p->pCvCurr = (PUCHAR) p->pCvCurr + sizeof(OMFSignature); ! 74: return 1; ! 75: } /* CreateSignature() */ ! 76: ! 77: ! 78: DWORD ! 79: CreateDirectories( PPOINTERS p ) ! 80: ! 81: /*++ ! 82: ! 83: Routine Description: ! 84: ! 85: This is the control function for the generation of the CV directories. ! 86: It calls individual functions for the generation of specific types of ! 87: debug directories. ! 88: ! 89: ! 90: Arguments: ! 91: ! 92: p - pointer to a POINTERS structure (see cofftocv.h) ! 93: ! 94: ! 95: Return Value: ! 96: ! 97: the number of directories created. ! 98: ! 99: --*/ ! 100: ! 101: { ! 102: OMFDirHeader *omfDir = (OMFDirHeader *)p->pCvCurr; ! 103: OMFSignature *omfSig = (OMFSignature *)p->pCvStart.ptr; ! 104: OMFDirEntry *omfDirEntry = NULL; ! 105: ! 106: omfSig->filepos = (DWORD)p->pCvCurr - (DWORD)p->pCvStart.ptr; ! 107: ! 108: omfDir->cbDirHeader = sizeof(OMFDirHeader); ! 109: omfDir->cbDirEntry = sizeof(OMFDirEntry); ! 110: omfDir->cDir = 0; ! 111: omfDir->lfoNextDir = 0; ! 112: omfDir->flags = 0; ! 113: ! 114: p->pCvStart.size += sizeof(OMFDirHeader); ! 115: p->pCvCurr = (PUCHAR) p->pCvCurr + sizeof(OMFDirHeader); ! 116: ! 117: omfDir->cDir += CreateModuleDirectoryEntries( p ); ! 118: omfDir->cDir += CreatePublicDirectoryEntries( p ); ! 119: omfDir->cDir += CreateSegMapDirectoryEntries( p ); ! 120: ! 121: strcpy(p->pCvCurr, "NB080000"); ! 122: p->pCvStart.size += 8; ! 123: p->pCvCurr += 8; ! 124: *((DWORD *) (p->pCvCurr-4)) = p->pCvStart.size; ! 125: ! 126: return omfDir->cDir; ! 127: } /* CreateDirectories() */ ! 128: ! 129: ! 130: DWORD ! 131: CreateModuleDirectoryEntries( PPOINTERS p ) ! 132: ! 133: /*++ ! 134: ! 135: Routine Description: ! 136: ! 137: Creates directory entries for each module in the image. ! 138: ! 139: ! 140: Arguments: ! 141: ! 142: p - pointer to a POINTERS structure (see cofftocv.h) ! 143: ! 144: ! 145: Return Value: ! 146: ! 147: the number of directory entries created. ! 148: ! 149: --*/ ! 150: ! 151: { ! 152: OMFDirEntry *omfDirEntry = NULL; ! 153: OMFModule *m = NULL; ! 154: OMFModule *mNext = NULL; ! 155: DWORD i = 0; ! 156: DWORD mSize = 0; ! 157: DWORD lfo = (DWORD)p->pCvModules.ptr - (DWORD)p->pCvStart.ptr; ! 158: ! 159: m = (OMFModule *) p->pCvModules.ptr; ! 160: for (i=0; i<p->pCvModules.count; i++) { ! 161: mNext = NextMod(m); ! 162: ! 163: omfDirEntry = (OMFDirEntry *) p->pCvCurr; ! 164: ! 165: mSize = (DWORD)mNext - (DWORD)m; ! 166: omfDirEntry->SubSection = sstModule; ! 167: omfDirEntry->iMod = (USHORT) i + 1; ! 168: omfDirEntry->lfo = lfo; ! 169: omfDirEntry->cb = mSize; ! 170: ! 171: lfo += mSize; ! 172: ! 173: p->pCvStart.size += sizeof(OMFDirEntry); ! 174: p->pCvCurr = (PUCHAR) p->pCvCurr + sizeof(OMFDirEntry); ! 175: ! 176: m = mNext; ! 177: } ! 178: ! 179: return p->pCvModules.count; ! 180: } /* CreateModuleDirectoryEntries() */ ! 181: ! 182: ! 183: DWORD ! 184: CreatePublicDirectoryEntries( PPOINTERS p ) ! 185: ! 186: /*++ ! 187: ! 188: Routine Description: ! 189: ! 190: Creates the directory entry for the global publics. ! 191: ! 192: Arguments: ! 193: ! 194: p - pointer to a POINTERS structure (see cofftocv.h) ! 195: ! 196: ! 197: Return Value: ! 198: ! 199: the number of directory entries created, always 1. ! 200: ! 201: --*/ ! 202: ! 203: { ! 204: OMFDirEntry *omfDirEntry = (OMFDirEntry *) p->pCvCurr; ! 205: ! 206: omfDirEntry->SubSection = sstGlobalPub; ! 207: omfDirEntry->iMod = 0xffff; ! 208: omfDirEntry->lfo = (DWORD)p->pCvPublics.ptr - (DWORD)p->pCvStart.ptr; ! 209: omfDirEntry->cb = p->pCvPublics.size; ! 210: ! 211: p->pCvStart.size += sizeof(OMFDirEntry); ! 212: p->pCvCurr = (PUCHAR) p->pCvCurr + sizeof(OMFDirEntry); ! 213: ! 214: return 1; ! 215: } /* CreatePublicDirectoryEntries() */ ! 216: ! 217: ! 218: DWORD ! 219: CreateSegMapDirectoryEntries( PPOINTERS p ) ! 220: ! 221: /*++ ! 222: ! 223: Routine Description: ! 224: ! 225: Creates the directory entry for the segment map. ! 226: ! 227: ! 228: Arguments: ! 229: ! 230: p - pointer to a POINTERS structure (see cofftocv.h) ! 231: ! 232: ! 233: Return Value: ! 234: ! 235: the number of directory entries created, always 1. ! 236: ! 237: --*/ ! 238: ! 239: { ! 240: OMFDirEntry *omfDirEntry = (OMFDirEntry *) p->pCvCurr; ! 241: ! 242: omfDirEntry->SubSection = sstSegMap; ! 243: omfDirEntry->iMod = 0xffff; ! 244: omfDirEntry->lfo = (DWORD)p->pCvSegMap.ptr - (DWORD)p->pCvStart.ptr; ! 245: omfDirEntry->cb = p->pCvSegMap.size; ! 246: ! 247: p->pCvStart.size += sizeof(OMFDirEntry); ! 248: p->pCvCurr = (PUCHAR) p->pCvCurr + sizeof(OMFDirEntry); ! 249: ! 250: return 1; ! 251: } /* CreateSegMapDirectoryEntries() */ ! 252: ! 253: ! 254: DWORD ! 255: DWordXorLrl( char *szSym ) ! 256: ! 257: /*++ ! 258: ! 259: Routine Description: ! 260: ! 261: This function will take an ascii character string and generate ! 262: a hash for that string. The hash algorithm is the CV NB08 hash ! 263: algorithm. ! 264: ! 265: ! 266: Arguments: ! 267: ! 268: szSym - a character pointer, the first char is the string length ! 269: ! 270: ! 271: Return Value: ! 272: ! 273: The generated hash value. ! 274: ! 275: --*/ ! 276: ! 277: { ! 278: char *pName = szSym+1; ! 279: int cb = *szSym; ! 280: char *pch; ! 281: DWORD hash = 0; ! 282: DWORD UNALIGNED *pul = (DWORD *) pName; ! 283: static rgMask[] = {0, 0xff, 0xffff, 0xffffff}; ! 284: ! 285: pch = pName + cb - 1; ! 286: while (isdigit(*pch)) { ! 287: pch--; ! 288: } ! 289: ! 290: if (*pch == '@') { ! 291: cb = pch - pName; ! 292: } ! 293: ! 294: for (; cb > 3; cb-=4, pul++) { ! 295: hash = _lrotl(hash, 4); ! 296: hash ^= (*pul & 0xdfdfdfdf); ! 297: } ! 298: ! 299: if (cb > 0) { ! 300: hash = _lrotl(hash,4); ! 301: hash ^= ((*pul & rgMask[cb]) & 0xdfdfdfdf); ! 302: } ! 303: ! 304: return hash; ! 305: } /* DWordXorLrl() */ ! 306: ! 307: ! 308: ! 309: OMFModule * ! 310: NextMod( ! 311: OMFModule * pMod ! 312: ) ! 313: /*++ ! 314: ! 315: Routine Description: ! 316: ! 317: description-of-function. ! 318: ! 319: Arguments: ! 320: ! 321: argument-name - Supplies | Returns description of argument. ! 322: . ! 323: . ! 324: ! 325: Return Value: ! 326: ! 327: return-value - Description of conditions needed to return value. - or - ! 328: None. ! 329: ! 330: --*/ ! 331: ! 332: { ! 333: char * pb; ! 334: ! 335: pb = (char *) &(pMod->SegInfo[pMod->cSeg]); ! 336: pb += *pb + 1; ! 337: pb = (char *) (((unsigned long) pb + 3) & ~3); ! 338: ! 339: return (OMFModule *) pb; ! 340: } /* NextMod() */ ! 341: ! 342: ! 343: ! 344: int ! 345: _CRTAPI1 ! 346: SymHashCompare( ! 347: const void * arg1, ! 348: const void * arg2 ! 349: ) ! 350: /*++ ! 351: ! 352: Routine Description: ! 353: ! 354: Sort compare function for sorting SYMHASH records by hashed ! 355: bucket number. ! 356: ! 357: ! 358: Arguments: ! 359: ! 360: arg1 - record #1 ! 361: arg2 - record #2 ! 362: ! 363: ! 364: Return Value: ! 365: ! 366: -1 - record #1 is < record #2 ! 367: 0 - records are equal ! 368: 1 - record #1 is > record #2 ! 369: ! 370: --*/ ! 371: ! 372: { ! 373: if (((SYMHASH*)arg1)->dwHashBucket < ((SYMHASH*)arg2)->dwHashBucket) { ! 374: return -1; ! 375: } ! 376: if (((SYMHASH*)arg1)->dwHashBucket > ((SYMHASH*)arg2)->dwHashBucket) { ! 377: return 1; ! 378: } ! 379: return 0; ! 380: } /* SymHashCompare() */ ! 381: ! 382: ! 383: DWORD ! 384: CreateSymbolHashTable( ! 385: PPOINTERS p ! 386: ) ! 387: /*++ ! 388: ! 389: Routine Description: ! 390: ! 391: ! 392: Creates the CV symbol hash table. This hash table is used ! 393: primarily by debuggers to access symbols in a quick manner. ! 394: ! 395: ! 396: Arguments: ! 397: ! 398: p - pointer to a POINTERS structure (see cofftocv.h) ! 399: ! 400: ! 401: Return Value: ! 402: ! 403: The number of buckets is the hash table. ! 404: ! 405: --*/ ! 406: ! 407: { ! 408: DWORD i; ! 409: DWORD j; ! 410: int k; ! 411: DWORD numsyms; ! 412: DWORD numbuckets; ! 413: OMFSymHash *omfSymHash; ! 414: DATASYM16 *dataSymStart; ! 415: DATASYM16 *dataSym; ! 416: LPVOID pHashData; ! 417: USHORT *pCHash; ! 418: DWORD *pHashTable; ! 419: USHORT *pBucketCounts; ! 420: DWORD *pChainTable; ! 421: SYMHASH *symHashStart; ! 422: SYMHASH *symHash; ! 423: DWORD dwHashVal; ! 424: char * sz; ! 425: ! 426: numsyms = p->pCvPublics.count; ! 427: numbuckets = (numsyms+9) / 10; ! 428: numbuckets = (1 + numbuckets) & ~1; ! 429: ! 430: symHashStart = ! 431: symHash = (SYMHASH *) malloc( numsyms * sizeof(SYMHASH) ); ! 432: if (symHashStart == NULL) { ! 433: return 0; ! 434: } ! 435: ! 436: memset( symHashStart, 0, numsyms * sizeof(SYMHASH) ); ! 437: ! 438: pHashData = (LPVOID) p->pCvCurr; ! 439: pCHash = (USHORT *) pHashData; ! 440: pHashTable = (DWORD *) ((DWORD)pHashData + sizeof(DWORD)); ! 441: pBucketCounts = (USHORT *) ((DWORD)pHashTable + ! 442: (sizeof(DWORD) * numbuckets)); ! 443: pChainTable = (DWORD *) ((DWORD)pBucketCounts + ! 444: ((sizeof(USHORT) * numbuckets))); ! 445: ! 446: omfSymHash = (OMFSymHash *) p->pCvPublics.ptr; ! 447: dataSymStart = ! 448: dataSym = (DATASYM16 *) ((DWORD)omfSymHash + sizeof(OMFSymHash)); ! 449: ! 450: *pCHash = (USHORT)numbuckets; ! 451: ! 452: /* ! 453: * cruise thru the symbols and calculate the hash values ! 454: * and the hash bucket numbers; save the info away for later use ! 455: */ ! 456: for (i=0; i<numsyms; i++, symHash++) { ! 457: switch( dataSym->rectyp ) { ! 458: case S_PUB16: ! 459: sz = dataSym->name; ! 460: break; ! 461: ! 462: case S_PUB32: ! 463: sz = ((DATASYM32 *) dataSym)->name; ! 464: break; ! 465: ! 466: default: ! 467: continue; ! 468: exit(1); ! 469: } ! 470: ! 471: dwHashVal = DWordXorLrl( sz ); ! 472: symHash->dwHashBucket = dwHashVal % numbuckets; ! 473: pBucketCounts[symHash->dwHashBucket] += 1; ! 474: symHash->dataSym = dataSym; ! 475: dataSym = ((DATASYM16 *) ((char *) dataSym + dataSym->reclen + 2)); ! 476: } ! 477: ! 478: qsort( (void*)symHashStart, numsyms, sizeof(SYMHASH), SymHashCompare ); ! 479: ! 480: j = (char *)pChainTable - (char *)pHashData; ! 481: for (i=0, k = 0; i<numbuckets; ! 482: k += pBucketCounts[i], i += 1, pHashTable++ ) { ! 483: *pHashTable = (DWORD) j + (k * 4); ! 484: } ! 485: ! 486: dataSymStart = (DATASYM16 *) (PUCHAR)((DWORD)omfSymHash); ! 487: for (i=0,symHash=symHashStart; i<numsyms; i++,symHash++,pChainTable++) { ! 488: *pChainTable = (DWORD) (DWORD)symHash->dataSym - (DWORD)dataSymStart; ! 489: } ! 490: ! 491: UpdatePtrs( p, &p->pCvSymHash, (LPVOID)pChainTable, numsyms ); ! 492: ! 493: omfSymHash->symhash = 6; ! 494: omfSymHash->cbHSym = p->pCvSymHash.size; ! 495: ! 496: free( symHashStart ); ! 497: ! 498: return numbuckets; ! 499: } /* CreateSymbolHashTable() */ ! 500: ! 501: ! 502: VOID ! 503: UpdatePtrs( PPOINTERS p, PPTRINFO pi, LPVOID lpv, DWORD count ) ! 504: ! 505: /*++ ! 506: ! 507: Routine Description: ! 508: ! 509: This function is called by ALL functions that put data into the ! 510: CV data area. After putting the data into the CV memory this function ! 511: must be called. It will adjust all of the necessary pointers so the ! 512: the next guy doesn't get hosed. ! 513: ! 514: ! 515: Arguments: ! 516: ! 517: p - pointer to a POINTERS structure (see cofftocv.h) ! 518: pi - the CV pointer that is to be updated ! 519: lpv - current pointer into the CV data ! 520: count - the number of items that were placed into the CV data ! 521: ! 522: ! 523: Return Value: ! 524: ! 525: void ! 526: ! 527: --*/ ! 528: ! 529: { ! 530: pi->ptr = p->pCvCurr; ! 531: pi->size = (DWORD) ((DWORD)lpv - (DWORD)p->pCvCurr); ! 532: pi->count = count; ! 533: ! 534: p->pCvStart.size += pi->size; ! 535: p->pCvCurr = (PUCHAR) lpv; ! 536: ! 537: return; ! 538: } /* UpdatePtrs() */ ! 539: ! 540: ! 541: int ! 542: _CRTAPI1 ! 543: OffsetSortCompare( const void *arg1, const void *arg2 ) ! 544: ! 545: /*++ ! 546: ! 547: Routine Description: ! 548: ! 549: Sort compare function for sorting OFFETSORT records by section number. ! 550: ! 551: ! 552: Arguments: ! 553: ! 554: arg1 - record #1 ! 555: arg2 - record #2 ! 556: ! 557: ! 558: Return Value: ! 559: ! 560: -1 - record #1 is < record #2 ! 561: 0 - records are equal ! 562: 1 - record #1 is > record #2 ! 563: ! 564: --*/ ! 565: ! 566: { ! 567: if (((OFFSETSORT*)arg1)->dwSection < ((OFFSETSORT*)arg2)->dwSection) { ! 568: return -1; ! 569: } ! 570: if (((OFFSETSORT*)arg1)->dwSection > ((OFFSETSORT*)arg2)->dwSection) { ! 571: return 1; ! 572: } ! 573: if (((OFFSETSORT*)arg1)->dwOffset < ((OFFSETSORT*)arg2)->dwOffset) { ! 574: return -1; ! 575: } ! 576: if (((OFFSETSORT*)arg1)->dwOffset > ((OFFSETSORT*)arg2)->dwOffset) { ! 577: return 1; ! 578: } ! 579: return 0; ! 580: } /* OffsetSortCompare() */ ! 581: ! 582: ! 583: DWORD ! 584: CreateAddressSortTable( PPOINTERS p ) ! 585: ! 586: /*++ ! 587: ! 588: Routine Description: ! 589: ! 590: ! 591: Creates the CV address sort table. This hash table is used ! 592: primarily by debuggers to access symbols in a quick manner when ! 593: all you have is an address. ! 594: ! 595: Arguments: ! 596: ! 597: p - pointer to a POINTERS structure (see cofftocv.h) ! 598: ! 599: ! 600: Return Value: ! 601: ! 602: The number of sections in the table. ! 603: ! 604: --*/ ! 605: ! 606: { ! 607: DWORD i; ! 608: DWORD j; ! 609: int k; ! 610: DWORD numsyms = p->pCvPublics.count; ! 611: DWORD numsections; ! 612: OMFSymHash *omfSymHash; ! 613: DATASYM16 *dataSymStart; ! 614: DATASYM16 *dataSym; ! 615: LPVOID pAddressData; ! 616: USHORT *pCSeg; ! 617: DWORD *pSegTable; ! 618: USHORT *pOffsetCounts; ! 619: DWORD *pOffsetTable; ! 620: OFFSETSORT *pOffsetSortStart; ! 621: OFFSETSORT *pOffsetSort; ! 622: ! 623: extern int CSymSegs; ! 624: ! 625: if (p->iptrs.fileHdr) { ! 626: numsections = p->iptrs.fileHdr->NumberOfSections; ! 627: } else if (p->iptrs.sepHdr) { ! 628: numsections = p->iptrs.sepHdr->NumberOfSections; ! 629: } else { ! 630: numsections = CSymSegs; ! 631: } ! 632: ! 633: pOffsetSortStart = ! 634: pOffsetSort = (OFFSETSORT *) malloc( numsyms * sizeof(OFFSETSORT) ); ! 635: ! 636: if (pOffsetSort == NULL) { ! 637: return 0; ! 638: } ! 639: ! 640: memset( pOffsetSortStart, 0, numsyms * sizeof(OFFSETSORT) ); ! 641: ! 642: pAddressData = (LPVOID) p->pCvCurr; ! 643: pCSeg = (USHORT *) pAddressData; ! 644: pSegTable = (DWORD *) ((DWORD)pAddressData + sizeof(DWORD)); ! 645: pOffsetCounts = (USHORT *) ((DWORD)pSegTable + ! 646: (sizeof(DWORD) * numsections)); ! 647: pOffsetTable = (DWORD *) ((DWORD)pOffsetCounts + ! 648: ((sizeof(USHORT) * numsections))); ! 649: if (numsections & 1) { ! 650: pOffsetTable = (DWORD *) ((DWORD)pOffsetTable + 2); ! 651: } ! 652: ! 653: omfSymHash = (OMFSymHash *) p->pCvPublics.ptr; ! 654: dataSymStart = ! 655: dataSym = (DATASYM16 *) ((DWORD)omfSymHash + sizeof(OMFSymHash)); ! 656: ! 657: *pCSeg = (USHORT)numsections; ! 658: ! 659: for (i=0; ! 660: i<numsyms; ! 661: i++, pOffsetSort++) ! 662: { ! 663: switch(dataSym->rectyp) { ! 664: case S_PUB16: ! 665: pOffsetSort->dwOffset = dataSym->off; ! 666: pOffsetSort->dwSection = dataSym->seg; ! 667: break; ! 668: ! 669: case S_PUB32: ! 670: pOffsetSort->dwOffset = ((DATASYM32 *) dataSym)->off; ! 671: pOffsetSort->dwSection = ((DATASYM32 *) dataSym)->seg; ! 672: } ! 673: ! 674: pOffsetSort->dataSym = dataSym; ! 675: pOffsetCounts[pOffsetSort->dwSection - 1] += 1; ! 676: dataSym = ((DATASYM16 *) ((char *) dataSym + dataSym->reclen + 2)); } ! 677: ! 678: //#if 0 ! 679: qsort((void*)pOffsetSortStart, numsyms, sizeof(OFFSETSORT), ! 680: OffsetSortCompare ); ! 681: //#endif ! 682: ! 683: j = (DWORD) (DWORD)pOffsetTable - (DWORD)pAddressData; ! 684: for (i=0, k=0; i<numsections; ! 685: k += pOffsetCounts[i], i += 1, pSegTable++) { ! 686: *pSegTable = (DWORD) j + (k * 4); ! 687: } ! 688: ! 689: dataSymStart = (DATASYM16 *) (PUCHAR)((DWORD)omfSymHash); ! 690: for (i=0, pOffsetSort=pOffsetSortStart; ! 691: i < numsyms; ! 692: i++, pOffsetSort++, pOffsetTable++) { ! 693: *pOffsetTable = (DWORD)pOffsetSort->dataSym - (DWORD)dataSymStart; ! 694: } ! 695: ! 696: UpdatePtrs( p, &p->pCvAddrSort, (LPVOID)pOffsetTable, numsyms ); ! 697: ! 698: omfSymHash->addrhash = 5; ! 699: omfSymHash->cbHAddr = p->pCvAddrSort.size; ! 700: ! 701: free( pOffsetSortStart ); ! 702: ! 703: return numsections; ! 704: } /* CreateAddressSort() */ ! 705:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.