dwloc.c

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

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


/*
    Location expressions, and location lists.
*/
#include <stdarg.h>
#include <stddef.h>
#include "dwpriv.h"
#include "dwutils.h"
#include "dwmem.h"
#include "dwloc.h"


typedef struct loc_op {
    struct loc_op *             next;
    uint_8                      size;
    char                        op_code;
    char                        data[1];
} loc_op;
#define BASE_SIZE               ( sizeof( loc_op ) - 1 )


struct dw_loc_id {
    loc_op *                    first;
    loc_op *                    last;
    dw_loc_label                labels;
    uint                        num_syms;       // number of DWLocStatic's
    uint_16                     addr;
};


struct dw_loc_label {
    dw_loc_label                next;
    uint_16                     addr;
};

typedef struct {
    dw_sym_handle  sym;
    dw_relocs      kind;
}dw_sym_reloc;

typedef struct list_entry {
    struct list_entry *         next;
    dw_sym_handle               begin;
    dw_sym_handle               end;
    dw_loc_handle               loc;
} list_entry;

struct dw_loc_handle {
    struct dw_loc_handle *      next;
    enum {
        LOC_EXPR,
        LOC_LIST,
        LOC_LIST_REF,
    }is_expr;
    union {
        struct loc_handle_expr {
            uint_16             size;
            uint_16             num_syms;
            char                expr[1];
        }                       expr;
        debug_ref               ref;
        list_entry *            list;

    } x;  // possible variable size so nothing can follow this
};
#define BASE_HANDLE_SIZE        offsetof( struct dw_loc_handle, x )


struct dw_list_id {
    struct dw_loc_handle        hdl;
};


dw_loc_id DWENTRY DWLocInit(
    dw_client                   cli )
{
    dw_loc_id                   new;

    new = CLIAlloc( sizeof( struct dw_loc_id ) );
    new->first = NULL;
    new->last = NULL;
    new->labels = NULL;
    new->num_syms = 0;
    new->addr = 0;
    return( new );
}


dw_loc_label DWENTRY DWLocNewLabel(
    dw_client                   cli,
    dw_loc_id                   loc )
{
    dw_loc_label                new;

    new = CarveAlloc( cli, cli->debug_loc.label_carver );
    new->next = loc->labels;
    loc->labels = new;
    new->addr = 0;

    return( new );
}


void DWENTRY DWLocSetLabel(
    dw_client                   cli,
    dw_loc_id                   loc,
    dw_loc_label                label )
{
    cli = cli;
    label->addr = loc->addr;
}


#define ADD_ADDR( cli, loc, amt )                               \
    {                                                           \
        uint_16                 __old;                          \
                                                                \
        __old = (loc)->addr;                                    \
        (loc)->addr += (amt);                                   \
        if( loc->addr < __old ) _Abort( ABORT_LOC_EXPR_TOO_LONG );\
    }


static loc_op *nextOp(
    dw_client                   cli,
    dw_loc_id                   loc,
    uint_8                      op_code,
    uint                        extra_size )
{
    loc_op *                    new;

    new = CLIAlloc( BASE_SIZE + extra_size );
    if( loc->first == NULL ) {
        loc->first = new;
        loc->last = new;
    } else {
        loc->last->next = new;
    }
    loc->last = new;
    new->size = extra_size;
    new->next = NULL;
    new->op_code = op_code;
    ADD_ADDR( cli, loc, 1 );
    return( new );
}


void DWENTRY DWLocReg(
    dw_client                   cli,
    dw_loc_id                   loc,
    uint                        reg )
{
    char                        buf[ MAX_LEB128 ];
    char *                      end;
    loc_op *                    op;

    if( reg < 32 ) {
        op = nextOp( cli, loc, DW_OP_reg( reg ), 0 );
    } else {
        end = ULEB128( buf, reg );
        op = nextOp( cli, loc, DW_OP_regx, end - buf );
        ADD_ADDR( cli, loc, end - buf );
        memcpy( op->data, buf, end - buf );
    }
}

void DWENTRY DWLocPiece(
    dw_client                   cli,
    dw_loc_id                   loc,
    uint                        size )
{
    char                        buf[ MAX_LEB128 ];
    char *                      end;
    loc_op *                    op;

    end = ULEB128( buf, size );
    op = nextOp( cli, loc, DW_OP_piece, end - buf );
    ADD_ADDR( cli, loc, end - buf );
    memcpy( op->data, buf, end - buf );
}


void DWENTRY DWLocStatic(
    dw_client                   cli,
    dw_loc_id                   loc,
    dw_sym_handle               sym )
{
    loc_op *                    op;
    dw_sym_reloc               *reloc_info;

    op = nextOp( cli, loc, DW_OP_addr, sizeof( *reloc_info ) );
    ++loc->num_syms;
    reloc_info = (dw_sym_reloc *)op->data;
    reloc_info->sym = sym;
    reloc_info->kind = DW_W_STATIC;
    ADD_ADDR( cli, loc, cli->offset_size );
}

void DWENTRY DWLocSym(
    dw_client                   cli,
    dw_loc_id                   loc,
    dw_sym_handle               sym,
    dw_relocs                   kind )
{
    loc_op *                    op;
    dw_sym_reloc               *reloc_info;

    op = nextOp( cli, loc, DW_OP_addr, sizeof( *reloc_info ) );
    ++loc->num_syms;
    reloc_info = (dw_sym_reloc *)op->data;
    reloc_info->sym = sym;
    reloc_info->kind = kind;

    if( kind == DW_W_SEGMENT
     || kind == DW_W_LABEL_SEG ){ ///TODO :better linkage
        if( cli->segment_size != 0 ){
            ADD_ADDR( cli, loc, cli->segment_size );
        }else{
            ADD_ADDR( cli, loc, sizeof( dw_defseg ) );
        }
    }else{
        ADD_ADDR( cli, loc, cli->offset_size );
    }
}

