/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


// System includes --------------------------------------------------------

#include <dwarf.h>
#include <dr.h>
#include <stdio.h>
#include <wstring.hpp>

// Project includes -------------------------------------------------------

#include "drmisc.h"
#include "mbrfile.h"
#include "merge.h"
#include "errors.h"
#include "memstrm.h"

// Internally used types --------------------------------------------------

struct AbbrevData {
    AbbrevTable * list;
};


char * DwarfFileMerger::_lineSectionName = "LINE.DW";
char * DwarfFileMerger::_abbrevSectionName = "ABBREV.DW";
char * DwarfFileMerger::_prologueFileName = "PRO.DW";
char * DwarfFileMerger::_infoSectionName = "INFO.DW";
char * DwarfFileMerger::_refSectionName = "REF.DW";

DwarfFileMerger::DwarfFileMerger( ElfFile * outFile )
/***************************************************/
    : _prologue( NULL )
    , _symbolStream( _infoSectionName )
    , _compUnitSymbol( NULL )
    , _outputFile( outFile )
{
    ComponentFileList   files;
    MBRFile *           mbrFile;
    int                 i;

    _outputFile->getEnabledComponents( files );

    for( i = 0; i < files.entries(); i += 1 ) {
        try {
            mbrFile = new MBRFile( files[i]->name );
            _mbrFileTable.insert( mbrFile );
        }
        catch( MBRFile::MBRErr err ) {
            printf( "%s: invalid file\n", files[i]->name );
        }
        catch( ... ) {
            printf( "%s: unknown error\n", files[i]->name );
            throw;
        }
    }
}

DwarfFileMerger::~DwarfFileMerger()
/*********************************/
{
    int i;

    #if DEBUG_LIST
        printf( "DwarfFileMerger::~DwarfFileMerger() -- _mbrFileTable contains %d entries\n", _mbrFileTable.entries() );
        printf( "                                    -- _abbrevList contains %d entries\n", _abbrevList.count() );
    #endif

    for( i = 0; i < _mbrFileTable.entries(); i += 1 ) {
        delete _mbrFileTable[ i ];
    }

    _abbrevList.iterateOver( deleteAbbrev );

    FileInfo * fileInfo;
    for( i = 0; i < _globalFileTable.count(); i += 1 ) {
        fileInfo = ( FileInfo * )_globalFileTable[ i ];
        delete fileInfo;
    }

    DirInfo * dirInfo;
    for( i = 0; i < _globalDirTable.count(); i += 1 ) {
        dirInfo = ( DirInfo * )_globalDirTable[ i ];
        delete dirInfo;
    }

    if( _prologue != NULL ) {
        delete _prologue;
    }

    if( _compUnitSymbol != NULL ) {
        delete _compUnitSymbol;
    }
}

void DwarfFileMerger::doMerge()
/*****************************/
{
    int i;
    AbbrevData abbrevData = { &_abbrevList };
    MFile lineFile( (char *) _lineSectionName );
    MFile refFile( (char *) _refSectionName );

    lineFile.open( MFileOWriteB );

    for( i = 0; i < _mbrFileTable.entries(); i += 1 ) {
        _MARK_( ".debug_abbrev start ..." );
        _mbrFileTable[ i ]->scanAbbreviations( &DwarfFileMerger::cbAbbrevs,
                                               &abbrevData );
        _MARK_( "... .debug_abbrev end" );

        /*
         | Output into line.dw (note line prologue is in pro.dw)
         */
        _MARK_( ".debug_line start ..." );
        mergeLineSection( i, lineFile );
        _MARK_( "... .debug_line end" );

        /*
         * Processing .debug_info section must be done after processing
         * .debug_abbrev and .debug_line because we require the tables
         * generated by them.
         */
        _MARK_( ".debug_info 1 start ..." );
        processInfoPass1( i );
        _MARK_( "... .debug_info 1 end" );
    }

    lineFile.close();

    /*
     | Write abbrev.dw, and pro.dw
     */
    writeAbbreviations();
    writePrologue();

    _symbolStream.open();

    refFile.open( MFileOWriteB );
    for( i = 0; i < _mbrFileTable.entries(); i += 1 ) {
        _MARK_( ".debug_info 2 start ..." );
        processInfoPass2( i );
        _MARK_( "... .debug_info 2 end" );

        _MARK_( ".debug_ref start ..." );
        processRefSection( i, refFile );
        _MARK_( "... .debug_ref end" );
    }
    refFile.close();

    #if DEBUG_DUMP
    dumpData();
    #endif

    _symbolStream.close();

    writeMergedFile();

    #if DEBUG_DUMP
    _refUpdateTable.dumpData();
    #endif
}

