debugger_expr.cc Source File

Back to the index.

debugger_expr.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2004-2009 Anders Gavare. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *
28  * Expression evaluator.
29  *
30  *
31  * TODO:
32  * Sign-extension is arch dependent (e.g. MIPS has it).
33  * SPECIAL IMPORTANT CASE: Clear the delay_slot flag when writing
34  * to the pc register.
35  * TAB completion? :-)
36  */
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <ctype.h>
42 
43 #include "cpu.h"
44 #include "debugger.h"
45 #include "machine.h"
46 #include "misc.h"
47 #include "settings.h"
48 
49 
50 extern struct settings *global_settings;
51 
52 extern int debugger_cur_cpu;
53 extern int debugger_cur_machine;
54 
55 
56 /*
57  * debugger_parse_name():
58  *
59  * This function takes a string as input, and tries to match it to a register
60  * name or a more general "setting", a hexadecimal or decimal numeric value,
61  * or a registered symbol.
62  *
63  * Some examples:
64  *
65  * Settings (including register names):
66  * verbose
67  * pc
68  * r5
69  *
70  * Numeric values:
71  * 12345
72  * 0x7fff1234
73  *
74  * Symbols:
75  * memcpy
76  *
77  * To force detection of different types, a character can be added in front of
78  * the name: "$" for numeric values, "#" for registers or other settings,
79  * and "@" for symbols.
80  *
81  * Return value is:
82  *
83  * PARSE_NOMATCH no match
84  * PARSE_MULTIPLE multiple matches
85  *
86  * or one of these (and then *valuep is read or written, depending on
87  * the writeflag):
88  *
89  * PARSE_SETTINGS a setting (e.g. a register)
90  * PARSE_NUMBER a hex number
91  * PARSE_SYMBOL a symbol
92  */
93 int debugger_parse_name(struct machine *m, char *name, int writeflag,
94  uint64_t *valuep)
95 {
96  int match_settings = 0, match_symbol = 0, match_numeric = 0;
97  int skip_settings, skip_numeric, skip_symbol;
98 
99  if (m == NULL || name == NULL) {
100  fprintf(stderr, "debugger_parse_name(): NULL ptr\n");
101  exit(1);
102  }
103 
104  while (name[0] == '\t' || name[0] == ' ')
105  name ++;
106 
107  /* Warn about non-signextended values: */
108  if (writeflag) {
109  if (m->cpus[0]->is_32bit) {
110  /* Automagically sign-extend. TODO: Is this good? */
111  if (((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL)
112  (*valuep) |= 0xffffffff00000000ULL;
113  } else {
114  if (((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL)
115  printf("WARNING: The value is not sign-extende"
116  "d. Is this what you intended?\n");
117  }
118  }
119 
120  skip_settings = name[0] == '$' || name[0] == '@';
121  skip_numeric = name[0] == '#' || name[0] == '@';
122  skip_symbol = name[0] == '$' || name[0] == '#';
123 
124  if (!skip_settings) {
125  char setting_name[400];
126  int res;
127 
128  res = settings_access(global_settings, name, writeflag, valuep);
129  if (res == SETTINGS_OK)
130  match_settings = 1;
131 
132  if (!match_settings) {
133  snprintf(setting_name, sizeof(setting_name),
134  GLOBAL_SETTINGS_NAME".%s", name);
135  res = settings_access(global_settings, setting_name,
136  writeflag, valuep);
137  if (res == SETTINGS_OK)
138  match_settings = 1;
139  }
140 
141  if (!match_settings) {
142  snprintf(setting_name, sizeof(setting_name),
143  GLOBAL_SETTINGS_NAME".emul.%s", name);
144  res = settings_access(global_settings, setting_name,
145  writeflag, valuep);
146  if (res == SETTINGS_OK)
147  match_settings = 1;
148  }
149 
150  if (!match_settings) {
151  snprintf(setting_name, sizeof(setting_name),
152  GLOBAL_SETTINGS_NAME".emul.machine[%i].%s",
153  debugger_cur_machine, name);
154  res = settings_access(global_settings, setting_name,
155  writeflag, valuep);
156  if (res == SETTINGS_OK)
157  match_settings = 1;
158  }
159 
160  if (!match_settings) {
161  snprintf(setting_name, sizeof(setting_name),
162  GLOBAL_SETTINGS_NAME".emul.machine[%i]."
163  "cpu[%i].%s", debugger_cur_machine,
164  debugger_cur_cpu, name);
165  res = settings_access(global_settings, setting_name,
166  writeflag, valuep);
167  if (res == SETTINGS_OK)
168  match_settings = 1;
169  }
170  }
171 
172  /* Check for a number match: */
173  if (!skip_numeric && isdigit((int)name[0])) {
174  uint64_t x;
175  x = strtoull(name, NULL, 0);
176  if (writeflag)
177  printf("You cannot assign like that.\n");
178  else
179  *valuep = x;
180  match_numeric = 1;
181  }
182 
183  /* Check for a symbol match: */
184  if (!skip_symbol) {
185  uint64_t newaddr;
186  if (get_symbol_addr(&m->symbol_context, name, &newaddr)) {
187  if (writeflag)
188  printf("You cannot assign like that.\n");
189  else
190  *valuep = newaddr;
191  match_symbol = 1;
192  }
193  }
194 
195  if (match_settings + match_symbol + match_numeric > 1)
196  return PARSE_MULTIPLE;
197 
198  if (match_settings)
199  return PARSE_SETTINGS;
200  if (match_numeric)
201  return PARSE_NUMBER;
202  if (match_symbol)
203  return PARSE_SYMBOL;
204 
205  return PARSE_NOMATCH;
206 }
207 
208 
209 /*
210  * debugger_parse_expression()
211  *
212  * Input:
213  * writeflag = 0: expr = an expression to evaluate. The result is
214  * returned in *valuep.
215  *
216  * writeflag = 1: expr = an lvalue name. *valuep is written to that
217  * lvalue, using debugger_parse_name().
218  *
219  * Parentheses always have precedence.
220  * * / and % have second highest precedence.
221  * + - & | ^ have lowest precedence.
222  *
223  * Return value on failure is:
224  *
225  * PARSE_NOMATCH one or more words in the expression didn't
226  * match any known symbol/register/number
227  * PARSE_MULTIPLE multiple matches within the expression
228  *
229  * Return value on success is PARSE_NUMBER (for now).
230  *
231  *
232  * TODO: BETTER RETURN VALUE!
233  *
234  * NOTE: This is a quick hack, but hopefully it should work. The internal
235  * mechanism is to split the expression into a left half and a right
236  * half around an operator. This operator should be the operator
237  * in the string which has the lowest precedence (except those that
238  * are inside parentheses sub-expressions). E.g. if the expression
239  * is a * (b + c * d) / e then the operator with the lowest
240  * precedence is the first multiplication sign, and the split will
241  * be: left = a
242  * right = (b+c*d)/e
243  */
244 int debugger_parse_expression(struct machine *m, char *expr, int writeflag,
245  uint64_t *valuep)
246 {
247  int prec, res, i, nest;
248  char *copy;
249 
250  if (writeflag)
251  return debugger_parse_name(m, expr, writeflag, valuep);
252 
253  while (expr[0] == '\t' || expr[0] == ' ')
254  expr ++;
255 
256  CHECK_ALLOCATION(copy = strdup(expr));
257 
258  while (copy[0] && copy[strlen(copy)-1] == ' ')
259  copy[strlen(copy)-1] = '\0';
260 
261  /* Find the lowest operator precedence: */
262  i = 0; prec = 2; nest = 0;
263  while (copy[i] != '\0') {
264  switch (copy[i]) {
265  case '(':
266  nest ++;
267  break;
268  case ')':
269  nest --;
270  break;
271  case '+':
272  case '-':
273  case '^':
274  case '&':
275  case '|':
276  if (nest == 0)
277  prec = 0;
278  break;
279  case '*':
280  case '/':
281  case '%':
282  if (nest == 0 && prec > 1)
283  prec = 1;
284  break;
285  }
286 
287  i++;
288  }
289 
290  if (nest != 0) {
291  printf("Unmatching parentheses.\n");
292  return PARSE_NOMATCH;
293  }
294 
295  if (prec == 2 && copy[0] == '(' && copy[strlen(copy)-1] == ')') {
296  int res2;
297  copy[strlen(copy)-1] = '\0';
298  res2 = debugger_parse_expression(m, copy+1, 0, valuep);
299  free(copy);
300  return res2;
301  }
302 
303  /* Split according to the first lowest priority operator: */
304  i = 0; nest = 0;
305  while (copy[i] != '\0') {
306  switch (copy[i]) {
307  case '(':
308  nest ++;
309  break;
310  case ')':
311  nest --;
312  break;
313  case '*':
314  case '/':
315  case '%':
316  if (prec == 0)
317  break;
318  /* Fallthrough. */
319  case '+':
320  case '-':
321  case '^':
322  case '&':
323  case '|':
324  if (nest == 0) {
325  uint64_t left, right;
326  int res1, res2, j;
327  char op = copy[i];
328 
329  copy[i] = '\0';
330  j = i;
331  while (j>0 && copy[j-1] == ' ') {
332  copy[j-1] = '\0';
333  j --;
334  }
335 
337  m, copy, 0, &left);
339  m, copy + i + 1, 0, &right);
340 
341  if (res1 == PARSE_NOMATCH ||
342  res2 == PARSE_NOMATCH) {
343  res = PARSE_NOMATCH;
344  goto return_failure;
345  }
346 
347  if (res1 == PARSE_MULTIPLE ||
348  res2 == PARSE_MULTIPLE) {
349  res = PARSE_MULTIPLE;
350  goto return_failure;
351  }
352 
353  switch (op) {
354  case '+':
355  (*valuep) = left + right;
356  break;
357  case '-':
358  (*valuep) = left - right;
359  break;
360  case '^':
361  (*valuep) = left ^ right;
362  break;
363  case '&':
364  (*valuep) = left & right;
365  break;
366  case '|':
367  (*valuep) = left | right;
368  break;
369  case '*':
370  (*valuep) = left * right;
371  break;
372  case '/':
373  (*valuep) = left / right;
374  break;
375  case '%':
376  (*valuep) = left % right;
377  break;
378  }
379 
380  goto return_ok;
381  }
382  break;
383  }
384 
385  i ++;
386  }
387 
388  res = debugger_parse_name(m, expr, writeflag, valuep);
389  if (res == PARSE_NOMATCH || res == PARSE_MULTIPLE)
390  goto return_failure;
391 
392 return_ok:
393  free(copy);
394  return PARSE_NUMBER;
395 
396 return_failure:
397  free(copy);
398  return res;
399 }
400 
int debugger_parse_name(struct machine *m, char *name, int writeflag, uint64_t *valuep)
#define PARSE_SETTINGS
Definition: debugger.h:54
uint8_t is_32bit
Definition: cpu.h:350
struct cpu ** cpus
Definition: machine.h:140
int debugger_cur_cpu
Definition: debugger.cc:87
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
int debugger_cur_machine
Definition: debugger.cc:88
int settings_access(struct settings *settings, const char *fullname, int writeflag, uint64_t *valuep)
Definition: settings.cc:468
#define PARSE_MULTIPLE
Definition: debugger.h:53
#define SETTINGS_OK
Definition: settings.h:81
char ** name
Definition: settings.cc:74
void COMBINE() strlen(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
struct symbol_context symbol_context
Definition: machine.h:144
int get_symbol_addr(struct symbol_context *, const char *symbol, uint64_t *addr)
Definition: symbol.cc:63
#define GLOBAL_SETTINGS_NAME
Definition: settings.h:33
#define PARSE_NOMATCH
Definition: debugger.h:52
int debugger_parse_expression(struct machine *m, char *expr, int writeflag, uint64_t *valuep)
#define PARSE_SYMBOL
Definition: debugger.h:56
#define PARSE_NUMBER
Definition: debugger.h:55
char * op[16]
struct settings * global_settings
Definition: main.cc:59

Generated on Fri Dec 7 2018 19:52:23 for GXemul by doxygen 1.8.13