hllld.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 359 行

C
359
字号
/****************************************************************************
*
*                            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:  HLL/CV symbolic information loading and unloading.
*
****************************************************************************/


#include <string.h>
#include <stddef.h>
#include "hllinfo.h"
#include "exepe.h"
#include "exedos.h"


/* WD looks for this symbol to determine module bitness */
int __nullarea;
#pragma aux __nullarea "*";

imp_image_handle        *ImageList;

static void Cleanup( imp_image_handle *ii )
{
    imp_image_handle    **owner;
    imp_image_handle    *curr;
    unsigned            blocks;
    unsigned            i;

    owner = &ImageList;
    for( ;; ) {
        curr = *owner;
        if( curr == ii ) break;
        owner = &curr->next_image;
    }
    *owner = ii->next_image;
    if( ii->directory != NULL ) {
        blocks = BLOCK_FACTOR( ii->dir_count, DIRECTORY_BLOCK_ENTRIES );
        for( i = 0; i < blocks; ++i ) {
            if( ii->directory[i] != NULL ) {
                DCFree( ii->directory[i] );
            }
        }
        DCFree( ii->directory );
    }
    DCFree( ii->mapping );
    VMFini( ii );
}

static dip_status TryFindPE( dig_fhandle h, unsigned long *offp,
                                unsigned long *sizep )
{
    union {
        dos_exe_header  dos;
        pe_header       pe;
    }                   hdr;
    pe_object           obj;
    unsigned_32         nh_off;
    unsigned_32         section_off;
    unsigned            i;
    unsigned_32         debug_rva;
    debug_directory     dir;

    if( DCSeek( h, 0, DIG_ORG ) != 0 ) {
        return( DS_ERR | DS_FSEEK_FAILED );
    }
    if( DCRead( h, &hdr.dos, sizeof( hdr.dos ) ) != sizeof( hdr.dos ) ) {
        return( DS_ERR | DS_FREAD_FAILED );
    }
    if( hdr.dos.signature != DOS_SIGNATURE ) {
        return( DS_FAIL );
    }
    if( DCSeek( h, NH_OFFSET, DIG_ORG ) != NH_OFFSET ) {
        return( DS_ERR | DS_FSEEK_FAILED );
    }
    if( DCRead( h, &nh_off, sizeof( nh_off ) ) != sizeof( nh_off ) ) {
        return( DS_ERR | DS_FREAD_FAILED );
    }
    if( DCSeek( h, nh_off, DIG_ORG ) != nh_off ) {
        return( DS_ERR | DS_FSEEK_FAILED );
    }
    if( DCRead( h, &hdr.pe, sizeof( hdr.pe ) ) != sizeof( hdr.pe ) ) {
        return( DS_ERR | DS_FREAD_FAILED );
    }
    if( hdr.pe.signature != PE_SIGNATURE ) {
        return( DS_FAIL );
    }
    if( hdr.pe.table[ PE_TBL_DEBUG ].rva == 0 ) {
        return( DS_FAIL );
    }
    debug_rva = (hdr.pe.table[ PE_TBL_DEBUG ].rva / hdr.pe.object_align)*
                                hdr.pe.object_align;

    section_off = nh_off + offsetof( pe_header, flags ) +
                        sizeof( hdr.pe.flags ) + hdr.pe.nt_hdr_size;

    if( DCSeek( h, section_off, DIG_ORG ) != section_off ) {
        return( DS_ERR | DS_FSEEK_FAILED );
    }
    for( i=0; i < hdr.pe.num_objects; i++ ) {
        if( DCRead( h, &obj, sizeof( obj ) ) != sizeof( obj ) ) {
            return( DS_ERR | DS_FREAD_FAILED );
        }
        if( obj.rva == debug_rva ) {
            debug_rva = obj.physical_offset +
                            hdr.pe.table[ PE_TBL_DEBUG ].rva - debug_rva;
            if( DCSeek( h, debug_rva, DIG_ORG ) != debug_rva ) {
                return( DS_ERR | DS_FSEEK_FAILED );
            }
            if( DCRead( h, &dir, sizeof( dir ) ) != sizeof( dir ) ) {
                return( DS_ERR | DS_FREAD_FAILED );
            }
            if( dir.debug_type != DEBUG_TYPE_CODEVIEW ) {
                return( DS_FAIL );
            }
            *offp = dir.data_seek;
            *sizep = dir.debug_size;
        }
    }
    return( DS_FAIL );
}