static void DwarfFileMerger::writeHook( void * cli, ElfFile * file, int sect )
/****************************************************************************/
{
    DwarfFileMerger * client = (DwarfFileMerger *) cli;
    client->writeDwarfSections( file, sect );
}

void DwarfFileMerger::writeMergedFile()
/*************************************/
{
    uint_32 sizes[ DR_DEBUG_NUM_SECTS ];

    /*
     | We need to know the length of each section
     | length of info = size(info header) + size(comp unit DIE) +
     |                  filesizeof( INFO.DW ) + trailing null DIE
     */

    for( int i = 0; i < DR_DEBUG_NUM_SECTS; i += 1 ) {
        sizes[ i ] = 0L;
    }

    // .debug_info
    sizes[ DR_DEBUG_INFO ] = getDebugInfoLength();
    // .debug_ref
    sizes[ DR_DEBUG_REF ] = getDebugRefLength();
    // .debug_abbrev
    sizes[ DR_DEBUG_ABBREV ] = SafeFile::fileSize( _abbrevSectionName );
    // .debug_line
    sizes[ DR_DEBUG_LINE ] = getDebugLineLength();
    // .debug_macinfo
    sizes[ DR_DEBUG_MACINFO ] = 1;

    _outputFile->createFile( sizes, this, (ElfFile::writeCb)&writeHook );

}

void DwarfFileMerger::writeDwarfSections( ElfFile * file, int sect )
/******************************************************************/
{
    switch( sect ) {
    case DR_DEBUG_INFO:
        writeDebugInfo( file );
        break;

    case DR_DEBUG_REF:
        writeDebugRef( file );
        break;

    case DR_DEBUG_ABBREV:
        writeDebugAbbrev( file );
        break;

    case DR_DEBUG_LINE:
        writeDebugLine( file );
        break;

    case DR_DEBUG_MACINFO:
        writeDebugMacro( file );
        break;
    }
}

void DwarfFileMerger::writeDebugMacro( ElfFile * file )
/*****************************************************/
{
    char a = '\0';
    file->safeWrite( &a, sizeof( char ) );
}

void DwarfFileMerger::writeDebugLine( ElfFile * file )
/**************************************************/
{
    file->safeAppend( _prologueFileName );
    file->safeAppend( _lineSectionName );
}

void DwarfFileMerger::writeDebugRef( ElfFile * file )
/*************************************************/
{
    uint_32 length;

    length = ElfFile::fileSize( _refSectionName );
    file->safeWrite( &length, sizeof( length ));
    file->safeAppend( _refSectionName );
}

void DwarfFileMerger::writeDebugAbbrev( ElfFile * file )
/****************************************************/
{
    file->safeAppend( _abbrevSectionName );
}

void DwarfFileMerger::writeDebugInfo( ElfFile * file )
/**************************************************/
{
    // Write the header for .debug_info

    uint_32 ui32;
    uint_16 ui16;
    uint_8  ui8;

    ui32 = getDebugInfoLength() - sizeof( ui32 );
    file->safeWrite( &ui32, sizeof( ui32 ));

    ui16 = 2;
    file->safeWrite( &ui16, sizeof( ui16 ));

    ui32 = 0;
    file->safeWrite( &ui32, sizeof( ui32 ));

    ui8 = 2;
    file->safeWrite( &ui8, sizeof( ui8 ));

    // Write the compilation unit header

    fixCompUnitSymbol();
    file->safeWrite( _compUnitSymbol->data(), _compUnitSymbol->length() );

    // Tack on the processed symbols

    file->safeAppend( _infoSectionName );

    // Write a NULL byte to indicate the end of the .debug_info section
    // (the sibling of the compilation unit DIE).
    ui8 = 0;
    file->safeWrite( &ui8, sizeof( ui8 ));
}

uint_32 DwarfFileMerger::getDebugLineLength()
/******************************************/
{
    return( MFile::fileSize( _prologueFileName ) + MFile::fileSize( _lineSectionName ));
}

