1
0
Files
irix-657m-src/irix/cmd/icrash_old/lib/libeval/eval.c
2022-09-29 17:59:04 +03:00

3798 lines
78 KiB
C

#ident "$Header: /proj/irix6.5.7m/isms/irix/cmd/icrash_old/lib/libeval/RCS/eval.c,v 1.1 1999/05/25 19:19:20 tjm Exp $"
#define _KERNEL 1
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/param.h>
#include <libelf.h>
#include <dwarf.h>
#include <libdwarf.h>
#include <syms.h>
#include <sym.h>
#include "icrash.h"
#include "extern.h"
#include "eval.h"
#include "variable.h"
#include "dwarflib.h"
/* Global variables
*/
static int logical_flag;
/* The base_type[] array is necessary because base types are not
* directly accessible from the Dwarf database. Three of the entries
* have to be modified at startup if the vmcore image is from a
* 32-bit system. They are the entries for "long", "signed long",
* and "unsigned long". On a 32-bit core dump, these types take up
* four bytes. On a 64-bit system, they take up eight bytes.
*/
base_t base_type[] = {
/*---------------------------------------------------------*/
/* NAME ACTUAL_NAME BYTE_SIZE ENCODING */
/*---------------------------------------------------------*/
{ "char", (char *)0, 1, 6 },
{ "signed char", "char", 1, 6 },
{ "unsigned char", (char *)0, 1, 8 },
{ "short", (char *)0, 2, 5 },
{ "signed short", "short", 2, 5 },
{ "unsigned short", (char *)0, 2, 7 },
{ "int", (char *)0, 4, 5 },
{ "signed int", "int", 4, 5 },
{ "signed", "int", 4, 5 },
{ "unsigned int", (char *)0, 4, 7 },
{ "unsigned", "unsigned int", 4, 7 },
{ "long", (char *)0, 8, 5 },
{ "signed long", "long", 8, 5 },
{ "unsigned long", (char *)0, 8, 7 },
{ "long long", (char *)0, 8, 5 },
{ "signed long long", "long long", 8, 5 },
{ "unsigned long long", (char *)0, 8, 7 },
{ (char *)0, (char *)0, 0, 0 }
};
/*
* get_base_type()
*/
base_t *
get_base_type(char *s)
{
int i, count, blank_count = 0, len, gap = 0;
char *ptr, *first, *last, *gapp = 0, *cp, typename[128] = "";
strcat (typename, s);
ptr = typename;
len = strlen(typename);
/* Strip off any leading "white space" (spaces and tabs)
*/
while ((*ptr == ' ') || (*ptr == '\t')) {
blank_count++;
ptr++;
}
len -= blank_count;
bcopy (ptr, typename, len);
typename[len] = 0;
/* Compress any "white space" between words.
*/
ptr = typename;
blank_count = 0;
while (*ptr && (*ptr != '*')) {
if ((*ptr == ' ') || (*ptr == '\t')) {
cp = ptr + 1;
blank_count = 0;
while ((*cp == ' ') || (*cp == '\t')) {
blank_count++;
cp++;
}
if ((cp - ptr) > 1) {
bcopy(cp, ptr + 1, len - (cp - typename));
len -= blank_count;
}
}
ptr++;
}
*ptr = 0;
for (i = 0; base_type[i].name; i++) {
if (!strcmp(typename, base_type[i].name)) {
break;
}
}
if (base_type[i].name) {
return(&base_type[i]);
}
else {
return((base_t*)NULL);
}
}
/*
* base_typestr()
*/
char *
base_typestr(type_t *tp, int flags)
{
int i, len = 0, ptrcnt = 0;
type_t *t;
base_t *btp;
char *tsp, *c;
t = tp;
while (t->flag == POINTER_FLAG) {
ptrcnt++;
t = t->t_next;
}
btp = (base_t *)t->t_ptr;
if (btp->actual_name) {
len = strlen(btp->actual_name) + ptrcnt + 3;
}
else {
len = strlen(btp->name) + ptrcnt + 3;
}
tsp = (char *)ALLOC_BLOCK(len, flags);
c = tsp;
*c++ = '(';
if (btp->actual_name) {
strcat(c, btp->actual_name);
c += strlen(btp->actual_name);
}
else {
strcat(c, btp->name);
c += strlen(btp->name);
}
for (i = 0; i < ptrcnt; i++) {
*c++ = '*';
}
*c++ = ')';
*c = 0;
return(tsp);
}
/*
* get_type() -- Convert a typecast string into a type.
*
* Returns a pointer to a struct containing type information (dwarf,
* base, etc.) The type of struct returned is indicated by the
* contents of type. If the typecast contains an asterisk, set
* ptr_type equal to one, otherwise set it equal to zero.
*/
type_t *
get_type(char *s, int flags)
{
static int symtable_type = -1;
int len, type = 0;
char *cp, typename[128];
base_t *bp;
type_t *t, *head, *last;
dw_type_t *dtp;
dw_type_info_t *dti;
head = last = (type_t *)NULL;
if (symtable_type < 0) {
symtable_type = DWARF_TYPE_FLAG;
}
if (!strncmp(s, "struct", 6)) {
if (cp = strpbrk(s + 7, " \t*")) {
len = cp - (s + 7);
}
else {
len = strlen(s + 7);
}
bcopy (s + 7, typename, len);
typename[len] = 0;
if (symtable_type == DWARF_TYPE_FLAG) {
if (!(dtp = dw_lkup(stp, typename, DW_TAG_structure_type))) {
return ((type_t *)NULL);
}
type = DWARF_TYPE_FLAG;
}
}
else if (!strncmp(s, "union", 5)) {
if (cp = strpbrk(s + 6, " \t*")) {
len = cp - (s + 6);
}
else {
len = strlen(s + 6);
}
bcopy (s + 6, typename, len);
typename[len] = 0;
if (symtable_type == DWARF_TYPE_FLAG) {
if (!(dtp = dw_lkup(stp, typename, DW_TAG_union_type))) {
return ((type_t *)NULL);
}
type = DWARF_TYPE_FLAG;
}
}
else if (bp = get_base_type(s)) {
type = BASE_TYPE_FLAG;
}
else {
/* Check to see if this is a typedef
*/
if (cp = strpbrk(s, " \t*)")) {
len = cp - s;
}
else {
len = strlen(s);
}
bcopy (s, typename, len);
typename[len] = 0;
if (symtable_type == DWARF_TYPE_FLAG) {
if (!(dtp = dw_lkup(stp, typename, DW_TAG_typedef))) {
return ((type_t *)NULL);
}
type = DWARF_TYPE_FLAG;
}
}
/* check to see if this cast is a pointer to a type (or a pointer
* to a pointer to a type, etc.)
*/
cp = s;
while (cp = strpbrk(cp, "*")) {
t = (type_t *)ALLOC_BLOCK(sizeof(type_t), flags);
t->flag = POINTER_FLAG;
if (last) {
last->t_next = t;
last = t;
}
else {
head = last = t;
}
cp++;
}
/* Allocate a type block that will point to the type specific
* (BASE or DWARF) record
*/
t = (type_t *)ALLOC_BLOCK(sizeof(type_t), flags);
t->flag = type;
switch (t->flag) {
case BASE_TYPE_FLAG :
t->t_ptr = (void *)bp;
break;
case DWARF_TYPE_FLAG :
dti = (dw_type_info_t *)ALLOC_BLOCK(sizeof(*dti), flags);
if (!dw_type_info(dtp->dt_off, dti, flags)) {
return((type_t*)NULL);
}
t->t_ptr = (void *)dti;
break;
default :
free_type(head);
return((type_t*)NULL);
}
if (last) {
last->t_next = t;
}
else {
head = t;
}
return(head);
}
/*
* free_type()
*/
void
free_type(type_t *head)
{
type_t *t0, *t1;
t0 = head;
while(t0) {
if (t0->flag == POINTER_FLAG) {
t1 = t0->t_next;
free_block((k_ptr_t)t0);
t0 = t1;
}
else {
if (is_temp_block(t0->t_ptr)) {
if (t0->flag == DWARF_TYPE_FLAG) {
dw_free_type_info((dw_type_info_t*)t0->t_ptr);
}
else {
free_block((k_ptr_t)t0->t_ptr);
}
}
free_block((k_ptr_t)t0);
t0 = (type_t *)NULL;
}
}
}
/*
* member_to_type() -- Converts a struct/union member to a type
*
* With dwarf members, all DW_TAG_pointer dies are converted to
* type_t structs with POINTER_FLAG set. The original dw_type_info_t
* struct pointer is linked to the t_link field -- since it contains
* information necessary for the dowhatis() command.
*/
type_t *
member_to_type(void *x, int ntype, int flags)
{
dw_die_t *dp;
dw_type_info_t *t, *dti;
type_t *tp, *head = (type_t *)NULL, *last = (type_t *)NULL;
if (ntype == DWARF_TYPE_FLAG) {
t = (dw_type_info_t *)x;
/* Make sure this is a DW_TAG_member
*/
if (t->t_tag != DW_TAG_member) {
return((type_t *)NULL);
}
dp = t->t_actual_type;
while (dp && dp->d_tag == DW_TAG_pointer_type) {
tp = (type_t *)ALLOC_BLOCK(sizeof(type_t), flags);
tp->flag = POINTER_FLAG;
if (last) {
last->t_next = tp;
last = tp;
}
else {
head = last = tp;
}
dp = dp->d_next;
}
/* If We step past all the pointer dies and don't point at anything,
* this must be a void pointer. Setup a VOID type struct so that we
* can maintain a pointer to the type info in dw_type_info_t struct.
*/
if (!dp) {
tp = (type_t *)ALLOC_BLOCK(sizeof(type_t), flags);
tp->flag = VOID_FLAG;
tp->t_ptr = t;
if (last) {
last->t_next = tp;
last = tp;
}
else {
head = last = tp;
}
return(head);
}
dti = (dw_type_info_t *)ALLOC_BLOCK(sizeof(*dti), flags);
switch (dp->d_tag) {
case DW_TAG_structure_type :
/* Check to see if this die points to the struct
* members. If not, we need to search for the actual
* struct definition.
*/
if (!dp->d_sibling_off) {
dw_type_t *dtp;
if (!(dtp = dw_lkup(stp, dp->d_name,
DW_TAG_structure_type))) {
/* Information is not available for this
* struct. Make the actual type be dp. It's
* better to have something rather than
* nothing.
*/
t->t_actual_type = t->t_type;
tp = (type_t *)ALLOC_BLOCK(sizeof(type_t), flags);
tp->flag = DWARF_TYPE_FLAG;
tp->t_ptr = (void *)t;
if (last) {
last->t_next = tp;
}
else {
head = tp;
}
return(head);
}
if (!dw_type_info(dtp->dt_off, dti, flags)) {
return((type_t *)NULL);
}
}
else {
if (!dw_type_info(dp->d_off, dti, flags)) {
return((type_t *)NULL);
}
}
break;
case DW_TAG_union_type :
/* Check to see if this die points to the union
* members. If not, we need to search for the actual
* union definition.
*/
if (!dp->d_sibling_off) {
dw_type_t *dtp;
if (!(dtp = dw_lkup(stp,
dp->d_name, DW_TAG_union_type))) {
/* Information is not available for this
* union. Make the actual type be dp. It's
* better to have something rather than
* nothing.
*/
t->t_actual_type = t->t_type;
tp = (type_t *)ALLOC_BLOCK(sizeof(type_t), flags);
tp->flag = DWARF_TYPE_FLAG;
tp->t_ptr = (void *)t;
if (last) {
last->t_next = tp;
}
else {
head = tp;
}
return(head);
}
if (!dw_type_info(dtp->dt_off, dti, flags)) {
return((type_t *)NULL);
}
}
else {
if (!dw_type_info(dp->d_off, dti, flags)) {
return((type_t *)NULL);
}
}
break;
default :
if (!dw_type_info(dp->d_off, dti, flags)) {
return((type_t *)NULL);
}
break;
}
/* Check to see if the real type is a DW_TAG_base_type. If it is,
* then check to see if t_bit_offset and/or t_bit_size are set in
* the original dw_type_info_s struct. If they are, copy the values
* over to dti.
*/
if (dti->t_tag == DW_TAG_base_type) {
if (t->t_bit_offset) {
dti->t_bit_offset = t->t_bit_offset;
}
if (t->t_bit_size) {
dti->t_bit_size = t->t_bit_size;
}
dti->t_byte_size = t->t_byte_size;
}
/* Save the pointer to the info about the actual member (for
* use by dowhatis() )
*/
dti->t_link = t;
tp = (type_t *)ALLOC_BLOCK(sizeof(type_t), flags);
tp->flag = DWARF_TYPE_FLAG;
tp->t_ptr = (void *)dti;
if (last) {
last->t_next = tp;
}
else {
head = tp;
}
return(head);
}
return((type_t *)NULL);
}
/*
* is_keyword()
*/
int
is_keyword(char *c, int len)
{
/* This is temporary. Really need to lookup string to see if
* it is a type or typedef.
*/
if (!strncmp(c, "struct", len)) {
return(1);
}
else if (!strncmp(c, "union", len)) {
return(1);
}
else if (!strncmp(c, "char", len)) {
return(1);
}
else if (!strncmp(c, "short", len)) {
return(1);
}
else if (!strncmp(c, "int", len)) {
return(1);
}
else if (!strncmp(c, "long", len)) {
return(1);
}
else if (!strncmp(c, "unsigned", len)) {
return(1);
}
else if (!strncmp(c, "signed", len)) {
return(1);
}
else {
char *c1;
c1 = (char*)alloc_block(len+1, B_TEMP);
strncat(c1, c, len);
c1[len] = 0;
switch (symbol_table) {
case DWARF_TYPE_FLAG:
if (dw_lkup(stp, c1, DW_TAG_typedef)) {
free_block((k_ptr_t)c1);
return(1);
}
break;
}
free_block((k_ptr_t)c1);
}
return(0);
}
/*
* expand_variables()
*/
char *
expand_variables(char *exp, int flags)
{
int len;
char vname[64], *s, *e, *v, *newexp;
variable_t *vp;
newexp = (char *)ALLOC_BLOCK(256, flags);
e = exp;
v = strchr(e, '$');
while (v) {
vname[0] = 0;
strncat(newexp, e, (v - e));
if (s = strpbrk((v + 1), " .\t+-*/()[]|~!$&%^<>?:&=^\"\'")) {
len = (uint)s - (uint)v + 1;
}
else {
len = strlen(v) + 1;
}
strncpy(vname, v, len);
vname[len -1] = 0;
vp = find_variable(vtab, vname, V_TYPEDEF|V_STRING);
if (!vp) {
return((char *)NULL);
}
/* If this is a typedef, then make sure the typestr is between
* an open and close parenthesis. Otherwise, just include the
* string.
*/
if (vp->v_flags & V_TYPEDEF) {
strcat(newexp, "(");
strcat(newexp, vp->v_typestr);
strcat(newexp, ")");
}
else {
strcat(newexp, vp->v_exp);
}
if (e = s) {
v = strchr(e, '$');;
}
else {
v = (char *)NULL;
}
}
if (e) {
strcat(newexp, e);
}
return(newexp);
}
/*
* get_token_list()
*/
token_t *
get_token_list(char *str, int *error)
{
int i, paren_count = 0;
char *cp;
token_t *tok, *tok_head = (token_t*)NULL, *tok_last = (token_t*)NULL;
cp = str;
*error = 0;
while (*cp) {
/* Skip past any "white space" (spaces and tabs).
*/
switch (*cp) {
case ' ' :
case '\t' :
case '`' :
cp++;
continue;
case '\'' :
break;
case '\"' :
break;
default :
break;
}
/* Allocate space for the next token
*/
tok = (token_t *)alloc_block(sizeof(token_t), B_TEMP);
tok->ptr = cp;
switch(*cp) {
/* Check for operators
*/
case '+' :
if (*((char*)cp + 1) == '+') {
/* We aren't doing asignment here, so the ++ operator
* is not considered valid.
*/
*error = E_BAD_OPERATOR;
return (tok_last);
}
else if (!tok_last ||
(tok_last->operator && (tok_last->operator != CLOSE_PAREN))) {
tok->operator = UNARY_PLUS;
}
else {
tok->operator = ADD;
}
break;
case '-' :
if (*((char*)cp + 1) == '-') {
/* We aren't doing asignment here, so the -- operator
* is not considered valid.
*/
*error = E_BAD_OPERATOR;
return (tok_last);
}
else if (*((char*)cp + 1) == '>') {
tok->operator = RIGHT_ARROW;
cp++;
}
else if (!tok_last ||
(tok_last->operator && (tok_last->operator != CLOSE_PAREN))) {
tok->operator = UNARY_MINUS;
}
else {
tok->operator = SUBTRACT;
}
break;
case '.' :
/* XXX - need to check to see if this is a decimal point
* in the middle fo a floating point value.
*/
tok->operator = DOT;
break;
case '*' :
/* XXX - need a better way to tell if this is an INDIRECTION.
* perhaps check the next token?
*/
if (!tok_last ||
(tok_last->operator && ((tok_last->operator != CLOSE_PAREN) &&
(tok_last->operator != CAST)))) {
tok->operator = INDIRECTION;
}
else {
tok->operator = MULTIPLY;
}
break;
case '/' :
tok->operator = DIVIDE;
break;
case '%' :
tok->operator = MODULUS;
break;
case '(' : {
char *s;
int len;
/* Make sure the previous token is an operator
*/
if (tok_last && !tok_last->operator) {
*error = E_SYNTAX_ERROR;
return (tok_last);
}
if (tok_last && ((tok_last->operator == RIGHT_ARROW) ||
(tok_last->operator == DOT))) {
*error = E_SYNTAX_ERROR;
return (tok_last);
}
/* Check here to see if following tokens constitute a cast.
*/
/* Skip past any "white space" (spaces and tabs)
*/
while ((*(cp+1) == ' ') || (*(cp+1) == '\t')) {
cp++;
}
if ((*(cp+1) == '(') || (*(cp+1) == '*') || (*(cp+1) == ')')){
tok->operator = OPEN_PAREN;
paren_count++;
break;
}
if (s = strpbrk(cp+1, " *)")) {
len = (uint)s - (uint)(cp+1);
if (is_keyword((char*)((uint)(cp+1)), len)) {
if (!(s = strpbrk((cp+1), ")"))) {
*error = E_OPEN_PAREN;
return (tok);
}
len = (uint)s - (uint)(cp+1);
tok->string = (char *)alloc_block(len + 1, B_TEMP);
bcopy((cp+1), tok->string, len);
tok->string[len] = 0;
tok->operator = CAST;
cp = (char *)((uint)(cp+1) + len);
break;
}
}
tok->operator = OPEN_PAREN;
paren_count++;
break;
}
case ')' :
if (tok_last && ((tok_last->operator == RIGHT_ARROW) ||
(tok_last->operator == DOT))) {
*error = E_SYNTAX_ERROR;
return (tok_last);
}
tok->operator = CLOSE_PAREN;
paren_count--;
break;
case '&' :
if (*((char*)cp + 1) == '&') {
tok->operator = LOGICAL_AND;
cp++;
}
else if (!tok_last || (tok_last &&
(tok_last->operator &&
tok_last->operator != CLOSE_PAREN))) {
tok->operator = ADDRESS;
}
else {
tok->operator = BITWISE_AND;
}
break;
case '|' :
if (*((char*)cp + 1) == '|') {
tok->operator = LOGICAL_OR;
cp++;
}
else {
tok->operator = BITWISE_OR;
}
break;
case '=' :
if (*((char*)cp + 1) == '=') {
tok->operator = EQUAL;
cp++;
}
else {
/* ASIGNMENT -- NOT IMPLEMENTED
*/
tok->operator = NOT_YET;
}
break;
case '<' :
if (*((char*)cp + 1) == '<') {
tok->operator = LEFT_SHIFT;
cp++;
}
else if (*((char*)cp + 1) == '=') {
tok->operator = LESS_THAN_OR_EQUAL;
cp++;
}
else {
tok->operator = LESS_THAN;
}
break;
case '>' :
if (*((char*)(cp + 1)) == '>') {
tok->operator = RIGHT_SHIFT;
cp++;
}
else if (*((char*)cp + 1) == '=') {
tok->operator = GREATER_THAN_OR_EQUAL;
cp++;
}
else {
tok->operator = GREATER_THAN;
}
break;
case '!' :
if (*((char*)cp + 1) == '=') {
tok->operator = NOT_EQUAL;
cp++;
}
else {
tok->operator = LOGICAL_NEGATION;
}
break;
case '$' : {
int e, len;
char *s, *vname;
variable_t *vp;
token_t *t;
if (s = strpbrk((cp + 1), " .\t+-*/()[]|~!$&%^<>?:&=^\"\'")) {
len = (uint)s - (uint)cp + 1;
}
else {
len = strlen(cp) + 1;
}
vname = (char *)alloc_block(len, B_TEMP);
memcpy(vname, cp, (len -1));
vname[len - 1] = 0;
vp = find_variable(vtab, vname, 0);
if (!vp || (vp->v_flags & V_COMMAND)) {
*error = E_BAD_EVAR;
free_block((k_ptr_t)vname);
return(tok);
}
if (vp->v_flags & V_TYPEDEF) {
free_block((k_ptr_t)vname);
free_tokens(tok);
t = get_token_list(vp->v_typestr, &e);
if (!tok_head) {
tok_head = tok_last = t;
}
else {
tok_last->next = t;
while (t->next) {
t = t->next;
}
tok_last = t;
}
if (cp = s) {
continue;
}
else {
return(tok_head);
}
}
else if (vp->v_flags & V_STRING) {
if (tok_head) {
*error = E_END_EXPECTED;
return(tok);
}
/* Skip ahead to the first non-blank character
*/
while (s && (*s == ' ')) {
s++;
}
if (s && (*s != 0)) {
*error = E_END_EXPECTED;
tok->ptr = s;
return(tok);
}
tok->string =
(char *)alloc_block(strlen(vp->v_exp) + 1, B_TEMP);
/* We have to copy the string so that it doesn't
* get freed when the token is freed.
*/
strcpy(tok->string, vp->v_exp);
tok->type = TEXT;
return(tok);
}
}
case '~' :
tok->operator = ONES_COMPLEMENT;
break;
case '^' :
tok->operator = BITWISE_EXCLUSIVE_OR;
break;
case '?' :
tok->operator = CONDITIONAL;
break;
case ':' :
tok->operator = CONDITIONAL_ELSE;
break;
case '[' :
tok->operator = OPEN_SQUARE_BRACKET;;
break;
case ']' :
tok->operator = CLOSE_SQUARE_BRACKET;;
break;
default: {
char *s;
int len;
/* Check and see if this token is a STRING or CHARACTER
* type (begins with a single or double quote).
*/
if ((*cp == '\'') || (*cp == '\"')) {
/* Make sure we don't already have any tokens.
*/
if (tok_head) {
*error = E_END_EXPECTED;
return(tok);
}
switch (*cp) {
case '\'' :
s = strpbrk((cp + 1), "\'");
if (!s) {
*error = E_BAD_STRING;
return(tok);
}
len = (uint)s - (uint)cp;
if (len == 2) {
tok->type = CHARACTER;
}
else {
tok->type = TEXT;
}
break;
case '\"' :
s = strpbrk((cp + 1), "\"");
if (!s) {
*error = E_BAD_STRING;
return(tok);
}
len = (uint)s - (uint)cp;
tok->type = TEXT;
break;
}
if (strlen(cp) > (len + 1)) {
/* Check to see if there is a colon or
* semi-colon directly following the
* string. If there is, then the string
* is OK (the following characters are part
* of the next expression). Also, it's OK
* to have trailing blanks as long as that's
* all threre is.
*/
char *c;
c = s + 1;
while (*c) {
if ((*c == ',') || (*c == ';')) {
break;
}
else if (*c != ' ') {
*error = E_END_EXPECTED;
tok->ptr = c;
return(tok);
}
c++;
}
/* Truncate the trailing blanks (they are not part
* of the string).
*/
if (c != (s + 1)) {
*(s + 1) = 0;
}
}
tok->string = (char *)alloc_block(len, B_TEMP);
bcopy((cp + 1), tok->string, len - 1);
tok->string[len - 1] = 0;
return(tok);
}
if (s = strpbrk(cp, " .\t+-*/()[]|~!$&%^<>?:&=^\"\'")) {
len = (uint)s - (uint)cp + 1;
}
else {
len = strlen(cp) + 1;
}
tok->string = (char *)alloc_block(len, B_TEMP);
bcopy(cp, tok->string, len - 1);
tok->string[len - 1] = 0;
cp = (char *)((uint)cp + len - 2);
/* Check to see if this is the keyword "sizeof." If not,
* then check to see if the string is a member name.
*/
if (!strcmp(tok->string, "sizeof")) {
tok->operator = SIZEOF;
free_block((k_ptr_t)tok->string);
tok->string = 0;
}
else if (tok_last && ((tok_last->operator == RIGHT_ARROW) ||
(tok_last->operator == DOT))) {
tok->type = MEMBER;
}
else {
tok->type = STRING;
}
break;
}
}
if (!(tok->type)) {
tok->type = OPERATOR;
}
if (!tok_head) {
tok_head = tok_last = tok;
}
else {
tok_last->next = tok;
tok_last = tok;
}
cp++;
}
if (paren_count < 0) {
*error = E_CLOSE_PAREN;
return(tok);
}
else if (paren_count > 0) {
*error = E_OPEN_PAREN;
return(tok);
}
if (DEBUG(DC_EVAL, 1)) {
token_t *t;
fprintf(KL_ERRORFP, " TOKEN OPERATOR PTR "
"STRING NEXT\n");
fprintf(KL_ERRORFP, "--------------------------------------------------"
"----------------\n");
t = tok_head;
while(t) {
fprintf(KL_ERRORFP, "%8x %8d %8x %26s %8x\n",
t, t->operator, t->ptr, t->string, t->next);
t = t->next;
}
fprintf(KL_ERRORFP, "--------------------------------------------------"
"----------------\n");
}
return(tok_head);
}
/*
* is_unary()
*/
int
is_unary(int op)
{
switch (op) {
case LOGICAL_NEGATION :
case ADDRESS :
case INDIRECTION :
case UNARY_MINUS :
case UNARY_PLUS :
case ONES_COMPLEMENT :
case CAST :
return(1);
default :
return(0);
}
}
/*
* is_binary()
*/
int
is_binary(int op)
{
switch (op) {
case BITWISE_OR :
case BITWISE_EXCLUSIVE_OR :
case BITWISE_AND :
case RIGHT_SHIFT :
case LEFT_SHIFT :
case ADD :
case SUBTRACT :
case MULTIPLY :
case DIVIDE :
case MODULUS :
case LOGICAL_OR :
case LOGICAL_AND :
case EQUAL :
case NOT_EQUAL :
case LESS_THAN :
case GREATER_THAN :
case LESS_THAN_OR_EQUAL :
case GREATER_THAN_OR_EQUAL :
case RIGHT_ARROW :
case DOT :
return(1);
default :
return(0);
}
}
/*
* precedence()
*/
int
precedence(int a)
{
if ((a >= CONDITIONAL) && (a <= CONDITIONAL_ELSE)) {
return(1);
}
else if (a == LOGICAL_OR) {
return(2);
}
else if (a == LOGICAL_AND) {
return(3);
}
else if (a == BITWISE_OR) {
return(4);
}
else if (a == BITWISE_EXCLUSIVE_OR) {
return(5);
}
else if (a == BITWISE_AND) {
return(6);
}
else if ((a >= EQUAL) && (a <= NOT_EQUAL)) {
return(7);
}
else if ((a >= LESS_THAN) && (a <= GREATER_THAN_OR_EQUAL)) {
return(8);
}
else if ((a >= RIGHT_SHIFT) && (a <= LEFT_SHIFT)) {
return(9);
}
else if ((a >= ADD) && (a <= SUBTRACT)) {
return(10);
}
else if ((a >= MULTIPLY) && (a <= MODULUS)) {
return(11);
}
else if ((a >= LOGICAL_NEGATION) && (a <= SIZEOF)) {
return(12);
}
else if ((a >= RIGHT_ARROW) && (a <= DOT)) {
return(13);
}
else {
return(0);
}
}
/*
* make_node()
*/
node_t *
make_node(token_t *t, int flags)
{
node_t *np;
struct syment *sp;
symdef_t *sdp;
np = (node_t*)ALLOC_BLOCK(sizeof(*np), flags);
if (t->type == OPERATOR) {
/* Check to see if this token represents a typecast
*/
if (t->operator == CAST) {
type_t *tp;
if (!(np->type = get_type(t->string, flags))) {
free_nodes(np);
return((node_t*)NULL);
}
np->node_type = OPERATOR;
np->operator = CAST;
/* Determin whether or not this is a pointer to a type
* and the type class (base or dwarf).
*/
tp = np->type;
if (tp->flag == POINTER_FLAG) {
np->flags = POINTER_FLAG;
tp = tp->t_next;
while (tp->flag == POINTER_FLAG) {
tp = tp->t_next;
}
}
switch(tp->flag) {
case BASE_TYPE_FLAG:
np->flags |= BASE_TYPE_FLAG;
break;
case DWARF_TYPE_FLAG:
np->flags |= DWARF_TYPE_FLAG;
break;
default:
free_nodes(np);
return((node_t*)NULL);
}
}
else {
np->node_type = OPERATOR;
np->operator = t->operator;
}
}
else if (t->type == MEMBER) {
np->name = (char *)dup_block((k_ptr_t)t->string, B_TEMP);
np->node_type = MEMBER;
}
else if (t->type == STRING) {
if ((sp = get_sym(t->string, B_TEMP)) && !(flags & C_NOVARS)) {
np->address = sp->n_value;
np->flags |= ADDRESS_FLAG;
np->name = t->string;
t->string = (char*)NULL;
np->node_type = VARIABLE;
/* Need to make a call to sym_lkup() to see if there
* is type information available for this variable.
*
* XXX - The symdef_s struct actually overlays dw_type_s
* struct. In that struct is the die offset of the variable.
* If type information is available for this variable, then
* we need to follow this path (check the variable die, then
* the type, etc.) Not sure if there are any functions that
* will do this right now (get_type() takes a type name --
* something that we don't have yet).
*/
sdp = sym_lkup(stp, np->name);
free_sym(sp);
/* XXX - For now, addtach a type struct for type long (it will
* be the size of a kernel pointer). That will at least let us
* do something and will prevent the scenario where we have a
* type node with out a pointer to a type struct! This needs
* to be replaced with code to handle actual variable types.
*/
np->type = alloc_block(sizeof(type_t), flags);
np->type->flag = POINTER_FLAG;
np->type->t_ptr = get_type("long", flags);
np->node_type = TYPE_DEF;
np->flags |= POINTER_FLAG;
kl_get_block(K, np->address, K_NBPW(K),
&np->value, "pointer value");
if (!PTRSZ64(K)) {
np->value >>= 32;
}
}
else if (flags & (C_WHATIS|C_SIZEOF)) {
switch (symbol_table) {
case DWARF_TYPE_FLAG : {
dw_type_t *dtp;
/* Check and see if this is a struct name
*/
dtp = dw_lkup(stp, t->string, DW_TAG_structure_type);
if (!dtp) {
/* Check to see if this is a union name
*/
dtp = dw_lkup(stp, t->string, DW_TAG_union_type);
}
if (!dtp) {
/* Check to see if this is a typedef name
*/
dtp = dw_lkup(stp, t->string, DW_TAG_typedef);
}
if (dtp) {
/* If struct, union or typedef
*/
dw_type_info_t *dti;
dti =
(dw_type_info_t*)ALLOC_BLOCK(sizeof(*dti), flags);
dw_type_info(dtp->dt_off, dti, flags);
np->node_type = TYPE_DEF;
np->flags = DWARF_TYPE_FLAG;
np->type = (type_t*)alloc_block(sizeof(type_t), B_TEMP);
np->type->flag = DWARF_TYPE_FLAG;
np->type->t_ptr = dti;
}
else if (sp) {
np->address = sp->n_value;
np->flags |= ADDRESS_FLAG;
np->name = t->string;
t->string = (char*)NULL;
np->node_type = VARIABLE;
free_sym(sp);
}
else {
if (GET_VALUE(t->string, &np->value)) {
free_nodes(np);
return((node_t*)NULL);
}
np->node_type = NUMBER;
}
return(np);
}
}
}
else {
if (GET_VALUE(t->string, &np->value)) {
free_nodes(np);
return((node_t*)NULL);
}
np->node_type = NUMBER;
}
}
else if ((t->type == TEXT) || (t->type == CHARACTER)) {
np->node_type = t->type;
np->name = t->string;
t->string = (char*)NULL; /* So the block doesn't get freed twice */
}
else {
/* ERROR! */
}
np->tok_ptr = t->ptr;
return(np);
}
/*
* get_node()
*/
node_t *
get_node(token_t **tpp, int flags)
{
node_t *n;
n = make_node(*tpp, flags);
*tpp = (*tpp)->next;
return(n);
}
/*
* add_node()
*/
int
add_node(node_t *root, node_t *new_node)
{
node_t *n = root;
/* Find the most lower-right node
*/
while (n->right) {
n = n->right;
}
/* If the node we found is a leaf node, return an error (we will
* have to insert the node instead).
*/
if (n->node_type == NUMBER) {
return(-1);
}
else {
n->right = new_node;
}
return(0);
}
/*
* add_rchild()
*/
int
add_rchild(node_t *root, node_t *new_node)
{
if (add_node(root, new_node) == -1) {
return(-1);
}
return(0);
}
/*
* add_lchild()
*/
int
add_lchild(node_t *root, node_t *new_node)
{
node_t *n = root;
/* Find the most lower-left node and make sure it is not a leaf
* (child) node.
*/
while (n->left) {
n = n->left;
}
/* If the node we found is a leaf node, return an error.
*/
if (n->node_type == NUMBER) {
return(-1);
}
else {
n->left = new_node;
}
return(0);
}
/*
* node_to_typestr()
*
* Return a type string based on contents of node. The string is
* allocated as B_TEMP or B_PERM depending on the contents of flags.
*
*/
char *
node_to_typestr(node_t *np, int flags)
{
char *tsp = (char *)NULL;
type_t *t;
/* Determine if this is a Dwarf type or base type. Determine this
* by walking pointer chain until we get to the type-specific struct.
* However, pass a pointer to the entire chain on to the typestr
* routine.
*/
if (np->flags & DWARF_TYPE_FLAG) {
tsp = dw_typestr(np->type, flags);
}
else if (np->flags & BASE_TYPE_FLAG) {
tsp = base_typestr(np->type, flags);
}
else {
/* Assume the value is an int.
*/
tsp = (char *)ALLOC_BLOCK(6, flags);
strcpy(tsp, "(int)");
}
return(tsp);
}
/*
* free_tokens()
*/
void
free_tokens(token_t *tp)
{
token_t *t, *tnext;
t = tp;
while (t) {
tnext = t->next;
if (t->string) {
free_block((k_ptr_t)t->string);
}
free_block((k_ptr_t)t);
t = tnext;
}
}
/*
* free_nodes()
*/
void
free_nodes(node_t *np)
{
type_t *tp, *tnext;
node_t *q;
/* If there is nothing to free, just return.
*/
if (!np) {
return;
}
if (q = np->left) {
free_nodes(q);
}
if (q = np->right) {
free_nodes(q);
}
if (np->name) {
free_block((k_ptr_t)np->name);
}
free_type(np->type);
free_block((k_ptr_t)np);
}
/*
* get_sizeof()
*/
node_t *
get_sizeof(token_t **tpp, int *error)
{
int size;
node_t *n0;
/* The next token should be either a CAST or an OPEN_PAREN. If it's
* something else, then return with an error.
*/
if ((*tpp)->type == OPERATOR) {
if ((*tpp)->operator == OPEN_PAREN) {
n0 = do_eval(tpp, C_SIZEOF, error);
if (*error) {
return(n0);
}
}
else if ((*tpp)->operator == CAST) {
if (!(n0 = get_node(tpp, C_SIZEOF))) {
*error = E_SYNTAX_ERROR;
return((node_t*)NULL);
}
}
else {
*error = E_BAD_TYPE;
return(n0);
}
if (!n0->type) {
*error = E_NOTYPE;
return(n0);
}
if (n0->type->flag & POINTER_TYPE) {
n0->value = K_NBPW(K);
}
else if (n0->type->flag & DWARF_TYPE_FLAG) {
dw_type_info_t *dp = n0->type->t_ptr;
n0->value = dp->t_byte_size;
}
else if (n0->type->flag & BASE_TYPE_FLAG) {
base_t *bp = n0->type->t_ptr;
n0->value = bp->byte_size;
}
else {
*error = E_BAD_TYPE;
return(n0);
}
n0->node_type = NUMBER;
n0->flags = 0;
n0->operator = 0;
n0->byte_size = 0;
n0->address = 0;
if (n0->type) {
free_type(n0->type);
n0->type = 0;
}
}
return(n0);
}
/*
* do_eval() -- Reduces an equation to a single value.
*
* Any parenthesis (and nested parenthesis) within the equation will
* be solved first via a recursive call to do_eval().
*/
node_t *
do_eval(token_t **tpp, int flags, int *error)
{
node_t *root = (node_t*)NULL, *n0, *n1;
/* Loop through the tokens until we run out of tokens or we hit
* a CLOSE_PAREN. If we hit an OPEN_PAREN, make a recursive call
* to do_eval().
*/
while (*tpp) {
n0 = n1 = (node_t *)NULL;
/* Check for an OPEN_PAREN token
*/
if ((*tpp)->operator == OPEN_PAREN) {
/* skip over the OPEN_PAREN token
*/
*tpp = (*tpp)->next;
/* Get the value contained within the parenthesis. If there
* was an error, just return.
*/
n0 = do_eval(tpp, flags, error);
if (*error) {
free_nodes(root);
return(n0);
}
/* If CLOSE_PAREN was the last token, we are at the end of
* the token list. In that case, just return n0 (which should
* contain the result). Otherwise, just fall through and see
* what the next operator is (so that we can determine the
* proper location for this operand in the parse tree).
*
* Or, if do_eval() was called from get_sizeof(), then we
* need to return also (even if there are aditional tokens.
*/
if (!*tpp || (flags & C_SIZEOF)) {
if (root) {
add_rchild(root, n0);
}
else {
root = n0;
}
return(root);
}
}
else if ((*tpp)->operator == SIZEOF) {
/* skip over the SIZEOF token
*/
*tpp = (*tpp)->next;
n0 = get_sizeof(tpp, error);
if (*error) {
free_nodes(root);
return(n0);
}
}
else if (((*tpp)->operator == CLOSE_PAREN) ||
((*tpp)->operator == CLOSE_SQUARE_BRACKET)) {
/* Reduce the resulting tree to a single value
*/
replace(root, error, flags);
/* Advance the token pointer past the CLOSE_PAREN or
* CLOSE_SQUARE_BRACKET and then return.
*/
*tpp = (*tpp)->next;
return(root);
}
/* If we don't already have a token loaded into n0, get one
* now.
*/
if (!n0) {
if (!(n0 = get_node(tpp, flags))) {
*error = E_SYNTAX_ERROR;
return((node_t*)NULL);
}
}
if (n0->node_type == OPERATOR) {
if (is_unary(n0->operator)) {
int do_eval_call = 0;
if (n0->operator == INDIRECTION) {
/* Make a recursive call to do_eval() and then
* take the resulting value and link it in as
* the right child node (after making sure that
* no error occurred).
*/
do_eval_call++;
n1 = do_eval(tpp, flags, error);
if (*error) {
/* Free nodes, if there are any
*/
free_nodes(root);
free_nodes(n0);
return(n1);
}
}
else if (n0->operator == CAST) {
if (!*tpp) {
*error = E_SYNTAX_ERROR;
}
else if (((*tpp)->type == TYPE_DEF) ||
((*tpp)->type == OPERATOR) ||
((*tpp)->type == VARIABLE)) {
if ((*tpp)->operator == CLOSE_PAREN) {
/* Step over the CLOSE_PAREN and return
*/
*tpp = (*tpp)->next;
return(n0);
}
do_eval_call++;
n1 = do_eval(tpp, flags, error);
}
else if (!(n1 = get_node(tpp, flags))) {
*error = E_SYNTAX_ERROR;
}
if (*error) {
free_nodes(root);
return(n0);
}
}
else if (n0->operator == ADDRESS) {
if (!*tpp) {
*error = E_SYNTAX_ERROR;
}
else if (((*tpp)->operator == OPEN_PAREN) ||
((*tpp)->next &&
(((*tpp)->next->operator == RIGHT_ARROW) ||
((*tpp)->next->operator == DOT)))) {
do_eval_call++;
n1 = do_eval(tpp, flags, error);
}
else if (!(n1 = get_node(tpp, flags))) {
*error = E_SYNTAX_ERROR;
}
if (*error) {
free_nodes(root);
return(n0);
}
}
else if (*tpp && ((*tpp)->operator == OPEN_PAREN)) {
/* skip over the OPEN_PAREN token
*/
*tpp = (*tpp)->next;
/* Get the value contained within the parenthesis. If
* there was an error, just return.
*/
n1 = do_eval(tpp, flags, error);
if (*error) {
free_nodes(root);
free_nodes(n0);
return(n1);
}
}
else {
if ((*tpp == (token_t*)NULL) ||
!(n1 = get_node(tpp, flags))){
*error = E_SYNTAX_ERROR;
free_nodes(root);
return(n0);
}
}
n0->right = n1;
/* Check for nested unary operators
*/
while (is_unary(n1->operator)) {
node_t *n2 = (node_t *)NULL;
/* If there aren't any more tokens, return an
* error (there are none to match up with the
* unary operator).
*/
if (!(*tpp) || !(n2 = get_node(tpp, flags))) {
*error = E_SYNTAX_ERROR;
return(n1);
}
n1->right = n2;
n1 = n2;
}
if (replace_unary(n0, error, flags) == -1) {
if (n0->right) {
free_block((k_ptr_t)n0->right);
n0->right = (node_t *)NULL;
}
if (*error == 0) {
*error = E_SYNTAX_ERROR;
}
return(n0);
}
if (do_eval_call) {
if (!root) {
root = n0;
}
else {
add_rchild(root, n0);
}
if (!replace(root, error, flags)) {
if (!(*error)) {
*error = E_SYNTAX_ERROR;
}
}
return(root);
}
}
else {
/* ERROR? */
}
}
/* n0 should now contain a non-operator node. Check to see if
* there is a next token. If there isn't, just add the last
* rchild and return.
*/
if (!*tpp) {
if (!root) {
root = n0;
}
else {
add_rchild(root, n0);
}
if (!replace(root, error, flags)) {
if (!(*error)) {
*error = E_SYNTAX_ERROR;
}
}
return(root);
}
/* Make sure the next token is an operator.
*/
if (!(*tpp)->operator) {
free_nodes(root);
free_nodes(n0);
n1 = get_node(tpp, flags);
*error = E_SYNTAX_ERROR;
return(n1);
}
else if (((*tpp)->operator == CLOSE_PAREN) ||
((*tpp)->operator == CLOSE_SQUARE_BRACKET)) {
if (root) {
add_rchild(root, n0);
}
else {
root = n0;
}
/* Reduce the resulting tree to a single value
*/
if (!replace(root, error, flags)) {
if (!(*error)) {
*error = E_SYNTAX_ERROR;
}
return(root);
}
/* Advance the token pointer past the CLOSE_PAREN and then
* return.
*/
*tpp = (*tpp)->next;
return(root);
}
else if ((*tpp)->operator == OPEN_SQUARE_BRACKET) {
/* skip over the OPEN_SQUARE_BRACKET token
*/
*tpp = (*tpp)->next;
/* Get the value contained within the brackets. This
* value must represent an array index.
*/
n1 = get_array_index(tpp, error);
if (*error) {
free_nodes(root);
free_nodes(n0);
return(n1);
}
/* Convert the array (or pointer type) to an element type
* using the index value obtained above. Make sure that
* n0 contains some sort of type definition first, however.
*/
if (n0->node_type != TYPE_DEF) {
*error = E_BAD_TYPE;
free_nodes(n1);
return(n0);
}
array_to_element(n0, n1, error);
if (*error) {
free_nodes(n0);
return(n1);
}
free_nodes(n1);
/* If there aren't any more tokens, just
* return.
*/
if (!(*tpp)) {
return(n0);
}
}
else if (!is_binary((*tpp)->operator)) {
free_nodes(root);
n1 = get_node(tpp, flags);
*error = E_SYNTAX_ERROR;
return(n1);
}
/* Now get the operator node
*/
if (!(n1 = get_node(tpp, flags))) {
*error = E_SYNTAX_ERROR;
return((node_t*)NULL);
}
/* Check to see if this binary operator is RIGHT_ARROW or DOT.
* If it is, we need to reduce it to a single value node now.
*/
while ((n1->operator == RIGHT_ARROW) || (n1->operator == DOT)) {
/* The next node must contain the name of the struct|union
* member.
*/
if (!*tpp || ((*tpp)->type != MEMBER)) {
if (root) {
free_nodes(root);
}
free_nodes(n0);
*error = E_BAD_MEMBER;
return(n1);
}
n1->left = n0;
/* Now get the next node and link it as the right child.
*/
if (!(n0 = get_node(tpp, flags))) {
*error = E_SYNTAX_ERROR;
return((node_t*)NULL);
}
n1->right = n0;
if (!(n0 = replace(n1, error, flags))) {
if (!(*error)) {
*error = E_SYNTAX_ERROR;
}
return(n1);
};
/* Check to see if there is a next token. If there is, check
* to see if it is the operator CLOSE_PAREN. If it is, then
* return (skipping over the CLOSE_PAREN first).
*/
if ((*tpp && (*tpp)->operator == CLOSE_PAREN) ||
(*tpp && (*tpp)->operator == CLOSE_SQUARE_BRACKET)) {
if (root) {
add_rchild(root, n0);
}
else {
root = n0;
}
/* Reduce the resulting tree to a single value
*/
replace(root, error, flags);
/* Advance the token pointer past the CLOSE_PAREN and then
* return.
*/
*tpp = (*tpp)->next;
return(root);
}
/* Check to see if the next node is an OPEN_SQUARE_BRACKET.
* If it is, then we have to reduce the contents of the square
* brackets to an index array.
*/
if (*tpp && (*tpp)->operator == OPEN_SQUARE_BRACKET) {
/* Advance the token pointer and call do_eval() again.
*/
*tpp = (*tpp)->next;
n1 = get_array_index(tpp, error);
if (*error) {
free_nodes(root);
free_nodes(n0);
return(n1);
}
/* Convert the array (or pointer type) to an element type
* using the index value obtained above. Make sure that
* n0 contains some sort of type definition first, however.
*/
if (n0->node_type != TYPE_DEF) {
*error = E_BAD_TYPE;
free_nodes(n1);
return(n0);
}
array_to_element(n0, n1, error);
if (*error) {
free_nodes(n0);
return(n1);
}
free_nodes(n1);
}
/* Now get the next operator node (if there is one).
*/
if (!*tpp || !(n1 = get_node(tpp, flags))) {
if (root) {
add_rchild(root, n0);
}
else {
root = n0;
}
return(root);
}
}
if (!root) {
root = n1;
n1->left = n0;
}
else if (precedence(root->operator) >= precedence(n1->operator)) {
add_rchild(root, n0);
n1->left = root;
root = n1;
}
else {
if (!root->right) {
n1->left = n0;
root->right = n1;
}
else {
add_rchild(root, n0);
n1->left = root->right;
root->right = n1;
}
}
} /* while(*tpp) */
return(root);
}
/*
* get_array_index()
*
*/
node_t *
get_array_index(token_t **tpp, int *error)
{
int size, shft;
k_uint_t index;
node_t *n0;
dw_type_info_t *dp;
n0 = do_eval(tpp, 0, error);
if (*error) {
return(n0);
}
if (n0->node_type != NUMBER) {
if (n0->node_type == TYPE_DEF) {
if (n0->type->flag != DWARF_TYPE_FLAG) {
*error = E_BAD_INDEX;
}
else {
dp = n0->type->t_ptr;
if (dp->t_tag == DW_TAG_base_type) {
size = dp->t_byte_size;
kl_get_block(K, n0->address, size, &index, "index");
if (shft = (8 - size)) {
index = index >> (shft * 8);
}
n0->value = index;
n0->address = 0;
free_type(n0->type);
n0->type = 0;
n0->flags = 0;
}
else {
*error = E_BAD_INDEX;
}
}
}
else {
*error = E_BAD_INDEX;
}
}
n0->node_type = INDEX;
return(n0);
}
/*
* replace_cast()
*/
int
replace_cast(node_t *n, int *error, int flags)
{
int type;
k_uint_t value;
type_t *t;
if (!n || !n->right) {
*error = E_SYNTAX_ERROR;
return(-1);
}
if (n->flags & POINTER_FLAG) {
if (n->right->node_type == VADDR) {
if (n->right->flags & ADDRESS_FLAG) {
n->value = n->right->address;
}
else {
*error = E_SYNTAX_ERROR;
return(-1);
}
}
else if (n->right->node_type == VARIABLE) {
/* Replace a VARIABLE node with a TYPE_DEF node if possible.
* Return if there was an error.
*/
replace_variable(n->right, error, flags);
if (*error) {
return(-1);
}
/* Check and see if the attempt to determine this variable's
* type failed. We know that's the case when the NOTYPE_FLAG
* is set. If the ADDRESS_FLAG is also set, we can continue
* (using the address value in the cast). Otherwise, we have
* to return an error.
*/
if (n->right->flags & NOTYPE_FLAG) {
if (n->right->flags & ADDRESS_FLAG) {
n->value = n->right->address;
}
else {
*error = E_SYNTAX_ERROR;
return(-1);
}
}
else {
n->value = n->right->value;
}
}
else {
n->value = n->right->value;
}
n->node_type = TYPE_DEF;
n->operator = 0;
free_nodes(n->right);
n->right = (node_t *)NULL;
return(0);
}
if (!(t = eval_type(n))) {
*error = E_BAD_TYPE;
return(-1);
}
/* If we don't have a pointer and we're a dwarf type AND
* we don't point to a base type, return error.
*/
if (!(n->flags & POINTER_FLAG)) {
if (n->flags & DWARF_TYPE_FLAG) {
dw_type_info_t *atp = (dw_type_info_t*)n->type->t_ptr;
if (atp->t_actual_type->d_tag != DW_TAG_base_type) {
*error = E_BAD_TYPE;
return(-1);
}
}
else if (!(n->flags & BASE_TYPE_FLAG)) {
*error = E_BAD_TYPE;
return(-1);
}
}
if (t->flag & DWARF_TYPE_FLAG) {
if (n->right->node_type == TYPE_DEF) {
n->value = n->right->value;
}
else if (n->right->node_type == VARIABLE) {
/* XXX not working...
*/
n->value = n->right->address;
}
else if (n->right->node_type == NUMBER) {
n->value = n->right->value;
}
else {
*error = E_BAD_TYPE;
return(-1);
}
}
else if (t->flag & BASE_TYPE_FLAG) {
n->byte_size = ((base_t*)t->t_ptr)->byte_size;
value = n->right->value;
switch (((base_t*)t->t_ptr)->byte_size) {
case 1 :
if (((base_t*)(t->t_ptr))->encoding == 8) {
n->value = (unsigned char)value;
n->flags |= UNSIGNED_FLAG;
}
else {
n->value = (char)value;
}
break;
case 2 :
if (((base_t*)(t->t_ptr))->encoding == 7) {
n->value = (unsigned short)value;
n->flags |= UNSIGNED_FLAG;
}
else {
n->value = (short)value;
}
break;
case 4 :
if (((base_t*)(t->t_ptr))->encoding == 7) {
n->value = (unsigned int)value;
n->flags |= UNSIGNED_FLAG;
}
else {
n->value = (int)value;
}
break;
case 8 :
if (((base_t*)(t->t_ptr))->encoding == 7) {
n->value = (unsigned long long)value;
n->flags |= UNSIGNED_FLAG;
}
else {
n->value = (long long)value;
}
break;
default :
*error = E_BAD_TYPE;
return(-1);
}
}
n->node_type = TYPE_DEF;
n->operator = 0;
n->type = t;
free_block((k_ptr_t)n->right);
n->right = (node_t *)NULL;
return(0);
}
/*
* apply_unary()
*/
int
apply_unary(node_t *n, k_uint_t *value, int *error)
{
if (!n || !n->right) {
return(-1);
}
switch (n->operator) {
case UNARY_MINUS :
*value = (0 - n->right->value);
break;
case UNARY_PLUS :
*value = (n->right->value);
break;
case ONES_COMPLEMENT :
*value = ~(n->right->value);
break;
case LOGICAL_NEGATION :
if (n->right->value) {
*value = 0;
}
else {
*value = 1;
}
logical_flag++;
break;
default :
break;
}
return(0);
}
/*
* replace_unary() --
*
* Convert a unary operator node that contains a pointer to a value
* with a node containing the numerical result. Free the node that
* originally contained the value.
*/
int
replace_unary(node_t *n, int *error, int flags)
{
kaddr_t addr;
k_uint_t value;
if (!n->right) {
*error = E_SYNTAX_ERROR;
return(-1);
}
if (is_unary(n->right->operator)) {
replace_unary(n->right, error, flags);
}
if (n->operator == CAST) {
return(replace_cast(n, error, flags));
}
else if (n->operator == INDIRECTION) {
type_t *tp;
dw_die_t *d;
dw_type_info_t *dtp;
/* Replace a VARIABLE node with a TYPE_DEF node if possible.
* If it's not possible, return an error.
*/
if (n->right->node_type == VARIABLE) {
if (replace_variable(n->right, error, flags)) {
if (!(*error)) {
*error = E_NOTYPE;
}
return(-1);
}
}
/* Make sure we have a pointer
*/
if (!(n->right->flags & POINTER_FLAG)) {
*error = E_BAD_POINTER;
return(-1);
}
/* Get the pointer to the type_s struct
*/
if (!(tp = n->right->type)) {
*error = E_BAD_TYPE;
return(-1);
}
/* Make sure the right child is a TYPE_DEF.
*/
if (n->right->node_type != TYPE_DEF) {
*error = E_BAD_TYPE;
return(-1);
}
/* Make sure we have a pointer to a base or dwarf type
* structure.
*/
if (n->right->flags & BASE_TYPE_FLAG) {
n->flags = BASE_TYPE_FLAG;
}
else if (n->right->flags & DWARF_TYPE_FLAG) {
n->flags = DWARF_TYPE_FLAG;
}
else {
*error = E_BAD_TYPE;
return(-1);
}
n->node_type = TYPE_DEF;
n->operator = 0;
/* The first type_t struct MUST be a pointer to a type (BASE or
* DWARF). If it points to a DWARF type, strip off the
* pointer block and procede. If it points to a BASE type, we need
* to check if it points to type char. If it does, we have to set
* the STRING_FLAG before stripping off the pointer block.
*/
if (tp->flag == POINTER_FLAG) {
type_t *t;
if (!(t = eval_type(n->right))) {
*error = E_BAD_TYPE;
return(-1);
}
/* Zero out the type field in the right child so it wont
* accidently be freed when the right child is freed
* (upon success).
*/
n->right->type = (type_t*)NULL;
if (!strcmp(((base_t*)t->t_ptr)->name, "char")) {
n->flags |= STRING_FLAG;
}
n->type = tp->t_next;
/* Free the pointer block
*/
free_block((k_ptr_t)tp);
/* Get the pointer address
*/
addr = n->address = n->right->value;
n->flags |= (INDIRECTION_FLAG|ADDRESS_FLAG);
/* If this is a pointer to a pointer, just get the next
* pointer value and return.
*/
if (n->type->flag == POINTER_FLAG) {
kl_get_block(K, addr, K_NBPW(K), &n->value, "pointer value");
if (!PTRSZ64(K)) {
n->value >>= 32;
}
/* Set the appropriate node flag values
*/
n->flags |= POINTER_FLAG;
free_nodes(n->right);
n->left = n->right = (node_t *)NULL;
return(0);
}
n->value = addr;
/* Turn off the pointer flag
*/
n->flags &= (~POINTER_FLAG);
}
else {
*error = E_SYNTAX_ERROR;
return(-1);
}
/* Zero out the type field in the right child so it wont
* accidently be freed when the right child is freed
* (upon success).
*/
n->right->type = (type_t*)NULL;
free_nodes(n->right);
n->left = n->right = (node_t *)NULL;
return(0);
}
else if (n->operator == ADDRESS) {
type_t *t;
if (n->right->node_type == TYPE_DEF) {
t = n->right->type;
}
else if (n->right->node_type == VARIABLE) {
int ret;
ret = replace_variable(n->right, error, flags);
if (*error) {
return(-1);
}
/* If we can't find type information for this variable, we
* should convert the node to a VADDR node (with no type
* reference). That way pointer math will still work.
*/
if (ret == 1) {
n->node_type = VADDR;
n->flags = ADDRESS_FLAG;
n->operator = 0;
n->address = n->right->address;
n->name = n->right->name = 0;
n->type = n->right->type = 0;
n->value = 0;
free_nodes(n->right);
n->left = n->right = (node_t *)NULL;
return(0);
}
t = n->right->type;
}
else {
*error = E_BAD_TYPE;
return(-1);
}
n->type = (type_t*)ALLOC_BLOCK(sizeof(type_t), flags);
n->type->flag = POINTER_FLAG;
n->type->t_next = t;
n->node_type = TYPE_DEF;
n->operator = 0;
n->value = n->right->address;
n->flags = POINTER_FLAG;
if (!(t = eval_type(n))) {
*error = E_BAD_TYPE;
return(-1);
}
n->flags |= t->flag;
n->right->type = 0;
free_nodes(n->right);
n->left = n->right = (node_t *)NULL;
return(0);
}
else if (apply_unary(n, &value, error) == -1) {
return(-1);
}
free_nodes(n->right);
n->node_type = NUMBER;
n->operator = 0;
n->left = n->right = (node_t *)NULL;
bcopy(&value, &n->value, sizeof(k_uint_t));
return(0);
}
/*
* apply()
*/
int
apply(node_t *np, k_uint_t *value, int *error, int flags)
{
int do_signed = 0;
/* Each operator node must have two operands
*/
if (!np->right || !np->left) {
*error = E_SYNTAX_ERROR;
return(-1);
}
if (np->right->node_type == OPERATOR) {
replace(np->right, error, flags);
}
if (!(np->flags & UNSIGNED_FLAG)) {
do_signed++;
}
if ((np->left->node_type == TYPE_DEF) ||
(np->left->node_type == VARIABLE) ||
(np->left->node_type == VADDR)) {
int size;
k_uint_t lvalue;
/* If the left or right nodes are base types (either Dwarf or
* BAES_TYPE), convert them to proper numeric values. Otherwise,
* use the address/pointer value to perform pointer math.
*/
if (!type_to_number(np->left, error)) {
if (np->left->flags & ADDRESS_FLAG) {
size = K_NBPW(K);
lvalue = np->left->address;
}
else {
type_t *tp;
/* Since we only allow pointer math, anything other than
* a pointer causes failure.
*/
tp = (type_t*)np->left->type;
if (tp->flag != POINTER_FLAG) {
*error = E_SYNTAX_ERROR;
return(-1);
}
tp = tp->t_next;
switch (tp->flag) {
case POINTER_FLAG :
size = K_NBPW(K);
break;
case DWARF_TYPE_FLAG :
size = ((dw_type_info_t*)tp->t_ptr)->t_byte_size;
break;
default :
*error = E_SYNTAX_ERROR;
return(-1);
}
lvalue = np->left->value;
}
switch (np->operator) {
case ADD :
*value = lvalue + (np->right->value * size);
break;
case SUBTRACT :
*value = lvalue - (np->right->value * size);
break;
default :
*error = E_BAD_OPERATOR;
return(-1);
}
return(0);
}
}
if (do_signed) {
switch (np->operator) {
case ADD :
*value = (k_int_t)np->left->value + (k_int_t)np->right->value;
break;
case SUBTRACT :
*value = (k_int_t)np->left->value - (k_int_t)np->right->value;
break;
case MULTIPLY :
*value = (k_int_t)np->left->value * (k_int_t)np->right->value;
break;
case DIVIDE :
*value = (k_int_t)np->left->value / (k_int_t)np->right->value;
break;
case BITWISE_OR :
*value = (k_int_t)np->left->value | (k_int_t)np->right->value;
break;
case BITWISE_AND :
*value = (k_int_t)np->left->value & (k_int_t)np->right->value;
break;
case MODULUS :
*value = (k_int_t)np->left->value % (k_int_t)np->right->value;
break;
case RIGHT_SHIFT :
*value =
(k_int_t)np->left->value >> (k_int_t)np->right->value;
break;
case LEFT_SHIFT :
*value =
(k_int_t)np->left->value << (k_int_t)np->right->value;
break;
case LOGICAL_OR :
if ((k_int_t)np->left->value || (k_int_t)np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
case LOGICAL_AND :
if ((k_int_t)np->left->value && (k_int_t)np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
case EQUAL :
if ((k_int_t)np->left->value == (k_int_t)np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
case NOT_EQUAL :
if ((k_int_t)np->left->value != (k_int_t)np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
case LESS_THAN :
if ((k_int_t)np->left->value < (k_int_t)np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
case GREATER_THAN :
if ((k_int_t)np->left->value > (k_int_t)np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
case LESS_THAN_OR_EQUAL :
if ((k_int_t)np->left->value <= (k_int_t)np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
case GREATER_THAN_OR_EQUAL :
if ((k_int_t)np->left->value >= (k_int_t)np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
default :
break;
}
}
else {
switch (np->operator) {
case ADD :
*value = np->left->value + np->right->value;
break;
case SUBTRACT :
*value = np->left->value - np->right->value;
break;
case MULTIPLY :
*value = np->left->value * np->right->value;
break;
case DIVIDE :
*value = np->left->value / np->right->value;
break;
case BITWISE_OR :
*value = np->left->value | np->right->value;
break;
case BITWISE_AND :
*value = np->left->value & np->right->value;
break;
case MODULUS :
*value = np->left->value % np->right->value;
break;
case RIGHT_SHIFT :
*value = np->left->value >> np->right->value;
break;
case LEFT_SHIFT :
*value = np->left->value << np->right->value;
break;
case LOGICAL_OR :
if (np->left->value || np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
case LOGICAL_AND :
if (np->left->value && np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
case EQUAL :
if (np->left->value == np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
case NOT_EQUAL :
if (np->left->value != np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
case LESS_THAN :
if (np->left->value < np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
case GREATER_THAN :
if (np->left->value > np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
case LESS_THAN_OR_EQUAL :
if (np->left->value <= np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
case GREATER_THAN_OR_EQUAL :
if (np->left->value >= np->right->value) {
*value = 1;
}
else {
*value = 0;
}
logical_flag++;
break;
default :
break;
}
}
if ((np->flags & UNSIGNED_FLAG) && (np->byte_size < sizeof(k_uint_t))) {
k_uint_t mask;
mask = ((k_uint_t)1 << (np->byte_size * 8)) - 1;
*value &= mask;
}
return(0);
}
/*
* replace() --
*
* Replace the tree with a node containing the numerical result of
* the equation.
*/
node_t *
replace(node_t *np, int *error, int flags)
{
k_uint_t value;
node_t *q, *r;
if (!np) {
return((node_t *)NULL);
}
if (np->node_type == OPERATOR) {
if (!(q = np->left)) {
return((node_t *)NULL);
}
while (q) {
if (!replace(q, error, flags)) {
return((node_t *)NULL);
}
q = q->right;
}
/* If the left node is a VARIABLE, convert it to TYPE_DEF here.
*/
if (np->left->node_type == VARIABLE) {
/* Replace the VARIABLE node with a TYPE_DEF node. If
* there was an error, or if there wasn't any dwarf type
* info available, return an error.
*/
if (replace_variable(np->left, error, flags)) {
if (*error == 0) {
*error = E_NOTYPE;
}
return((node_t *)NULL);
}
}
if ((np->operator == RIGHT_ARROW) || (np->operator == DOT)) {
int i;
kaddr_t addr = 0;
type_t *tp, *mp;
/* The left node must point to a TYPE_DEF
*/
if (np->left->node_type != TYPE_DEF) {
if (np->left->flags & NOTYPE_FLAG) {
*error = E_NOTYPE;
}
else {
*error = E_BAD_TYPE;
}
return((node_t *)NULL);
}
/* Get the type information. Check to see if we have a
* pointer to a type. If we do, we need to strip off the
* pointer and get the type info.
*/
if (np->left->type->flag == POINTER_FLAG) {
tp = np->left->type->t_next;
free_block((k_ptr_t)np->left->type);
}
else {
tp = np->left->type;
}
/* We need to zero out the left child's type pointer
* to prevent the type structs from being prematurely
* freed (upon success). We have to remember, however, to
* the free the type information before we return.
*/
np->left->type = (type_t*)NULL;
/* tp should now point at a dwarf type_t struct. If it
* points to anything else, return failure.
*/
if (tp->flag != DWARF_TYPE_FLAG) {
*error = E_BAD_TYPE;
free_type(tp);
return((node_t *)NULL);
}
switch (tp->flag) {
case DWARF_TYPE_FLAG: {
dw_die_t *dp;
dw_type_info_t *dti;
/* Get the type die information entry. It should be
* one of the following:
*
* DW_TAG_structure_type
* DW_TAG_union_type
* DW_TAG_pointer_type
*
* If it's a DW_TAG_pointer_type, it must reference a
* DW_TAG_structure_type or DW_TAG_union_type. Otherwise
* return failure.
*/
dti = (dw_type_info_t *)tp->t_ptr;
/*
* XXX: Hack for the curnmlist musical
* chairs. Do a lookup on the name again.
*/
if(dti && dti->t_name)
dw_lkup(stp,dti->t_name,dti->t_tag);
dp = dti->t_actual_type;
/* If dp points to a DW_TAG_pointer_type, get the next
* die record (which should contain struct/union
* information).
*/
if (dp->d_tag == DW_TAG_pointer_type) {
dp = dp->d_next;
}
/* Make sure dp points to a DW_TAG_structure_type or
* DW_TAG_union_type. If it doesn't, return failure.
*/
if ((dp->d_tag != DW_TAG_structure_type) &&
(dp->d_tag != DW_TAG_union_type)) {
*error = E_BAD_TYPE;
free_type(tp);
return((node_t *)NULL);
}
/* Get type information for member. If member is a
* pointer to a type, get the pointer address and load
* it into value. Otherwise, load the struct/union
* address plus loc offset into address.
*/
if (!(mp = dw_lkup_member(stp,
tp->t_ptr, np->right->name, flags))) {
*error = E_BAD_MEMBER;
free_type(tp);
return((node_t *)NULL);
}
/* Now free the struct type information
*/
free_type(tp);
np->node_type = TYPE_DEF;
np->operator = 0;
addr = np->left->value +
((dw_type_info_t *)mp->t_ptr)->t_loc;
np->address = addr;
np->flags |= (DWARF_TYPE_FLAG|ADDRESS_FLAG);
if (!(np->type = member_to_type(mp->t_ptr,
DWARF_TYPE_FLAG, flags))) {
free_type(mp);
*error = E_BAD_MEMBER;
return((node_t *)NULL);
}
/* We have to free up the memory block that mp points
* to. We can't call free_type(), since it will free
* up the type information that np->type points to. So,
* we have to free the block manually...
*/
free_block((k_ptr_t)mp);
if (np->type->flag == POINTER_FLAG) {
np->flags |= POINTER_FLAG;
kl_get_block(K, addr, K_NBPW(K),
&np->value, "pointer value");
if (!PTRSZ64(K)) {
np->value >>= 32;
}
}
else {
np->value = addr;
}
break;
}
}
free_nodes(np->left);
free_nodes(np->right);
np->left = np->right = (node_t*)NULL;
return(np);
}
else {
if (np->left->byte_size && np->right->byte_size) {
if (np->left->byte_size > np->right->byte_size) {
/* Left byte_size is greater than right
*/
np->byte_size = np->left->byte_size;
np->type = np->left->type;
np->flags = np->left->flags;
free_type(np->right->type);
}
else if (np->left->byte_size < np->right->byte_size) {
/* Right byte_size is greater than left
*/
np->byte_size = np->right->byte_size;
np->type = np->right->type;
np->flags = np->right->flags;
free_type(np->left->type);
}
else {
/* Left and right byte_size is equal
*/
if (np->left->flags & UNSIGNED_FLAG) {
np->byte_size = np->left->byte_size;
np->type = np->left->type;
np->flags = np->left->flags;
free_type(np->right->type);
}
else if (np->right->flags & UNSIGNED_FLAG) {
np->byte_size = np->right->byte_size;
np->type = np->right->type;
np->flags = np->right->flags;
free_type(np->left->type);
}
else {
np->byte_size = np->left->byte_size;
np->type = np->left->type;
np->flags = np->left->flags;
free_type(np->right->type);
}
}
}
else if (np->left->byte_size) {
np->byte_size = np->left->byte_size;
np->type = np->left->type;
np->flags = np->left->flags;
free_type(np->right->type);
}
else if (np->right->byte_size) {
np->byte_size = np->right->byte_size;
np->type = np->right->type;
np->flags = np->right->flags;
}
else {
/* XXX - No byte sizes
*/
}
if (apply(np, &value, error, flags)) {
return((node_t *)NULL);
}
}
np->right->type = np->left->type = (type_t*)NULL;
/* Flesh out the rest of the node struct.
*/
np->node_type = NUMBER;
np->flags &= ~(DWARF_TYPE_FLAG|BASE_TYPE_FLAG);
np->operator = 0;
np->value = value;
free_block((k_ptr_t)np->left);
free_block((k_ptr_t)np->right);
np->left = np->right = (node_t*)NULL;
}
return(np);
}
/*
* replace_variable()
*/
int
replace_variable(node_t *n, int *error, int flags)
{
dw_type_t *dtp;
type_t *t;
dw_type_info_t *dti;
/* Check to see if this is a dwarf kernel
*/
if (!stp) {
/* Lookup the variable type by name
*/
if (!(dtp = dw_lkup(stp, n->name, DW_TAG_variable))) {
*error = E_BAD_VARIABLE;
return(-1);
}
/* Allocate some space for the dw_type_info_s struct and then
* get the struct referenced by d_off.
*/
dti = (dw_type_info_t*)ALLOC_BLOCK(sizeof(*dti), flags);
if (!dw_type_info(dtp->dt_off, dti, flags)) {
dw_free_type_info(dti);
*error = E_BAD_TYPE;
return(-1);
}
if (!(n->type = dw_var_to_type(dti, flags))) {
/* If we can't find type information for this variable, we
* set a flag (NOTYPE_FLAG) and return one (1). We don't,
* set *error, however. We may be able to get by with just
* the address of the variable.
*/
n->flags |= NOTYPE_FLAG;
dw_free_type_info(dti);
return(1);
}
n->node_type = TYPE_DEF;
n->operator = 0;
if (n->type->flag == POINTER_FLAG) {
n->flags = POINTER_FLAG;
kl_get_block(K, n->address, 8, &n->value, "pointer value (DWARF)");
}
else {
n->value = n->address;
}
if (!(t = eval_type(n))) {
*error = E_BAD_TYPE;
return(-1);
}
n->flags |= t->flag;
}
return(0);
}
/*
* array_to_element()
*/
void
array_to_element(node_t *n0, node_t *n1, int *error)
{
int size;
type_t *t;
base_t *btp;
dw_type_info_t *dtp;
dw_die_t *dp;
/* Take the array index and determine the proper pointer
* value for the type pointer or array data type.
*/
t = n0->type;
if (n0->node_type == TYPE_DEF) {
if (t->flag == POINTER_FLAG) {
if (t->t_next->flag == DWARF_TYPE_FLAG) {
dtp = (dw_type_info_t*)t->t_next->t_ptr;
t = t->t_next;
free_block((k_ptr_t)n0->type);
n0->type = t;
size = dtp->t_byte_size;
}
else if (t->t_next->flag == BASE_TYPE_FLAG) {
btp = (base_t*)t->t_next->t_ptr;
t = t->t_next;
free_block((k_ptr_t)n0->type);
n0->type = t;
size = btp->byte_size;
}
else {
*error = E_BAD_INDEX;
}
}
else if (t->flag == DWARF_TYPE_FLAG) {
dtp = (dw_type_info_t*)t->t_ptr;
if (dtp->t_tag == DW_TAG_array_type) {
dtp->t_tag = dtp->t_type->d_next->d_tag;
dtp->t_off = dtp->t_type->d_next->d_off;
dtp->t_name = dtp->t_type->d_next->d_name;
dp = dtp->t_type;
while (dp->d_next) {
dp = dp->d_next;
}
size = dp->d_byte_size;
dtp->t_type = dtp->t_type->d_next;
dtp->t_actual_type = dp;
dtp->t_byte_size = size;
}
else {
*error = E_BAD_INDEX;
}
}
else {
*error = E_BAD_INDEX;
}
if (!(*error)) {
n0->address = n0->value + (n1->value * size);
n0->value = n0->address;
n0->flags &= (~POINTER_FLAG);
n0->flags |= (ADDRESS_FLAG|INDIRECTION_FLAG);
}
}
else {
*error = E_BAD_INDEX;
}
}
/*
* type_to_number()
*
* Convert a base type (Dwarf or BASE_TYPE) to a numeric value. Return
* 1 on successful conversion, 0 if nothing was done.
*/
int
type_to_number(node_t *np, int *error)
{
int byte_size, bit_offset, bit_size, encoding, j, k;
k_uint_t value, value1;
dw_type_info_t *dti;
/* Make sure we point to a type
*/
if (!np->type) {
return(0);
}
if (np->type->flag == POINTER_FLAG) {
return(0);
}
dti = (dw_type_info_t*)np->type->t_ptr;
if (np->flags & BASE_TYPE_FLAG) {
/* Nothing needs to be done. It's already a base value
* (we still need to return a 1).
*/
return(1);
}
else if (np->flags & DWARF_TYPE_FLAG) {
if (dti->t_tag == DW_TAG_base_type) {
byte_size = dti->t_byte_size;
bit_offset = dti->t_bit_offset;
if (!(bit_size = dti->t_bit_size)) {
bit_size = (byte_size * 8);
}
encoding = dti->t_encoding;
}
else {
return(0);
}
}
kl_get_block(K, np->address, byte_size, &value1, "value");
value = kl_get_bit_value(&value1, byte_size, bit_size, bit_offset);
switch (byte_size) {
case 1 :
if (encoding == 8) {
np->value = (unsigned char)value;
np->flags |= UNSIGNED_FLAG;
}
else {
np->value = (char)value;
}
break;
case 2 :
if (encoding == 7) {
np->value = (unsigned short)value;
np->flags |= UNSIGNED_FLAG;
}
else {
np->value = (short)value;
}
break;
case 4 :
if (encoding == 7) {
np->value = (unsigned int)value;
np->flags |= UNSIGNED_FLAG;
}
else {
np->value = (int)value;
}
break;
case 8 :
if (encoding == 7) {
np->value = (unsigned long long)value;
np->flags |= UNSIGNED_FLAG;
}
else {
np->value = (long long)value;
}
break;
default :
*error = E_BAD_TYPE;
return(0);
}
np->node_type = NUMBER;
return(1);
}
/*
* eval_type()
*/
type_t *
eval_type(node_t *n)
{
type_t *t;
t = n->type;
while (t->flag == POINTER_FLAG) {
t = t->t_next;
/* If for some reason, there is no type pointer (this shouldn't
* happen but...), we have to make sure that we don't try to
* reference a NULL pointer and get a SEGV. Return an error if
* 't' is NULL.
*/
if (!t) {
return((type_t*)NULL);
}
}
if ((t->flag == BASE_TYPE_FLAG) || (t->flag == DWARF_TYPE_FLAG)) {
return (t);
}
return((type_t*)NULL);
}
/*
* eval()
*/
node_t *
eval(char **exp, int flags, int *error)
{
int i;
token_t *tok, *t;
node_t *n;
char *e, *s;
*error = 0;
logical_flag = 0;
/* Make sure we actually have a command line to evaluate
*/
if (!(*exp)) {
return ((node_t*)NULL);
}
/* Expand any variables that are in the expression string. Free
* the original string and change s so that it points to the new
* expression string (so that the new string will be freed up when
* we are done).
*/
if (e = expand_variables(*exp, 0)) {
free_block((k_ptr_t)*exp);
*exp = e;
s = *exp;
}
else {
*error = E_BAD_VARIABLE;
tok = (token_t *)alloc_block(sizeof(token_t), B_TEMP);
tok->ptr = *exp;
}
if (!(*error)) {
tok = get_token_list(s, error);
}
if (*error) {
n = (node_t *)ALLOC_BLOCK(sizeof(node_t), flags);
n->tok_ptr = tok->ptr;
}
else {
t = tok;
n = do_eval(&t, flags, error);
if (!*error) {
if (!(n = replace(n, error, flags))) {
n = (node_t *)ALLOC_BLOCK(sizeof (node_t), flags);
n->tok_ptr = s + strlen(s) -1;
*error = E_SYNTAX_ERROR;
}
else {
/* Check to see if the the result should be interpreted
* as 'true' or 'false'
*/
if (logical_flag && ((n->value == 0) || (n->value == 1))) {
n->flags |= BOOLIAN_FLAG;
}
}
}
}
if (!(*error) && (n->node_type == VARIABLE)) {
if (n->flags & NOTYPE_FLAG) {
if (!(n->flags & ADDRESS_FLAG)) {
*error = E_NOTYPE;
}
}
else {
if (replace_variable(n, error, flags) == 1) {
*error = E_NOTYPE;
}
}
}
free_tokens(tok);
return(n);
}
/*
* print_number()
*
* If we get here it means the type is BASE_TYPE. If there isn't
* a type_s struct linked in, then make type the default (int).
* Then, depending on the contents of flags, display the value
* in HEX, OCTAL, or DECIMAL form. There is a special case for
* type char (display as a character).
*/
void
print_number(node_t *np, FILE *ofp, int flags)
{
base_t *bt;
k_uint_t value;
/* Check to make sure we have a base_type pointer. This is kind
* of a hack since we can get to this routine from a number of
* different ways and it's not always clear that a type will have
* been designated along the way. Check the upper word and see if
* any bits are set. If they are, treat the value as a "long long"
* type (64-bit) value. Otherwise, treat it as an "int" value.
*/
if (!np->type) {
if (np->value & 0xffffffff00000000) {
np->type = get_type("long long", 0);
}
else {
np->type = get_type("int", 0);
}
np->byte_size = ((base_t *)np->type->t_ptr)->byte_size;
}
if (flags & C_HEX) {
if (np->byte_size && (np->byte_size != sizeof(k_uint_t))) {
np->value = np->value &
(((k_uint_t)1<<(k_uint_t)(np->byte_size*8))-1);
}
fprintf(ofp, "0x%llx", np->value);
}
else if (flags & C_OCTAL) {
fprintf(ofp, "0%llo", np->value);
}
else {
if (np->flags & UNSIGNED_FLAG) {
fprintf(ofp, "%llu", np->value);
}
else {
bt = (base_t *)np->type->t_ptr;
value = np->value << ((8 - np->byte_size) * 8);
print_base(&value, bt->byte_size, bt->encoding, flags, ofp);
}
}
}
/*
* print_eval_results()
*/
int
print_eval_results(node_t *np, FILE *ofp, int flags)
{
int size;
kaddr_t addr;
dw_type_info_t *t;
dw_die_t *d;
/* Print the results
*/
switch (np->node_type) {
case NUMBER:
print_number(np, ofp, flags);
break;
case TYPE_DEF: {
type_t *tp;
k_ptr_t ptr;
/* If this is a pointer just print out the address.
*/
if (np->flags & POINTER_FLAG) {
fprintf(ofp, "0x%llx", np->value);
break;
}
if (np->flags & DWARF_TYPE_FLAG) {
/* Get the type information
*/
t = (dw_type_info_t *)np->type->t_ptr;
/*
* XXX: Hack for the curnmlist musical chairs.
* Do a lookup on that name again.
*/
if(t && t->t_name)
dw_lkup(stp,t->t_name,t->t_tag);
if (t->t_type->d_tag == DW_TAG_typedef) {
d = t->t_actual_type;
}
else {
d = t->t_type;
}
size = t->t_byte_size;
ptr = alloc_block(size, B_TEMP);
if ((d->d_tag == DW_TAG_base_type) &&
!(np->flags & ADDRESS_FLAG)) {
switch (size) {
case 1:
*(unsigned char *)ptr = np->value;
break;
case 2:
*(unsigned short *)ptr = np->value;
break;
case 4:
*(unsigned int *)ptr = np->value;
break;
case 8:
*(unsigned long long *)ptr = np->value;
break;
}
dw_print_type(ptr, t, 0, flags|SUPPRESS_NAME, ofp);
free_block(ptr);
return(1);;
}
addr = np->value;
kl_get_block(K, addr, size, ptr, "type");
if (KL_ERROR) {
kl_print_error(K);
free_block(ptr);
return(1);
}
/* Print out the actual type
*/
switch (d->d_tag) {
case DW_TAG_structure_type:
case DW_TAG_union_type:
dw_print_type(ptr, t, 0, flags, ofp);
break;
default:
dw_print_type(ptr, t, 0,
(flags|SUPPRESS_NAME|SUPPRESS_NL), ofp);
break;
}
free_block(ptr);
}
else if (np->flags & BASE_TYPE_FLAG) {
base_t *b;
if (!(flags & ADDRESS_FLAG)) {
print_number(np, ofp, flags);
}
else {
/* Get the type information
*/
b = (base_t *)np->type->t_ptr;
size = b->byte_size;
ptr = alloc_block(size, B_TEMP);
addr = np->value;
kl_get_block(K, addr, size, ptr, "type");
if (KL_ERROR) {
free_block(ptr);
return(1);
}
print_base(ptr, size, b->encoding, flags, ofp);
}
}
break;
}
case VADDR:
case VARIABLE:
/* If we get here, there was no type info available.
* The ADDRESS_FLAG should be set (otherwise we would have
* returned an error). So, print out the address.
*/
fprintf(ofp, "0x%llx", np->address);
break;
default:
if (np->node_type == TEXT) {
print_string(np->name, ofp);
if (KL_ERROR) {
kl_print_error(K);
return(1);
}
}
else if (np->node_type == CHARACTER) {
fprintf(ofp, "\'%c\'", np->name[0]);
}
break;
}
return(0);
}
/*
* print_eval_error()
*/
void
print_eval_error(char *cmdname, char *s, char *bad_ptr, int error, int flags)
{
int i, cmd_len;
if ((cmdname[0] == 'p') || !strcmp(cmdname, "eval")) {
fprintf(KL_ERRORFP, "print");
if ((cmdname[1] == 'x') || (cmdname[1] == 'o')) {
fprintf(KL_ERRORFP, "%c %s\n", cmdname[1], s);
cmd_len = 6;
}
else {
fprintf(KL_ERRORFP, " %s\n", s);
cmd_len = 5;
}
}
else {
if (flags & CMD_STRING) {
fprintf(KL_ERRORFP, "%s%s\n", cmdname, s);
}
else {
fprintf(KL_ERRORFP, "%s %s\n", cmdname, s);
}
cmd_len = strlen(cmdname);
}
if (!bad_ptr) {
for (i = 0; i < (strlen(s) + cmd_len); i++) {
fprintf(KL_ERRORFP, " ");
}
}
else {
for (i = 0; i < (bad_ptr - s + 1 + cmd_len); i++) {
fprintf(KL_ERRORFP, " ");
}
}
fprintf(KL_ERRORFP, "^ ");
switch (error) {
case E_OPEN_PAREN :
fprintf(KL_ERRORFP, "Too many open parenthesis\n");
break;
case E_CLOSE_PAREN :
fprintf(KL_ERRORFP, "Too many close parenthesis\n");
break;
case E_BAD_MEMBER :
fprintf(KL_ERRORFP, "No such member\n");
break;
case E_BAD_OPERATOR :
fprintf(KL_ERRORFP, "Bad operator\n");
break;
case E_BAD_TYPE :
fprintf(KL_ERRORFP, "Bad type\n");
break;
case E_NOTYPE :
fprintf(KL_ERRORFP, "Could not find type information\n");
break;
case E_BAD_POINTER :
fprintf(KL_ERRORFP, "Bad pointer\n");
break;
case E_BAD_VARIABLE :
fprintf(KL_ERRORFP, "Not a variable\n");
break;
case E_BAD_INDEX :
fprintf(KL_ERRORFP, "Bad array index\n");
break;
case E_BAD_STRING :
fprintf(KL_ERRORFP, "Non-termining string\n");
break;
case E_END_EXPECTED :
fprintf(KL_ERRORFP, "Expected end of print statement\n");
break;
case E_BAD_EVAR :
fprintf(KL_ERRORFP, "Bad eval variable\n");
break;
default :
fprintf(KL_ERRORFP, "Syntax error\n");
break;
}
}