watlnum.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 654 行 · 第 1/2 页

C
654
字号
/****************************************************************************
*
*                            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!
*
****************************************************************************/


#include "dipwat.h"
#include "dbcue.h"
#include <stddef.h>
#include <string.h>

extern void             *InfoLoad(imp_image_handle *, imp_mod_handle,unsigned,unsigned,void (*)());
extern void             InfoUnlock(void);
extern void             InfoSpecUnlock(void *);
extern unsigned         InfoSize(imp_image_handle *, imp_mod_handle,unsigned int, unsigned );
extern mem_block        FindSegBlock(imp_image_handle *, imp_mod_handle,unsigned long );
extern mod_info         *ModPointer( imp_image_handle *, imp_mod_handle );
extern unsigned         PrimaryCueFile( imp_image_handle *, imp_cue_handle *, char *, unsigned );
extern void             *FindSpecCueTable( imp_image_handle *, imp_mod_handle, void ** );

extern address          NilAddr;

static void     *LinStart;
static void     *LinEnd;
static byte     V2Lines;


#define NO_LINE         ((unsigned_16)-1)

typedef union {
    v2_line_segment     v2;
    v3_line_segment     v3;
} line_segment;

#define NEXT_SEG( ptr ) (V2Lines ? ((line_segment *)&((ptr)->v2.line[(ptr)->v2.num])) \
                                 : ((line_segment *)&((ptr)->v3.line[(ptr)->v3.num])))
#define LINE_SEG( ptr ) (V2Lines ? (ptr)->v2.segment : (ptr)->v3.segment)
#define LINE_NUM( ptr ) (V2Lines ? (ptr)->v2.num : (ptr)->v3.num)
#define LINE_LINE( ptr) (V2Lines ? (ptr)->v2.line : (ptr)->v3.line)

static int  CueFind( cue_state *base, cue_idx cue, cue_state *ret )
{
    cue_state  *curr;
    long        diff;
    unsigned_16 lo;
    unsigned_16 mid;
    int         ok;
    unsigned    hi;

    if( base == NULL ) return( 0 );
    hi = *(unsigned_16*)base;
    base =  (void *)((char *)base + 2);
    cue -= PRIMARY_RANGE;
    ok = 0;
    lo = 0;
    for(;;){
        mid = (lo + hi)/2;
        curr = &base[mid];      // compare keys
        diff = (long)cue - (long)(curr->cue);
        if( mid == lo )break;
        if( diff < 0 ){       // key < mid
            hi = mid;
        }else if( diff > 0 ){ // key > mid
            lo = mid;
        }else{                // key == mid
            break;
        }
    }
    if( diff >= 0 ){
        ok = 1;
    }
    *ret = *curr;
    ret->line += diff;
    ret->fno += 2; /* 0 => no file, 1 => primary file */
    return( ok );
}

static unsigned long SpecCueLine( imp_image_handle *ii, imp_cue_handle *ic,
                                  unsigned cue_id )
{
    cue_state           info;
    unsigned long       ret;
    void                *start;
    void                *base;

    ret = 0;
    start = FindSpecCueTable( ii, ic->im, &base );
    if( start != NULL ) {
        if( CueFind( start, cue_id, &info ) ){
            ret = info.line;
        }
        InfoSpecUnlock( base );
    }
    return( ret );
}

static unsigned SpecCueFileId( imp_image_handle *ii, imp_cue_handle *ic,
                                unsigned cue_id )
{
    cue_state           info;
    unsigned long       ret;
    void                *start;
    void                *base;

    ret = 0;
    start = FindSpecCueTable( ii, ic->im, &base );
    if( start != NULL ) {
        if( CueFind( start, cue_id, &info ) ){
            ret = info.fno;
        }
        InfoSpecUnlock( base );
    }
    return( ret );
}

static unsigned SpecCueFile( imp_image_handle *ii, imp_cue_handle *ic,
                    unsigned file_id, char *buff, unsigned max )
{
    unsigned_16         size;
    unsigned_16         len;
    unsigned_16         *index;
    char                *name;
    void                *start;
    void                *base;

    len = 0;
    start = FindSpecCueTable( ii, ic->im, &base );
    if( start != NULL ) {
        size  = *(unsigned_16*)start;
        start =  (char *)start + 2;
        start =  (char *)start +  size * sizeof( cue_state );
        size  = *(unsigned_16*)start;
        start =  (char *)start + 2;
        index = start;
        name = (char *)start + size * sizeof( unsigned_16 );
        name += index[file_id-2]; /* see comment in CueFind */
        len = strlen( name );
        if( max > 0 ) {
            --max;
            if( max > len ) max = len;
            memcpy( buff, name, max );
            buff[ max ] = '\0';
        }
        InfoSpecUnlock( base );
    }
    return( len );
}


/*
 * GetLineInfo -- get the line number infomation for a module
 */

static void UnlockLine( void )
{
    if( LinStart != NULL ) {
        InfoSpecUnlock( LinStart );
        LinStart = NULL; /* so we don't unlock the same section twice */
    }
}