uint_32 DwarfFileMerger::getDebugRefLength()
/******************************************/
{
    // + 4 for the size information

    return( MFile::fileSize( _refSectionName ) + 4 );
}

void DwarfFileMerger::fixCompUnitSymbol()
/***************************************/
// Actually, we're just using the first DIE with DW_TAG_compile_unit
// found.  All we do is update the sibling reference.
{
    uint_32 form;
    uint_32 attr;
    uint_8 * p;
    uint_8 * abbrev;
    uint_32 ui32;

    if( _compUnitSymbol == NULL ) {
        throw ErrInvalidFormat;
    }

    p = _compUnitSymbol->data();
    p = SkipLEB128( p );                // skip abbrev_code

    abbrev = _compUnitSymbol->abbrev()->data;

    if( abbrev == NULL ) {
        throw ErrInvalidFormat;
    }

    abbrev = DecodeULEB128( abbrev, &ui32 );    // skip code
    abbrev = DecodeULEB128( abbrev, &ui32 );    // skip tag

    abbrev++;                                   // skip child flag

    for( ;; ) {
        abbrev = DecodeULEB128( abbrev, &attr );
        abbrev = DecodeULEB128( abbrev, &form );

        if( attr == 0 ) break;

        if( attr == DW_AT_sibling ) {
            /*
             | Trouble if form is variable length
             */
            writeDataForm( p, form, _symbolStream.offset() );
        } else {
            p = SkipForm( p, form );
        }
    }

}

uint_32 DwarfFileMerger::getDebugInfoLength()
/*******************************************/
{
    uint_32 length;

    /*
     | Since all symbols should have been processed by now, the length
     | is just the offset of the symbol stream, + 1 byte for the NULL DIE
     | that is the sibling of the comp unit DIE (yet to be written).
     */
    length = _symbolStream.offset() + 1;
    return( length );
}

// .debug_abbrev processing ------------------------------------------------

static bool DwarfFileMerger::cbAbbrevs( uint_32 code, const uint_8 * pAb,
                                        unsigned long length, void * data )
/*************************************************************************/
// data = ptr to AbbrevData structure
//
// RH: Maybe we want to keep a list of all the reference forms so that
//     we know what bytes to change in the DIEs?  In fact, we probably
//     want to get the whole damn block instead of one abbrev at a time!
//     Bleh.  Ok, but what if abbrev section is too big to fit into memory?
//
{
    Abbreviation * ab;
    AbbrevData * pData;

    pData = (AbbrevData *) data;

    ab = new Abbreviation;

    if( !ab ) {
        throw ErrOutOfMemory;
    }

    ab->code = code;
    ab->length = length;

    if( (*(pData->list))[ code ] == NULL ) {
        ab->data = new uint_8[ length ];

        if( ab->data ) {
            memcpy( ab->data, pAb, length );

            /*
             | Only add if there isn't already an abbreviation with this code
             */
            if( !pData->list->placeAt( code, ab )) {
                delete ab;
            }
        } else {
            delete ab;

            throw ErrOutOfMemory;
        }
    } else {
        delete ab;
        return TRUE;
    }

    return TRUE;
}

static void DwarfFileMerger::deleteAbbrev( Abbreviation * & ab )
/*************************************************************/
{
    delete ab;
    ab = NULL;
}

void DwarfFileMerger::writeAbbreviations()
/****************************************/
{
    MFile file( ( char * )_abbrevSectionName );
    bool rc;
    int i;

    rc = file.open( MFileOWriteB );

    if( rc == TRUE ) {

        for( i = 0; i <= _abbrevList.count(); i += 1 ) {
            if( _abbrevList[ i ] != NULL ) {
                file.write( _abbrevList[ i ]->data, _abbrevList[ i ]->length );
            }
        }

        // Indicate end of abbreviation section
        file.putch( 0x00 );

        file.close();
    } else {
        printf( "Error: Open failed.\n" );
    }
}

// .debug_line processing --------------------------------------------------