static dip_status TryFindTrailer( dig_fhandle h, unsigned_32 *offp,
                                  unsigned long *sizep )
{
    hll_trailer         sig;
    unsigned long       pos;

    pos = DCSeek( h, -(long)sizeof( sig ), DIG_END );
    if( pos == -1UL ) {
        return( DS_ERR | DS_FSEEK_FAILED );
    }
    if( DCRead( h, &sig, sizeof( sig ) ) != sizeof( sig ) ) {
        return( DS_ERR | DS_FREAD_FAILED );
    }
    if( memcmp( sig.sig, HLL_NB04, sizeof( sig.sig ) ) != 0 ) {
        return( DS_FAIL );
    }
    *sizep = sig.offset - sizeof( sig );
    *offp = pos - *sizep;
    return( DS_OK );
}

static dip_status FindHLL( dig_fhandle h, unsigned_32 *offp,
                           unsigned long *sizep )
{
    char        sig[HLL_SIG_SIZE];
    dip_status  ds;

    ds = TryFindPE( h, offp, sizep );
    if( ds & DS_ERR ) return( ds );
    if( ds != DS_OK ) {
        ds = TryFindTrailer( h, offp, sizep );
        if( ds != DS_OK ) return( ds );
    }
    if( DCSeek( h, *offp, DIG_ORG ) != *offp ) {
        return( DS_ERR | DS_FSEEK_FAILED );
    }
    if( DCRead( h, sig, sizeof( sig ) ) != sizeof( sig ) ) {
        return( DS_ERR | DS_FREAD_FAILED );
    }
    if( memcmp( sig, HLL_NB04, sizeof( sig ) ) != 0 ) {
        return( DS_FAIL );
    }
    return( DS_OK );
}

static dip_status LoadDirectory( imp_image_handle *ii, unsigned_32 off )
{
    unsigned_32             directory;
    hll_debug_dirinfo       dir_header;
    unsigned                block_count;
    unsigned                i;
    unsigned                left;
    unsigned                block_size;
    unsigned                num;

    if( DCSeek( ii->sym_file, off, DIG_ORG ) != off ) {
        return( DS_ERR | DS_FSEEK_FAILED );
    }
    if( DCRead( ii->sym_file, &directory, sizeof( directory ) ) != sizeof( directory ) ) {
        return( DS_ERR | DS_FREAD_FAILED );
    }
    if( DCSeek( ii->sym_file, ii->bias + directory, DIG_ORG ) != (ii->bias + directory) ) {
        return( DS_ERR | DS_FSEEK_FAILED );
    }
    if( DCRead( ii->sym_file, &dir_header, sizeof( dir_header ) ) != sizeof( dir_header ) ) {
        return( DS_ERR | DS_FREAD_FAILED );
    }
    if( dir_header.cbDirHeader != sizeof( dir_header )
     || dir_header.cbDirEntry  != sizeof( hll_debug_dir ) ) {
        return( DS_ERR | DS_INFO_INVALID );
    }
    ii->dir_count = dir_header.cDir;
    block_count = BLOCK_FACTOR( ii->dir_count, DIRECTORY_BLOCK_ENTRIES );
    ii->directory = DCAlloc( block_count * sizeof( void * ) );
    if( ii->directory == NULL ) {
        return( DS_ERR | DS_NO_MEM );
    }
    memset( ii->directory, 0, block_count * sizeof( void * ) );
    i = 0;
    left = ii->dir_count;
    for( ;; ) {
        num = left;
        if( num > DIRECTORY_BLOCK_ENTRIES ) {
            num = DIRECTORY_BLOCK_ENTRIES;
        }
        block_size = num * sizeof( hll_debug_dir );
        ii->directory[i] = DCAlloc( block_size );
        if( ii->directory[i] == NULL ) {
            return( DS_ERR | DS_NO_MEM );
        }
        if( DCRead( ii->sym_file, ii->directory[i], block_size ) != block_size ) {
            return( DS_ERR | DS_FREAD_FAILED );
        }
        ++i;
        left -= num;
        if( left == 0 ) break;
    }
    return( DS_OK );
}

