1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_soltools.hxx"
26
27 #include <string.h>
28 #include <direct.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #include "ldump.hxx"
33 #include "hashtbl.hxx"
34
35 #define MAXSYM 65536
36 #define MAXBASE 98304
37 #define MAX_MAN 4096
38
39 int bFilter = 0;
40 int bLdump3 = 0;
41 int bUseDirectives = 0;
42 int bVerbose = 0;
43 int bExportByName = 0;
44
45 class ExportSet : public HashTable
46 {
47 public:
ExportSet(unsigned long lSize,double dMaxLoadFactor=HashTable::m_defMaxLoadFactor,double dGrowFactor=HashTable::m_defDefGrowFactor)48 ExportSet
49 (
50 unsigned long lSize,
51 double dMaxLoadFactor = HashTable::m_defMaxLoadFactor,
52 double dGrowFactor = HashTable::m_defDefGrowFactor
53 )
54 : HashTable(lSize,false,dMaxLoadFactor,dGrowFactor) {}
55
~ExportSet()56 virtual ~ExportSet() {}
57
Find(char * const & Key) const58 LibExport * Find (char * const& Key) const
59 { return (LibExport *) HashTable::Find((char *) Key); }
60
Insert(char * const & Key,LibExport * Object)61 bool Insert (char * const& Key, LibExport * Object)
62 { return HashTable::Insert((char *) Key, (void*) Object); }
63
Delete(char * const & Key)64 LibExport * Delete (char * const&Key)
65 { return (LibExport *) HashTable::Delete ((char *) Key); }
66 };
67
LibDump(char * cFileName,int bExportByName)68 LibDump::LibDump( char *cFileName, int bExportByName )
69 : cBName( NULL ),
70 cAPrefix( NULL ),
71 cLibName( NULL ),
72 cFilterName( NULL ),
73 cModName( NULL )
74 {
75 fprintf( stderr, "LIB-NT File Dumper v4.00 (C) 2000 Sun Microsystems, Inc.\n\n" );
76 fprintf( stderr, "%s ", cFileName );
77
78 bExportName = bExportByName;
79
80 unsigned long nSlots = 0xfffff;
81 pBaseTab = new ExportSet( nSlots );
82 pIndexTab = new ExportSet( nSlots );
83 pFilterLines = new char * [MAXFILT];
84 CheckLibrary(cFileName);
85 bBase = 0;
86 bAll = false;
87 nDefStart = 0;
88 nBaseLines = 0;
89 nFilterLines = 0;
90 bDef = true;
91 cAPrefix = new char[ 1 ];
92 cAPrefix[ 0 ] = 0;
93 if (!bExportName)
94 CheckDataBase();
95 }
96
Dump()97 bool LibDump::Dump()
98 {
99 FILE *pList;
100 char aBuf[MAX_MAN];
101 int nLen;
102 char aName[MAX_MAN];
103
104 pList = fopen( cLibName, "rb");
105 if (!pList)
106 DumpError(10);
107
108 // forget about offset when working on linker directives
109 if ( !bUseDirectives )
110 {
111 // calculating offset for name section
112 unsigned char TmpBuffer[4];
113 fread( TmpBuffer, 1, 4, pList);
114 // anzahl bigendian mal laenge + ueberspringen der naechsten laengenangabe
115 unsigned long nOffSet = (unsigned long) ( TmpBuffer[2] * 256 + TmpBuffer[3] ) * 4 + 4;
116 fseek( pList, (long) nOffSet, 0);
117 }
118
119 char aTmpBuf[4096];
120 // reading file containing symbols
121 while( !feof( pList ) )
122 {
123 int i = 0;
124 if ( !bUseDirectives )
125 {
126 // symbol komplett einlesen
127 for (;;)
128 {
129 int c = fgetc( pList );
130 if ( c == '\0' )
131 {
132 break;
133 }
134 if ( ((c >= 33) && (c <= 126)) && ( c!=40 && c!=41) )
135 aBuf[i] = static_cast< char >(c);
136 else
137 {
138 aBuf[0] = '\0';
139 break;
140 }
141 i++;
142 }
143 // Namen found
144 aBuf[i] = '\0';
145 }
146 else
147 {
148 fgets( aTmpBuf, 4096, pList );
149 char * pEnd = 0;
150 char *pFound = 0;
151 aBuf[0] = '\0';
152 pFound = strchr( aTmpBuf, 'E' );
153 while ( pFound )
154 {
155 if ( strncmp( "EXPORT:", pFound, 7) == 0 )
156 {
157 pFound += 7;
158 pEnd = strchr( pFound, ',');
159 if ( pEnd )
160 *pEnd = '\0';
161 strncpy( aBuf, pFound, strlen( pFound));
162 aBuf[ strlen( pFound) ] = '\0';
163 // fprintf( stderr, "\n--- %s\n", aBuf);
164 break;
165 }
166 else
167 {
168 pFound++;
169 pFound = strchr( pFound, 'E' );
170 }
171 }
172 }
173
174 // A modern MSVC puts its SSE and AVX vector constants into the archive
175 // symbol table as __xmm@<hex>, and __ymm@/__zmm@ for the wider ones,
176 // exactly as every MSVC has done for __real@<hex>. They are merged
177 // COMDAT constants, not exports, and a .def naming one fails to link:
178 //
179 // icharttools.exp : error LNK2001: unresolved external symbol
180 // _xmm@41f00000000000000000000000000000
181 //
182 // The two modules that carry a symbol filter list _real for the same
183 // reason, but most export-all modules carry no filter at all -- ldump
184 // does no filtering when the file is absent -- so this has to be here
185 // rather than in a .flt. VC9 emits none of these, so it is unaffected.
186 if ( !strncmp( aBuf, "__xmm@", 6 )
187 || !strncmp( aBuf, "__ymm@", 6 )
188 || !strncmp( aBuf, "__zmm@", 6 ) )
189 {
190 continue;
191 }
192
193 if ((aBuf[0] =='?') || !strncmp(aBuf, "__CT",4))
194 {
195 nLen = (int) strlen(aBuf);
196 memset( aName, 0, sizeof( aName ) );
197 int nName = 0;
198 for( i = 0; i < nLen; i++ )
199 {
200 if ( (aBuf[i] != '\n') && (aBuf[i] != '\r') )
201 {
202 aName[nName] = aBuf[i];
203 nName++;
204 }
205 }
206 // und raus damit
207 PrintSym( aName, bExportByName );
208 }
209 else if ( bAll == true )
210 {
211 int nPreLen = (int) strlen( cAPrefix );
212
213 nLen = (int) strlen(aBuf);
214 memset( aName, 0, sizeof( aName ) );
215 int nName = 0;
216
217 for( i = 0; i < nLen; i++ )
218 {
219 if ( (aBuf[i] != '\n') && (aBuf[i] != '\r') )
220 {
221 aName[nName] = aBuf[i];
222 nName++;
223 }
224 }
225 //fprintf( stderr, "Gefundenen Prefix : %s %d \n", aTmpBuf, nPreLen );
226 // den ersten _ raus
227 nLen = (int) strlen(aName);
228 if (aName[0] == '_')
229 strcpy( aBuf , &aName[1] );
230 strncpy ( aTmpBuf, aBuf, (size_t) nPreLen );
231 aTmpBuf[nPreLen] = '\0';
232 if ( !strcmp( aTmpBuf, cAPrefix ))
233 {
234 if ( bLdump3 ) {
235 int nChar = '@';
236 char *pNeu = strchr( aBuf, nChar );
237 int nPos = pNeu - aBuf + 1;
238 if ( nPos > 0 )
239 {
240 char aOldBuf[MAX_MAN];
241 strcpy( aOldBuf, aBuf );
242 char pChar[MAX_MAN];
243 strncpy( pChar, aBuf, (size_t) (nPos -1) );
244 pChar[nPos-1] = '\0';
245 strcpy( aBuf, pChar );
246 strcat( aBuf, "=" );
247 strcat( aBuf, aOldBuf );
248 strcpy( pChar, "" );
249 }
250 }
251 // und raus damit
252 PrintSym( aBuf, true );
253 }
254 }
255 }
256 fclose(pList);
257 return true;
258 }
259
ReadFilter(char * cFilterName)260 bool LibDump::ReadFilter( char * cFilterName )
261 {
262 FILE* pfFilter = 0;
263 char aBuf[MAX_MAN];
264 char* pStr;
265 int nLen;
266
267 pfFilter = fopen( cFilterName, "r" );
268
269 if ( !pfFilter )
270 {
271 ::bFilter = 0;
272 DumpError( 500 );
273 }
274
275 while( fgets( aBuf, MAX_MAN, pfFilter ) != 0 )
276 {
277 nLen = (int) strlen(aBuf);
278 pStr = new char[(unsigned int) nLen];
279 if ( !pStr )
280 DumpError( 98 );
281 memcpy( pStr, aBuf, (unsigned int) nLen );
282 if ( *(pStr+nLen-1) == '\n' )
283 *(pStr+nLen-1) = '\0';
284 pFilterLines[nFilterLines] = pStr;
285 nFilterLines++;
286 if ( nFilterLines >= MAXFILT )
287 DumpError( 510 );
288 }
289
290 fclose( pfFilter );
291 return true;
292 }
293
PrintSym(char * pName,bool bName)294 bool LibDump::PrintSym(char *pName, bool bName )
295 {
296 LibExport *pData;
297
298
299 // Filter auswerten
300 if ( Filter( pName ) )
301 {
302 if ( strlen( pName ) > 3 )
303 {
304 if ( bDef )
305 {
306 if (!bBase)
307 if (bExportName) {
308 fprintf( stdout, "\t%s\n", pName );
309 } else {
310 fprintf( stdout, "\t%s\t\t@%lu\n", pName, nDefStart );
311 }
312 else
313 {
314 pData = pBaseTab->Find( pName );
315 if ( pData )
316 {
317 pData->bExport = true;
318 if ( bName )
319 pData->bByName = true;
320 else
321 pData->bByName = false;
322 if ( bVerbose )
323 fprintf(stderr,".");
324 }
325 else
326 {
327 // neuen Export eintragen
328 pData = new LibExport;
329 pData->cExportName = new char[ strlen( pName ) + 1 ];
330 strcpy( pData->cExportName, pName );
331 pData->nOrdinal = nBaseLines++;
332 pData->bExport = true;
333 if ( bName )
334 pData->bByName = true;
335 else
336 pData->bByName = false;
337 pBaseTab->Insert( pData->cExportName, pData );
338 char *cBuffer = new char[ 30 ];
339 sprintf( cBuffer, "%lu", pData->nOrdinal );
340 pIndexTab->Insert( cBuffer, pData );
341 delete [] cBuffer;
342 if ( bVerbose )
343 fprintf(stderr,"n");
344 }
345 }
346 }
347 else
348 printf( "%s\n", pName );
349 nDefStart++;
350 }
351 }
352 return true;
353 }
354
IsFromAnonymousNamespace(char * pExportName)355 bool LibDump::IsFromAnonymousNamespace (char *pExportName) {
356 char* pattern1 = "@?A0x";
357
358 if (strstr(pExportName, pattern1)) {
359 return true;
360 };
361 return false;
362 };
363
Filter(char * pExportName)364 bool LibDump::Filter(char *pExportName)
365 {
366 unsigned long i;
367 char pTest[256];
368
369 // filter out symbols from anonymous namespaces
370 if (IsFromAnonymousNamespace (pExportName))
371 return false;
372
373 // Kein Filter gesetzt
374 if ( ::bFilter == 0 )
375 return true;
376
377 for ( i=0; i<nFilterLines; i++ )
378 {
379 //Zum vergleichen mu� das Plus abgeschnitteb werden
380 if(pFilterLines[i][0] != '+')
381 {
382 if ( strstr( pExportName, pFilterLines[i]))
383 return false;
384 }
385 else
386 {
387 strcpy(pTest,&pFilterLines[i][1]);
388 if ( strstr( pExportName, pTest))
389 return true;
390 }
391 }
392 return true;
393 }
394
SetFilter(char * cFilterName)395 bool LibDump::SetFilter(char * cFilterName)
396 {
397 ReadFilter( cFilterName );
398 return true;
399 }
400
CheckLibrary(char * cName)401 bool LibDump::CheckLibrary(char * cName)
402 {
403 delete [] cLibName;
404 cLibName = new char[ strlen( cName ) + 1 ];
405 strcpy( cLibName, cName );
406 return true;
407 }
408
ReadDataBase()409 bool LibDump::ReadDataBase()
410 {
411 FILE* pfBase = 0;
412 char aBuf[MAX_MAN];
413 char* pStr;
414 char cBuffer[ 30 ];
415 int nLen;
416 LibExport *pData;
417
418 pfBase = fopen( cBName, "r" );
419
420 if ( !pfBase )
421 {
422 bBase = 0;
423 DumpError( 600 );
424 }
425
426 bool bRet = true;
427 while( fgets( aBuf, MAX_MAN, pfBase ) != 0 )
428 {
429 nLen = (int) strlen(aBuf);
430 pStr = new char[(unsigned int) nLen];
431 if ( !pStr )
432 DumpError( 98 );
433 memcpy( pStr, aBuf, (size_t) nLen );
434 if ( *(pStr+nLen-1) == '\n' )
435 *(pStr+nLen-1) = '\0';
436 pData = new LibExport;
437 pData->cExportName = pStr;
438 pData->nOrdinal = nBaseLines;
439 pData->bExport=false;
440
441 if (pBaseTab->Insert(pData->cExportName, pData ) == NULL)
442 bRet = false;
443 ltoa( (long) pData->nOrdinal, cBuffer, 10 );
444 if (pIndexTab->Insert( cBuffer, pData ) == NULL)
445 bRet = false;
446 nBaseLines++;
447 if ( nBaseLines >= MAXBASE )
448 DumpError( 610 );
449 }
450 fclose( pfBase );
451 return bRet;
452 }
453
454 class ExportSetIter : public HashTableIterator
455 {
456 public:
ExportSetIter(HashTable const & aTable)457 ExportSetIter(HashTable const& aTable)
458 : HashTableIterator(aTable) {}
459
GetFirst()460 LibExport * GetFirst()
461 { return (LibExport *)HashTableIterator::GetFirst(); }
GetNext()462 LibExport * GetNext()
463 { return (LibExport *)HashTableIterator::GetNext(); }
GetLast()464 LibExport * GetLast()
465 { return (LibExport *)HashTableIterator::GetLast(); }
GetPrev()466 LibExport * GetPrev()
467 { return (LibExport *)HashTableIterator::GetPrev(); }
468
469 private:
470 void operator =(ExportSetIter &); // not defined
471 };
472
PrintDataBase()473 bool LibDump::PrintDataBase()
474 {
475 if (bExportName)
476 return true;
477 FILE *pFp;
478 pFp = fopen (cBName,"w+");
479 if (!pFp)
480 fprintf( stderr, "Error opening DataBase File\n" );
481
482 LibExport *pData;
483 for ( unsigned long i=0; i < nBaseLines+10; i++ )
484 {
485 char * cBuffer = new char[ 30 ];
486 sprintf( cBuffer, "%lu", i );
487 pData = pIndexTab->Find( cBuffer );
488 delete [] cBuffer;
489 if ( pData )
490 fprintf(pFp,"%s\n",pData->cExportName);
491 }
492 fclose(pFp);
493 return true;
494 }
495
PrintDefFile()496 bool LibDump::PrintDefFile()
497 {
498 #ifdef FAST
499 ExportSetIter aIterator( *pBaseTab );
500 for ( LibExport *pData = aIterator.GetFirst(); pData != NULL;
501 pData = aIterator.GetNext() )
502 {
503 if ( pData->bExport )
504 {
505 if ( pData->bByName )
506 {
507 fprintf(stdout,"\t%s\n",
508 pData->sExportName.GetBuffer());
509 }
510 else
511 {
512 fprintf(stdout,"\t%s\t\t@%d NONAME\n",
513 pData->sExportName.GetBuffer(), pData->nOrdinal+nBegin);
514 }
515 }
516 }
517 #else
518 // sortiert nach Ordinals;
519 LibExport *pData;
520 for ( unsigned long i=0; i<nBaseLines+1; i++)
521 {
522 char * cBuffer = new char[ 30 ];
523 sprintf( cBuffer, "%lu", i );
524 pData = pIndexTab->Find( cBuffer );
525 delete [] cBuffer;
526 if ( pData )
527 if ( pData->bExport )
528 {
529 if ( pData->bByName )
530 {
531 if ( strlen( pData->cExportName ))
532 fprintf(stdout,"\t%s\n",
533 pData->cExportName);
534 }
535 else
536 {
537 if ( strlen( pData->cExportName ))
538 fprintf(stdout,"\t%s\t\t@%d NONAME\n",
539 pData->cExportName, pData->nOrdinal+nBegin);
540 }
541 }
542 }
543 #endif
544 return true;
545 }
546
CheckDataBase()547 bool LibDump::CheckDataBase()
548 {
549 // existiert eine Datenbasis ?
550 if (!bBase)
551 {
552 cBName = new char[ 2048 ];
553 char *pTmp = "defs\\";
554
555 FILE *fp;
556 #ifdef OS2
557 _mkdir ("defs", 0777);
558 #else
559 _mkdir ("defs");
560 #endif
561 strcpy(cBName,pTmp);
562 #ifdef OS2
563 strcat(cBName,"gcc");
564 #else
565 strcat(cBName,getenv ("COMP_ENV"));
566 #endif
567
568 fp = fopen (cBName,"r");
569 if (fp)
570 {
571 bBase = true;
572 }
573 else
574 {
575 fp = fopen (cBName,"w+");
576 bBase = true;
577 }
578 fclose (fp);
579 }
580 // lese Datenbasis !
581 if (bBase)
582 {
583 ReadDataBase();
584 }
585 return true;
586 }
587
~LibDump()588 LibDump::~LibDump()
589 {
590 delete [] cBName;
591 delete [] cAPrefix;
592 // delete [] cLibName;
593 delete [] cFilterName;
594 delete [] cModName;
595 }
596
SetCExport(char * pName)597 void LibDump::SetCExport( char* pName )
598 {
599 delete [] cAPrefix;
600 cAPrefix = new char[ strlen( pName ) + 1 ];
601 strcpy( cAPrefix, pName );bAll = true;
602 }
603
604 //******************************************************************
605 //* Error() - Gibt Fehlermeldumg aus
606 //******************************************************************
607
DumpError(unsigned long n)608 void LibDump::DumpError( unsigned long n )
609 {
610 char *p;
611
612 switch (n)
613 {
614 case 1: p = "Input error in library file"; break;
615 case 2: p = "Position error in library file (no THEADR set)"; break;
616 case 3: p = "Overflow of symbol table"; break;
617 #ifdef WNT
618 case 10: p = "EXP file not found"; break;
619 case 11: p = "No valid EXP file"; break;
620 #else
621 case 10: p = "Library file not found"; break;
622 case 11: p = "No valid library file"; break;
623 #endif
624 case 98: p = "Out of memory"; break;
625 case 99: p = "LDUMP [-LD3] [-D] [-N] [-A] [-E nn] [-F name] Filename[.LIB]\n"
626 "-LD3 : Supports feature set of ldump3 (default: ldump/ldump2)\n"
627 "-A : all symbols (default: only C++)\n"
628 "-E nn : gerenration of export table beginning with number nn\n"
629 "-F name: Filter file\n"
630 "-D : file contains \"dumpbin\" directives\n"
631 "-N : export by name\n"
632 "-V : be verbose\n"; break;
633 case 500: p = "Unable to open filter file\n"; break;
634 case 510: p = "Overflow of filter table\n"; break;
635 case 600: p = "Unable to open base database file\n"; break;
636 case 610: p = "Overflow in base database table\n"; break;
637 default: p = "Unspecified error";
638 }
639 fprintf( stdout, "%s\n", p );
640 exit (1);
641 }
642
643 /*********************************************************************
644 Test Funktionen
645 *********************************************************************/
646
647
usage()648 void usage()
649 {
650 LibDump::DumpError(99);
651 }
652
653 #define STATE_NON 0x0000
654 #define STATE_BEGIN 0x0001
655 #define STATE_FILTER 0x0002
656 #define STATE_CEXPORT 0x0003
657
658 int
659 #ifdef WNT
660 __cdecl
661 #endif
main(int argc,char ** argv)662 main( int argc, char **argv )
663 {
664 char *pLibName = NULL, *pFilterName = NULL, *pCExport= NULL;
665 unsigned short nBegin=1;
666
667 unsigned short nState = STATE_NON;
668
669 if ( argc == 1 ) {
670 usage();
671 }
672
673 for ( int i = 1; i < argc; i++ ) {
674 if (( !strcmp( argv[ i ], "-H" )) ||
675 ( !strcmp( argv[ i ], "-h" )) ||
676 ( !strcmp( argv[ i ], "-?" )))
677 {
678 usage();
679 }
680 else if (( !strcmp( argv[ i ], "-LD3" )) ||
681 ( !strcmp( argv[ i ], "-Ld3" )) ||
682 ( !strcmp( argv[ i ], "-ld3" )) ||
683 ( !strcmp( argv[ i ], "-lD3" )))
684 {
685 if ( nState != STATE_NON ) {
686 usage();
687 }
688 bLdump3 = 1;
689 }
690 else if (( !strcmp( argv[ i ], "-E" )) || ( !strcmp( argv[ i ], "-e" ))) {
691 if ( nState != STATE_NON ) {
692 usage();
693 }
694 nState = STATE_BEGIN;
695 }
696 else if (( !strcmp( argv[ i ], "-F" )) || ( !strcmp( argv[ i ], "-f" ))) {
697 if ( nState != STATE_NON ) {
698 usage();
699 }
700 nState = STATE_FILTER;
701 }
702 else if (( !strcmp( argv[ i ], "-A" )) || ( !strcmp( argv[ i ], "-a" ))) {
703 if ( nState != STATE_NON ) {
704 usage();
705 }
706 nState = STATE_CEXPORT;
707 pCExport = new char[ 1 ];
708 pCExport[ 0 ] = 0;
709 }
710 else if (( !strcmp( argv[ i ], "-D" )) || ( !strcmp( argv[ i ], "-d" ))) {
711 if ( nState != STATE_NON ) {
712 usage();
713 }
714 bUseDirectives = 1;
715 }
716 else if (( !strcmp( argv[ i ], "-N" )) || ( !strcmp( argv[ i ], "-n" ))) {
717 if ( nState != STATE_NON ) {
718 usage();
719 }
720 bExportByName = 1;
721 }
722 else if (( !strcmp( argv[ i ], "-V" )) || ( !strcmp( argv[ i ], "-v" ))) {
723 if ( nState != STATE_NON ) {
724 usage();
725 }
726 bVerbose = 1;
727 }
728 else {
729 switch ( nState ) {
730 case STATE_BEGIN:
731 nBegin = static_cast< unsigned short >(atoi( argv[ i ] ));
732 nState = STATE_NON;
733 break;
734 case STATE_FILTER:
735 pFilterName = new char[ strlen( argv[ i ] ) + 1 ];
736 strcpy( pFilterName, argv[ i ] );
737 bFilter = 1;
738 nState = STATE_NON;
739 break;
740 case STATE_CEXPORT:
741 delete [] pCExport;
742 pCExport = new char[ strlen( argv[ i ] ) + 1 ];
743 strcpy( pCExport, argv[ i ] );
744 nState = STATE_NON;
745 break;
746 default:
747 pLibName = new char[ strlen( argv[ i ] ) + 1 ];
748 strcpy( pLibName, argv[ i ] );
749 break;
750 }
751 }
752 }
753
754 if ( !pLibName ) {
755 usage();
756 }
757
758 LibDump *pDump = new LibDump( pLibName, bExportByName );
759 pDump->SetBeginExport(nBegin);
760 if ( bFilter != 0 )
761 pDump->SetFilter( pFilterName );
762 if ( pCExport )
763 pDump->SetCExport( pCExport );
764 else {
765 char *pEmpty = "";
766 pDump->SetCExport( pEmpty );
767 }
768 pDump->Dump();
769 pDump->PrintDefFile();
770 pDump->PrintDataBase();
771 delete pDump;
772 return 0;
773 }
774