void DwarfFileMerger::writePrologue()
/***********************************/
{
    MFile file(( char * ) _prologueFileName );
    MemoryStream mem;
    uint_8 nullByte;
    unsigned long startPro;
    int i;

    file.open( MFileOWriteB );

    nullByte = '\0';

    /*
     * Save room for total_length, version, and prologue_length.
     * These will be filled in later since the total length and the
     * prologue length are known yet.
     */
    mem.seek( sizeof( uint_32 ) + sizeof( uint_16 ) + sizeof( uint_32 ));

    startPro = mem.tell();

    mem.write( &_prologue->min_instr, sizeof( _prologue->min_instr ));
    mem.write( &_prologue->default_is_stmt, sizeof( _prologue->default_is_stmt ));
    mem.write( &_prologue->line_base, sizeof( _prologue->line_base ));
    mem.write( &_prologue->line_range, sizeof( _prologue->line_range ));
    mem.write( &_prologue->opcode_base, sizeof( _prologue->opcode_base ));

    for( i = 0; i < _prologue->opcode_base - 1; i += 1 ) {
        mem.write( & _prologue->opcode_lengths[ i ], sizeof( uint_8 ));
    }

    DirInfo * dirInfo;

    for( i = 0; i < _globalDirTable.count(); i += 1 ) {
        dirInfo = ( DirInfo * )_globalDirTable.find( i );
        mem.write( dirInfo->name(), strlen( dirInfo->name() ) + 1 );
    }

    mem.write( &nullByte, sizeof( nullByte ));

    FileInfo * fileInfo;

    for( i = 0; i < _globalFileTable.count(); i += 1 ) {
        fileInfo = ( FileInfo * )_globalFileTable.find( i );
        fileInfo->encode( mem );
    }

    mem.write( &nullByte, sizeof( nullByte ));

    _prologue->prologue_length = mem.tell() - startPro;
    _prologue->unit_length= mem.tell() - sizeof( uint_32 ) +
                            MFile::fileSize(( char * ) _lineSectionName );
    mem.seek( 0 );

    mem.write( &_prologue->unit_length, sizeof( _prologue->unit_length ));
    mem.write( &_prologue->version, sizeof( _prologue->version ));
    mem.write( &_prologue->prologue_length, sizeof( _prologue->prologue_length ));

    file.write( mem.getPtr(), mem.size() );

    file.close();
}

void DwarfFileMerger::mergeLineSection( int mbrIndex, MFile & outfile )
/*********************************************************************/
{
    LinePrologue * pro;
    unsigned long length;
    int fileBase;               // # of files in global table b4 adding any

    pro = new LinePrologue;
    if( !pro ) {
        throw ErrOutOfMemory;
    }

    _mbrFileTable[ mbrIndex ]->getLineInfo( *pro, length );

    addDirectories( mbrIndex, pro->directories );

    fileBase = _globalFileTable.count();

    addFiles( mbrIndex, pro->filenames );

    if( _prologue == NULL ) {
        _prologue = pro;

    } else {
        if( *pro != *_prologue ) {
            printf( "Warning : .debug_line prologues are incompatible!\n" );
        }
        delete pro;
    }

    processStatementProgram( *_mbrFileTable[ mbrIndex ], outfile,
                             length, mbrIndex, fileBase );
}

void DwarfFileMerger::addDirectories( int mbrIndex, DebugObjectVector & dirs )
/****************************************************************************/
{
    int i;

    for( i = 0; i < dirs.entries(); i += 1 ) {
        if( _globalDirTable.add( mbrIndex, dirs[ i ]->name(), dirs[ i ]) == FALSE ) {
            delete dirs[ i ];
            dirs[ i ] = NULL;
        }
    }
}

void DwarfFileMerger::addFiles( int mbrIndex, DebugObjectVector & files )
/***********************************************************************/
{
    int i;

    for( i = 0; i < files.entries(); i += 1 ) {
        if( _globalFileTable.add( mbrIndex, files[ i ]->name(), files[ i ] ) == FALSE ) {
            delete files[ i ];
            files[ i ] = NULL;
        }
    }
}

void DwarfFileMerger::processStatementProgram( MBRFile & infile,
                                               MFile & outfile,
                                               unsigned long length,
                                               int mbrIndex,
                                               int fileBase )
/******************************************************************/
{
    unsigned long currLength;
    uint_8 opcode;

    currLength = 0;

    while( currLength < length ) {

        /*
         * Don't write the opcode out yet -- if the opcode is
         * DW_LNE_define_file, we don't want to copy it!
         */
        infile.readSect( DR_DEBUG_LINE, &opcode, sizeof( opcode ));
        currLength += sizeof( opcode );

        // Extended op-code?
        if( opcode == 0 ) {
            processExtendedOpcode( infile, outfile, mbrIndex, currLength );
        } else {
            outfile.write( &opcode, sizeof( opcode ));

            if( opcode < _prologue->opcode_base ) {
                processStandardOpcode( infile, outfile, opcode, mbrIndex, currLength, fileBase );
            }
        }
    }
}

