mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-31 12:54:13 +00:00
966 lines
23 KiB
C
966 lines
23 KiB
C
/*
|
|
* File expr.c - expression handling for Wine internal debugger.
|
|
*
|
|
* Copyright (C) 1997, Eric Youngdale.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "winbase.h"
|
|
#include "wine/winbase16.h"
|
|
#include "debugger.h"
|
|
#include "expr.h"
|
|
|
|
#include <stdarg.h>
|
|
|
|
struct expr
|
|
{
|
|
unsigned int perm;
|
|
unsigned int type:31;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
int value;
|
|
} constant;
|
|
|
|
struct
|
|
{
|
|
const char * str;
|
|
} string;
|
|
|
|
struct
|
|
{
|
|
unsigned int value;
|
|
} u_const;
|
|
|
|
struct
|
|
{
|
|
const char * name;
|
|
} symbol;
|
|
|
|
struct
|
|
{
|
|
const char * name;
|
|
} intvar;
|
|
|
|
struct
|
|
{
|
|
int unop_type;
|
|
struct expr * exp1;
|
|
int result;
|
|
} unop;
|
|
|
|
struct
|
|
{
|
|
int binop_type;
|
|
int result;
|
|
struct expr * exp1;
|
|
struct expr * exp2;
|
|
} binop;
|
|
|
|
struct
|
|
{
|
|
struct datatype * cast;
|
|
struct expr * expr;
|
|
} cast;
|
|
|
|
struct
|
|
{
|
|
struct expr * exp1;
|
|
const char * element_name;
|
|
int result;
|
|
} structure;
|
|
|
|
struct
|
|
{
|
|
struct expr * base;
|
|
struct expr * index;
|
|
} array;
|
|
|
|
struct
|
|
{
|
|
const char * funcname;
|
|
int nargs;
|
|
int result;
|
|
struct expr * arg[5];
|
|
} call;
|
|
|
|
} un;
|
|
};
|
|
|
|
#define EXPR_TYPE_CONST 0
|
|
#define EXPR_TYPE_US_CONST 1
|
|
#define EXPR_TYPE_SYMBOL 2
|
|
#define EXPR_TYPE_INTVAR 3
|
|
#define EXPR_TYPE_BINOP 4
|
|
#define EXPR_TYPE_UNOP 5
|
|
#define EXPR_TYPE_STRUCT 6
|
|
#define EXPR_TYPE_PSTRUCT 7
|
|
#define EXPR_TYPE_ARRAY 8
|
|
#define EXPR_TYPE_CALL 9
|
|
#define EXPR_TYPE_STRING 10
|
|
#define EXPR_TYPE_CAST 11
|
|
|
|
static char expr_list[4096];
|
|
static unsigned int next_expr_free = 0;
|
|
|
|
/*
|
|
* This is how we turn an expression address into the actual value.
|
|
* This works well in the 32 bit domain - not sure at all about the
|
|
* 16 bit world.
|
|
*/
|
|
#define VAL(_exp) DEBUG_GetExprValue(&_exp, NULL)
|
|
|
|
static
|
|
struct expr *
|
|
DEBUG_GetFreeExpr(void)
|
|
{
|
|
struct expr * rtn;
|
|
|
|
rtn = (struct expr *) &expr_list[next_expr_free];
|
|
|
|
next_expr_free += sizeof(struct expr);
|
|
assert(next_expr_free < sizeof(expr_list));
|
|
|
|
return rtn;
|
|
}
|
|
|
|
void
|
|
DEBUG_FreeExprMem(void)
|
|
{
|
|
next_expr_free = 0;
|
|
}
|
|
|
|
struct expr *
|
|
DEBUG_TypeCastExpr(struct datatype * dt, struct expr * exp)
|
|
{
|
|
struct expr * ex;
|
|
|
|
ex = DEBUG_GetFreeExpr();
|
|
|
|
ex->type = EXPR_TYPE_CAST;
|
|
ex->un.cast.cast = dt;
|
|
ex->un.cast.expr = exp;
|
|
return ex;
|
|
}
|
|
|
|
struct expr *
|
|
DEBUG_IntVarExpr(const char* name)
|
|
{
|
|
struct expr * ex;
|
|
|
|
ex = DEBUG_GetFreeExpr();
|
|
|
|
ex->type = EXPR_TYPE_INTVAR;
|
|
ex->un.intvar.name = name;
|
|
return ex;
|
|
}
|
|
|
|
struct expr *
|
|
DEBUG_SymbolExpr(const char * name)
|
|
{
|
|
struct expr * ex;
|
|
|
|
ex = DEBUG_GetFreeExpr();
|
|
|
|
ex->type = EXPR_TYPE_SYMBOL;
|
|
ex->un.symbol.name = name;
|
|
return ex;
|
|
}
|
|
|
|
struct expr *
|
|
DEBUG_ConstExpr(int value)
|
|
{
|
|
struct expr * ex;
|
|
|
|
ex = DEBUG_GetFreeExpr();
|
|
|
|
ex->type = EXPR_TYPE_CONST;
|
|
ex->un.constant.value = value;
|
|
return ex;
|
|
}
|
|
|
|
struct expr *
|
|
DEBUG_StringExpr(const char * str)
|
|
{
|
|
struct expr * ex;
|
|
char * pnt;
|
|
ex = DEBUG_GetFreeExpr();
|
|
|
|
ex->type = EXPR_TYPE_STRING;
|
|
ex->un.string.str = str+1;
|
|
pnt = strrchr(ex->un.string.str, '"');
|
|
if( pnt != NULL )
|
|
{
|
|
*pnt = '\0';
|
|
}
|
|
return ex;
|
|
}
|
|
|
|
struct expr *
|
|
DEBUG_USConstExpr(unsigned int value)
|
|
{
|
|
struct expr * ex;
|
|
|
|
ex = DEBUG_GetFreeExpr();
|
|
|
|
ex->type = EXPR_TYPE_CONST;
|
|
ex->un.u_const.value = value;
|
|
return ex;
|
|
}
|
|
|
|
struct expr *
|
|
DEBUG_BinopExpr(int operator_type, struct expr * exp1, struct expr * exp2)
|
|
{
|
|
struct expr * ex;
|
|
|
|
ex = DEBUG_GetFreeExpr();
|
|
|
|
ex->type = EXPR_TYPE_BINOP;
|
|
ex->un.binop.binop_type = operator_type;
|
|
ex->un.binop.exp1 = exp1;
|
|
ex->un.binop.exp2 = exp2;
|
|
return ex;
|
|
}
|
|
|
|
struct expr *
|
|
DEBUG_UnopExpr(int operator_type, struct expr * exp1)
|
|
{
|
|
struct expr * ex;
|
|
|
|
ex = DEBUG_GetFreeExpr();
|
|
|
|
ex->type = EXPR_TYPE_UNOP;
|
|
ex->un.unop.unop_type = operator_type;
|
|
ex->un.unop.exp1 = exp1;
|
|
return ex;
|
|
}
|
|
|
|
struct expr *
|
|
DEBUG_StructExpr(struct expr * exp, const char * element)
|
|
{
|
|
struct expr * ex;
|
|
|
|
ex = DEBUG_GetFreeExpr();
|
|
|
|
ex->type = EXPR_TYPE_STRUCT;
|
|
ex->un.structure.exp1 = exp;
|
|
ex->un.structure.element_name = element;
|
|
return ex;
|
|
}
|
|
|
|
struct expr *
|
|
DEBUG_StructPExpr(struct expr * exp, const char * element)
|
|
{
|
|
struct expr * ex;
|
|
|
|
ex = DEBUG_GetFreeExpr();
|
|
|
|
ex->type = EXPR_TYPE_PSTRUCT;
|
|
ex->un.structure.exp1 = exp;
|
|
ex->un.structure.element_name = element;
|
|
return ex;
|
|
}
|
|
|
|
struct expr *
|
|
DEBUG_CallExpr(const char * funcname, int nargs, ...)
|
|
{
|
|
struct expr * ex;
|
|
va_list ap;
|
|
int i;
|
|
|
|
ex = DEBUG_GetFreeExpr();
|
|
|
|
ex->type = EXPR_TYPE_CALL;
|
|
ex->un.call.funcname = funcname;
|
|
ex->un.call.nargs = nargs;
|
|
|
|
va_start(ap, nargs);
|
|
for(i=0; i < nargs; i++)
|
|
{
|
|
ex->un.call.arg[i] = va_arg(ap, struct expr *);
|
|
}
|
|
va_end(ap);
|
|
return ex;
|
|
}
|
|
|
|
DBG_VALUE DEBUG_EvalExpr(struct expr * exp)
|
|
{
|
|
DBG_VALUE rtn;
|
|
int i;
|
|
DBG_VALUE exp1;
|
|
DBG_VALUE exp2;
|
|
unsigned int cexp[5];
|
|
int scale1;
|
|
int scale2;
|
|
int scale3;
|
|
struct datatype * type1;
|
|
struct datatype * type2;
|
|
|
|
rtn.type = NULL;
|
|
rtn.cookie = DV_INVALID;
|
|
rtn.addr.off = 0;
|
|
rtn.addr.seg = 0;
|
|
|
|
switch(exp->type)
|
|
{
|
|
case EXPR_TYPE_CAST:
|
|
rtn = DEBUG_EvalExpr(exp->un.cast.expr);
|
|
rtn.type = exp->un.cast.cast;
|
|
if (!rtn.type)
|
|
{
|
|
DEBUG_Printf(DBG_CHN_MESG, "Can't cast to unknown type\n");
|
|
RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL);
|
|
}
|
|
if (DEBUG_GetType(rtn.type) == DT_POINTER)
|
|
rtn.cookie = DV_TARGET;
|
|
break;
|
|
case EXPR_TYPE_STRING:
|
|
rtn.type = DEBUG_GetBasicType(DT_BASIC_STRING);
|
|
rtn.cookie = DV_HOST;
|
|
rtn.addr.off = (unsigned int) &exp->un.string.str;
|
|
rtn.addr.seg = 0;
|
|
break;
|
|
case EXPR_TYPE_CONST:
|
|
rtn.type = DEBUG_GetBasicType(DT_BASIC_CONST_INT);
|
|
rtn.cookie = DV_HOST;
|
|
rtn.addr.off = (unsigned int) &exp->un.constant.value;
|
|
rtn.addr.seg = 0;
|
|
break;
|
|
case EXPR_TYPE_US_CONST:
|
|
rtn.type = DEBUG_GetBasicType(DT_BASIC_USHORTINT);
|
|
rtn.cookie = DV_HOST;
|
|
rtn.addr.off = (unsigned int) &exp->un.u_const.value;
|
|
rtn.addr.seg = 0;
|
|
break;
|
|
case EXPR_TYPE_SYMBOL:
|
|
switch (DEBUG_GetSymbolValue(exp->un.symbol.name, -1, &rtn, FALSE))
|
|
{
|
|
case gsv_found:
|
|
break;
|
|
case gsv_unknown:
|
|
RaiseException(DEBUG_STATUS_NO_SYMBOL, 0, 0, NULL);
|
|
/* should never be here */
|
|
case gsv_aborted:
|
|
RaiseException(DEBUG_STATUS_ABORT, 0, 0, NULL);
|
|
/* should never be here */
|
|
}
|
|
break;
|
|
case EXPR_TYPE_PSTRUCT:
|
|
exp1 = DEBUG_EvalExpr(exp->un.structure.exp1);
|
|
if( exp1.type == NULL )
|
|
{
|
|
RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL);
|
|
}
|
|
rtn.cookie = DV_TARGET;
|
|
rtn.addr.off = DEBUG_TypeDerefPointer(&exp1, &rtn.type);
|
|
if( rtn.type == NULL )
|
|
{
|
|
RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL);
|
|
}
|
|
if (!DEBUG_FindStructElement(&rtn, exp->un.structure.element_name,
|
|
&exp->un.structure.result))
|
|
{
|
|
DEBUG_Printf(DBG_CHN_MESG, "%s\n", exp->un.structure.element_name);
|
|
RaiseException(DEBUG_STATUS_NO_FIELD, 0, 0, NULL);
|
|
}
|
|
|
|
break;
|
|
case EXPR_TYPE_STRUCT:
|
|
exp1 = DEBUG_EvalExpr(exp->un.structure.exp1);
|
|
if( exp1.type == NULL )
|
|
{
|
|
RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL);
|
|
}
|
|
rtn = exp1;
|
|
if (!DEBUG_FindStructElement(&rtn, exp->un.structure.element_name,
|
|
&exp->un.structure.result))
|
|
{
|
|
DEBUG_Printf(DBG_CHN_MESG, "%s\n", exp->un.structure.element_name);
|
|
RaiseException(DEBUG_STATUS_NO_FIELD, 0, 0, NULL);
|
|
}
|
|
break;
|
|
case EXPR_TYPE_CALL:
|
|
/*
|
|
* First, evaluate all of the arguments. If any of them are not
|
|
* evaluable, then bail.
|
|
*/
|
|
for(i=0; i < exp->un.call.nargs; i++)
|
|
{
|
|
exp1 = DEBUG_EvalExpr(exp->un.call.arg[i]);
|
|
if( exp1.type == NULL )
|
|
{
|
|
return rtn;
|
|
}
|
|
cexp[i] = DEBUG_GetExprValue(&exp1, NULL);
|
|
}
|
|
|
|
/*
|
|
* Now look up the address of the function itself.
|
|
*/
|
|
switch (DEBUG_GetSymbolValue(exp->un.call.funcname, -1, &rtn, FALSE ))
|
|
{
|
|
case gsv_found:
|
|
break;
|
|
case gsv_unknown:
|
|
RaiseException(DEBUG_STATUS_NO_SYMBOL, 0, 0, NULL);
|
|
/* should never be here */
|
|
case gsv_aborted:
|
|
RaiseException(DEBUG_STATUS_ABORT, 0, 0, NULL);
|
|
/* should never be here */
|
|
}
|
|
|
|
#if 0
|
|
/* FIXME: NEWDBG NIY */
|
|
/* Anyway, I wonder how this could work depending on the calling order of
|
|
* the function (cdecl vs pascal for example)
|
|
*/
|
|
int (*fptr)();
|
|
|
|
fptr = (int (*)()) rtn.addr.off;
|
|
switch(exp->un.call.nargs)
|
|
{
|
|
case 0:
|
|
exp->un.call.result = (*fptr)();
|
|
break;
|
|
case 1:
|
|
exp->un.call.result = (*fptr)(cexp[0]);
|
|
break;
|
|
case 2:
|
|
exp->un.call.result = (*fptr)(cexp[0], cexp[1]);
|
|
break;
|
|
case 3:
|
|
exp->un.call.result = (*fptr)(cexp[0], cexp[1], cexp[2]);
|
|
break;
|
|
case 4:
|
|
exp->un.call.result = (*fptr)(cexp[0], cexp[1], cexp[2], cexp[3]);
|
|
break;
|
|
case 5:
|
|
exp->un.call.result = (*fptr)(cexp[0], cexp[1], cexp[2], cexp[3], cexp[4]);
|
|
break;
|
|
}
|
|
#else
|
|
DEBUG_Printf(DBG_CHN_MESG, "Function call no longer implemented\n");
|
|
/* would need to set up a call to this function, and then restore the current
|
|
* context afterwards...
|
|
*/
|
|
exp->un.call.result = 0;
|
|
#endif
|
|
rtn.type = DEBUG_GetBasicType(DT_BASIC_INT);
|
|
rtn.cookie = DV_HOST;
|
|
rtn.addr.off = (unsigned int) &exp->un.call.result;
|
|
|
|
break;
|
|
case EXPR_TYPE_INTVAR:
|
|
{
|
|
|
|
DBG_INTVAR* div = DEBUG_GetIntVar(exp->un.intvar.name);
|
|
|
|
if (!div) RaiseException(DEBUG_STATUS_NO_SYMBOL, 0, 0, NULL);
|
|
rtn.cookie = DV_HOST;
|
|
rtn.type = div->type;
|
|
rtn.addr.off = (unsigned int)div->pval;
|
|
/* EPP FIXME rtn.addr.seg = ?? */
|
|
}
|
|
break;
|
|
case EXPR_TYPE_BINOP:
|
|
exp1 = DEBUG_EvalExpr(exp->un.binop.exp1);
|
|
exp2 = DEBUG_EvalExpr(exp->un.binop.exp2);
|
|
rtn.cookie = DV_HOST;
|
|
if( exp1.type == NULL || exp2.type == NULL )
|
|
{
|
|
RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL);
|
|
}
|
|
if( exp1.type == DEBUG_GetBasicType(DT_BASIC_CONST_INT) &&
|
|
exp2.type == DEBUG_GetBasicType(DT_BASIC_CONST_INT) )
|
|
{
|
|
rtn.type = exp1.type;
|
|
}
|
|
else
|
|
{
|
|
rtn.type = DEBUG_GetBasicType(DT_BASIC_INT);
|
|
}
|
|
rtn.addr.seg = 0;
|
|
rtn.addr.off = (unsigned int) &exp->un.binop.result;
|
|
switch(exp->un.binop.binop_type)
|
|
{
|
|
case EXP_OP_ADD:
|
|
type1 = DEBUG_GetPointerType(exp1.type);
|
|
type2 = DEBUG_GetPointerType(exp2.type);
|
|
scale1 = 1;
|
|
scale2 = 1;
|
|
if( type1 != NULL && type2 != NULL )
|
|
{
|
|
RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL);
|
|
}
|
|
else if( type1 != NULL )
|
|
{
|
|
scale2 = DEBUG_GetObjectSize(type1);
|
|
rtn.type = exp1.type;
|
|
}
|
|
else if( type2 != NULL )
|
|
{
|
|
scale1 = DEBUG_GetObjectSize(type2);
|
|
rtn.type = exp2.type;
|
|
}
|
|
exp->un.binop.result = (VAL(exp1) * scale1 + scale2 * VAL(exp2));
|
|
break;
|
|
case EXP_OP_SUB:
|
|
type1 = DEBUG_GetPointerType(exp1.type);
|
|
type2 = DEBUG_GetPointerType(exp2.type);
|
|
scale1 = 1;
|
|
scale2 = 1;
|
|
scale3 = 1;
|
|
if( type1 != NULL && type2 != NULL )
|
|
{
|
|
if( type1 != type2 )
|
|
{
|
|
RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL);
|
|
}
|
|
scale3 = DEBUG_GetObjectSize(type1);
|
|
}
|
|
else if( type1 != NULL )
|
|
{
|
|
scale2 = DEBUG_GetObjectSize(type1);
|
|
rtn.type = exp1.type;
|
|
}
|
|
|
|
else if( type2 != NULL )
|
|
{
|
|
scale1 = DEBUG_GetObjectSize(type2);
|
|
rtn.type = exp2.type;
|
|
}
|
|
exp->un.binop.result = (VAL(exp1) - VAL(exp2)) / scale3;
|
|
break;
|
|
case EXP_OP_SEG:
|
|
rtn.cookie = DV_TARGET;
|
|
rtn.type = NULL;
|
|
rtn.addr.seg = VAL(exp1);
|
|
rtn.addr.off = VAL(exp2);
|
|
break;
|
|
case EXP_OP_LOR:
|
|
exp->un.binop.result = (VAL(exp1) || VAL(exp2));
|
|
break;
|
|
case EXP_OP_LAND:
|
|
exp->un.binop.result = (VAL(exp1) && VAL(exp2));
|
|
break;
|
|
case EXP_OP_OR:
|
|
exp->un.binop.result = (VAL(exp1) | VAL(exp2));
|
|
break;
|
|
case EXP_OP_AND:
|
|
exp->un.binop.result = (VAL(exp1) & VAL(exp2));
|
|
break;
|
|
case EXP_OP_XOR:
|
|
exp->un.binop.result = (VAL(exp1) ^ VAL(exp2));
|
|
break;
|
|
case EXP_OP_EQ:
|
|
exp->un.binop.result = (VAL(exp1) == VAL(exp2));
|
|
break;
|
|
case EXP_OP_GT:
|
|
exp->un.binop.result = (VAL(exp1) > VAL(exp2));
|
|
break;
|
|
case EXP_OP_LT:
|
|
exp->un.binop.result = (VAL(exp1) < VAL(exp2));
|
|
break;
|
|
case EXP_OP_GE:
|
|
exp->un.binop.result = (VAL(exp1) >= VAL(exp2));
|
|
break;
|
|
case EXP_OP_LE:
|
|
exp->un.binop.result = (VAL(exp1) <= VAL(exp2));
|
|
break;
|
|
case EXP_OP_NE:
|
|
exp->un.binop.result = (VAL(exp1) != VAL(exp2));
|
|
break;
|
|
case EXP_OP_SHL:
|
|
exp->un.binop.result = ((unsigned) VAL(exp1) << VAL(exp2));
|
|
break;
|
|
case EXP_OP_SHR:
|
|
exp->un.binop.result = ((unsigned) VAL(exp1) >> VAL(exp2));
|
|
break;
|
|
case EXP_OP_MUL:
|
|
exp->un.binop.result = (VAL(exp1) * VAL(exp2));
|
|
break;
|
|
case EXP_OP_DIV:
|
|
if( VAL(exp2) == 0 )
|
|
{
|
|
RaiseException(DEBUG_STATUS_DIV_BY_ZERO, 0, 0, NULL);
|
|
}
|
|
exp->un.binop.result = (VAL(exp1) / VAL(exp2));
|
|
break;
|
|
case EXP_OP_REM:
|
|
if( VAL(exp2) == 0 )
|
|
{
|
|
RaiseException(DEBUG_STATUS_DIV_BY_ZERO, 0, 0, NULL);
|
|
}
|
|
exp->un.binop.result = (VAL(exp1) % VAL(exp2));
|
|
break;
|
|
case EXP_OP_ARR:
|
|
DEBUG_ArrayIndex(&exp1, &rtn, VAL(exp2));
|
|
break;
|
|
default:
|
|
RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
|
|
break;
|
|
}
|
|
break;
|
|
case EXPR_TYPE_UNOP:
|
|
exp1 = DEBUG_EvalExpr(exp->un.unop.exp1);
|
|
rtn.cookie = DV_HOST;
|
|
if( exp1.type == NULL )
|
|
{
|
|
RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL);
|
|
}
|
|
rtn.addr.seg = 0;
|
|
rtn.addr.off = (unsigned int) &exp->un.unop.result;
|
|
if( exp1.type == DEBUG_GetBasicType(DT_BASIC_CONST_INT) )
|
|
{
|
|
rtn.type = exp1.type;
|
|
}
|
|
else
|
|
{
|
|
rtn.type = DEBUG_GetBasicType(DT_BASIC_INT);
|
|
}
|
|
switch(exp->un.unop.unop_type)
|
|
{
|
|
case EXP_OP_NEG:
|
|
exp->un.unop.result = -VAL(exp1);
|
|
break;
|
|
case EXP_OP_NOT:
|
|
exp->un.unop.result = !VAL(exp1);
|
|
break;
|
|
case EXP_OP_LNOT:
|
|
exp->un.unop.result = ~VAL(exp1);
|
|
break;
|
|
case EXP_OP_DEREF:
|
|
/* FIXME: this is currently buggy.
|
|
* there is no way to tell were the deref:ed value is...
|
|
* for example:
|
|
* x is a pointer to struct s, x being on the stack
|
|
* => exp1 is target, result is target
|
|
* x is a pointer to struct s, x being optimized into a reg
|
|
* => exp1 is host, result is target
|
|
* x is a pointer to internal variable x
|
|
* => exp1 is host, result is host
|
|
* so we force DV_TARGET, because dereferencing pointers to
|
|
* internal variables is very unlikely. a correct fix would be
|
|
* rather large.
|
|
*/
|
|
rtn.cookie = DV_TARGET;
|
|
rtn.addr.off = (unsigned int) DEBUG_TypeDerefPointer(&exp1, &rtn.type);
|
|
if (!rtn.type)
|
|
{
|
|
RaiseException(DEBUG_STATUS_BAD_TYPE, 0, 0, NULL);
|
|
}
|
|
break;
|
|
case EXP_OP_FORCE_DEREF:
|
|
rtn.cookie = exp1.cookie;
|
|
rtn.addr.seg = exp1.addr.seg;
|
|
if (exp1.cookie == DV_TARGET)
|
|
DEBUG_READ_MEM((void*)exp1.addr.off, &rtn.addr.off, sizeof(rtn.addr.off));
|
|
else
|
|
memcpy(&rtn.addr.off, (void*)exp1.addr.off, sizeof(rtn.addr.off));
|
|
break;
|
|
case EXP_OP_ADDR:
|
|
/* FIXME: even for a 16 bit entity ? */
|
|
rtn.type = DEBUG_FindOrMakePointerType(exp1.type);
|
|
exp->un.unop.result = exp1.addr.off;
|
|
break;
|
|
default:
|
|
RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
|
|
}
|
|
break;
|
|
default:
|
|
DEBUG_Printf(DBG_CHN_MESG,"Unexpected expression (%d).\n", exp->type);
|
|
RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
|
|
break;
|
|
}
|
|
|
|
assert(rtn.cookie == DV_TARGET || rtn.cookie == DV_HOST);
|
|
|
|
return rtn;
|
|
}
|
|
|
|
|
|
int
|
|
DEBUG_DisplayExpr(const struct expr * exp)
|
|
{
|
|
int i;
|
|
|
|
switch(exp->type)
|
|
{
|
|
case EXPR_TYPE_CAST:
|
|
DEBUG_Printf(DBG_CHN_MESG, "((");
|
|
DEBUG_PrintTypeCast(exp->un.cast.cast);
|
|
DEBUG_Printf(DBG_CHN_MESG, ")");
|
|
DEBUG_DisplayExpr(exp->un.cast.expr);
|
|
DEBUG_Printf(DBG_CHN_MESG, ")");
|
|
break;
|
|
case EXPR_TYPE_INTVAR:
|
|
DEBUG_Printf(DBG_CHN_MESG, "$%s", exp->un.intvar.name);
|
|
break;
|
|
case EXPR_TYPE_US_CONST:
|
|
DEBUG_Printf(DBG_CHN_MESG, "%ud", exp->un.u_const.value);
|
|
break;
|
|
case EXPR_TYPE_CONST:
|
|
DEBUG_Printf(DBG_CHN_MESG, "%d", exp->un.u_const.value);
|
|
break;
|
|
case EXPR_TYPE_STRING:
|
|
DEBUG_Printf(DBG_CHN_MESG, "\"%s\"", exp->un.string.str);
|
|
break;
|
|
case EXPR_TYPE_SYMBOL:
|
|
DEBUG_Printf(DBG_CHN_MESG, "%s" , exp->un.symbol.name);
|
|
break;
|
|
case EXPR_TYPE_PSTRUCT:
|
|
DEBUG_DisplayExpr(exp->un.structure.exp1);
|
|
DEBUG_Printf(DBG_CHN_MESG, "->%s", exp->un.structure.element_name);
|
|
break;
|
|
case EXPR_TYPE_STRUCT:
|
|
DEBUG_DisplayExpr(exp->un.structure.exp1);
|
|
DEBUG_Printf(DBG_CHN_MESG, ".%s", exp->un.structure.element_name);
|
|
break;
|
|
case EXPR_TYPE_CALL:
|
|
DEBUG_Printf(DBG_CHN_MESG, "%s(",exp->un.call.funcname);
|
|
for(i=0; i < exp->un.call.nargs; i++)
|
|
{
|
|
DEBUG_DisplayExpr(exp->un.call.arg[i]);
|
|
if( i != exp->un.call.nargs - 1 )
|
|
{
|
|
DEBUG_Printf(DBG_CHN_MESG, ", ");
|
|
}
|
|
}
|
|
DEBUG_Printf(DBG_CHN_MESG, ")");
|
|
break;
|
|
case EXPR_TYPE_BINOP:
|
|
DEBUG_Printf(DBG_CHN_MESG, "( ");
|
|
DEBUG_DisplayExpr(exp->un.binop.exp1);
|
|
switch(exp->un.binop.binop_type)
|
|
{
|
|
case EXP_OP_ADD:
|
|
DEBUG_Printf(DBG_CHN_MESG, " + ");
|
|
break;
|
|
case EXP_OP_SUB:
|
|
DEBUG_Printf(DBG_CHN_MESG, " - ");
|
|
break;
|
|
case EXP_OP_SEG:
|
|
DEBUG_Printf(DBG_CHN_MESG, ":");
|
|
break;
|
|
case EXP_OP_LOR:
|
|
DEBUG_Printf(DBG_CHN_MESG, " || ");
|
|
break;
|
|
case EXP_OP_LAND:
|
|
DEBUG_Printf(DBG_CHN_MESG, " && ");
|
|
break;
|
|
case EXP_OP_OR:
|
|
DEBUG_Printf(DBG_CHN_MESG, " | ");
|
|
break;
|
|
case EXP_OP_AND:
|
|
DEBUG_Printf(DBG_CHN_MESG, " & ");
|
|
break;
|
|
case EXP_OP_XOR:
|
|
DEBUG_Printf(DBG_CHN_MESG, " ^ ");
|
|
break;
|
|
case EXP_OP_EQ:
|
|
DEBUG_Printf(DBG_CHN_MESG, " == ");
|
|
break;
|
|
case EXP_OP_GT:
|
|
DEBUG_Printf(DBG_CHN_MESG, " > ");
|
|
break;
|
|
case EXP_OP_LT:
|
|
DEBUG_Printf(DBG_CHN_MESG, " < ");
|
|
break;
|
|
case EXP_OP_GE:
|
|
DEBUG_Printf(DBG_CHN_MESG, " >= ");
|
|
break;
|
|
case EXP_OP_LE:
|
|
DEBUG_Printf(DBG_CHN_MESG, " <= ");
|
|
break;
|
|
case EXP_OP_NE:
|
|
DEBUG_Printf(DBG_CHN_MESG, " != ");
|
|
break;
|
|
case EXP_OP_SHL:
|
|
DEBUG_Printf(DBG_CHN_MESG, " << ");
|
|
break;
|
|
case EXP_OP_SHR:
|
|
DEBUG_Printf(DBG_CHN_MESG, " >> ");
|
|
break;
|
|
case EXP_OP_MUL:
|
|
DEBUG_Printf(DBG_CHN_MESG, " * ");
|
|
break;
|
|
case EXP_OP_DIV:
|
|
DEBUG_Printf(DBG_CHN_MESG, " / ");
|
|
break;
|
|
case EXP_OP_REM:
|
|
DEBUG_Printf(DBG_CHN_MESG, " %% ");
|
|
break;
|
|
case EXP_OP_ARR:
|
|
DEBUG_Printf(DBG_CHN_MESG, "[");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
DEBUG_DisplayExpr(exp->un.binop.exp2);
|
|
if( exp->un.binop.binop_type == EXP_OP_ARR )
|
|
{
|
|
DEBUG_Printf(DBG_CHN_MESG, "]");
|
|
}
|
|
DEBUG_Printf(DBG_CHN_MESG, " )");
|
|
break;
|
|
case EXPR_TYPE_UNOP:
|
|
switch(exp->un.unop.unop_type)
|
|
{
|
|
case EXP_OP_NEG:
|
|
DEBUG_Printf(DBG_CHN_MESG, "-");
|
|
break;
|
|
case EXP_OP_NOT:
|
|
DEBUG_Printf(DBG_CHN_MESG, "!");
|
|
break;
|
|
case EXP_OP_LNOT:
|
|
DEBUG_Printf(DBG_CHN_MESG, "~");
|
|
break;
|
|
case EXP_OP_DEREF:
|
|
DEBUG_Printf(DBG_CHN_MESG, "*");
|
|
break;
|
|
case EXP_OP_ADDR:
|
|
DEBUG_Printf(DBG_CHN_MESG, "&");
|
|
break;
|
|
}
|
|
DEBUG_DisplayExpr(exp->un.unop.exp1);
|
|
break;
|
|
default:
|
|
DEBUG_Printf(DBG_CHN_MESG,"Unexpected expression.\n");
|
|
RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
struct expr *
|
|
DEBUG_CloneExpr(const struct expr * exp)
|
|
{
|
|
int i;
|
|
struct expr * rtn;
|
|
|
|
rtn = (struct expr *) DBG_alloc(sizeof(struct expr));
|
|
|
|
/*
|
|
* First copy the contents of the expression itself.
|
|
*/
|
|
*rtn = *exp;
|
|
|
|
|
|
switch(exp->type)
|
|
{
|
|
case EXPR_TYPE_CAST:
|
|
rtn->un.cast.expr = DEBUG_CloneExpr(exp->un.cast.expr);
|
|
break;
|
|
case EXPR_TYPE_INTVAR:
|
|
rtn->un.intvar.name = DBG_strdup(exp->un.intvar.name);
|
|
break;
|
|
case EXPR_TYPE_US_CONST:
|
|
case EXPR_TYPE_CONST:
|
|
break;
|
|
case EXPR_TYPE_STRING:
|
|
rtn->un.string.str = DBG_strdup(exp->un.string.str);
|
|
break;
|
|
case EXPR_TYPE_SYMBOL:
|
|
rtn->un.symbol.name = DBG_strdup(exp->un.symbol.name);
|
|
break;
|
|
case EXPR_TYPE_PSTRUCT:
|
|
case EXPR_TYPE_STRUCT:
|
|
rtn->un.structure.exp1 = DEBUG_CloneExpr(exp->un.structure.exp1);
|
|
rtn->un.structure.element_name = DBG_strdup(exp->un.structure.element_name);
|
|
break;
|
|
case EXPR_TYPE_CALL:
|
|
for(i=0; i < exp->un.call.nargs; i++)
|
|
{
|
|
rtn->un.call.arg[i] = DEBUG_CloneExpr(exp->un.call.arg[i]);
|
|
}
|
|
rtn->un.call.funcname = DBG_strdup(exp->un.call.funcname);
|
|
break;
|
|
case EXPR_TYPE_BINOP:
|
|
rtn->un.binop.exp1 = DEBUG_CloneExpr(exp->un.binop.exp1);
|
|
rtn->un.binop.exp2 = DEBUG_CloneExpr(exp->un.binop.exp2);
|
|
break;
|
|
case EXPR_TYPE_UNOP:
|
|
rtn->un.unop.exp1 = DEBUG_CloneExpr(exp->un.unop.exp1);
|
|
break;
|
|
default:
|
|
DEBUG_Printf(DBG_CHN_MESG,"Unexpected expression.\n");
|
|
RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
|
|
break;
|
|
}
|
|
|
|
return rtn;
|
|
}
|
|
|
|
|
|
/*
|
|
* Recursively go through an expression tree and free all memory associated
|
|
* with it.
|
|
*/
|
|
int
|
|
DEBUG_FreeExpr(struct expr * exp)
|
|
{
|
|
int i;
|
|
|
|
switch(exp->type)
|
|
{
|
|
case EXPR_TYPE_CAST:
|
|
DEBUG_FreeExpr(exp->un.cast.expr);
|
|
break;
|
|
case EXPR_TYPE_INTVAR:
|
|
DBG_free((char *) exp->un.intvar.name);
|
|
break;
|
|
case EXPR_TYPE_US_CONST:
|
|
case EXPR_TYPE_CONST:
|
|
break;
|
|
case EXPR_TYPE_STRING:
|
|
DBG_free((char *) exp->un.string.str);
|
|
break;
|
|
case EXPR_TYPE_SYMBOL:
|
|
DBG_free((char *) exp->un.symbol.name);
|
|
break;
|
|
case EXPR_TYPE_PSTRUCT:
|
|
case EXPR_TYPE_STRUCT:
|
|
DEBUG_FreeExpr(exp->un.structure.exp1);
|
|
DBG_free((char *) exp->un.structure.element_name);
|
|
break;
|
|
case EXPR_TYPE_CALL:
|
|
for(i=0; i < exp->un.call.nargs; i++)
|
|
{
|
|
DEBUG_FreeExpr(exp->un.call.arg[i]);
|
|
}
|
|
DBG_free((char *) exp->un.call.funcname);
|
|
break;
|
|
case EXPR_TYPE_BINOP:
|
|
DEBUG_FreeExpr(exp->un.binop.exp1);
|
|
DEBUG_FreeExpr(exp->un.binop.exp2);
|
|
break;
|
|
case EXPR_TYPE_UNOP:
|
|
DEBUG_FreeExpr(exp->un.unop.exp1);
|
|
break;
|
|
default:
|
|
DEBUG_Printf(DBG_CHN_MESG,"Unexpected expression.\n");
|
|
RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
|
|
break;
|
|
}
|
|
|
|
DBG_free(exp);
|
|
return TRUE;
|
|
}
|