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 + -
显示快捷键?