void DwarfFileMerger::processExtendedOpcode( MBRFile & infile,
                                             MFile & outfile,
                                             int mbrIndex,
                                             unsigned long & currLength )
/***********************************************************************/
// RH : Hey, do we want to write out the defined file here or not???
//      If we do, we better mark it in the file table as already being
//      written so that we don't have two copies of it.
//      If we don't, will we have to watch for empty begin/end sequences
//      and remove these?
// Note : Should we catch DW_LNE_end_sequence and ignore it??? maybe just
//        emit one at the end?
{
    uint_8   oplen;
    uint_8   opcode;
    uint_8 * data;
    uint_8 * pos;
    uint_32  startpos = infile.getSectOff( DR_DEBUG_LINE );

    // get opcode length ( == # of bytes left, not including oplen )
    infile.readSect( DR_DEBUG_LINE, &oplen, sizeof( oplen ));

    data = new uint_8[ oplen ];
    if( data == NULL ) {
        throw ErrOutOfMemory;
    }

    infile.readSect( DR_DEBUG_LINE, data, oplen );

    pos = data;

    // get sub-opcode
    opcode = *pos;
    pos += sizeof( opcode );

    if( opcode == DW_LNE_define_file ) {

        /*
         * Add defined file to global file table, but don't write
         * out this info to the statement program.  We'll write out
         * all this data to the prologue and combine everything later
         */

        char * str;
        uint_32 oldDir;
        uint_32 newDir;
        uint_32 modTime;
        uint_32 length;

        newDir = 0;

        pos = readString( pos, &str );
        pos = DecodeULEB128( pos, &oldDir );
        pos = DecodeULEB128( pos, &modTime );
        pos = DecodeULEB128( pos, &length );

        // Get new directory number

        // Make sure not current directory

        if( oldDir != 0 ) {
            newDir = _globalDirTable.find( mbrIndex, oldDir );
        }

        FileInfo * fileInfo;

        fileInfo = new FileInfo( str, oldDir, modTime, length, newDir );
        if( fileInfo == NULL ) {
            throw ErrOutOfMemory;
        }
        if( _globalFileTable.add( mbrIndex, fileInfo->name(), fileInfo ) == FALSE ) {
            delete fileInfo;
            fileInfo = NULL;
        }

    } else if( opcode == DW_LNE_end_sequence ) {
        outfile.putch( '\0' );                          // Extended op-code
        outfile.putch( '\1' );
        outfile.putch( DW_LNE_end_sequence );
    } else {
        /*
         * Hmm.  What if we are writing DW_LNE_end_sequence but the
         * sequence is empty... In that case, we don't want to write
         * it out.  This happens if the only opcode is a define_file
         * extended opcode (which isn't written out)
         */
        // Just copy data
        outfile.putch( '\0' );                          // Extended op-code
        outfile.write( &oplen, sizeof( oplen ));        // Length of op
        outfile.write( data, oplen );                   // op data
    }

    delete [] data;

    currLength += infile.getSectOff( DR_DEBUG_LINE ) - startpos;
}

void DwarfFileMerger::processStandardOpcode( MBRFile & infile,
                                             MFile & outfile,
                                             uint_8 opcode,
                                             int,
                                             unsigned long & currLength,
                                             int fileBase )
/***********************************************************************/
{
    uint_8 ui8;

    switch( opcode ) {

        // Opcodes with no arguments
        case DW_LNS_copy :
        case DW_LNS_negate_stmt :
        case DW_LNS_set_basic_block :
        case DW_LNS_const_add_pc :
            break;

        // Opcodes with LEB128 arguments :
        case DW_LNS_advance_pc :
        case DW_LNS_advance_line :
        case DW_LNS_set_column :
            for( ;; ) {
                infile.readSect( DR_DEBUG_LINE, &ui8, sizeof( ui8 ) );
                outfile.putch( ui8 );
                currLength += sizeof( ui8 );
                if(( ui8 & 0x80 )== 0 ) {
                    break;
                }
            }
            break;

        // Special case : DW_LNS_set_file
        //      Have to change file # to new file #... Hmm, what if
        //      the file # hasn't been encountered yet?
        case DW_LNS_set_file :
            uint_32 ui32;

            ui32 = infile.readULEB128( DR_DEBUG_LINE );

            /*
             * RH: the new filenum might be off by one
             */
            currLength += outfile.writeULEB128( ui32 + fileBase );
            break;

        default :
            throw ErrInvalidFormat;
    }
}

