xref: /AOO41X/main/soltools/ldump/ldump.cxx (revision 7a4715d38e2b2b0b3018baee48d4fff8c3b378ce)
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         if ((aBuf[0] =='?') || !strncmp(aBuf, "__CT",4))
175         {
176             nLen = (int) strlen(aBuf);
177             memset( aName, 0, sizeof( aName ) );
178             int nName = 0;
179             for( i = 0; i < nLen; i++ )
180             {
181                 if ( (aBuf[i] != '\n') && (aBuf[i] != '\r') )
182                 {
183                     aName[nName] = aBuf[i];
184                     nName++;
185                 }
186             }
187             // und raus damit
188             PrintSym( aName, bExportByName );
189         }
190         else if ( bAll == true )
191         {
192             int nPreLen = (int) strlen( cAPrefix );
193 
194             nLen = (int) strlen(aBuf);
195             memset( aName, 0, sizeof( aName ) );
196             int nName = 0;
197 
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             //fprintf( stderr, "Gefundenen Prefix : %s %d \n", aTmpBuf, nPreLen );
207             // den ersten _ raus
208             nLen = (int) strlen(aName);
209             if (aName[0] == '_')
210                 strcpy( aBuf , &aName[1] );
211             strncpy ( aTmpBuf, aBuf, (size_t) nPreLen );
212             aTmpBuf[nPreLen] = '\0';
213             if ( !strcmp( aTmpBuf, cAPrefix ))
214             {
215                 if ( bLdump3 ) {
216                     int nChar = '@';
217                     char *pNeu = strchr( aBuf, nChar );
218                     int nPos = pNeu - aBuf + 1;
219                     if ( nPos > 0 )
220                     {
221                         char aOldBuf[MAX_MAN];
222                         strcpy( aOldBuf, aBuf );
223                         char pChar[MAX_MAN];
224                         strncpy( pChar, aBuf, (size_t) (nPos -1) );
225                         pChar[nPos-1] = '\0';
226                         strcpy( aBuf, pChar );
227                         strcat( aBuf, "=" );
228                         strcat( aBuf, aOldBuf );
229                         strcpy( pChar, "" );
230                     }
231                 }
232                 // und raus damit
233                 PrintSym( aBuf, true );
234             }
235         }
236     }
237     fclose(pList);
238     return true;
239 }
240 
ReadFilter(char * cFilterName)241 bool LibDump::ReadFilter( char * cFilterName )
242 {
243     FILE* pfFilter = 0;
244     char  aBuf[MAX_MAN];
245     char* pStr;
246     int   nLen;
247 
248     pfFilter = fopen( cFilterName, "r" );
249 
250     if ( !pfFilter )
251     {
252         ::bFilter = 0;
253         DumpError( 500 );
254     }
255 
256     while( fgets( aBuf, MAX_MAN, pfFilter ) != 0 )
257     {
258         nLen = (int) strlen(aBuf);
259         pStr = new char[(unsigned int) nLen];
260         if ( !pStr )
261             DumpError( 98 );
262         memcpy( pStr, aBuf, (unsigned int) nLen );
263         if ( *(pStr+nLen-1) == '\n' )
264             *(pStr+nLen-1) = '\0';
265         pFilterLines[nFilterLines] = pStr;
266         nFilterLines++;
267         if ( nFilterLines >= MAXFILT )
268                 DumpError( 510 );
269     }
270 
271     fclose( pfFilter );
272     return true;
273 }
274 
PrintSym(char * pName,bool bName)275 bool LibDump::PrintSym(char *pName, bool bName )
276 {
277     LibExport *pData;
278 
279 
280     // Filter auswerten
281     if ( Filter( pName ) )
282     {
283         if ( strlen( pName ) > 3 )
284         {
285             if ( bDef )
286             {
287                 if (!bBase)
288                     if (bExportName) {
289                         fprintf( stdout, "\t%s\n", pName );
290                     } else {
291                         fprintf( stdout, "\t%s\t\t@%lu\n", pName, nDefStart );
292                     }
293                 else
294                 {
295                      pData = pBaseTab->Find( pName );
296                      if ( pData )
297                      {
298                         pData->bExport = true;
299                         if ( bName )
300                             pData->bByName = true;
301                         else
302                             pData->bByName = false;
303                         if ( bVerbose )
304                             fprintf(stderr,".");
305                      }
306                      else
307                      {
308                         // neuen Export eintragen
309                         pData = new LibExport;
310                         pData->cExportName = new char[ strlen( pName ) + 1 ];
311                         strcpy( pData->cExportName, pName );
312                         pData->nOrdinal = nBaseLines++;
313                         pData->bExport = true;
314                         if ( bName )
315                             pData->bByName = true;
316                         else
317                             pData->bByName = false;
318                         pBaseTab->Insert( pData->cExportName, pData );
319                         char *cBuffer = new char[ 30 ];
320                         sprintf( cBuffer, "%lu", pData->nOrdinal );
321                         pIndexTab->Insert( cBuffer, pData );
322                         delete [] cBuffer;
323                         if ( bVerbose )
324                             fprintf(stderr,"n");
325                      }
326                 }
327             }
328             else
329                 printf( "%s\n", pName );
330             nDefStart++;
331         }
332     }
333     return true;
334 }
335 
IsFromAnonymousNamespace(char * pExportName)336 bool LibDump::IsFromAnonymousNamespace (char *pExportName) {
337     char* pattern1 = "@?A0x";
338 
339     if (strstr(pExportName, pattern1)) {
340         return true;
341     };
342     return false;
343 };
344 
Filter(char * pExportName)345 bool LibDump::Filter(char *pExportName)
346 {
347     unsigned long i;
348     char pTest[256];
349 
350     // filter out symbols from anonymous namespaces
351     if (IsFromAnonymousNamespace (pExportName))
352         return false;
353 
354     // Kein Filter gesetzt
355     if ( ::bFilter == 0 )
356         return true;
357 
358     for ( i=0; i<nFilterLines; i++ )
359     {
360         //Zum vergleichen mu� das Plus abgeschnitteb werden
361         if(pFilterLines[i][0] != '+')
362         {
363             if ( strstr( pExportName, pFilterLines[i]))
364                 return false;
365         }
366         else
367         {
368             strcpy(pTest,&pFilterLines[i][1]);
369             if ( strstr( pExportName, pTest))
370                 return true;
371         }
372     }
373     return true;
374 }
375 
SetFilter(char * cFilterName)376 bool LibDump::SetFilter(char * cFilterName)
377 {
378     ReadFilter( cFilterName );
379     return true;
380 }
381 
CheckLibrary(char * cName)382 bool LibDump::CheckLibrary(char * cName)
383 {
384     delete [] cLibName;
385     cLibName = new char[ strlen( cName ) + 1 ];
386     strcpy( cLibName, cName );
387     return true;
388 }
389 
ReadDataBase()390 bool LibDump::ReadDataBase()
391 {
392     FILE* pfBase = 0;
393     char  aBuf[MAX_MAN];
394     char* pStr;
395     char  cBuffer[ 30 ];
396     int   nLen;
397     LibExport *pData;
398 
399     pfBase = fopen( cBName, "r" );
400 
401     if ( !pfBase )
402     {
403         bBase = 0;
404         DumpError( 600 );
405     }
406 
407     bool bRet = true;
408     while( fgets( aBuf, MAX_MAN, pfBase ) != 0 )
409     {
410         nLen = (int) strlen(aBuf);
411         pStr = new char[(unsigned int) nLen];
412         if ( !pStr )
413             DumpError( 98 );
414         memcpy( pStr, aBuf, (size_t) nLen );
415         if ( *(pStr+nLen-1) == '\n' )
416             *(pStr+nLen-1) = '\0';
417         pData = new LibExport;
418         pData->cExportName = pStr;
419         pData->nOrdinal = nBaseLines;
420         pData->bExport=false;
421 
422         if (pBaseTab->Insert(pData->cExportName, pData ) == NULL)
423             bRet = false;
424         ltoa( (long) pData->nOrdinal, cBuffer, 10 );
425         if (pIndexTab->Insert( cBuffer, pData ) == NULL)
426             bRet = false;
427         nBaseLines++;
428         if ( nBaseLines >= MAXBASE )
429             DumpError( 610 );
430     }
431     fclose( pfBase );
432     return bRet;
433 }
434 
435 class ExportSetIter : public HashTableIterator
436 {
437 public:
ExportSetIter(HashTable const & aTable)438     ExportSetIter(HashTable const& aTable)
439         : HashTableIterator(aTable) {}
440 
GetFirst()441     LibExport * GetFirst()
442     { return (LibExport *)HashTableIterator::GetFirst(); }
GetNext()443     LibExport * GetNext()
444     { return (LibExport *)HashTableIterator::GetNext();  }
GetLast()445     LibExport * GetLast()
446     { return (LibExport *)HashTableIterator::GetLast();  }
GetPrev()447     LibExport * GetPrev()
448     { return (LibExport *)HashTableIterator::GetPrev();  }
449 
450 private:
451     void operator =(ExportSetIter &); // not defined
452 };
453 
PrintDataBase()454 bool LibDump::PrintDataBase()
455 {
456     if (bExportName)
457         return true;
458     FILE *pFp;
459     pFp = fopen (cBName,"w+");
460     if (!pFp)
461         fprintf( stderr, "Error opening DataBase File\n" );
462 
463     LibExport *pData;
464     for ( unsigned long i=0; i < nBaseLines+10; i++ )
465     {
466         char * cBuffer = new char[ 30 ];
467         sprintf( cBuffer, "%lu", i );
468         pData = pIndexTab->Find( cBuffer );
469         delete [] cBuffer;
470         if ( pData )
471             fprintf(pFp,"%s\n",pData->cExportName);
472     }
473     fclose(pFp);
474     return true;
475 }
476 
PrintDefFile()477 bool LibDump::PrintDefFile()
478 {
479 #ifdef FAST
480     ExportSetIter aIterator( *pBaseTab );
481     for ( LibExport *pData = aIterator.GetFirst(); pData != NULL;
482                                         pData = aIterator.GetNext() )
483     {
484         if ( pData->bExport )
485         {
486             if ( pData->bByName )
487             {
488                 fprintf(stdout,"\t%s\n",
489                     pData->sExportName.GetBuffer());
490             }
491             else
492             {
493                 fprintf(stdout,"\t%s\t\t@%d NONAME\n",
494                     pData->sExportName.GetBuffer(), pData->nOrdinal+nBegin);
495             }
496         }
497     }
498 #else
499     // sortiert nach Ordinals;
500     LibExport *pData;
501     for ( unsigned long i=0; i<nBaseLines+1; i++)
502     {
503         char * cBuffer = new char[ 30 ];
504         sprintf( cBuffer, "%lu", i );
505         pData = pIndexTab->Find( cBuffer );
506         delete [] cBuffer;
507         if ( pData )
508             if ( pData->bExport )
509             {
510                 if ( pData->bByName )
511                 {
512                     if ( strlen( pData->cExportName ))
513                         fprintf(stdout,"\t%s\n",
514                             pData->cExportName);
515                 }
516                 else
517                 {
518                     if ( strlen( pData->cExportName ))
519                         fprintf(stdout,"\t%s\t\t@%d NONAME\n",
520                             pData->cExportName, pData->nOrdinal+nBegin);
521                 }
522             }
523     }
524 #endif
525     return true;
526 }
527 
CheckDataBase()528 bool LibDump::CheckDataBase()
529 {
530     // existiert eine Datenbasis ?
531     if (!bBase)
532     {
533         cBName = new char[ 2048 ];
534         char *pTmp = "defs\\";
535 
536         FILE *fp;
537 #ifdef OS2
538         _mkdir ("defs", 0777);
539 #else
540         _mkdir ("defs");
541 #endif
542         strcpy(cBName,pTmp);
543 #ifdef OS2
544         strcat(cBName,"gcc");
545 #else
546         strcat(cBName,getenv ("COMP_ENV"));
547 #endif
548 
549         fp = fopen (cBName,"r");
550         if (fp)
551         {
552             bBase = true;
553         }
554         else
555         {
556             fp = fopen (cBName,"w+");
557             bBase = true;
558         }
559         fclose (fp);
560     }
561     // lese Datenbasis !
562     if (bBase)
563     {
564         ReadDataBase();
565     }
566     return true;
567 }
568 
~LibDump()569 LibDump::~LibDump()
570 {
571     delete [] cBName;
572     delete [] cAPrefix;
573 //  delete [] cLibName;
574     delete [] cFilterName;
575     delete [] cModName;
576 }
577 
SetCExport(char * pName)578 void LibDump::SetCExport( char* pName )
579 {
580     delete [] cAPrefix;
581     cAPrefix = new char[ strlen( pName ) + 1 ];
582     strcpy( cAPrefix, pName );bAll = true;
583 }
584 
585 //******************************************************************
586 //* Error() - Gibt Fehlermeldumg aus
587 //******************************************************************
588 
DumpError(unsigned long n)589 void LibDump::DumpError( unsigned long n )
590 {
591     char *p;
592 
593     switch (n)
594     {
595         case 1:  p = "Input error in library file"; break;
596         case 2:  p = "Position error in library file (no THEADR set)"; break;
597         case 3:  p = "Overflow of symbol table"; break;
598 #ifdef WNT
599         case 10: p = "EXP file not found"; break;
600         case 11: p = "No valid EXP file"; break;
601 #else
602         case 10: p = "Library file not found"; break;
603         case 11: p = "No valid library file"; break;
604 #endif
605         case 98: p = "Out of memory"; break;
606         case 99: p = "LDUMP [-LD3] [-D] [-N] [-A] [-E nn] [-F name] Filename[.LIB]\n"
607                      "-LD3   : Supports feature set of ldump3 (default: ldump/ldump2)\n"
608                      "-A     : all symbols (default: only C++)\n"
609                      "-E nn  : gerenration of export table beginning with number nn\n"
610                      "-F name: Filter file\n"
611                      "-D     : file contains \"dumpbin\" directives\n"
612                      "-N     : export by name\n"
613                      "-V     : be verbose\n"; break;
614         case 500: p = "Unable to open filter file\n"; break;
615         case 510: p = "Overflow of filter table\n"; break;
616         case 600: p = "Unable to open base database file\n"; break;
617         case 610: p = "Overflow in base database table\n"; break;
618         default: p = "Unspecified error";
619     }
620     fprintf( stdout, "%s\n", p );
621     exit (1);
622 }
623 
624 /*********************************************************************
625         Test Funktionen
626 *********************************************************************/
627 
628 
usage()629 void usage()
630 {
631     LibDump::DumpError(99);
632 }
633 
634 #define STATE_NON       0x0000
635 #define STATE_BEGIN     0x0001
636 #define STATE_FILTER    0x0002
637 #define STATE_CEXPORT   0x0003
638 
639 int
640 #ifdef WNT
641 __cdecl
642 #endif
main(int argc,char ** argv)643 main( int argc, char **argv )
644 {
645     char *pLibName = NULL, *pFilterName = NULL, *pCExport= NULL;
646     unsigned short nBegin=1;
647 
648     unsigned short nState = STATE_NON;
649 
650     if ( argc == 1 ) {
651         usage();
652     }
653 
654     for ( int i = 1; i < argc; i++ ) {
655         if (( !strcmp( argv[ i ], "-H" )) ||
656             ( !strcmp( argv[ i ], "-h" )) ||
657             ( !strcmp( argv[ i ], "-?" )))
658         {
659             usage();
660         }
661         else if (( !strcmp( argv[ i ], "-LD3" )) ||
662             ( !strcmp( argv[ i ], "-Ld3" )) ||
663             ( !strcmp( argv[ i ], "-ld3" )) ||
664             ( !strcmp( argv[ i ], "-lD3" )))
665         {
666             if ( nState != STATE_NON ) {
667                 usage();
668             }
669             bLdump3 = 1;
670         }
671         else if (( !strcmp( argv[ i ], "-E" )) || ( !strcmp( argv[ i ], "-e" ))) {
672             if ( nState != STATE_NON ) {
673                 usage();
674             }
675             nState = STATE_BEGIN;
676         }
677         else if (( !strcmp( argv[ i ], "-F" )) || ( !strcmp( argv[ i ], "-f" ))) {
678             if ( nState != STATE_NON ) {
679                 usage();
680             }
681             nState = STATE_FILTER;
682         }
683         else if (( !strcmp( argv[ i ], "-A" )) || ( !strcmp( argv[ i ], "-a" ))) {
684             if ( nState != STATE_NON ) {
685                 usage();
686             }
687             nState = STATE_CEXPORT;
688             pCExport = new char[ 1 ];
689             pCExport[ 0 ] = 0;
690         }
691         else if (( !strcmp( argv[ i ], "-D" )) || ( !strcmp( argv[ i ], "-d" ))) {
692             if ( nState != STATE_NON ) {
693                 usage();
694             }
695             bUseDirectives = 1;
696         }
697         else if (( !strcmp( argv[ i ], "-N" )) || ( !strcmp( argv[ i ], "-n" ))) {
698             if ( nState != STATE_NON ) {
699                 usage();
700             }
701             bExportByName = 1;
702         }
703         else if (( !strcmp( argv[ i ], "-V" )) || ( !strcmp( argv[ i ], "-v" ))) {
704             if ( nState != STATE_NON ) {
705                 usage();
706             }
707             bVerbose = 1;
708         }
709         else {
710             switch ( nState ) {
711                 case STATE_BEGIN:
712                     nBegin = static_cast< unsigned short >(atoi( argv[ i ] ));
713                     nState = STATE_NON;
714                 break;
715                 case STATE_FILTER:
716                     pFilterName = new char[ strlen( argv[ i ] ) + 1 ];
717                     strcpy( pFilterName, argv[ i ] );
718                     bFilter = 1;
719                     nState = STATE_NON;
720                 break;
721                 case STATE_CEXPORT:
722                     delete [] pCExport;
723                     pCExport = new char[ strlen( argv[ i ] ) + 1 ];
724                     strcpy( pCExport, argv[ i ] );
725                     nState = STATE_NON;
726                 break;
727                 default:
728                     pLibName = new char[ strlen( argv[ i ] ) + 1 ];
729                     strcpy( pLibName, argv[ i ] );
730                 break;
731             }
732         }
733     }
734 
735     if ( !pLibName ) {
736         usage();
737     }
738 
739     LibDump *pDump = new LibDump( pLibName, bExportByName );
740     pDump->SetBeginExport(nBegin);
741     if ( bFilter != 0 )
742         pDump->SetFilter( pFilterName );
743     if ( pCExport )
744         pDump->SetCExport( pCExport );
745     else {
746         char *pEmpty = "";
747         pDump->SetCExport( pEmpty );
748     }
749     pDump->Dump();
750     pDump->PrintDefFile();
751     pDump->PrintDataBase();
752     delete pDump;
753     return 0;
754 }
755