void DWENTRY DWLocSegment(
    dw_client                   cli,
    dw_loc_id                   loc,
    dw_sym_handle               sym )
{
    loc_op *                    op;
    dw_sym_reloc               *reloc_info;
    int                         segment_size;

    op = nextOp( cli, loc, DW_OP_addr, sizeof( *reloc_info ) );
    /*
        We need some way of telling DWLocStatic and DWLocSegment apart;
        so we'll stash the reloc type with the sym
    */
    ++loc->num_syms;
    reloc_info = (dw_sym_reloc *)op->data;
    reloc_info->sym = sym;
    reloc_info->kind = DW_W_SEGMENT;
    if( cli->segment_size == 0 ){  //TODO not hardwire seg size
        segment_size = sizeof( dw_defseg );
    }else{
        segment_size = cli->segment_size;
    }
    ADD_ADDR( cli, loc, segment_size ); // size of info written u2
}


void DWENTRY DWLocConstU(
    dw_client                   cli,
    dw_loc_id                   loc,
    dw_uconst                   value )
{
    char                        buf[ MAX_LEB128 ];
    char *                      end;
    loc_op *                    op;

    _Validate( loc != NULL );

    /* determine how we'll store this thing */
    if( value < 32ul ) {
        nextOp( cli, loc, DW_OP_lit( value ), 0 );
    } else if( value < 256ul ) {
        op = nextOp( cli, loc, DW_OP_const1u, 1 );
        op->data[0] = value;
        ADD_ADDR( cli, loc, 1 );
    } else if( value < 16384ul ) {
        op = nextOp( cli, loc, DW_OP_const2u, sizeof( uint_16 ) );
        WriteU16( op->data, value );
        ADD_ADDR( cli, loc, sizeof( uint_16 ) );
    } else if( value < ( 1ul << 21 ) ) {
        /* will only take 3 bytes to encode in ULEB128 form */
        end = ULEB128( buf, value );
        _Assert( end - buf == 3 );
        op = nextOp( cli, loc, DW_OP_constu, 3 );
        op->data[0] = buf[0];
        op->data[1] = buf[1];
        op->data[2] = buf[2];
        ADD_ADDR( cli, loc, 3 );
    } else {
        op = nextOp( cli, loc, DW_OP_const4u, sizeof( uint_32 ) );
        WriteU32( op->data, value );
        ADD_ADDR( cli, loc, 4 );
    }
}


void DWENTRY DWLocConstS(
    dw_client                   cli,
    dw_loc_id                   loc,
    dw_sconst                   value )
{
    char                        buf[ MAX_LEB128 ];
    char *                      end;
    loc_op *                    op;

    _Validate( loc != NULL );

    /* determine how we'll store this thing */
    if( 0 <= value && value < 32l ) {
        nextOp( cli, loc, DW_OP_lit( value ), 0 );
    } else if( -128l <= value && value < 128l ) {
        op = nextOp( cli, loc, DW_OP_const1s, 1 );
        op->data[0] = value;
        ADD_ADDR( cli, loc, 1 );
    } else if( -16384l <= value && value < 16384l ) {
        op = nextOp( cli, loc, DW_OP_const2s, sizeof( int_16 ) );
        WriteS16( op->data, value );
        op->data[0] = value;
        ADD_ADDR( cli, loc, sizeof( int_16 ) );
    } else {
        /* test length of LEB128 form before using DW_OP_const4s */
        end = LEB128( buf, value );
        if( end - buf > 4 ) {
            op = nextOp( cli, loc, DW_OP_const4s, sizeof( int_32 ) );
            WriteS32( op->data, value );
            ADD_ADDR( cli, loc, sizeof( int_32 ) );
        } else {
            op = nextOp( cli, loc, DW_OP_consts, end - buf );
            memcpy( op->data, buf, end - buf );
            ADD_ADDR( cli, loc, end - buf );
        }
    }
}


static uint_8 const translateOp[] = {
#define DW_LOC_OP( __n, __v )   __v,
#include "dwlocop.h"
#undef DW_LOC_OP
    DW_OP_bregx
};


void DWENTRY DWLocOp0(
    dw_client                   cli,
    dw_loc_id                   loc,
    uint                        user_op )
{
    _Validate( loc != NULL );
    if( user_op >= DW_LOC_max ) _Abort( ABORT_ILLEGAL_LOC_OP );
    nextOp( cli, loc, translateOp[ user_op ], 0 );
}


void DWENTRY DWLocOp(
    dw_client                   cli,
    dw_loc_id                   loc,
    uint                        user_op,
    ... )
{
    char                        buf[ 2*MAX_LEB128 ];
    char *                      end;
    uint_8                      op_code;
    loc_op *                    op;
    va_list                     args;
    uint                        reg;

    _Validate( loc != NULL );

    if( user_op >= DW_LOC_max ) _Abort( ABORT_ILLEGAL_LOC_OP );
    op_code = translateOp[ user_op ];
    va_start( args, user_op );
    switch( user_op ) {
    case DW_LOC_deref_size:
    case DW_LOC_xderef_size:
    case DW_LOC_pick:
        op = nextOp( cli, loc, op_code, 1 );
        op->data[0] = (uint_8)va_arg( args, int );
        ADD_ADDR( cli, loc, 1 );

⌨️ 快捷键说明

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