static dip_status LoadMapping( imp_image_handle *ii )
{
    hll_debug_dir       *cde;
    cv_sst_seg_map      *map;
    unsigned            size;

    cde = FindDirEntry( ii, MH_GBL, sstSegMap );
    if( cde == NULL ) return( DS_ERR | DS_INFO_INVALID );
    map = VMBlock( ii, cde->lfo, cde->cb );
    if( map == NULL ) return( DS_ERR | DS_FAIL );
    size = map->cSegLog * sizeof( map->segdesc[0] );
    ii->mapping = DCAlloc( size );
    if( ii->mapping == NULL ) return( DS_ERR | DS_NO_MEM );
    map = VMBlock( ii, cde->lfo, cde->cb ); /* malloc might have unloaded */
    memcpy( ii->mapping, &map->segdesc[0], size );
    ii->map_count = map->cSegLog;
    return( DS_OK );
}

#if 0
static walk_result FindCompUnit( imp_image_handle *ii,
                                 hll_debug_dir *cde, void *d )
{
    cs_compile          **rec = d;

    if( cde->subsection != hll_sstModules ) return( WR_CONTINUE );
    *rec = GetCompInfo( ii, cde->iMod );
    if( *rec == NULL ) return( WR_CONTINUE );
    return( WR_STOP );
}
#endif

dip_status  DIPENTRY DIPImpLoadInfo( dig_fhandle h, imp_image_handle *ii )
{
    dip_status                  ds;
    unsigned_32                 off;
    unsigned long               size;
    hll_debug_dir               *cde;
    cv_sst_global_types_header  *hdr;

    memset( ii, 0, sizeof( *ii ) );
    ds = FindHLL( h, &off, &size );
    if( ds != DS_OK ) return( ds );
    ii->sym_file = h;
    ii->bias = off;
    ds = VMInit( ii, size );
    if( ds != DS_OK ) return( ds );
    ii->next_image = ImageList;
    ImageList = ii;
    ds = LoadDirectory( ii, off + HLL_SIG_SIZE );
    if( ds != DS_OK ) {
        DCStatus( ds );
        Cleanup( ii );
        return( ds );
    }
    ds = LoadMapping( ii );
    if( ds != DS_OK ) {
//        DCStatus( ds );
//        Cleanup( ii );
//        return( ds );
    }
    cde = FindDirEntry( ii, MH_GBL, sstGlobalTypes );
    if( cde != NULL ) {
        hdr = VMBlock( ii, cde->lfo, sizeof( *hdr ) );
        if( hdr == NULL ) {
            Cleanup( ii );
            return( DS_ERR | DS_FAIL );
        }
        ii->types_base = cde->lfo
            + offsetof( cv_sst_global_types_header, offType )
            + hdr->cType * sizeof( hdr->offType[0] );
    }
    ii->mad = MAD_X86;      /* No known non-x86 support */
    return( DS_OK );
}

void    DIPENTRY DIPImpMapInfo( imp_image_handle *ii, void *d )
{
    unsigned    i;
    addr_ptr    addr;

    for( i = 0; i < ii->map_count; ++i ) {
        addr.segment = ii->mapping[i].frame;
        addr.offset  = ii->mapping[i].offset;
        DCMapAddr( &addr, d );
        ii->mapping[i].frame  = addr.segment;
        ii->mapping[i].offset = addr.offset;
    }
}

dip_status SegIsExecutable( imp_image_handle *ii, unsigned log )
{
    seg_desc    *map;

    map = &ii->mapping[log-1];
    return( map->u.b.fExecute ? DS_OK : DS_FAIL );
}

void MapLogical( imp_image_handle *ii, address *a )
{
    seg_desc    *map;

    map = &ii->mapping[a->mach.segment-1];
    a->mach.segment = map->frame;
    a->mach.offset += map->offset;
    a->sect_id = map->ovl;
    a->indirect = 1;
}

void    DIPENTRY DIPImpUnloadInfo( imp_image_handle *ii )
{
    Cleanup( ii );
    DCClose( ii->sym_file );
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?