void DwarfFileMerger::writeFileInfo( MFile & file, FileInfo * info )
/******************************************************************/
{
    uint_32  infoLength;
    uint_32  lengthLength;
    uint_8 * ulebData;
    uint_8   ulebDataLen[ MAX_ULEB_SIZE ];
    uint_8 * pos;

    ulebData = new uint_8[ 3 * MAX_ULEB_SIZE + strlen( info->name() ) + 1 ];
    if( ulebData == NULL ) {
        throw ErrOutOfMemory;
    }

    strcpy( ( char * )ulebData, ( char * )info->name() );
    pos = ulebData + strlen( info->name() ) + 1;
    pos = EncodeULEB128( pos, info->newDirIndex() );
    pos = EncodeULEB128( pos, info->lastModified() );
    pos = EncodeULEB128( pos, info->length() );

    infoLength = pos - ulebData;

    pos = EncodeULEB128( ulebDataLen, infoLength );
    lengthLength = pos - ulebDataLen;

    file.write( ulebDataLen, lengthLength );
    file.write( ulebData, infoLength );

    delete [] ulebData;
}

// .debug_ref processing

void DwarfFileMerger::processRefSection( int mbrIndex, MFile & outfile )
/*********************************************************************/
{
    uint_8 * pRef;
    uint_8 * p;
    uint_8 * unit_base;
    uint_32 length;
    uint_32 unit_length;
    uint_32 oldFileIndex;
    uint_32 newFileIndex;
    uint_32 oldOffset;
    uint_32 newOffset;
    uint_32 tmp;
    uint_8  op_code;
    int_32  itmp;
    MemoryStream mem;

    _mbrFileTable[ mbrIndex ]->getSectionRawData( DR_DEBUG_REF, pRef, &length );

    p = pRef;

    while( p - pRef < length ) {
        unit_length = *(uint_32 *)p;

        p += sizeof( uint_32 );

        unit_base = p;

        while( p - unit_base < unit_length ) {

            mem.write( p, sizeof( *p ));
            op_code = *p++;

            if( op_code < REF_CODE_BASE ) {
                switch( op_code ) {
                case REF_BEGIN_SCOPE:
                    oldOffset = * ( uint_32 * ) p;
                    if( !_refUpdateTable.getNewOffset( mbrIndex, oldOffset, newOffset )) {
                        printf( "Warning: [ .debug_ref ]\n" );
                        printf( "         Cannot find offset for file %d, offset 0x%x\n", mbrIndex, oldOffset );
                        newOffset = 0;
                    }

                    mem.write( &newOffset, sizeof( uint_32 ));
                    p += sizeof( uint_32 );
                    break;
                case REF_END_SCOPE:
                case REF_COPY:
                    break;
                case REF_SET_FILE:
                    p = DecodeULEB128( p, &oldFileIndex );
                    newFileIndex = _globalFileTable.find( mbrIndex, oldFileIndex );
                    mem.writeULEB128( newFileIndex ) ;
                    break;
                case REF_SET_LINE:
                case REF_SET_COLUMN:
                    p = DecodeULEB128( p, &tmp );
                    mem.writeULEB128( tmp );
                    break;
                case REF_ADD_LINE:
                case REF_ADD_COLUMN:
                    p = DecodeLEB128( p, &itmp );
                    mem.writeLEB128( itmp );
                    break;
                }
            } else {
                oldOffset = * ( uint_32 * ) p;
                if( !_refUpdateTable.getNewOffset( mbrIndex, oldOffset, newOffset )) {
                    printf( "Warning: [ .debug_ref ]\n" );
                    printf( "         Cannot find offset for file %d, offset 0x%x\n", mbrIndex, oldOffset );
                    newOffset = 0;
                }

                mem.write( &newOffset, sizeof( uint_32 ));
                p += sizeof( uint_32 );
            }
        }
    }

    outfile.write( mem.getPtr(), mem.length() );
}