static dip_status GetLineInfo( imp_image_handle *ii, imp_mod_handle im,
                                 unsigned entry )
{
    if( entry != 0 ) UnlockLine();
    LinStart = InfoLoad( ii, im, DMND_LINES, entry, NULL );
    if( LinStart == NULL ) return( DS_FAIL );
    LinEnd = (byte *)LinStart + InfoSize( ii, im, DMND_LINES, entry );
    V2Lines = ii->v2;
    return( DS_OK );
}

struct search_info {
    imp_cue_handle      ic;
    unsigned            num;
    addr_off            off;
    search_result       have;
    byte                found;
    void                *special_table;
    enum { ST_UNKNOWN, ST_NO, ST_YES } have_spec_table;
};


static line_info *FindLineOff( addr_off off, addr_off adj,
                        void *start, void *end,
                        struct search_info *close, imp_image_handle *ii )
{
    line_info   *ln_ptr;
    int         low, high, target;
    addr_off    chk;
    void        *dummy;

    low = 0;
    /* get number of entries minus one */
    high = ((char *)end - (char *)start) / sizeof( line_info ) - 1;
    /* point at first entry */
    ln_ptr = start;
    while( low <= high ) {
        target = (low + high) >> 1;
        chk = ln_ptr[ target ].code_offset + adj;
        if( off < chk ) {
            high = target - 1;
        } else if( off > chk ) {
            low = target + 1;
        } else {                  /* exact match */
            if( ln_ptr[ target ].line_number >= PRIMARY_RANGE ) {
                /* a special cue - have to make sure we have the table */
                if( close->have_spec_table == ST_UNKNOWN ) {
                    if( FindSpecCueTable( ii, close->ic.im, &dummy ) != NULL ) {
                        close->have_spec_table = ST_YES;
                    } else {
                        close->have_spec_table = ST_NO;
                    }
                }
                if( close->have_spec_table == ST_YES ) {
                    return( &ln_ptr[ target ] );
                }
            } else {
                return( &ln_ptr[ target ] );
            }
            /* if it's a special & we don't have the table, ignore entry */
            high = target - 1;
        }
    }
    if( high < 0 ) return( NULL );
    if( ln_ptr[ high ].line_number >= PRIMARY_RANGE ) {
        /* a special cue - have to make sure we have the table */
        if( close->have_spec_table == ST_UNKNOWN ) {
            if( FindSpecCueTable( ii, close->ic.im, &dummy ) != NULL ) {
                close->have_spec_table = ST_YES;
            } else {
                close->have_spec_table = ST_NO;
            }
        }
        if( close->have_spec_table == ST_NO ) {
            /* if it's a special & we don't have the table, ignore entry */
            for( ;; ) {
                --high;
                if( high < 0 ) return( NULL );
                if( ln_ptr[ high ].line_number < PRIMARY_RANGE ) break;
            }
        }
    }
    return( &ln_ptr[ high ] );
}

#define BIAS( p )       ((byte *)(p) - (byte *)LinStart)
#define UNBIAS( o )     ((void *)((byte *)LinStart + (o)))

static void SearchSection( imp_image_handle *ii,
                    struct search_info *close, address addr )
{
    line_segment        *seg;
    line_segment        *next;
    line_info           *info;
    mem_block           block;

    close->found = 0;
    for( seg = LinStart; seg < LinEnd; seg = next ) {
        next = NEXT_SEG( seg );
        block = FindSegBlock( ii, close->ic.im, LINE_SEG( seg ) );
        if( DCSameAddrSpace( block.start, addr ) != DS_OK ) continue;
        if( block.start.mach.offset > addr.mach.offset ) continue;
        if( block.start.mach.offset + block.len <= addr.mach.offset ) continue;
        info = FindLineOff( addr.mach.offset, block.start.mach.offset,
                            LINE_LINE( seg ), next, close, ii );
        if( info == NULL ) continue;
        if( close->have == SR_NONE
                || info->code_offset+block.start.mach.offset>close->off ) {
            close->found = 1;
            close->ic.seg_bias = BIAS( seg );
            close->ic.info_bias = BIAS( info );
            close->off = block.start.mach.offset + info->code_offset;
            if( close->off == addr.mach.offset ) {
                close->have = SR_EXACT;
            } else {
                close->have = SR_CLOSEST;
            }
        }
    }
}

search_result DIPENTRY DIPImpAddrCue( imp_image_handle *ii, imp_mod_handle im,
                address addr, imp_cue_handle *ic )
{
    struct search_info  close;
    unsigned            save_entry;

    close.ic.im = im;
    close.have = SR_NONE;
    close.ic.entry = 0;
    close.have_spec_table = ST_UNKNOWN;
    for( ;; ) {
        if( GetLineInfo( ii, close.ic.im, close.ic.entry ) != DS_OK ) break;
        SearchSection( ii, &close, addr );
        if( close.found ) save_entry = close.ic.entry;
        if( close.have == SR_EXACT ) break;
        ++close.ic.entry;
    }
    *ic = close.ic;

⌨️ 快捷键说明

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