1 |
vapier 07/12/29 21:06:07 |
2 |
|
3 |
Modified: README.history |
4 |
Added: 10_all_gdb-6.6-duel.patch |
5 |
11_all_gdb-6.6-duel-integrate.patch |
6 |
Log: |
7 |
add DUEL support #199987 by Sergei Golubchik |
8 |
|
9 |
Revision Changes Path |
10 |
1.2 src/patchsets/gdb/6.7.1/README.history |
11 |
|
12 |
file : http://sources.gentoo.org/viewcvs.py/gentoo/src/patchsets/gdb/6.7.1/README.history?rev=1.2&view=markup |
13 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo/src/patchsets/gdb/6.7.1/README.history?rev=1.2&content-type=text/plain |
14 |
diff : http://sources.gentoo.org/viewcvs.py/gentoo/src/patchsets/gdb/6.7.1/README.history?r1=1.1&r2=1.2 |
15 |
|
16 |
Index: README.history |
17 |
=================================================================== |
18 |
RCS file: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/README.history,v |
19 |
retrieving revision 1.1 |
20 |
retrieving revision 1.2 |
21 |
diff -u -r1.1 -r1.2 |
22 |
--- README.history 29 Oct 2007 20:40:43 -0000 1.1 |
23 |
+++ README.history 29 Dec 2007 21:06:06 -0000 1.2 |
24 |
@@ -1,3 +1,7 @@ |
25 |
+1.1 [29.12.2007] |
26 |
+ + 10_all_gdb-6.6-duel.patch |
27 |
+ + 11_all_gdb-6.6-duel-integrate.patch |
28 |
+ |
29 |
1.0 [29.10.2007] |
30 |
+ 35_all_gdb-6.3-security-errata-20050610.patch |
31 |
+ 45_all_gdb-hppa-offsets.patch |
32 |
|
33 |
|
34 |
|
35 |
1.1 src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch |
36 |
|
37 |
file : http://sources.gentoo.org/viewcvs.py/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch?rev=1.1&view=markup |
38 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch?rev=1.1&content-type=text/plain |
39 |
|
40 |
Index: 10_all_gdb-6.6-duel.patch |
41 |
=================================================================== |
42 |
ftp://ftp.cs.princeton.edu/pub/duel/ |
43 |
|
44 |
--- gdb/duel/MANUAL |
45 |
+++ gdb/duel/MANUAL |
46 |
@@ -0,0 +1,501 @@ |
47 |
+ |
48 |
+ |
49 |
+ |
50 |
+ DDDDuuuueeeellll((((1111)))) VVVVeeeerrrrssssiiiioooonnnn 1111....11110000 ((((MMMMaaaarrrr 99993333)))) DDDDuuuueeeellll((((1111)))) |
51 |
+ |
52 |
+ |
53 |
+ |
54 |
+ NNNNAAAAMMMMEEEE |
55 |
+ duel - A high level C debugging language extension to gdb |
56 |
+ |
57 |
+ SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS |
58 |
+ dddduuuueeeellll [gdb options] [_p_r_o_g[_c_o_r_e|_p_r_o_c_I_D]] |
59 |
+ |
60 |
+ DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN |
61 |
+ Duel is a special purpose language designed for concise state |
62 |
+ exploration of debugged C programs, currently implemented under the |
63 |
+ GNU debugger _g_d_b(1). Duel is invoked by entering the shell command |
64 |
+ _d_u_e_l instead of _g_d_b. It is identical to gdb except for comments, which |
65 |
+ begin with `##' instead of `#', and the new _d_l command for Duel |
66 |
+ expressions: |
67 |
+ |
68 |
+ _g_d_b> dl x[1..10] >? 5 |
69 |
+ x[3] = 14 |
70 |
+ x[8] = 6 |
71 |
+ |
72 |
+ prints the array elements x[1] to x[10] that are greater than 5. The |
73 |
+ output includes the values 14 and 6, as well as their symbolic |
74 |
+ representation "x[3]" and "x[8]". |
75 |
+ |
76 |
+ IIIIFFFF YYYYOOOOUUUU NNNNEEEEVVVVEEEERRRR UUUUSSSSEEEEDDDD GGGGDDDDBBBB |
77 |
+ The improved functionality added by Duel merits a fresh look even by |
78 |
+ debugger shunners. Gdb is a powerful debugger with many commands, a |
79 |
+ thick manual and various interfaces including _e_m_a_c_s(1) and _x_x_g_d_b(1). |
80 |
+ These gdb commands should help you get started: |
81 |
+ |
82 |
+ _b _l_i_n_e set a breakpoint at the line (b func to break at a function) |
83 |
+ _d _n delete breakpoint number n (gdb prints n when bp occurs) |
84 |
+ _l _l_i_n_e list the source beginning at line (l file.c:line for module) |
85 |
+ _r _p_a_r_m run/restart the program with the given parameters |
86 |
+ _s single-step to the next statement (steps into function calls) |
87 |
+ _n single-step to the next line, skipping over function calls |
88 |
+ _c continue execution |
89 |
+ _b_t show a stack trace |
90 |
+ _p _e_x_p evaluate a symbolic expression |
91 |
+ _d_l _e_x_p evaluate a Duel expression |
92 |
+ _d_l _g_d_b give a gdb command summary |
93 |
+ |
94 |
+ The most common use is `b func' followed by `r' followed by several |
95 |
+ `n' and `s', evaluating expressions in between. |
96 |
+ |
97 |
+ DDDDUUUUEEEELLLL QQQQUUUUIIIICCCCKKKK SSSSTTTTAAAARRRRTTTT |
98 |
+ Duel is implemented by adding the _d_l command to gdb. All gdb commands |
99 |
+ work as before. The dl command, however, is interpreted by duel. Gdb |
100 |
+ concepts (such as the value history) do not work in the dl command, |
101 |
+ and duel concepts are not understood by other gdb command. |
102 |
+ |
103 |
+ Duel is based on expressions which return multiple values. The x..y |
104 |
+ operator returns the integers from x to y; the x,y operator returns x |
105 |
+ and then y, e.g. |
106 |
+ |
107 |
+ _g_d_b> dl (1,9,12..15,22) |
108 |
+ |
109 |
+ prints 1, 9, 12, 13, 14, 15 and 22. Such expressions can be used |
110 |
+ wherever a single value is used, e.g. |
111 |
+ |
112 |
+ _g_d_b> dl x[0..99]=0 ; |
113 |
+ |
114 |
+ assigns zero to the first 100 elements of array x. The semantics of |
115 |
+ x[i] are the same as in C. They are applied for each of the values |
116 |
+ returned by 0..99, which can be thought of as an implied external |
117 |
+ loop. The trailing semicolon indicates evaluation for side-effects |
118 |
+ only, with no output. Duel incorporates C operators, casts C |
119 |
+ statements as expressions, and supports limited variable declaration: |
120 |
+ |
121 |
+ _g_d_b> dl int i;for(i=0;i<100;i++) |
122 |
+ if(x[i]<0) printf("x[%d]=%d\n",i,x[i]); |
123 |
+ x[7] = -4 |
124 |
+ |
125 |
+ The semicolon prevents Duel output; only output from printf is |
126 |
+ printed. Aliases are defined with x:=y and provide an alternative to |
127 |
+ variable declaration. We could also return x[i] instead of using |
128 |
+ printf: |
129 |
+ |
130 |
+ _g_d_b> dl if(x[i:=0..99]<0) x[i] |
131 |
+ x[i] = -4 |
132 |
+ |
133 |
+ The symbolic output "x[i]" can be fixed by surrounding i with {}, i.e. |
134 |
+ |
135 |
+ _g_d_b> dl if(x[i:=0..99]<0) x[{i}] |
136 |
+ x[7] = -4 |
137 |
+ |
138 |
+ The {} are like (), but force the symbolic evaluation to use i's |
139 |
+ value, instead of "i". You can usually avoid this altogether with |
140 |
+ direct Duel operators: |
141 |
+ |
142 |
+ _g_d_b> dl x[..100] <? 0 |
143 |
+ x[7] = -4 |
144 |
+ |
145 |
+ The ..n operator is a shorthand for 0..n-1, i.e. ..100 is the same as |
146 |
+ 0..99. The x<?y, x==?y, x>=?y, etc., operators compare their left |
147 |
+ side operand to their right side operand as in C, but return the left |
148 |
+ side value if the comparison result is true. Otherwise, they look for |
149 |
+ the next values to compare, without returning anything. |
150 |
+ |
151 |
+ Duel's x.y and x->y allow an expression y, evaluated under x's scope: |
152 |
+ |
153 |
+ _g_d_b> dl emp[..100].(if(code>400) (code,name)) |
154 |
+ emp[46].code = 682 |
155 |
+ emp[46].name = "Ela" |
156 |
+ |
157 |
+ The if() expression is evaluated under the scope of each element of |
158 |
+ emp[], an array of structures. In C terms, we had to write: |
159 |
+ |
160 |
+ _g_d_b> dl int i; for(i=0; i<100 ; i++) |
161 |
+ if(emp[i].code>400) emp[{i}].code,emp[{i}].name |
162 |
+ |
163 |
+ A useful alternative to loops is the x=>y operator. It returns y for |
164 |
+ each value of x, setting `_' to reference x's value, e.g. |
165 |
+ |
166 |
+ _g_d_b> ..100 => if(emp[_].code>400) emp[_].code,emp[_].name |
167 |
+ |
168 |
+ Using `_' instead of `i' also avoids the need for {i}. Finally, the |
169 |
+ x-->y operator expands lists and other data structures. If head points |
170 |
+ to a linked list threaded through the next field, then: |
171 |
+ |
172 |
+ _g_d_b> dl head-->next->data |
173 |
+ head->data = 12 |
174 |
+ head->next->data = 14 |
175 |
+ head-->next[[2]]->data = 20 |
176 |
+ head-->next[[3]]->data = 26 |
177 |
+ |
178 |
+ produce the data field for each node in the list. x-->y returns x, x- |
179 |
+ >y, x->y->y, x->y->y->y, ... until a NULL is found. The symbolic |
180 |
+ output "x-->y[[n]]" indicates that ->y was applied n times. x[[y]] is |
181 |
+ also the selection operator: |
182 |
+ |
183 |
+ _g_d_b> dl head-->next[[50..60]]->data |
184 |
+ |
185 |
+ return the 50th through the 60th elements in the list. The #/x |
186 |
+ operator counts the number of values, so |
187 |
+ |
188 |
+ _g_d_b> dl #/( head-->next->data >? 50 ) |
189 |
+ |
190 |
+ counts the number of data elements over 50 on the list. Several other |
191 |
+ operators, including x@y, x#y and active call stack access are |
192 |
+ described in the operators section. |
193 |
+ |
194 |
+ OOOOPPPPEEEERRRRAAAATTTTOOOORRRRSSSS SSSSUUUUMMMMMMMMAAAARRRRYYYY |
195 |
+ Assoc Operators Details |
196 |
+ left {} () [] -> . f() --> x-->y expands x->y x->y->y ... |
197 |
+ x[[y]] x#y x@y generate x; select, index or stop-at y |
198 |
+ right #/ - * & ! ~ ++ -- (cast) #/x number of x values |
199 |
+ frame(n) sizeof(x) reference to call stack level n |
200 |
+ left x/y x*y x%y multiply, divide, reminder |
201 |
+ left x-y x+y add, subtract |
202 |
+ left x<<y x>>y shift left/right |
203 |
+ none x..y ..y x.. ..y = 0..y-1. x..y return x, x+1...y |
204 |
+ left < > <= >= <? >? <=? >=? x>?y return x if x>y |
205 |
+ left == != ==? !=? x==?y return x if x==y |
206 |
+ left x&y bit-and |
207 |
+ left x^y bit-xor |
208 |
+ left x|y bit-or |
209 |
+ left x&&y &&/x &&/x are all x values non-zero? |
210 |
+ left x||y ||/x ||/x is any x value non-zero? |
211 |
+ right x? y:z foreach x, if(x) y else z |
212 |
+ right x:=y x=y x+=y ... x:=y set x as an alias to y |
213 |
+ left x,y return x, then y |
214 |
+ right x=>y foreach x, evaluate y with x value `_' |
215 |
+ right if() else while() for() C statements cast as operators |
216 |
+ left x;y evaluate and ignore x, return y |
217 |
+ |
218 |
+ |
219 |
+ EEEEXXXXAAAAMMMMPPPPLLLLEEEESSSS |
220 |
+ dl (0xff-0x12)*3 compute simple expression |
221 |
+ dl (1..10)*(1..10) display multiplication table |
222 |
+ dl x[10..20,22,24,40..60] display x[i] for the selected indexes |
223 |
+ dl x[9..0] display x[i] backwards |
224 |
+ dl x[..100] >? 5 display x[i] that are greater than 5 |
225 |
+ dl x[..100] >? 5 <? 10 display x[i] if 5<x[i]<10 |
226 |
+ dl x[..100] ==? (6..9) same |
227 |
+ dl x[0..99]=>if(_>5 && _<10) _ same |
228 |
+ dl y[x[..100] !=? 0] display y[x[i]] for each non-zero x[i] |
229 |
+ dl emp[..50].code display emp[i].code for i=0 to 49 |
230 |
+ dl emp[..50].(code,name) display emp[i].code & emp[i].name |
231 |
+ dl val[..50].(is_dbl? x:y) display val[i].x or val[i].y depending |
232 |
+ on val[i].is_dbl. |
233 |
+ dl val[..50].if(is_dbl) x else y same as above |
234 |
+ dl x[..100]=0 ; assign 0 to x[i] |
235 |
+ dl x[i:=..100]=y[i] ; assign y[i] to x[i] |
236 |
+ dl x[..100]=y[..100] *ERR* assign y[99] to each x[j] |
237 |
+ dl x[i:=..3]=(4,5,9)[[i]] assign x[0]=4 x[1]=5 x[2]=9 |
238 |
+ dl x[..3]=(4,5,9) *ERR* assign 9 to each element |
239 |
+ dl if(x[i:=..100]<0) x[i]=0 ; assign 0 to negative x[i] |
240 |
+ dl (hash[..1024]!=?0)->scope hash[i].scope for non-null hash[i] |
241 |
+ dl x[i:=..100] >? x[i+1] check if x[i] is not sorted |
242 |
+ dl x[i:=..100] ==? x[j:=..100]=> checks if x has non-unique elements |
243 |
+ if(i<j) x[{i,j}] |
244 |
+ dl if(x[i:=..99] == same |
245 |
+ x[j:=i+1..99]) x[{i,j}] |
246 |
+ dl (x[..100] >? 0)[[0]] the 1st (0th element) positive x[i] |
247 |
+ dl (x[..100] >? 0)[[2]] return the 3rd positive x[i] |
248 |
+ dl (x[..100] >? 0)[[..5]] return the first 5 positive x[i] |
249 |
+ dl (x[0..] >? 6)[[0]] return the first x[i]>6, no limit on i |
250 |
+ dl argv[0..]@0 argv[0] argv[1] .. until first null |
251 |
+ dl x[0..]@-1 >? 9 x[0..n]>9 where n is first x[n]== -1 |
252 |
+ dl emp[0..]@(code==0) emp[0]..emp[n-1] where emp[n].code==0 |
253 |
+ |
254 |
+ dl head-->next->val val of each element in a linked list |
255 |
+ dl head-->next[[20]] the 21st element of a linked list |
256 |
+ dl *head-->next[[20]] display above as a struct |
257 |
+ dl strcmp(head-->next->msg, search linked list for a string |
258 |
+ "testing") ==? 0 |
259 |
+ dl #/head-->next count elements on a linked list |
260 |
+ dl x-->y[[#/x-->y - 1]] last element of a linked list |
261 |
+ dl x-->y[[#/x-->y - 10..1]] last 10 elements of a linked list |
262 |
+ dl head-->next-> check if the list is sorted by val |
263 |
+ if(next) val >? next->val |
264 |
+ |
265 |
+ dl head-->(next!=?head) expand cyclic linked list (tail->head) |
266 |
+ dl head-->(next!=?_) handle termination with p->next==p |
267 |
+ dl root-->(left,right)->key expand binary tree, show keys |
268 |
+ dl root-->(left,right)->( check bin tree sorted by key |
269 |
+ (left!=?0)->key>=?key, (right !=?0 )->key<=?key) |
270 |
+ |
271 |
+ dl (1000..=>if(&&/(2,3.._-1=>__%_ find first 10 primes over 1000 |
272 |
+ ) _)[[..10]] |
273 |
+ dl (T mytype) x convert x to user defined type mytype |
274 |
+ dl (struct s*) x convert x to struct s pointer |
275 |
+ dl if(x) y; else z *ERR* ';' must be followed by an expression |
276 |
+ dl {x} y *ERR* '}' requires ';' if followed by exp |
277 |
+ |
278 |
+ SSSSEEEEMMMMAAAANNNNTTTTIIIICCCCSSSS |
279 |
+ Duel's semantics are modeled after the Icon programming language. The |
280 |
+ input consists of expressions which return sequences of values. C |
281 |
+ statements are cast as expressions, too. Expressions are parsed into |
282 |
+ abstract syntax trees, which are traversed during evaluation. The |
283 |
+ evaluation of most nodes (operators) recursively evaluates the next |
284 |
+ value for each operand, and then applies the operator to produce the |
285 |
+ next result. Only one value is produced each time, and Duel's eval |
286 |
+ function keeps a `state' for each node (backtracking, co-routines, |
287 |
+ consumer-producer or threads are good metaphors for the evaluation |
288 |
+ mechanism.) |
289 |
+ |
290 |
+ For example, in (5,3)+6..8, the evaluation of `+' first retrieves the |
291 |
+ operands 5 and 6, to compute and return 5+6. Then 7, the next right |
292 |
+ operand is retrieved and 5+7 is returned, followed by 5+8. Since |
293 |
+ there are no other right operand value, the next left operand, 3 is |
294 |
+ fetched. The right operand's computation is restarted returning 6, and |
295 |
+ 3+6 is returned. The final return values are 3+7 and 3+8. |
296 |
+ |
297 |
+ The computation for operators like x>?y is similar, but when x<=y, the |
298 |
+ next values are fetched instead of returning a value, forming the |
299 |
+ basis for an implicit search. Operators like `..' return a sequence of |
300 |
+ values for each pair of operands. For a better understanding of the |
301 |
+ evaluation mechanism, see the USENIX Winter/93 conference paper "DUEL |
302 |
+ - A Very High Level Debugging Language". |
303 |
+ |
304 |
+ Duel values follow the C semantics. A value is either an "lvalue" (can |
305 |
+ be used as the left hand side of assignment), or an "rvalue". |
306 |
+ Therefor, objects like arrays can not be directly manipulated |
307 |
+ (However, operators like x..y can accomplish such tasks.) |
308 |
+ |
309 |
+ Duel types also follow the C semantics, with some important |
310 |
+ differences. C types are checked statically; Duel types are checked |
311 |
+ when operators are applied, e.g., (1,1.0)/2 returns 0 (int) and 0.5 |
312 |
+ (double); (x,y).z returns x.z and y.z even if x and y are of different |
313 |
+ types, as long as they both have a field z. |
314 |
+ |
315 |
+ Values and types of symbols are looked up at run-time (using gdb's |
316 |
+ lookup rules), allowing dynamic scoping and types, but causing a |
317 |
+ parsing problem: (x)(y) can be parsed as either a function call x(y) |
318 |
+ or a cast (x)y; x*y can be parsed as a declaration of y as (x*) or as |
319 |
+ multiplication. |
320 |
+ |
321 |
+ To avoid this ambiguity, the keyword T must precede a user defined |
322 |
+ type. For example, if value is a typedef, C's (value (*)()) x is |
323 |
+ written in Duel as: (T value (*)()) x. Types that begin with a |
324 |
+ reserved keyword don't need T, e.g. (struct value*) x and (long *[5]) |
325 |
+ y are accepted. As special cases, (type)x and (type*)x are accepted |
326 |
+ but discouraged (it causes (printf)("hi"), which is valid in C, to |
327 |
+ fail). A side effect is that "sizeof x" must be written as sizeof(x). |
328 |
+ |
329 |
+ OOOOPPPPEEEERRRRAAAATTTTOOOORRRRSSSS |
330 |
+ _x+_y _x-_y _x*_y _x/_y _x%_y _x^_y _x|_y _x&_y _x<<_y _x>>_y |
331 |
+ _x>_y _x<_y _x>=_y _x<=_y _x==_y _x!=_y _x=_y _x[_y] |
332 |
+ |
333 |
+ These binary operators follow their C semantics. For each value of x, |
334 |
+ they are evaluated for every value of y, .e.g. (5,2)>(4,1) evaluates |
335 |
+ as 5>4, 5>1, 2>4, 2>1 returning 1, 1, 0, 1. The y values are re- |
336 |
+ evaluated for each new value of x, e.g. i=4; (4,5)>i++ evaluates as |
337 |
+ 4>4 and 5>5. Beware of multiple y values in assignment, e.g. |
338 |
+ x[..3]=(4,6,9) does not set x[0]=4, x[1]=6 and x[2]=9. It assigns 4, 6 |
339 |
+ and 9 to each element, having the same effect as x[..3]=9. Use |
340 |
+ x[i:=..3]=(4,6,9)[[i]] to achieve the desired effect. |
341 |
+ |
342 |
+ -_x ~_x &_x *_x !_x ++_x --_x _x++ _x-- _s_i_z_e_o_f(_x) (_t_y_p_e)_x |
343 |
+ |
344 |
+ These unary operators follow their C semantics. They are applied to |
345 |
+ each value of x. The increment and decrement operators require an |
346 |
+ lvalue, so i:=0 ; i++ produces an error because i is an alias to 0, an |
347 |
+ rvalue. Parenthesis must be used with sizeof(x), "sizeof x" is not |
348 |
+ allowed. Cast to user defined type requires generally requires T, |
349 |
+ e.g., |
350 |
+ (T val(*)())x, but (val)x and (val*)x are accepted as special cases. |
351 |
+ |
352 |
+ _x&&_y _x||_y |
353 |
+ |
354 |
+ These logical operators also follow their C semantics, but have non- |
355 |
+ intuitive results for multi-valued x and y, e.g. (1,0,0) || (1,0) |
356 |
+ returns 1,1,0,1,0 -- the right hand-side (1,0) is returned for each |
357 |
+ left-hand side 0. It is best to use these operators only in single |
358 |
+ value expressions. |
359 |
+ |
360 |
+ _x? _y:_z _i_f(_x)_y _i_f(_x)_y _e_l_s_e _z |
361 |
+ |
362 |
+ These expressions return the values of y for each non-zero value |
363 |
+ returned by x, and the values of z for each zero value returned by x, |
364 |
+ e.g. if(x[..100]==0) y returns y for every x[i]==0, not if all x[i] |
365 |
+ are zero (if(&&/(x[..100]==0)) y does that). Also, "if(x) y; else z" |
366 |
+ is illegal. Duel's semicolon is an expression separator, not a |
367 |
+ terminator. |
368 |
+ |
369 |
+ _w_h_i_l_e(_x)_y _f_o_r(_w;_x;_y)_z |
370 |
+ |
371 |
+ The while(x)y expression returns y as long as all values of x are |
372 |
+ non-zero. The for() expression is similar and both have the expected |
373 |
+ C semantics. For example, "for(i=0 ; i<100 ; i++) x[i]" is the same as |
374 |
+ x[..100]. Unlike the if() expression, while(x[..100]==0) continue to |
375 |
+ execute only if all elements of x are zero, i.e. the condition is |
376 |
+ evaluated into a single value using an implicit &&/x. |
377 |
+ |
378 |
+ VVVVaaaarrrriiiiaaaabbbblllleeee ddddeeeeccccllllaaaarrrraaaattttiiiioooonnnn:::: _t_y_p_e _n_a_m_e [,_n_a_m_e ...] ; ... |
379 |
+ |
380 |
+ Expressions can begin with variables declaration (but not |
381 |
+ initialization). Internally, a declaration sets an alias to space |
382 |
+ allocated in the target by calling malloc(), e.g. `int x' is the same |
383 |
+ as "x:= *(int *) malloc(sizeof(int))". This is oblivious to the user. |
384 |
+ The allocated memory is not claimed when a variable is redeclared. |
385 |
+ Declared variables addresses can be passed to functions and used in |
386 |
+ other data structures. The keyword `T' must precede user defined types |
387 |
+ (typedef), e.g. if val is a user defined type, The C code "val |
388 |
+ *p=(val*) x" becomes "T val *p; p=(T val *) x" in Duel. |
389 |
+ |
390 |
+ FFFFuuuunnnnccccttttiiiioooonnnn ccccaaaallllllllssss:::: _f_u_n_c(_p_a_r_m,...) |
391 |
+ |
392 |
+ Function calls to the debugged program can be intermixed with Duel |
393 |
+ code. Multi-valued parameters are handled as with binary operators. |
394 |
+ The call value can have multiple values, e.g. (x,y)() calls x() and |
395 |
+ y(). Currently, struct/union parameters and return values are not |
396 |
+ supported. |
397 |
+ |
398 |
+ _x,_y _x.._y .._x _x.. |
399 |
+ |
400 |
+ These operators produce multiple values for single value operands. x,y |
401 |
+ returns x, then y. x..y returns the integers from x to y. When x>y the |
402 |
+ sequence is returned in descending order, i.e. 5..3 returns 5, 4, 3. |
403 |
+ The operator ..x is a shorthand for 0..x-1, e.g. ..3 returns 0, 1, 2. |
404 |
+ The x.. operator is a shorthand for x..maxint. It returns increasing |
405 |
+ integer values starting at x indefinitely, and should be bounded by |
406 |
+ [[n]] or @n operators. `,' retains its precedence level in C. The |
407 |
+ precedence of `..' is above `<' and below arithmetic operators, so |
408 |
+ 0..n-1 and x==1..9 work as expected. |
409 |
+ |
410 |
+ _x<?_y _x>?_y _x>=?_y _x<=?_y _x!=?_y _x==?_y |
411 |
+ |
412 |
+ These operators work like their C counterparts but return x if the |
413 |
+ comparison is true. If the comparison is false, the next (x,y) value |
414 |
+ is tried, forming the basis of an implicit search. |
415 |
+ |
416 |
+ (_x) {_x} _x;_y _x=>_y |
417 |
+ |
418 |
+ Both () and {} act as C parenthesis. The curly braces set the returned |
419 |
+ symbolic value as the actual value, e.g. if i=5 and x[5]=3, then x[i] |
420 |
+ produces the output "x[i] = 3", x[{i}] produces "x[5] = 3" and {x[i]} |
421 |
+ produces just "3". The semicolon is an operator. x;y evaluates x, |
422 |
+ ignoring the results, then evaluate and return y, e.g. (i:=1..3 ; i+5) |
423 |
+ sets i to 3 and return 8. The x=>y operator evaluate and return y for |
424 |
+ each value of x, e.g. (i:=1..3 => i+5) returns 6, 7 and 8. The value |
425 |
+ returned by x is also stored implicitly in `_' which can be used in y, |
426 |
+ e.g. 1..5 => z[_][_] will output z[1][1], z[2][2] etc. The symbolic |
427 |
+ value for _ is that of the left side value, hence {_} is not needed. |
428 |
+ Semicolon has the lowest precedence, so it must be used inside () or |
429 |
+ {} for compound expressions. The precedence of `=>' is just below `,'. |
430 |
+ Beware that "if(a) x; else {y;} z" is illegal; a semicolon is not |
431 |
+ allowed before '}' or 'else' and must be inserted before z. |
432 |
+ |
433 |
+ _x->_y _x._y |
434 |
+ |
435 |
+ These expression work as in C for a symbol y. If y is an expression, |
436 |
+ it is evaluated under the scope of x. e.g. x.(a+b) is the same as |
437 |
+ x.a+x.b, if a and b are field of x (if they are not, they are looked |
438 |
+ up as local or global variables). x may return multiple values of |
439 |
+ different types, e.g. (u,v).a returns u.a and v.a, even if u and v are |
440 |
+ different structures. Also, the value of x is available as `_' inside |
441 |
+ y, e.g. x[..100].(if(a) _) produces x[i] for each x[i].a!=0. Nested |
442 |
+ x.y are allowed, e.g. u.(v.(a+b)) would lookup a and b first under v, |
443 |
+ then under u. |
444 |
+ |
445 |
+ AAAAlllliiiiaaaasssseeeessss:::: _x:=_y |
446 |
+ |
447 |
+ Aliases store a reference to y in x. Any reference to x is then |
448 |
+ replaced by y. If y is a constant or an rvalue, its value is replaced |
449 |
+ for x. If y is an lvalue (e.g. a variable), a reference to same lvalue |
450 |
+ is returned. for example, x:=emp[5] ; x=9 assigns 9 to emp[5]. |
451 |
+ Aliases retain their values across invocation of the "dl" command. An |
452 |
+ alias to a local variable will reference a stray address when the |
453 |
+ variable goes out of scope. The special command "dl clear" delete all |
454 |
+ the aliases, and "dl alias" show all current aliases. Symbols are |
455 |
+ looked up as aliases first, so an alias x will hide a local x. |
456 |
+ |
457 |
+ _x-->_y |
458 |
+ |
459 |
+ The expansion operator x-->y expands a data structure x following the |
460 |
+ y links. It returns x, x->y, x->y->y, until a null is found. If x is |
461 |
+ null, no values are produced. If y returns multiple values, they are |
462 |
+ stacked and each is further expanded in a depth-first notion. For |
463 |
+ example, if r is the root of a tree with children u->childs[..u- |
464 |
+ >nchilds], then u-->(childs[..nchilds]) expands the whole tree. y is |
465 |
+ an arbitrary expression, evaluated exactly like x->y (this includes |
466 |
+ `_'.) |
467 |
+ |
468 |
+ _x@_y |
469 |
+ |
470 |
+ The expression x@y produces the values of x until x.y is non-zero, |
471 |
+ e.g. for(i=0 ; x[i].code!= -1 && i<100 ; i++) x[i] can be written as |
472 |
+ x[..100]@(code==-1). The evaluation of x is stopped as soon as y |
473 |
+ evaluates to true. x->y or x=>y are used to evaluate y when x is not a |
474 |
+ struct or a union. If y is a constant,(_==y) is used. e.g. s[0..]@0 |
475 |
+ produces the characters in string s up to but not including the |
476 |
+ terminating null. |
477 |
+ |
478 |
+ #/_x &&/_x ||/_x |
479 |
+ |
480 |
+ These operator return a single "summary" value for all the values |
481 |
+ returned by x. #/x returns the number of values returned by x, e.g. |
482 |
+ #/(x[..100]>?0) counts the number of positive x[i]. &&/x returns 1 if |
483 |
+ all the values produced by x are non-zero, and ||/x returns 1 if any |
484 |
+ of x's values are non-zero. Like in C, the evaluation stops as soon as |
485 |
+ possible. For example, ||/(x[..100]==0) and &&/(x[..100]==0) check if |
486 |
+ one or all of x[i] are zero, respectively. |
487 |
+ |
488 |
+ _x#_y _x[[_y]] |
489 |
+ |
490 |
+ The operator x#y produces the values of x and arranges for y to be an |
491 |
+ alias for the index of each value in x. It is commonly used with x-->y |
492 |
+ to produce the element's index, e.g. head-->next->val#i=i assigns |
493 |
+ each val field its element number in the list. |
494 |
+ The selection operator x[[y]] produces the yth result of x. If y |
495 |
+ returns multiple value, each select a value of x, e.g. |
496 |
+ (5,7,11,13)[3,0,2] returns 13, 5 and 11 (13 is the 3rd element, 5 is |
497 |
+ the 0th element). Don't use side effects in x, since its evaluation |
498 |
+ can be restarted depending on y, e.g. after (x[0..i++])[[3,5]] the |
499 |
+ value of i is unpredictable. |
500 |
+ |
501 |
+ _f_r_a_m_e(_n) _f_r_a_m_e_s__n_o _f_u_n_c._x |
502 |
+ |
503 |
+ frame(n) for an integer n returns a reference to the nth frame on the |
504 |
+ stack (0 is the inner most function and frame(frames_no-1) is main()). |
505 |
+ Frame values can be compared to function pointers, e.g. |
506 |
+ frame(3)==myfunc is true if the 4th frame is a call to myfunc, and in |
507 |
+ scope resolution, e.g. frame(3).x return the local variable x of the |
508 |
+ 4th frame. frames_no is the number of active frames on the stack, |
509 |
+ e.g. (frames(..frames_no) ==? myfunc).x displays x for all active |
510 |
+ invocations of myfunc. As a special case, |
511 |
+ (frames(..frames_no)==?f)[[0]].x can be written as f.x (x can be an |
512 |
+ expression). |
513 |
+ |
514 |
+ |
515 |
+ BBBBUUUUGGGGSSSS |
516 |
+ Both `{}' and `;' are operators, not statements or expression |
517 |
+ separators; "if(x) y; else {z;} u" is illegal; use "if(x) y else {z} ; |
518 |
+ u". Ambiguities require preceding user-defined types (typedef) with |
519 |
+ the keyword T, e.g., if value is a user type, C's "sizeof(value*)" is |
520 |
+ written "sizeof(T value*)", except for the casts "(t)x" and "(t*)x"; |
521 |
+ sizeof(x) requires parenthesis for variable x. |
522 |
+ |
523 |
+ Unimplemented C idiom include: modified-assignment (x+=y), switch, |
524 |
+ break, continue, do, goto, scopes, function declarations, initializing |
525 |
+ declared variables, assignment to bit-fields and register variables, |
526 |
+ and calling functions with a struct/union parameter or return value. |
527 |
+ gdb does not store function prototypes, so parameters are not checked. |
528 |
+ |
529 |
+ Gdb itself is buggy, which shows up, especially in symbol tables and |
530 |
+ calling target functions. Before you report bug, try to do the closest |
531 |
+ thing under gdb's "print". Send bug to: mg@××××××××××××.edu. |
532 |
+ |
533 |
+ FFFFIIIILLLLEEEESSSS |
534 |
+ duel.out tracks duel commands usage. Help analyze duel's use by |
535 |
+ mailing a copy to mg@××××××××××××.edu. |
536 |
+ Duel is available by anonymous ftp at ftp.cs.princeton.edu:/duel. |
537 |
+ |
538 |
+ AAAAUUUUTTTTHHHHOOOORRRR |
539 |
+ Duel is public domain code -- no copy left or right. See the internals |
540 |
+ documentation for details on porting Duel and using its code. Duel |
541 |
+ was designed and written by Michael Golan as part of a PhD thesis in |
542 |
+ the Computer Science Department of Princeton University. I would like |
543 |
+ to thank my advisor, Dave Hanson, who helped in all phases of this |
544 |
+ project and to Matt Blaze for his support and useful insight. |
545 |
+ |
546 |
+ Duel stands for Debugging U (might) Even Like, or Don't Use this |
547 |
+ Exotic Language. Judge for yourself! |
548 |
--- gdb/duel/Makefile |
549 |
+++ gdb/duel/Makefile |
550 |
@@ -0,0 +1,44 @@ |
551 |
+# |
552 |
+# generic makefile for Duel 1.10 |
553 |
+# nothing fancy is required: yacc/bison of parse.y, compile all other modules, |
554 |
+# and put all of the OBJ= modules into duel.a library. |
555 |
+# gdb is compiled with its own makefile (you add duel.a and duelgdb.c) |
556 |
+# selfduel, for testing, is compiled and linked with duel.a |
557 |
+ |
558 |
+# NOTE: |
559 |
+# for sunOS4.x you must use gcc or another ANSI compiler. cc doesnt |
560 |
+# support prototypes! |
561 |
+# Also for sunOS4.x, yacc inserts a declaration of malloc() at the first line |
562 |
+# of y.tab.c, which is WRONG (return char*). just delete it. |
563 |
+ |
564 |
+CFLAGS= -g |
565 |
+CC= cc # won't work on sunOS. need ANSI C prototypes support. |
566 |
+#CC= gcc |
567 |
+YACC=yacc |
568 |
+RANLIB=ranlib # for BSD-derived systems |
569 |
+ |
570 |
+#CC = gcc -U__GNUC__ #ONLY if you get __eprintf undefined (assert.h problem) |
571 |
+#RANLIB=echo # for System V, there is no 'ranlib' |
572 |
+ |
573 |
+OBJ= duel.o types.o eval.o misc.o y.tab.o error.o evalops.o print.o |
574 |
+ |
575 |
+all: duel.a duelself |
576 |
+ |
577 |
+duelself: duel.a duelself.o output.o |
578 |
+ $(CC) duelself.o duel.a output.o -o duelself |
579 |
+ |
580 |
+duel.a: $(OBJ) |
581 |
+ ar ru duel.a $(OBJ) |
582 |
+ $(RANLIB) duel.a |
583 |
+ |
584 |
+y.tab.c: parse.y |
585 |
+ $(YACC) parse.y |
586 |
+clean: |
587 |
+ rm -f $(OBJ) y.tab.c duelself.o duelself duel.a |
588 |
+ |
589 |
+install: |
590 |
+ |
591 |
+test: duelself |
592 |
+ duelself <tsuite.self >self.out |
593 |
+ @echo NOTE: diffs of the @xxxx values are ok |
594 |
+ diff tsuite.self.out self.out |
595 |
--- gdb/duel/README |
596 |
+++ gdb/duel/README |
597 |
@@ -0,0 +1,57 @@ |
598 |
+------------------------------------------------------------------------------- |
599 |
+README for DUEL 1.10 distribution mg@××××××××××××.edu (M. Golan) Mar 93 |
600 |
+------------------------------------------------------------------------------- |
601 |
+see WHATNEW for what's new in version 1.10. |
602 |
+ |
603 |
+DUEL - A high level language for debugging C programs. |
604 |
+ |
605 |
+ Duel is a special purpose language designed for concise state |
606 |
+ exploration of debugged C programs under existing debuggers. |
607 |
+ It allows you to explore your program's state better than either |
608 |
+ the debugger's commands, a C interpreter, or print statements |
609 |
+ added to your programs. The debugger is extended with the new |
610 |
+ 'dl' command for Duel expressions, e.g., |
611 |
+ |
612 |
+ gdb> dl x[0..10].level >? 5 |
613 |
+ x[3].level = 14 |
614 |
+ x[8].level = 6 |
615 |
+ |
616 |
+ prints the "level" fields of array elements x[0] to x[10] that are greater |
617 |
+ than 5. The output includes the values 14 and 6, as well as their |
618 |
+ symbolic representation "x[3].level" and "x[8].level". Linked list and |
619 |
+ other complex data structures are just as easy. Most of C (e.g. for, if) |
620 |
+ is also supported, e.g., int i; for(i=0; i<11; i++) if(x[i].level>5) x[i]. |
621 |
+ |
622 |
+Even if you don't normally use debuggers, but you are programming in C, give |
623 |
+Duel a try! The man page & help even include a summary of useful gdb commands. |
624 |
+The man page (duel.1) contains an introduction & many examples. |
625 |
+ |
626 |
+Duel is debugger-independent, but the current distribution interface only |
627 |
+with gdb. You will need the source for gdb-4.6, 4.7 or 4.8. Duel is public |
628 |
+domain code. Do whatever you like with it - add it to commercial debuggers, |
629 |
+to dbx/sdb or even make it part of the GNU project. |
630 |
+ |
631 |
+NO PART OF THIS DISTRIBUTION CONTAINS ANY COPYRIGHT OR DERIVED CODE, |
632 |
+(i.e. no GPL code, either). Free and public domain code need no disclaimer, |
633 |
+which is obvious to anyone in the software business. |
634 |
+ |
635 |
+Duel is available for anonymous ftp from ftp.cs.princeton.edu, in |
636 |
+/duel/duel.tar.Z. "tar.Z" format means you should use the command |
637 |
+ "zcat duel.tar.Z | tar xf -" to unpack the files. |
638 |
+ |
639 |
+The Usenix Jan/93 paper about Duel is also available as tech report 399, |
640 |
+in /reports/1992/399.ps.Z on ftp.cs.princeton.edu, or, in it Usenix |
641 |
+formatting, as /duel/usenix.paper.ps.Z. The software & man page are more |
642 |
+up-to-date though. |
643 |
+ |
644 |
+See MANIFEST for a list of files in the distribution. The file INSTALL |
645 |
+explains how to install duel. MANUAL is a formatted version of the manual |
646 |
+duel.1. |
647 |
+ |
648 |
+If you are using duel and find it useful, or have any comments or suggestion, |
649 |
+please drop me a line! duel.out is automatically produced to contain |
650 |
+the dl commands you have used, I would appreciate it if you email it to |
651 |
+me so that I could collect usage information. Thanks! |
652 |
+ |
653 |
+Michael Golan |
654 |
+mg@××××××××××××.edu |
655 |
--- gdb/duel/WHATNEW |
656 |
+++ gdb/duel/WHATNEW |
657 |
@@ -0,0 +1,38 @@ |
658 |
+------------------------------------------------------------------------------- |
659 |
+WHATNEW for DUEL 1.10 distribution mg@××××××××××××.edu (M. Golan) Mar 93 |
660 |
+------------------------------------------------------------------------------- |
661 |
+patch 1.10.4 fix use of system("date") to support OS/2 |
662 |
+patch 1.10.3 bug fix left->left bad symbolic, long symbolics caused crash |
663 |
+patch 1.10.2 bug fix (type*) casting was wrong |
664 |
+patch 1.10.1 bug fix frame(0).bad_name crashed duel. enum size zero, |
665 |
+ sometimes possible in symbol tables, now allowed. |
666 |
+ |
667 |
+What's New in version 1.10 |
668 |
+-------------------------- |
669 |
+Previously, all typedefs had to be preceded with 'T', e.g. (T uint) x. |
670 |
+The parsing is now hacked, so that the most common cases don't require T: |
671 |
+(type)x and (type*)x, e.g., (uint)x, *(value *)p. T is still required in |
672 |
+complex casts like (T value (*)())p, in variable declaration "T uint x ;" |
673 |
+and with sizeof(T uint). Side effects of this change: (printf)("hi\n") |
674 |
+won't work, since (printf) is recognized as a cast. This shouldn't be a |
675 |
+problem - you can use {x} for (x). Also, "sizeof x" is no longer supported, |
676 |
+you must use sizeof(x) instead. |
677 |
+ |
678 |
+An experimental output control through a pipe has been added. To try it, |
679 |
+you should change duel/src/Makefile to compile output2.o instead of output.o |
680 |
+(delete duel.a to make sure it won't have both output.o and output2.o). |
681 |
+When output2.o is linked into duelself and/or gdb, duel fork and execute |
682 |
+the command duel.pipe in the current directory. All the output from expression |
683 |
+evaluation is sent to this program and its output is displayed. An example |
684 |
+duel.pipe, a Perl script, is provided. A lot that can be done with duel.pipe |
685 |
+to process the results symbolically, e.g., display integers in decimal, |
686 |
+place values on the same line, fork and execute xgraph, check |
687 |
+for unique values, etc. I would appreciate any comments on its use. |
688 |
+ |
689 |
+A few minor bugs have been fixed. duel.man now contains a nicely formatted |
690 |
+version of duel.1. Portability was improved. #/(x) provide a better symbolic |
691 |
+expression. |
692 |
+ |
693 |
+What's new in version 1.02 |
694 |
+-------------------------- |
695 |
+a few bug fixed, improved portability, gdb4.8 support. |
696 |
--- gdb/duel/duel.1 |
697 |
+++ gdb/duel/duel.1 |
698 |
@@ -0,0 +1,547 @@ |
699 |
+'\" t |
700 |
+.\" This document and the Duel source code are in the public domain. |
701 |
+.\" Note that the duel executable contains GNU code and is not public domain. |
702 |
+.TH Duel 1 "Mar 93" "Version 1.10" |
703 |
+.SH NAME |
704 |
+duel \- A high level C debugging language extension to gdb |
705 |
+.SH SYNOPSIS |
706 |
+.B duel |
707 |
+[gdb options] |
708 |
+.RB "[\|" \c |
709 |
+.I prog\c |
710 |
+.RB "[\|" \c |
711 |
+.IR core \||\| procID\c |
712 |
+\&\|]\&\|] |
713 |
+.ad b |
714 |
+.SH DESCRIPTION |
715 |
+Duel is a special purpose language designed for concise state exploration |
716 |
+of debugged C programs, currently implemented under the GNU debugger |
717 |
+.IR gdb (1). |
718 |
+Duel is invoked by entering the shell command |
719 |
+.I duel |
720 |
+instead of |
721 |
+.I gdb. |
722 |
+It is identical to gdb except for |
723 |
+comments, which begin with `##' instead of `#', and the new |
724 |
+.I dl |
725 |
+command for Duel expressions: |
726 |
+.nf |
727 |
+ |
728 |
+\f2gdb>\f1 dl x[1..10] >? 5 |
729 |
+x[3] = 14 |
730 |
+x[8] = 6 |
731 |
+ |
732 |
+.fi |
733 |
+prints the array elements x[1] to x[10] that are greater than 5. |
734 |
+The output includes the values 14 and 6, as well as their |
735 |
+symbolic representation "x[3]" and "x[8]". |
736 |
+.SH IF YOU NEVER USED GDB |
737 |
+The improved functionality added by Duel merits a fresh look |
738 |
+even by debugger shunners. |
739 |
+Gdb is a powerful debugger with many commands, a thick manual and |
740 |
+various interfaces including |
741 |
+.IR emacs (1) |
742 |
+and |
743 |
+.IR xxgdb (1). |
744 |
+These gdb commands should help you get started: |
745 |
+ |
746 |
+.TS |
747 |
+l l. |
748 |
+\f2b line\f1 set a breakpoint at the line (b func to break at a function) |
749 |
+\f2d n\f1 delete breakpoint number n (gdb prints n when bp occurs) |
750 |
+\f2l line\f1 list the source beginning at line (l file.c:line for module) |
751 |
+\f2r parm\f1 run/restart the program with the given parameters |
752 |
+\f2s\f1 single-step to the next statement (steps into function calls) |
753 |
+\f2n\f1 single-step to the next line, skipping over function calls |
754 |
+\f2c\f1 continue execution |
755 |
+\f2bt\f1 show a stack trace |
756 |
+\f2p exp\f1 evaluate a symbolic expression |
757 |
+\f2dl exp\f1 evaluate a Duel expression |
758 |
+\f2dl gdb\f1 give a gdb command summary |
759 |
+.TE |
760 |
+ |
761 |
+The most common use is `b func' followed by `r' followed by several |
762 |
+`n' and `s', evaluating expressions in between. |
763 |
+.SH DUEL QUICK START |
764 |
+Duel is implemented by adding the |
765 |
+.I dl |
766 |
+command to gdb. All gdb commands |
767 |
+work as before. The dl command, however, is interpreted by duel. |
768 |
+Gdb concepts (such as the value history) do not work in the dl command, |
769 |
+and duel concepts are not understood by other gdb command. |
770 |
+ |
771 |
+Duel is based on expressions which return multiple values. |
772 |
+The x..y operator returns |
773 |
+the integers from x to y; the x,y operator returns x and then y, e.g. |
774 |
+.sp |
775 |
+\f2gdb>\f1 dl (1,9,12..15,22) |
776 |
+.sp |
777 |
+prints 1, 9, 12, 13, 14, 15 and 22. Such expressions can |
778 |
+be used wherever a single value is used, e.g. |
779 |
+.sp |
780 |
+\f2gdb>\f1 dl x[0..99]=0 ; |
781 |
+.sp |
782 |
+assigns zero to the first 100 elements of array x. The semantics of x[i] |
783 |
+are the same as in C. They are applied for each of the values |
784 |
+returned by 0..99, which can be thought of as an implied external loop. |
785 |
+The trailing semicolon indicates evaluation for side-effects only, with no |
786 |
+output. |
787 |
+Duel incorporates C operators, casts C statements as |
788 |
+expressions, and supports limited variable declaration: |
789 |
+.sp |
790 |
+.br |
791 |
+\f2gdb>\f1 dl int i;for(i=0;i<100;i++) |
792 |
+.br |
793 |
+ if(x[i]<0) printf("x[%d]=%d\\n",i,x[i]); |
794 |
+.br |
795 |
+x[7] = -4 |
796 |
+.sp |
797 |
+The semicolon prevents Duel output; |
798 |
+only output from printf is printed. |
799 |
+Aliases are defined with x:=y and provide an alternative to variable |
800 |
+declaration. We could also return x[i] instead of using printf: |
801 |
+.sp |
802 |
+\f2gdb>\f1 dl if(x[i:=0..99]<0) x[i] |
803 |
+.br |
804 |
+x[i] = -4 |
805 |
+.sp |
806 |
+The symbolic output "x[i]" can be fixed by surrounding i with {}, i.e. |
807 |
+.sp |
808 |
+\f2gdb>\f1 dl if(x[i:=0..99]<0) x[{i}] |
809 |
+.br |
810 |
+x[7] = -4 |
811 |
+.sp |
812 |
+The {} are like (), but force the symbolic evaluation to use i's value, |
813 |
+instead of "i". You can usually avoid this altogether |
814 |
+with direct Duel operators: |
815 |
+.sp |
816 |
+\f2gdb>\f1 dl x[..100] <? 0 |
817 |
+.br |
818 |
+x[7] = -4 |
819 |
+.sp |
820 |
+The ..n operator is a shorthand for 0..n-1, i.e. ..100 is the same as 0..99. |
821 |
+The x<?y, x==?y, x>=?y, etc., operators compare their left side operand to |
822 |
+their right side operand as in C, but return the left side value if |
823 |
+the comparison result is true. Otherwise, they look for the next |
824 |
+values to compare, without returning anything. |
825 |
+ |
826 |
+Duel's x.y and x->y allow an expression y, evaluated under x's scope: |
827 |
+.sp |
828 |
+\f2gdb>\f1 dl emp[..100].(if(code>400) (code,name)) |
829 |
+.br |
830 |
+emp[46].code = 682 |
831 |
+.br |
832 |
+emp[46].name = "Ela" |
833 |
+.sp |
834 |
+The if() expression is evaluated under the scope of each element |
835 |
+of emp[], an array of structures. In C terms, we had to write: |
836 |
+.sp |
837 |
+\f2gdb>\f1 dl int i; for(i=0; i<100 ; i++) |
838 |
+.br |
839 |
+ if(emp[i].code>400) emp[{i}].code,emp[{i}].name |
840 |
+.sp |
841 |
+A useful alternative to loops is the x=>y operator. It returns y for each |
842 |
+value of x, setting `_' to reference x's value, e.g. |
843 |
+.sp |
844 |
+\f2gdb>\f1 ..100 => if(emp[_].code>400) emp[_].code,emp[_].name |
845 |
+.sp |
846 |
+Using `_' instead of `i' also avoids the need for {i}. Finally, |
847 |
+the x\-\->y operator expands lists and other data structures. If head points |
848 |
+to a linked list threaded through the next field, then: |
849 |
+.sp |
850 |
+\f2gdb>\f1 dl head-->next->data |
851 |
+.br |
852 |
+head->data = 12 |
853 |
+.br |
854 |
+head->next->data = 14 |
855 |
+.br |
856 |
+head-->next[[2]]->data = 20 |
857 |
+.br |
858 |
+head-->next[[3]]->data = 26 |
859 |
+.sp |
860 |
+produce the data field for each node in the list. x\-\->y |
861 |
+returns x, x->y, x->y->y, x->y->y->y, ... until a NULL is found. |
862 |
+The symbolic output "x\-\->y[[n]]" |
863 |
+indicates that ->y was applied n times. x[[y]] is also the selection |
864 |
+operator: |
865 |
+.sp |
866 |
+\f2gdb>\f1 dl head-->next[[50..60]]->data |
867 |
+.sp |
868 |
+return the 50th through the 60th elements in the list. The #/x operator |
869 |
+counts the number of values, so |
870 |
+.sp |
871 |
+\f2gdb>\f1 dl #/( head-->next->data >? 50 ) |
872 |
+.sp |
873 |
+counts the number of data elements over 50 on the list. |
874 |
+Several other operators, including x@y, x#y and |
875 |
+active call stack access are described in the operators section. |
876 |
+.SH OPERATORS SUMMARY |
877 |
+.\"All the C operators have the same precedence and associativity as in C. C |
878 |
+.\"statements have precedence just below `,' and `;' has the lowest precedence. |
879 |
+.\"Most Duel operators have the same precedence as their C counterparts. The |
880 |
+.\"following table is in decreasing precedence: |
881 |
+.TS |
882 |
+l l l. |
883 |
+Assoc Operators Details |
884 |
+left {} () [] -> . f() --> x-->y expands x->y x->y->y ... |
885 |
+ x[[y]] x#y x@y generate x; select, index or stop-at y |
886 |
+right #/ - * & ! ~ ++ -- (cast) #/x number of x values |
887 |
+ frame(n) sizeof(x) reference to call stack level n |
888 |
+left x/y x*y x%y multiply, divide, reminder |
889 |
+left x-y x+y add, subtract |
890 |
+left x<<y x>>y shift left/right |
891 |
+none x..y ..y x.. ..y = 0..y-1. x..y return x, x+1...y |
892 |
+left < > <= >= <? >? <=? >=? x>?y return x if x>y |
893 |
+left == != ==? !=? x==?y return x if x==y |
894 |
+left x&y bit-and |
895 |
+left x^y bit-xor |
896 |
+left x|y bit-or |
897 |
+left x&&y &&/x &&/x are all x values non-zero? |
898 |
+left x||y ||/x ||/x is any x value non-zero? |
899 |
+right x? y:z foreach x, if(x) y else z |
900 |
+right x:=y x=y x+=y ... x:=y set x as an alias to y |
901 |
+left x,y return x, then y |
902 |
+right x=>y foreach x, evaluate y with x value `_' |
903 |
+right if() else while() for() C statements cast as operators |
904 |
+left x;y evaluate and ignore x, return y |
905 |
+.TE |
906 |
+ |
907 |
+.SH EXAMPLES |
908 |
+.TS |
909 |
+l l. |
910 |
+dl (0xff-0x12)*3 compute simple expression |
911 |
+dl (1..10)*(1..10) display multiplication table |
912 |
+dl x[10..20,22,24,40..60] display x[i] for the selected indexes |
913 |
+dl x[9..0] display x[i] backwards |
914 |
+dl x[..100] >? 5 display x[i] that are greater than 5 |
915 |
+dl x[..100] >? 5 <? 10 display x[i] if 5<x[i]<10 |
916 |
+dl x[..100] ==? (6..9) same |
917 |
+dl x[0..99]=>if(_>5 && _<10) _ same |
918 |
+dl y[x[..100] !=? 0] display y[x[i]] for each non-zero x[i] |
919 |
+dl emp[..50].code display emp[i].code for i=0 to 49 |
920 |
+dl emp[..50].(code,name) display emp[i].code & emp[i].name |
921 |
+dl val[..50].(is_dbl? x:y) display val[i].x or val[i].y depending |
922 |
+ on val[i].is_dbl. |
923 |
+dl val[..50].if(is_dbl) x else y same as above |
924 |
+dl x[..100]=0 ; assign 0 to x[i] |
925 |
+dl x[i:=..100]=y[i] ; assign y[i] to x[i] |
926 |
+dl x[..100]=y[..100] *ERR* assign y[99] to each x[j] |
927 |
+dl x[i:=..3]=(4,5,9)[[i]] assign x[0]=4 x[1]=5 x[2]=9 |
928 |
+dl x[..3]=(4,5,9) *ERR* assign 9 to each element |
929 |
+dl if(x[i:=..100]<0) x[i]=0 ; assign 0 to negative x[i] |
930 |
+dl (hash[..1024]!=?0)->scope hash[i].scope for non-null hash[i] |
931 |
+dl x[i:=..100] >? x[i+1] check if x[i] is not sorted |
932 |
+dl x[i:=..100] ==? x[j:=..100]=> checks if x has non-unique elements |
933 |
+ if(i<j) x[{i,j}] |
934 |
+dl if(x[i:=..99] == same |
935 |
+ x[j:=i+1..99]) x[{i,j}] |
936 |
+dl (x[..100] >? 0)[[0]] the 1st (0th element) positive x[i] |
937 |
+dl (x[..100] >? 0)[[2]] return the 3rd positive x[i] |
938 |
+dl (x[..100] >? 0)[[..5]] return the first 5 positive x[i] |
939 |
+dl (x[0..] >? 6)[[0]] return the first x[i]>6, no limit on i |
940 |
+dl argv[0..]@0 argv[0] argv[1] .. until first null |
941 |
+dl x[0..]@-1 >? 9 x[0..n]>9 where n is first x[n]== -1 |
942 |
+dl emp[0..]@(code==0) emp[0]..emp[n-1] where emp[n].code==0 |
943 |
+ |
944 |
+dl head-->next->val val of each element in a linked list |
945 |
+dl head-->next[[20]] the 21st element of a linked list |
946 |
+dl *head-->next[[20]] display above as a struct |
947 |
+dl strcmp(head-->next->msg, search linked list for a string |
948 |
+ "testing") ==? 0 |
949 |
+dl #/head-->next count elements on a linked list |
950 |
+dl x-->y[[#/x-->y - 1]] last element of a linked list |
951 |
+dl x-->y[[#/x-->y - 10..1]] last 10 elements of a linked list |
952 |
+dl head-->next-> check if the list is sorted by val |
953 |
+ if(next) val >? next->val |
954 |
+ |
955 |
+dl head-->(next!=?head) expand cyclic linked list (tail->head) |
956 |
+dl head-->(next!=?_) handle termination with p->next==p |
957 |
+dl root-->(left,right)->key expand binary tree, show keys |
958 |
+dl root-->(left,right)->( check bin tree sorted by key |
959 |
+ (left!=?0)->key>=?key, (right !=?0 )->key<=?key) |
960 |
+ |
961 |
+dl (1000..=>if(&&/(2,3.._-1=>__%_ find first 10 primes over 1000 |
962 |
+ ) _)[[..10]] |
963 |
+dl (T mytype) x convert x to user defined type mytype |
964 |
+dl (struct s*) x convert x to struct s pointer |
965 |
+dl if(x) y; else z *ERR* ';' must be followed by an expression |
966 |
+dl {x} y *ERR* '}' requires ';' if followed by exp |
967 |
+.TE |
968 |
+.SH SEMANTICS |
969 |
+Duel's semantics are modeled after the Icon programming language. |
970 |
+The input consists of expressions which return sequences of values. |
971 |
+C statements are cast as expressions, too. |
972 |
+Expressions are parsed into abstract syntax trees, which are |
973 |
+traversed during evaluation. The evaluation of most nodes (operators) |
974 |
+recursively evaluates the next value for each operand, and then applies the |
975 |
+operator to produce the next result. Only one value is produced each time, |
976 |
+and Duel's eval function keeps a `state' for each node |
977 |
+(backtracking, co-routines, consumer-producer or threads are good metaphors |
978 |
+for the evaluation mechanism.) |
979 |
+ |
980 |
+For example, in (5,3)+6..8, the |
981 |
+evaluation of `+' first retrieves the operands 5 and 6, to compute and |
982 |
+return 5+6. Then 7, the next right operand is retrieved |
983 |
+and 5+7 is returned, followed by 5+8. |
984 |
+Since there are no other right operand value, the next left operand, 3 |
985 |
+is fetched. The right operand's computation is restarted returning |
986 |
+6, and 3+6 is returned. The final return values are 3+7 and 3+8. |
987 |
+ |
988 |
+The computation for operators like x>?y is similar, but when x<=y, |
989 |
+the next values are fetched instead of returning a value, |
990 |
+forming the basis for an implicit search. Operators like `..' return a |
991 |
+sequence of values for each pair of operands. For a better understanding |
992 |
+of the evaluation mechanism, see the USENIX Winter/93 conference paper |
993 |
+"DUEL - A Very High Level Debugging Language". |
994 |
+ |
995 |
+Duel values follow the C semantics. A value is either an |
996 |
+"lvalue" (can be used as the left hand side of assignment), or an "rvalue". |
997 |
+Therefor, objects like arrays can not be directly manipulated (However, |
998 |
+operators like x..y can accomplish such tasks.) |
999 |
+ |
1000 |
+Duel types also follow the C semantics, with some important |
1001 |
+differences. C types are checked statically; Duel types are checked |
1002 |
+when operators are applied, e.g., (1,1.0)/2 returns 0 (int) and |
1003 |
+0.5 (double); (x,y).z returns x.z and y.z even if |
1004 |
+x and y are of different types, as long as they both have a field z. |
1005 |
+ |
1006 |
+Values and types of symbols are looked up at run-time (using gdb's lookup |
1007 |
+rules), allowing dynamic scoping and types, but causing a parsing |
1008 |
+problem: (x)(y) can be parsed as either a function call x(y) or a |
1009 |
+cast (x)y; x*y can be parsed as a declaration of y as (x*) or as |
1010 |
+multiplication. |
1011 |
+ |
1012 |
+To avoid this ambiguity, the |
1013 |
+keyword T must precede a user defined type. For example, |
1014 |
+if value is a typedef, C's (value (*)()) x is written in Duel as: |
1015 |
+(T value (*)()) x. Types that begin with a reserved keyword don't |
1016 |
+need T, e.g. (struct value*) x and (long *[5]) y are accepted. |
1017 |
+As special cases, (type)x and (type*)x are accepted but |
1018 |
+discouraged (it causes (printf)("hi"), which is valid in C, to fail). |
1019 |
+A side effect is that "sizeof x" must be written as sizeof(x). |
1020 |
+.SH OPERATORS |
1021 |
+.sp |
1022 |
+.I "x+y x-y x*y x/y x%y x^y x|y x&y x<<y x>>y " |
1023 |
+.br |
1024 |
+.I "x>y x<y x>=y x<=y x==y x!=y x=y x[y]" |
1025 |
+.sp |
1026 |
+These binary operators follow their C semantics. For each value of x, |
1027 |
+they are evaluated for every value of y, .e.g. (5,2)>(4,1) |
1028 |
+evaluates as 5>4, 5>1, 2>4, 2>1 returning 1, 1, 0, 1. |
1029 |
+The y values are re-evaluated for each new value of x, e.g. |
1030 |
+i=4; (4,5)>i++ evaluates as 4>4 and 5>5. |
1031 |
+Beware of multiple y values in assignment, e.g. x[..3]=(4,6,9) does not |
1032 |
+set x[0]=4, x[1]=6 and x[2]=9. It assigns 4, 6 and 9 to each element, having |
1033 |
+the same effect as x[..3]=9. Use x[i:=..3]=(4,6,9)[[i]] to achieve the |
1034 |
+desired effect. |
1035 |
+.sp |
1036 |
+.I "-x ~x &x *x !x ++x --x x++ x-- sizeof(x) (type)x" |
1037 |
+.sp |
1038 |
+These unary operators follow their C semantics. They are applied |
1039 |
+to each value of x. The increment and decrement operators require an |
1040 |
+lvalue, so i:=0 ; i++ produces an error because i is an alias to 0, |
1041 |
+an rvalue. Parenthesis must be used with sizeof(x), "sizeof x" is not |
1042 |
+allowed. Cast to user defined type requires generally requires T, e.g., |
1043 |
+ (T val(*)())x, but (val)x and (val*)x are accepted as special cases. |
1044 |
+.sp |
1045 |
+.I "x&&y x||y" |
1046 |
+.sp |
1047 |
+These logical operators also follow their C semantics, but have non-intuitive |
1048 |
+results for multi-valued x and y, e.g. (1,0,0) || (1,0) returns 1,1,0,1,0 -- |
1049 |
+the right hand-side (1,0) is returned for each left-hand side 0. It is best |
1050 |
+to use these operators only in single value expressions. |
1051 |
+.sp |
1052 |
+.I "x? y:z if(x)y if(x)y else z" |
1053 |
+.sp |
1054 |
+These expressions return the values of y for each non-zero value |
1055 |
+returned by x, and the values of z for each zero value returned by x, e.g. |
1056 |
+if(x[..100]==0) y returns y for every x[i]==0, not if all x[i] are zero |
1057 |
+(if(&&/(x[..100]==0)) y does that). |
1058 |
+Also, "if(x) y; else z" is illegal. Duel's semicolon is |
1059 |
+an expression separator, not a terminator. |
1060 |
+.sp |
1061 |
+.I "while(x)y for(w;x;y)z" |
1062 |
+.sp |
1063 |
+The while(x)y expression returns y as long as all values of x are non-zero. |
1064 |
+The for() expression is similar and both have the expected C semantics. For |
1065 |
+example, "for(i=0 ; i<100 ; i++) x[i]" is the same as x[..100]. Unlike |
1066 |
+the if() expression, while(x[..100]==0) continue to execute only if all |
1067 |
+elements of x are zero, i.e. the condition is evaluated into a single value |
1068 |
+using an implicit &&/x. |
1069 |
+.sp |
1070 |
+.BI "Variable declaration: " "type name [,name ...] ; ..." |
1071 |
+.sp |
1072 |
+Expressions can begin with variables declaration (but not initialization). |
1073 |
+Internally, a declaration sets an alias to space allocated |
1074 |
+in the target by calling malloc(), e.g. `int x' is the same as |
1075 |
+"x:= *(int *) malloc(sizeof(int))". This is oblivious to the user. |
1076 |
+The allocated memory is not claimed when a variable is redeclared. |
1077 |
+Declared variables addresses can be passed to functions and used in other |
1078 |
+data structures. The keyword `T' must precede user defined types (typedef), |
1079 |
+e.g. if val is a user defined type, The C code "val *p=(val*) x" becomes |
1080 |
+"T val *p; p=(T val *) x" in Duel. |
1081 |
+.sp |
1082 |
+.BI "Function calls: " "func(parm,...)" |
1083 |
+.sp |
1084 |
+Function calls to the debugged program can be intermixed with Duel |
1085 |
+code. Multi-valued parameters are handled as with binary operators. |
1086 |
+The call value can have multiple values, e.g. (x,y)() calls x() |
1087 |
+and y(). Currently, struct/union parameters and return values are not |
1088 |
+supported. |
1089 |
+.sp |
1090 |
+.I "x,y x..y ..x x.." |
1091 |
+.sp |
1092 |
+These operators produce multiple values for single value operands. |
1093 |
+x,y returns x, then y. x..y returns the integers from x to y. |
1094 |
+When x>y the sequence is returned in descending order, i.e. 5..3 |
1095 |
+returns 5, 4, 3. |
1096 |
+The operator ..x is a shorthand for 0..x-1, e.g. ..3 returns 0, 1, 2. |
1097 |
+The x.. operator is a shorthand for x..maxint. It returns increasing |
1098 |
+integer values starting at x indefinitely, and should be bounded |
1099 |
+by [[n]] or @n operators. |
1100 |
+`,' retains its precedence level in C. The precedence of `..' |
1101 |
+is above `<' and below arithmetic operators, so 0..n-1 and x==1..9 work |
1102 |
+as expected. |
1103 |
+.sp |
1104 |
+.I "x<?y x>?y x>=?y x<=?y x!=?y x==?y" |
1105 |
+.sp |
1106 |
+These operators work like their C counterparts but return x if the comparison |
1107 |
+is true. If the comparison is false, the next (x,y) value is tried, forming |
1108 |
+the basis of an implicit search. |
1109 |
+.sp |
1110 |
+.I "(x) {x} x;y x=>y" |
1111 |
+.sp |
1112 |
+Both () and {} act as C parenthesis. |
1113 |
+The curly braces set the returned symbolic value |
1114 |
+as the actual value, e.g. if i=5 and x[5]=3, then |
1115 |
+x[i] produces the output "x[i] = 3", x[{i}] produces |
1116 |
+"x[5] = 3" and {x[i]} produces just "3". |
1117 |
+The semicolon is an operator. x;y evaluates x, ignoring the results, |
1118 |
+then evaluate and return y, e.g. (i:=1..3 ; i+5) sets i to 3 and return 8. |
1119 |
+The x=>y operator evaluate and return y for each value of x, |
1120 |
+e.g. (i:=1..3 => i+5) returns 6, 7 and 8. The value returned by x is |
1121 |
+also stored implicitly in `_' which can be used in y, e.g. 1..5 => z[_][_] |
1122 |
+will output z[1][1], z[2][2] etc. The symbolic value for _ is that of the |
1123 |
+left side value, hence {_} is not needed. |
1124 |
+.br |
1125 |
+Semicolon has the lowest precedence, so it must be used inside () or {} |
1126 |
+for compound expressions. The precedence of `=>' is just below `,'. |
1127 |
+Beware that "if(a) x; else {y;} z" is illegal; a semicolon is not allowed |
1128 |
+before '}' or 'else' and must be inserted before z. |
1129 |
+.sp |
1130 |
+.IB "x->y x.y" |
1131 |
+.sp |
1132 |
+These expression work as in C for a symbol y. If y is an expression, it |
1133 |
+is evaluated under the scope of x. e.g. x.(a+b) is the same as x.a+x.b, |
1134 |
+if a and b are field of x (if they are not, they are looked up as local |
1135 |
+or global variables). x may return multiple values of different types, |
1136 |
+e.g. (u,v).a returns u.a and v.a, even if u and v are different structures. |
1137 |
+Also, the value of x is available as `_' inside y, e.g. x[..100].(if(a) _) |
1138 |
+produces x[i] for each x[i].a!=0. Nested x.y are allowed, e.g. |
1139 |
+u.(v.(a+b)) would lookup a and b first under v, then under u. |
1140 |
+.sp |
1141 |
+.BI Aliases: " x:=y" |
1142 |
+.sp |
1143 |
+Aliases store a reference to y in x. Any reference to x is |
1144 |
+then replaced by y. If y is a constant or an rvalue, its |
1145 |
+value is replaced for x. If y is an lvalue (e.g. a variable), a reference |
1146 |
+to same lvalue is returned. for example, x:=emp[5] ; x=9 assigns 9 to |
1147 |
+emp[5]. |
1148 |
+Aliases retain their values across invocation of the "dl" command. An alias |
1149 |
+to a local variable will reference a stray address when the variable |
1150 |
+goes out of scope. |
1151 |
+The special command "dl clear" delete all the aliases, and "dl alias" |
1152 |
+show all current aliases. Symbols are looked up |
1153 |
+as aliases first, so an alias x will hide a local x. |
1154 |
+.sp |
1155 |
+.I x-->y |
1156 |
+.sp |
1157 |
+The expansion operator x-->y expands a data structure x following the y links. |
1158 |
+It returns x, x->y, x->y->y, until a null is found. If x is null, no values |
1159 |
+are produced. If y returns multiple values, they are stacked and each is |
1160 |
+further expanded in a depth-first notion. For example, if r is the root of |
1161 |
+a tree with children u->childs[..u->nchilds], then |
1162 |
+u-->(childs[..nchilds]) expands the whole tree. y is an arbitrary |
1163 |
+expression, evaluated exactly like x->y (this includes `_'.) |
1164 |
+.sp |
1165 |
+.I x@y |
1166 |
+.sp |
1167 |
+The expression x@y produces the values of x until x.y is non-zero, e.g. |
1168 |
+for(i=0 ; x[i].code!= -1 && i<100 ; i++) x[i] can be written as |
1169 |
+x[..100]@(code==-1). |
1170 |
+The evaluation of x is stopped as soon as y evaluates to true. |
1171 |
+x->y or x=>y are used to evaluate y when x is not a struct or a union. If |
1172 |
+y is a constant,(_==y) is used. e.g. s[0..]@0 produces the characters in |
1173 |
+string s up to but not including the terminating null. |
1174 |
+.sp |
1175 |
+.IB "#/x &&/x ||/x" |
1176 |
+.sp |
1177 |
+These operator return a single "summary" value for all the values returned by |
1178 |
+x. #/x returns the number of values returned by x, e.g. |
1179 |
+#/(x[..100]>?0) counts the number of positive x[i]. &&/x returns 1 if all |
1180 |
+the values produced by x are non-zero, and ||/x returns 1 if any of x's values |
1181 |
+are non-zero. Like in C, the evaluation stops as soon as possible. |
1182 |
+For example, ||/(x[..100]==0) and &&/(x[..100]==0) check if one or all of |
1183 |
+x[i] are zero, respectively. |
1184 |
+.sp |
1185 |
+.IB "x#y x[[y]]" |
1186 |
+.sp |
1187 |
+The operator x#y produces the values of x and arranges for y to be an alias |
1188 |
+for the index of each value in x. It is commonly used with x-->y to produce |
1189 |
+the element's index, e.g. head-->next->val#i=i assigns each val field |
1190 |
+its element number in the list. |
1191 |
+.br |
1192 |
+The selection operator x[[y]] produces the yth result of x. If y returns |
1193 |
+multiple value, each select a value of x, e.g. (5,7,11,13)[3,0,2] |
1194 |
+returns 13, 5 and 11 (13 is the 3rd element, 5 is the 0th element). |
1195 |
+Don't use side effects in x, since its evaluation can be restarted depending |
1196 |
+on y, e.g. after (x[0..i++])[[3,5]] the value of i is unpredictable. |
1197 |
+.sp |
1198 |
+.IB "frame(n) frames_no func.x" |
1199 |
+.sp |
1200 |
+frame(n) for an integer n returns a reference to the nth frame |
1201 |
+on the stack (0 is the inner most function and frame(frames_no-1) is main()). |
1202 |
+Frame values can be compared to function pointers, |
1203 |
+e.g. frame(3)==myfunc is true if the 4th frame is a call to myfunc, and in |
1204 |
+scope resolution, e.g. frame(3).x return the local variable x of the 4th frame. |
1205 |
+frames_no is the number of active frames on the stack, e.g. |
1206 |
+(frames(..frames_no) ==? myfunc).x displays x for all active |
1207 |
+invocations of myfunc. As a special case, (frames(..frames_no)==?f)[[0]].x |
1208 |
+can be written as f.x (x can be an expression). |
1209 |
+.sp |
1210 |
+.SH BUGS |
1211 |
+Both `{}' and `;' are operators, not statements or expression separators; |
1212 |
+"if(x) y; else {z;} u" is illegal; use "if(x) y else {z} ; u". Ambiguities |
1213 |
+require preceding |
1214 |
+user-defined types (typedef) with the keyword T, e.g., if |
1215 |
+value is a user type, C's "sizeof(value*)" is written |
1216 |
+"sizeof(T value*)", except for the casts "(t)x" and "(t*)x"; sizeof(x) |
1217 |
+requires parenthesis for variable x. |
1218 |
+ |
1219 |
+Unimplemented C idiom include: modified-assignment |
1220 |
+(x+=y), switch, break, continue, do, goto, scopes, function declarations, |
1221 |
+initializing declared variables, |
1222 |
+assignment to bit-fields and register variables, and |
1223 |
+calling functions with a struct/union parameter or return value. |
1224 |
+gdb does not store function prototypes, so parameters are not checked. |
1225 |
+ |
1226 |
+Gdb itself is buggy, which shows up, especially in symbol tables and |
1227 |
+calling target functions. Before you report bug, try to do the closest |
1228 |
+thing under gdb's "print". Send bug to: mg@××××××××××××.edu. |
1229 |
+.SH FILES |
1230 |
+duel.out tracks duel commands usage. Help analyze duel's use by mailing a |
1231 |
+copy to mg@××××××××××××.edu. |
1232 |
+.br |
1233 |
+Duel is available by anonymous ftp at ftp.cs.princeton.edu:/duel. |
1234 |
+.SH AUTHOR |
1235 |
+Duel is public domain code -- no copy left or right. See the internals |
1236 |
+documentation for details on porting Duel and using its code. |
1237 |
+Duel was designed and written by Michael Golan as part of a PhD thesis |
1238 |
+in the Computer Science Department of Princeton University. |
1239 |
+I would like to thank my advisor, Dave Hanson, who helped in all phases |
1240 |
+of this project and to Matt Blaze for his support and useful insight. |
1241 |
+.sp |
1242 |
+Duel stands for Debugging U (might) Even Like, or Don't Use this Exotic |
1243 |
+Language. Judge for yourself! |
1244 |
+ |
1245 |
+ |
1246 |
--- gdb/duel/duel.c |
1247 |
+++ gdb/duel/duel.c |
1248 |
@@ -0,0 +1,692 @@ |
1249 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
1250 |
+/* Public domain code */ |
1251 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
1252 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
1253 |
+ |
1254 |
+/* this module contains the entery point to duel - duel_eval_and_pasre. |
1255 |
+ */ |
1256 |
+ |
1257 |
+/* |
1258 |
+ * $Log: 10_all_gdb-6.6-duel.patch,v $ |
1259 |
+ * Revision 1.1 2007/12/29 21:06:06 vapier |
1260 |
+ * add DUEL support #199987 by Sergei Golubchik |
1261 |
+ * |
1262 |
+ * Revision 1.11 93/03/13 04:03:07 mg |
1263 |
+ * moved VERSION to patchlevel.h |
1264 |
+ * |
1265 |
+ * Revision 1.10 93/03/12 05:41:54 mg |
1266 |
+ * Version 1.10 - support (x)y cast, piped output. |
1267 |
+ * |
1268 |
+ * Revision 1.9 93/02/23 19:09:35 mg |
1269 |
+ * new version 1.02 release (support gdb4.8) |
1270 |
+ * |
1271 |
+ * Revision 1.8 93/02/03 21:56:33 mg |
1272 |
+ * version 1.01 |
1273 |
+ * |
1274 |
+ * Revision 1.7 93/01/12 21:28:44 mg |
1275 |
+ * cleanup and set for release |
1276 |
+ * |
1277 |
+ * Revision 1.6 93/01/06 23:57:10 mg |
1278 |
+ * added alias, clear commands, new memory alloc/release |
1279 |
+ * |
1280 |
+ * Revision 1.5 93/01/03 07:26:47 mg |
1281 |
+ * new printing setup |
1282 |
+ * |
1283 |
+ * Revision 1.4 92/12/24 23:32:38 mg |
1284 |
+ * better struct support, misc changes |
1285 |
+ * |
1286 |
+ * Revision 1.3 92/10/19 15:02:04 mg |
1287 |
+ * lcc happy, size zero arrays |
1288 |
+ * |
1289 |
+ * Revision 1.2 92/10/14 02:03:15 mg |
1290 |
+ * misc |
1291 |
+ * |
1292 |
+ */ |
1293 |
+ |
1294 |
+#include <setjmp.h> |
1295 |
+#define DEF /* define global variables */ |
1296 |
+#include "duel.h" |
1297 |
+#include "patchlevel.h" |
1298 |
+ |
1299 |
+static jmp_buf duel_abort_jmp ; /* abort current execution */ |
1300 |
+static tnode *root ; /* root of current eval node */ |
1301 |
+ |
1302 |
+ |
1303 |
+/* abort evaluation of current expression */ |
1304 |
+ |
1305 |
+PROC duel_abort(void) |
1306 |
+{ |
1307 |
+ longjmp(duel_abort_jmp,1); |
1308 |
+} |
1309 |
+ |
1310 |
+PROC duel_cleanup(void *unused) /* cleanup malloc, etc, when duel eval ends*/ |
1311 |
+{ |
1312 |
+ duel_redirectable_output_abort(); |
1313 |
+ duel_free_nodes(root); |
1314 |
+ root=NULL ; |
1315 |
+} |
1316 |
+ |
1317 |
+LPROC longhelp(void) |
1318 |
+{ |
1319 |
+ duel_printf( |
1320 |
+"Duel(1) Duel(1)\n\ |
1321 |
+\n\ |
1322 |
+NAME\n\ |
1323 |
+ duel - A high level C debugging language extension to gdb\n\ |
1324 |
+\n\ |
1325 |
+DESCRIPTION\n\ |
1326 |
+ Duel is a special purpose language designed for concise state explo-\n\ |
1327 |
+ ration of debugged C programs, currently implemented under the GNU\n\ |
1328 |
+ debugger gdb(1). Duel is invoked by entering the shell command duel\n\ |
1329 |
+ instead of gdb. It is identical to gdb except for comments, which\n\ |
1330 |
+ begin with `##' instead of `#', and the new dl command for Duel expres-\n\ |
1331 |
+ sions:\n\ |
1332 |
+\n\ |
1333 |
+ gdb> dl x[1..10] >? 5\n\ |
1334 |
+ x[3] = 14\n\ |
1335 |
+ x[8] = 6\n\ |
1336 |
+\n\ |
1337 |
+ prints the array elements x[1] to x[10] that are greater than 5. The\n\ |
1338 |
+ output includes the values 14 and 6, as well as their symbolic repre-\n\ |
1339 |
+ sentation \"x[3]\" and \"x[8]\".\n\ |
1340 |
+\n\ |
1341 |
+DUEL QUICK START\n\ |
1342 |
+ Duel is implemented by adding the dl command to gdb. All gdb commands\n\ |
1343 |
+ work as before. The dl command, however, is interpreted by duel. Gdb\n\ |
1344 |
+ concepts (such as the value history) do not work in the dl command, and\n\ |
1345 |
+ duel concepts are not understood by other gdb command.\n\ |
1346 |
+\n\ |
1347 |
+ Duel is based on expressions which return multiple values. The x..y\n\ |
1348 |
+ operator returns the integers from x to y; the x,y operator returns x\n\ |
1349 |
+ and then y, e.g.\n\ |
1350 |
+\n\ |
1351 |
+ gdb> dl (1,9,12..15,22)\n\ |
1352 |
+\n\ |
1353 |
+ prints 1, 9, 12, 13, 14, 15 and 22. Such expressions can be used wher-\n\ |
1354 |
+ ever a single value is used, e.g.\n\ |
1355 |
+\n\ |
1356 |
+ gdb> dl x[0..99]=0 ;\n\ |
1357 |
+\n\ |
1358 |
+ assigns zero to the first 100 elements of array x. The semantics of\n\ |
1359 |
+ x[i] are the same as in C. They are applied for each of the values\n\ |
1360 |
+ returned by 0..99, which can be thought of as an implied external loop.\n\ |
1361 |
+ The trailing semicolon indicates evaluation for side-effects only, with\n\ |
1362 |
+ no output. Duel incorporates C operators, casts C statements as\n\ |
1363 |
+ expressions, and supports limited variable declaration:\n\ |
1364 |
+\n\ |
1365 |
+ gdb> dl int i;for(i=0;i<100;i++)\n\ |
1366 |
+ if(x[i]<0) printf(\"x[%%d]=%%d\\n\",i,x[i]);\n\ |
1367 |
+ x[7] = -4\n\ |
1368 |
+\n\ |
1369 |
+ The semicolon prevents Duel output; only output from printf is printed.\n\ |
1370 |
+ Aliases are defined with x:=y and provide an alternative to variable\n\ |
1371 |
+ declaration. We could also return x[i] instead of using printf:\n\ |
1372 |
+\n\ |
1373 |
+ gdb> dl if(x[i:=0..99]<0) x[i]\n\ |
1374 |
+ x[i] = -4\n\ |
1375 |
+\n\ |
1376 |
+ The symbolic output \"x[i]\" can be fixed by surrounding i with {}, i.e.\n\ |
1377 |
+\n\ |
1378 |
+ gdb> dl if(x[i:=0..99]<0) x[{i}]\n\ |
1379 |
+ x[7] = -4\n\ |
1380 |
+\n\ |
1381 |
+ The {} are like (), but force the symbolic evaluation to use i's value,\n\ |
1382 |
+ instead of \"i\". You can usually avoid this altogether with direct Duel\n\ |
1383 |
+ operators:\n\ |
1384 |
+\n\ |
1385 |
+ gdb> dl x[..100] <? 0\n\ |
1386 |
+ x[7] = -4\n\ |
1387 |
+\n\ |
1388 |
+ The ..n operator is a shorthand for 0..n-1, i.e. ..100 is the same as\n\ |
1389 |
+ 0..99. The x<?y, x==?y, x>=?y, etc., operators compare their left side\n\ |
1390 |
+ operand to their right side operand as in C, but return the left side\n\ |
1391 |
+ value if the comparison result is true. Otherwise, they look for the\n\ |
1392 |
+ next values to compare, without returning anything.\n\ |
1393 |
+\n\ |
1394 |
+ Duel's x.y and x->y allow an expression y, evaluated under x's scope:\n\ |
1395 |
+\n\ |
1396 |
+ gdb> dl emp[..100].(if(code>400) (code,name))\n\ |
1397 |
+ emp[46].code = 682\n\ |
1398 |
+ emp[46].name = \"Ela\"\n\ |
1399 |
+\n\ |
1400 |
+ The if() expression is evaluated under the scope of each element of\n\ |
1401 |
+ emp[], an array of structures. In C terms, we had to write:\n\ |
1402 |
+\n\ |
1403 |
+ gdb> dl int i; for(i=0; i<100 ; i++)\n\ |
1404 |
+ if(emp[i].code>400) emp[{i}].code,emp[{i}].name\n\ |
1405 |
+\n\ |
1406 |
+ A useful alternative to loops is the x=>y operator. It returns y for\n\ |
1407 |
+ each value of x, setting `_' to reference x's value, e.g.\n\ |
1408 |
+\n\ |
1409 |
+ gdb> ..100 => if(emp[_].code>400) emp[_].code,emp[_].name\n\ |
1410 |
+\n\ |
1411 |
+ Using `_' instead of `i' also avoids the need for {i}. Finally, the\n\ |
1412 |
+ x-->y operator expands lists and other data structures. If head points\n\ |
1413 |
+ to a linked list threaded through the next field, then:\n\ |
1414 |
+\n\ |
1415 |
+ gdb> dl head-->next->data\n\ |
1416 |
+ head->data = 12\n\ |
1417 |
+ head->next->data = 14\n\ |
1418 |
+ head-->next[[2]]->data = 20\n\ |
1419 |
+ head-->next[[3]]->data = 26\n\ |
1420 |
+\n\ |
1421 |
+ produce the data field for each node in the list. x-->y returns x,\n\ |
1422 |
+ x->y, x->y->y, x->y->y->y, ... until a NULL is found. The symbolic\n\ |
1423 |
+ output \"x-->y[[n]]\" indicates that ->y was applied n times. x[[y]] is\n\ |
1424 |
+ also the selection operator:\n\ |
1425 |
+\n\ |
1426 |
+ gdb> dl head-->next[[50..60]]->data\n\ |
1427 |
+\n\ |
1428 |
+ return the 50th through the 60th elements in the list. The #/x operator\n\ |
1429 |
+ counts the number of values, so\n\ |
1430 |
+\n\ |
1431 |
+ gdb> dl #/( head-->next->data >? 50 )\n\ |
1432 |
+\n\ |
1433 |
+ counts the number of data elements over 50 on the list. Several other\n\ |
1434 |
+ operators, including x@y, x#y and active call stack access are\n\ |
1435 |
+ described in the operators section.\n\ |
1436 |
+\n\ |
1437 |
+OPERATORS SUMMARY\n\ |
1438 |
+ Assoc Operators Details\n\ |
1439 |
+ left {} () [] -> . f() --> x-->y expands x->y x->y->y ...\n\ |
1440 |
+ x[[y]] x#y x@y generate x; select, index or stop-at y\n\ |
1441 |
+ right #/ - * & ! ~ ++ -- (cast) #/x number of x values\n\ |
1442 |
+ frame(n) sizeof(x) reference to call stack level n\n\ |
1443 |
+ left x/y x*y x%%y multiply, divide, reminder\n\ |
1444 |
+ left x-y x+y add, subtract\n\ |
1445 |
+ left x<<y x>>y shift left/right\n\ |
1446 |
+ none x..y ..y x.. ..y = 0..y-1. x..y return x, x+1...y\n\ |
1447 |
+ left < > <= >= <? >? <=? >=? x>?y return x if x>y\n\ |
1448 |
+ left == != ==? !=? x==?y return x if x==y\n\ |
1449 |
+ left x&y bit-and\n\ |
1450 |
+ left x^y bit-xor\n\ |
1451 |
+ left x|y bit-or\n\ |
1452 |
+ left x&&y &&/x &&/x are all x values non-zero?\n\ |
1453 |
+ left x||y ||/x ||/x is any x value non-zero?\n\ |
1454 |
+ right x? y:z foreach x, if(x) y else z\n\ |
1455 |
+ right x:=y x=y x+=y ... x:=y set x as an alias to y\n\ |
1456 |
+ left x,y return x, then y\n\ |
1457 |
+ right x=>y foreach x, evaluate y with x value `_'\n\ |
1458 |
+ right if() else while() for() C statements cast as operators\n\ |
1459 |
+ left x;y evaluate and ignore x, return y\n\ |
1460 |
+\n\ |
1461 |
+\n\ |
1462 |
+EXAMPLES\n\ |
1463 |
+ dl (0xff-0x12)*3 compute simple expression\n\ |
1464 |
+ dl (1..10)*(1..10) display multiplication table\n\ |
1465 |
+ dl x[10..20,22,24,40..60] display x[i] for the selected indexes\n\ |
1466 |
+ dl x[9..0] display x[i] backwards\n\ |
1467 |
+ dl x[..100] >? 5 display x[i] that are greater than 5\n\ |
1468 |
+ dl x[..100] >? 5 <? 10 display x[i] if 5<x[i]<10\n\ |
1469 |
+ dl x[..100] ==? (6..9) same\n\ |
1470 |
+ dl x[0..99]=>if(_>5 && _<10) _ same\n\ |
1471 |
+ dl y[x[..100] !=? 0] display y[x[i]] for each non-zero x[i]\n\ |
1472 |
+ dl emp[..50].code display emp[i].code for i=0 to 49\n\ |
1473 |
+ dl emp[..50].(code,name) display emp[i].code & emp[i].name\n\ |
1474 |
+ dl val[..50].(is_dbl? x:y) display val[i].x or val[i].y depending\n\ |
1475 |
+ on val[i].is_dbl.\n\ |
1476 |
+ dl val[..50].if(is_dbl) x else y same as above\n\ |
1477 |
+ dl x[..100]=0 ; assign 0 to x[i]\n\ |
1478 |
+ dl x[i:=..100]=y[i] ; assign y[i] to x[i]\n\ |
1479 |
+ dl x[..100]=y[..100] *ERR* assign y[99] to each x[j]\n\ |
1480 |
+ dl x[i:=..3]=(4,5,9)[[i]] assign x[0]=4 x[1]=5 x[2]=9\n\ |
1481 |
+ dl x[..3]=(4,5,9) *ERR* assign 9 to each element\n\ |
1482 |
+ dl if(x[i:=..100]<0) x[i]=0 ; assign 0 to negative x[i]\n\ |
1483 |
+ dl (hash[..1024]!=?0)->scope hash[i].scope for non-null hash[i]\n\ |
1484 |
+ dl x[i:=..100] >? x[i+1] check if x[i] is not sorted\n\ |
1485 |
+ dl x[i:=..100] ==? x[j:=..100]=> checks if x has non-unique elements\n\ |
1486 |
+ if(i<j) x[{i,j}]\n\ |
1487 |
+ dl if(x[i:=..99] == same\n\ |
1488 |
+ x[j:=i+1..99]) x[{i,j}]\n\ |
1489 |
+ dl (x[..100] >? 0)[[0]] the 1st (0th element) positive x[i]\n\ |
1490 |
+\n\ |
1491 |
+ dl (x[..100] >? 0)[[2]] return the 3rd positive x[i]\n\ |
1492 |
+ dl (x[..100] >? 0)[[..5]] return the first 5 positive x[i]\n\ |
1493 |
+ dl (x[0..] >? 6)[[0]] return the first x[i]>6, no limit on i\n\ |
1494 |
+ dl argv[0..]@0 argv[0] argv[1] .. until first null\n\ |
1495 |
+ dl x[0..]@-1 >? 9 x[0..n]>9 where n is first x[n]== -1\n\ |
1496 |
+ dl emp[0..]@(code==0) emp[0]..emp[n-1] where emp[n].code==0\n\ |
1497 |
+\n\ |
1498 |
+ dl head-->next->val val of each element in a linked list\n\ |
1499 |
+ dl head-->next[[20]] the 21st element of a linked list\n\ |
1500 |
+ dl *head-->next[[20]] display above as a struct\n\ |
1501 |
+ dl strcmp(head-->next->msg, search linked list for a string\n\ |
1502 |
+ \"testing\") ==? 0\n\ |
1503 |
+ dl #/head-->next count elements on a linked list\n\ |
1504 |
+ dl x-->y[[#/x-->y - 1]] last element of a linked list\n\ |
1505 |
+ dl x-->y[[#/x-->y - 10..1]] last 10 elements of a linked list\n\ |
1506 |
+ dl head-->next-> check if the list is sorted by val\n\ |
1507 |
+ if(next) val >? next->val\n\ |
1508 |
+\n\ |
1509 |
+ dl head-->(next!=?head) expand cyclic linked list (tail->head)\n\ |
1510 |
+ dl head-->(next!=?_) handle termination with p->next==p\n\ |
1511 |
+ dl root-->(left,right)->key expand binary tree, show keys\n\ |
1512 |
+ dl root-->(left,right)->( check bin tree sorted by key\n\ |
1513 |
+ (left!=?0)->key>=?key, (right !=?0 )->key<=?key)\n\ |
1514 |
+\n\ |
1515 |
+ dl (1000..=>if(&&/(2,3.._-1=>__%%_ find first 10 primes over 1000\n\ |
1516 |
+ ) _)[[..10]]\n\ |
1517 |
+ dl (T mytype) x convert x to user defined type mytype\n\ |
1518 |
+ dl (struct s*) x convert x to struct s pointer\n\ |
1519 |
+ dl if(x) y; else z *ERR* ';' must be followed by an expression\n\ |
1520 |
+ dl {x} y *ERR* '}' requires ';' if followed by exp\n\ |
1521 |
+\n\ |
1522 |
+SEMANTICS\n\ |
1523 |
+ Duel's semantics are modeled after the Icon programming language. The\n\ |
1524 |
+ input consists of expressions which return sequences of values. C\n\ |
1525 |
+ statements are cast as expressions, too. Expressions are parsed into\n\ |
1526 |
+ abstract syntax trees, which are traversed during evaluation. The eval-\n\ |
1527 |
+ uation of most nodes (operators) recursively evaluates the next value\n\ |
1528 |
+ for each operand, and then applies the operator to produce the next\n\ |
1529 |
+ result. Only one value is produced each time, and Duel's eval function\n\ |
1530 |
+ keeps a `state' for each node (backtracking, co-routines, consumer-pro-\n\ |
1531 |
+ ducer or threads are good metaphors for the evaluation mechanism.)\n\ |
1532 |
+\n\ |
1533 |
+ For example, in (5,3)+6..8, the evaluation of `+' first retrieves the\n\ |
1534 |
+ operands 5 and 6, to compute and return 5+6. Then 7, the next right op-\n\ |
1535 |
+ erand is retrieved and 5+7 is returned, followed by 5+8. Since there\n\ |
1536 |
+ are no other right operand value, the next left operand, 3 is fetched.\n\ |
1537 |
+ The right operand's computation is restarted returning 6, and 3+6 is\n\ |
1538 |
+ returned. The final return values are 3+7 and 3+8.\n\ |
1539 |
+\n\ |
1540 |
+ The computation for operators like x>?y is similar, but when x<=y, the\n\ |
1541 |
+ next values are fetched instead of returning a value, forming the basis\n\ |
1542 |
+ for an implicit search. Operators like `..' return a sequence of values\n\ |
1543 |
+ for each pair of operands. For a better understanding of the evaluation\n\ |
1544 |
+ mechanism, see the USENIX Winter/93 conference paper \"DUEL - A Very\n\ |
1545 |
+ High Level Debugging Language\".\n\ |
1546 |
+\n\ |
1547 |
+ Duel values follow the C semantics. A value is either an \"lvalue\" (can\n\ |
1548 |
+ be used as the left hand side of assignment), or an \"rvalue\". There-\n\ |
1549 |
+ for, objects like arrays can not be directly manipulated (However,\n\ |
1550 |
+ operators like x..y can accomplish such tasks.)\n\ |
1551 |
+\n\ |
1552 |
+ Duel types also follow the C semantics, with some important differ-\n\ |
1553 |
+ ences. C types are checked statically; Duel types are checked when\n\ |
1554 |
+ operators are applied, e.g., (1,1.0)/2 returns 0 (int) and 0.5 (dou-\n\ |
1555 |
+ ble); (x,y).z returns x.z and y.z even if x and y are of different\n\ |
1556 |
+ types, as long as they both have a field z.\n\ |
1557 |
+\n\ |
1558 |
+ Values and types of symbols are looked up at run-time (using gdb's\n\ |
1559 |
+ lookup rules), allowing dynamic scoping and types, but causing a pars-\n\ |
1560 |
+ ing problem: (x)(y) can be parsed as either a function call x(y) or a\n\ |
1561 |
+ cast (x)y; x*y can be parsed as a declaration of y as (x*) or as multi-\n\ |
1562 |
+ plication.\n\ |
1563 |
+\n\ |
1564 |
+ To avoid this ambiguity, the keyword T must precede a user defined\n\ |
1565 |
+ type. For example, if value is a typedef, C's (value (*)()) x is writ-\n\ |
1566 |
+ ten in Duel as: (T value (*)()) x. Types that begin with a reserved\n\ |
1567 |
+ keyword don't need T, e.g. (struct value*) x and (long *[5]) y are\n\ |
1568 |
+ accepted. As special cases, (type)x and (type*)x are accepted but dis-\n\ |
1569 |
+ couraged (it causes (printf)(\"hi\"), which is valid in C, to fail). A\n\ |
1570 |
+ side effect is that \"sizeof x\" must be written as sizeof(x).\n\ |
1571 |
+\n\ |
1572 |
+OPERATORS\n\ |
1573 |
+ x+y x-y x*y x/y x%%y x^y x|y x&y x<<y x>>y\n\ |
1574 |
+ x>y x<y x>=y x<=y x==y x!=y x=y x[y]\n\ |
1575 |
+\n\ |
1576 |
+ These binary operators follow their C semantics. For each value of x,\n\ |
1577 |
+ they are evaluated for every value of y, .e.g. (5,2)>(4,1) evaluates as\n\ |
1578 |
+ 5>4, 5>1, 2>4, 2>1 returning 1, 1, 0, 1. The y values are re-evalu-\n\ |
1579 |
+ ated for each new value of x, e.g. i=4; (4,5)>i++ evaluates as 4>4 and\n\ |
1580 |
+ 5>5. Beware of multiple y values in assignment, e.g. x[..3]=(4,6,9)\n\ |
1581 |
+ does not set x[0]=4, x[1]=6 and x[2]=9. It assigns 4, 6 and 9 to each\n\ |
1582 |
+ element, having the same effect as x[..3]=9. Use x[i:=..3]=(4,6,9)[[i]]\n\ |
1583 |
+ to achieve the desired effect.\n\ |
1584 |
+\n\ |
1585 |
+ -x ~x &x *x !x ++x --x x++ x-- sizeof(x) (type)x\n\ |
1586 |
+\n\ |
1587 |
+ These unary operators follow their C semantics. They are applied to\n\ |
1588 |
+ each value of x. The increment and decrement operators require an\n\ |
1589 |
+ lvalue, so i:=0 ; i++ produces an error because i is an alias to 0, an\n\ |
1590 |
+ rvalue. Parenthesis must be used with sizeof(x), \"sizeof x\" is not\n\ |
1591 |
+ allowed. Cast to user defined type requires generally requires T, e.g.,\n\ |
1592 |
+ (T val(*)())x, but (val)x and (val*)x are accepted as special cases.\n\ |
1593 |
+\n\ |
1594 |
+ x&&y x||y\n\ |
1595 |
+\n\ |
1596 |
+ These logical operators also follow their C semantics, but have non-\n\ |
1597 |
+ intuitive results for multi-valued x and y, e.g. (1,0,0) || (1,0)\n\ |
1598 |
+ returns 1,1,0,1,0 -- the right hand-side (1,0) is returned for each\n\ |
1599 |
+ left-hand side 0. It is best to use these operators only in single\n\ |
1600 |
+ value expressions.\n\ |
1601 |
+\n\ |
1602 |
+ x? y:z if(x)y if(x)y else z\n\ |
1603 |
+\n\ |
1604 |
+ These expressions return the values of y for each non-zero value\n\ |
1605 |
+ returned by x, and the values of z for each zero value returned by x,\n\ |
1606 |
+ e.g. if(x[..100]==0) y returns y for every x[i]==0, not if all x[i]\n\ |
1607 |
+ are zero (if(&&/(x[..100]==0)) y does that). Also, \"if(x) y; else z\"\n\ |
1608 |
+ is illegal. Duel's semicolon is an expression separator, not a termina-\n\ |
1609 |
+ tor.\n\ |
1610 |
+\n\ |
1611 |
+ while(x)y for(w;x;y)z\n\ |
1612 |
+\n\ |
1613 |
+ The while(x)y expression returns y as long as all values of x are non-\n\ |
1614 |
+ zero. The for() expression is similar and both have the expected C\n\ |
1615 |
+ semantics. For example, \"for(i=0 ; i<100 ; i++) x[i]\" is the same as\n\ |
1616 |
+ x[..100]. Unlike the if() expression, while(x[..100]==0) continue to\n\ |
1617 |
+ execute only if all elements of x are zero, i.e. the condition is eval-\n\ |
1618 |
+ uated into a single value using an implicit &&/x.\n\ |
1619 |
+\n\ |
1620 |
+ Variable declaration: type name [,name ...] ; ...\n\ |
1621 |
+\n\ |
1622 |
+ Expressions can begin with variables declaration (but not initializa-\n\ |
1623 |
+ tion). Internally, a declaration sets an alias to space allocated in\n\ |
1624 |
+ the target by calling malloc(), e.g. `int x' is the same as \"x:= *(int\n\ |
1625 |
+ *) malloc(sizeof(int))\". This is oblivious to the user. The allocated\n\ |
1626 |
+ memory is not claimed when a variable is redeclared. Declared vari-\n\ |
1627 |
+ ables addresses can be passed to functions and used in other data\n\ |
1628 |
+ structures. The keyword `T' must precede user defined types (typedef),\n\ |
1629 |
+ e.g. if val is a user defined type, The C code \"val *p=(val*) x\"\n\ |
1630 |
+ becomes \"T val *p; p=(T val *) x\" in Duel.\n\ |
1631 |
+\n\ |
1632 |
+ Function calls: func(parm,...)\n\ |
1633 |
+\n\ |
1634 |
+ Function calls to the debugged program can be intermixed with Duel\n\ |
1635 |
+ code. Multi-valued parameters are handled as with binary operators.\n\ |
1636 |
+ The call value can have multiple values, e.g. (x,y)() calls x() and\n\ |
1637 |
+ y(). Currently, struct/union parameters and return values are not sup-\n\ |
1638 |
+ ported.\n\ |
1639 |
+\n\ |
1640 |
+ x,y x..y ..x x..\n\ |
1641 |
+\n\ |
1642 |
+ These operators produce multiple values for single value operands. x,y\n\ |
1643 |
+ returns x, then y. x..y returns the integers from x to y. When x>y the\n\ |
1644 |
+ sequence is returned in descending order, i.e. 5..3 returns 5, 4, 3.\n\ |
1645 |
+ The operator ..x is a shorthand for 0..x-1, e.g. ..3 returns 0, 1, 2.\n\ |
1646 |
+ The x.. operator is a shorthand for x..maxint. It returns increasing\n\ |
1647 |
+ integer values starting at x indefinitely, and should be bounded by\n\ |
1648 |
+ [[n]] or @n operators. `,' retains its precedence level in C. The\n\ |
1649 |
+ precedence of `..' is above `<' and below arithmetic operators, so\n\ |
1650 |
+ 0..n-1 and x==1..9 work as expected.\n\ |
1651 |
+\n\ |
1652 |
+ x<?y x>?y x>=?y x<=?y x!=?y x==?y\n\ |
1653 |
+\n\ |
1654 |
+ These operators work like their C counterparts but return x if the com-\n\ |
1655 |
+ parison is true. If the comparison is false, the next (x,y) value is\n\ |
1656 |
+ tried, forming the basis of an implicit search.\n\ |
1657 |
+\n\ |
1658 |
+ (x) {x} x;y x=>y\n\ |
1659 |
+\n\ |
1660 |
+ Both () and {} act as C parenthesis. The curly braces set the returned\n\ |
1661 |
+ symbolic value as the actual value, e.g. if i=5 and x[5]=3, then x[i]\n\ |
1662 |
+ produces the output \"x[i] = 3\", x[{i}] produces \"x[5] = 3\" and {x[i]}\n\ |
1663 |
+ produces just \"3\". The semicolon is an operator. x;y evaluates x,\n\ |
1664 |
+ ignoring the results, then evaluate and return y, e.g. (i:=1..3 ; i+5)\n\ |
1665 |
+ sets i to 3 and return 8. The x=>y operator evaluate and return y for\n\ |
1666 |
+ each value of x, e.g. (i:=1..3 => i+5) returns 6, 7 and 8. The value\n\ |
1667 |
+ returned by x is also stored implicitly in `_' which can be used in y,\n\ |
1668 |
+ e.g. 1..5 => z[_][_] will output z[1][1], z[2][2] etc. The symbolic\n\ |
1669 |
+ value for _ is that of the left side value, hence {_} is not needed.\n\ |
1670 |
+ Semicolon has the lowest precedence, so it must be used inside () or {}\n\ |
1671 |
+ for compound expressions. The precedence of `=>' is just below `,'.\n\ |
1672 |
+ Beware that \"if(a) x; else {y;} z\" is illegal; a semicolon is not\n\ |
1673 |
+ allowed before '}' or 'else' and must be inserted before z.\n\ |
1674 |
+\n\ |
1675 |
+ x->y x.y\n\ |
1676 |
+\n\ |
1677 |
+ These expression work as in C for a symbol y. If y is an expression, it\n\ |
1678 |
+ is evaluated under the scope of x. e.g. x.(a+b) is the same as x.a+x.b,\n\ |
1679 |
+ if a and b are field of x (if they are not, they are looked up as local\n\ |
1680 |
+ or global variables). x may return multiple values of different types,\n\ |
1681 |
+ e.g. (u,v).a returns u.a and v.a, even if u and v are different struc-\n\ |
1682 |
+ tures. Also, the value of x is available as `_' inside y, e.g.\n\ |
1683 |
+ x[..100].(if(a) _) produces x[i] for each x[i].a!=0. Nested x.y are\n\ |
1684 |
+ allowed, e.g. u.(v.(a+b)) would lookup a and b first under v, then\n\ |
1685 |
+ under u.\n\ |
1686 |
+\n\ |
1687 |
+ Aliases: x:=y\n\ |
1688 |
+\n\ |
1689 |
+ Aliases store a reference to y in x. Any reference to x is then\n\ |
1690 |
+ replaced by y. If y is a constant or an rvalue, its value is replaced\n\ |
1691 |
+ for x. If y is an lvalue (e.g. a variable), a reference to same lvalue\n\ |
1692 |
+ is returned. for example, x:=emp[5] ; x=9 assigns 9 to emp[5]. Aliases\n\ |
1693 |
+ retain their values across invocation of the \"dl\" command. An alias to\n\ |
1694 |
+ a local variable will reference a stray address when the variable goes\n\ |
1695 |
+ out of scope. The special command \"dl clear\" delete all the aliases,\n\ |
1696 |
+ and \"dl alias\" show all current aliases. Symbols are looked up as\n\ |
1697 |
+ aliases first, so an alias x will hide a local x.\n\ |
1698 |
+\n\ |
1699 |
+ x-->y\n\ |
1700 |
+\n\ |
1701 |
+ The expansion operator x-->y expands a data structure x following the y\n\ |
1702 |
+ links. It returns x, x->y, x->y->y, until a null is found. If x is\n\ |
1703 |
+ null, no values are produced. If y returns multiple values, they are\n\ |
1704 |
+ stacked and each is further expanded in a depth-first notion. For exam-\n\ |
1705 |
+ ple, if r is the root of a tree with children u->childs[..u->nchilds],\n\ |
1706 |
+ then u-->(childs[..nchilds]) expands the whole tree. y is an arbitrary\n\ |
1707 |
+ expression, evaluated exactly like x->y (this includes `_'.)\n\ |
1708 |
+\n\ |
1709 |
+ x@y\n\ |
1710 |
+\n\ |
1711 |
+ The expression x@y produces the values of x until x.y is non-zero, e.g.\n\ |
1712 |
+ for(i=0 ; x[i].code!= -1 && i<100 ; i++) x[i] can be written as\n\ |
1713 |
+ x[..100]@(code==-1). The evaluation of x is stopped as soon as y eval-\n\ |
1714 |
+ uates to true. x->y or x=>y are used to evaluate y when x is not a\n\ |
1715 |
+ struct or a union. If y is a constant,(_==y) is used. e.g. s[0..]@0\n\ |
1716 |
+ produces the characters in string s up to but not including the termi-\n\ |
1717 |
+ nating null.\n\ |
1718 |
+\n\ |
1719 |
+ #/x &&/x ||/x\n\ |
1720 |
+\n\ |
1721 |
+ These operator return a single \"summary\" value for all the values\n\ |
1722 |
+ returned by x. #/x returns the number of values returned by x, e.g.\n\ |
1723 |
+ #/(x[..100]>?0) counts the number of positive x[i]. &&/x returns 1 if\n\ |
1724 |
+ all the values produced by x are non-zero, and ||/x returns 1 if any of\n\ |
1725 |
+ x's values are non-zero. Like in C, the evaluation stops as soon as\n\ |
1726 |
+ possible. For example, ||/(x[..100]==0) and &&/(x[..100]==0) check if\n\ |
1727 |
+ one or all of x[i] are zero, respectively.\n\ |
1728 |
+\n\ |
1729 |
+ x#y x[[y]]\n\ |
1730 |
+\n\ |
1731 |
+ The operator x#y produces the values of x and arranges for y to be an\n\ |
1732 |
+ alias for the index of each value in x. It is commonly used with x-->y\n\ |
1733 |
+ to produce the element's index, e.g. head-->next->val#i=i assigns each\n\ |
1734 |
+ val field its element number in the list.\n\ |
1735 |
+ The selection operator x[[y]] produces the yth result of x. If y\n\ |
1736 |
+ returns multiple value, each select a value of x, e.g.\n\ |
1737 |
+ (5,7,11,13)[3,0,2] returns 13, 5 and 11 (13 is the 3rd element, 5 is\n\ |
1738 |
+ the 0th element). Don't use side effects in x, since its evaluation\n\ |
1739 |
+ can be restarted depending on y, e.g. after (x[0..i++])[[3,5]] the\n\ |
1740 |
+ value of i is unpredictable.\n\ |
1741 |
+\n\ |
1742 |
+ frame(n) frames_no func.x\n\ |
1743 |
+\n\ |
1744 |
+ frame(n) for an integer n returns a reference to the nth frame on the\n\ |
1745 |
+ stack (0 is the inner most function and frame(frames_no-1) is main()).\n\ |
1746 |
+ Frame values can be compared to function pointers, e.g.\n\ |
1747 |
+ frame(3)==myfunc is true if the 4th frame is a call to myfunc, and in\n\ |
1748 |
+ scope resolution, e.g. frame(3).x return the local variable x of the\n\ |
1749 |
+ 4th frame. frames_no is the number of active frames on the stack, e.g.\n\ |
1750 |
+ (frames(..frames_no) ==? myfunc).x displays x for all active invoca-\n\ |
1751 |
+ tions of myfunc. As a special case, (frames(..frames_no)==?f)[[0]].x\n\ |
1752 |
+ can be written as f.x (x can be an expression).\n\ |
1753 |
+\n\ |
1754 |
+\n\ |
1755 |
+BUGS\n\ |
1756 |
+ Both `{}' and `;' are operators, not statements or expression separa-\n\ |
1757 |
+ tors; \"if(x) y; else {z;} u\" is illegal; use \"if(x) y else {z} ; u\".\n\ |
1758 |
+ Ambiguities require preceding user-defined types (typedef) with the\n\ |
1759 |
+ keyword T, e.g., if value is a user type, C's \"sizeof(value*)\" is\n\ |
1760 |
+ written \"sizeof(T value*)\", except for the casts \"(t)x\" and \"(t*)x\";\n\ |
1761 |
+ sizeof(x) requires parenthesis for variable x.\n\ |
1762 |
+\n\ |
1763 |
+ Unimplemented C idiom include: modified-assignment (x+=y), switch,\n\ |
1764 |
+ break, continue, do, goto, scopes, function declarations, initializing\n\ |
1765 |
+ declared variables, assignment to bit-fields and register variables,\n\ |
1766 |
+ and calling functions with a struct/union parameter or return value.\n\ |
1767 |
+ gdb does not store function prototypes, so parameters are not checked.\n\ |
1768 |
+\n\ |
1769 |
+ Gdb itself is buggy, which shows up, especially in symbol tables and\n\ |
1770 |
+ calling target functions. Before you report bug, try to do the closest\n\ |
1771 |
+ thing under gdb's \"print\". Send bug to: mg@××××××××××××.edu.\n\ |
1772 |
+\n\ |
1773 |
+FILES\n\ |
1774 |
+ duel.out tracks duel commands usage. Help analyze duel's use by mailing\n\ |
1775 |
+ a copy to mg@××××××××××××.edu.\n\ |
1776 |
+ Duel is available by anonymous ftp at ftp.cs.princeton.edu:/duel.\n\ |
1777 |
+\n\ |
1778 |
+AUTHOR\n\ |
1779 |
+ Duel is public domain code -- no copy left or right. See the internals\n\ |
1780 |
+ documentation for details on porting Duel and using its code. Duel was\n\ |
1781 |
+ designed and written by Michael Golan as part of a PhD thesis in the\n\ |
1782 |
+ Computer Science Department of Princeton University. I would like to\n\ |
1783 |
+ thank my advisor, Dave Hanson, who helped in all phases of this project\n\ |
1784 |
+ and to Matt Blaze for his support and useful insight.\n\ |
1785 |
+\n\ |
1786 |
+ Duel stands for Debugging U (might) Even Like, or Don't Use this Exotic\n\ |
1787 |
+ Language. Judge for yourself!\n\ |
1788 |
+\n\ |
1789 |
+Version 1.10 Mar 93 Duel(1)\n\n"); |
1790 |
+} |
1791 |
+ |
1792 |
+LPROC help(void) |
1793 |
+{ |
1794 |
+ duel_printf( |
1795 |
+"Duel - Debugging U (might) Even Like -- A high level debugging language\n\n\ |
1796 |
+Duel was designed to overcome problems with traditional debuggers' print\n\ |
1797 |
+statement. It supports the C operators, many C constructs, and many new\n\ |
1798 |
+operators for easy exploration of the program's space, e.g.\n\ |
1799 |
+x[..100] >? 0 show positive x[i] for i=0 to 99\n\ |
1800 |
+y[10..20].code !=? 0 show non-zero y[i].code for i=10 to 20\n\ |
1801 |
+h-->next->code expand linked list h->next, h->next->next ...\n\ |
1802 |
+head-->next.if(code>0) name show name for each element with code>0\n\ |
1803 |
+x[i:=..100]=y[i]; array copy. i is an alias to vals 0..99\n\ |
1804 |
+head-->next[[10..15]] the 10th to 15th element of a linked list\n\ |
1805 |
+#/(head-->next->val==?4) count elements with val==4\n\ |
1806 |
+head-->next->if(next) val >? next->val check if list is sorted by val\n\ |
1807 |
+\n\ |
1808 |
+Duel was written by Michael Golan at Princeton University. Send email to\n\ |
1809 |
+mg@××××××××××××.edu. Duel is public domain code. No copy left or right.\n\ |
1810 |
+all but 500 lines are independent of gdb. Port it! Make it Commercial!\n\ |
1811 |
+\n\ |
1812 |
+Try \"dl ops\" for op summary; \"dl\" alone lists all commands\n"); |
1813 |
+} |
1814 |
+ |
1815 |
+LPROC examples(void) |
1816 |
+{ |
1817 |
+ duel_printf("\ |
1818 |
+x[10..20,22,24,40..60] display x[i] for the selected indexes\n\ |
1819 |
+x[9..0] display x[i] backwards\n\ |
1820 |
+x[..100] >? 5 <? 10 display x[i] if 5<x[i]<10\n\ |
1821 |
+x[0..99]=>if(_>5 && _<10) _ same\n\ |
1822 |
+val[..50].if(is_dx) x else y \ |
1823 |
+val[i].x or val[i].y depending on val[i].is_dx\n\ |
1824 |
+emp[..50].if(is_m) _ return emp[i] if emp[i].is_m.\n\ |
1825 |
+x[i:=..100]=y[i] ; assign y[i] to x[i]\n\ |
1826 |
+x[i:=..100] >? x[i+1] check if x[i] is not sorted\n\ |
1827 |
+(x[..100] >? 0)[[2]] return the 3rd positive x[i]\n\ |
1828 |
+argv[0..]@0 argv[0] argv[1] .. until first null\n\ |
1829 |
+emp[0..]@(code==0) emp[0]..emp[n-1] where emp[n].code==0\n\ |
1830 |
+head-->next->val val of each element in a linked list\n\ |
1831 |
+*head-->next[[20]] element 20 of list, '*' display struct w/fields\n\ |
1832 |
+#/head-->next count elements on a linked list\n\ |
1833 |
+#/(head-->next-val>?5) count those over 5\n\ |
1834 |
+head-->(next!=?head) expand cyclic linked list (tail->head)\n\ |
1835 |
+T mytype x ; declare var for user defined type (need 'T')\n\ |
1836 |
+int i ; for(i=0 ;i<5 .. declare variable, use C construct.\n"); |
1837 |
+} |
1838 |
+ |
1839 |
+LPROC operators(void) |
1840 |
+{ |
1841 |
+ duel_printf("\ |
1842 |
+DUEL operators in decreasing precedence. All C operators are accepted!\n\ |
1843 |
+note: precede typedefs by 'T', eg \"sizeof(T uint)\"\n\n\ |
1844 |
+{x} same as (x) but x's value is used for symbol emp[{i}]\n\ |
1845 |
+x-->y expands data structure from x, using y root-->(left,right)->key\n\ |
1846 |
+x.y eval y under x's scope, like pascal \"with\". x is accesible as '_'\n\ |
1847 |
+x->y same as (*x).y. hash[..50]->if(_!=0) key\n\ |
1848 |
+x[[y]] select the y'th elements of x head-->next[[..6]]\n\ |
1849 |
+x@y eval x, stop as soon as y true (_==y if y const). argv[0..]@0\n\ |
1850 |
+x#y eval x, set alias y as values counter (x-->next#n)->level==?n"); |
1851 |
+ duel_printf("\n\ |
1852 |
+#/x count number of values from x #/head-->next\n\ |
1853 |
+frame(n) use with '.' to reference stack frames. frame(3).val\n\ |
1854 |
+x..y x, x+1, x+2 .. y. (if x>y, return them backwards) x[10..20]\n\ |
1855 |
+..y like 0..y-1 x[..1024]\n\ |
1856 |
+x.. like x..maxint. Caution: use only with x@y or x[[y]] name[0..]@0\n\ |
1857 |
+x>?y x if x>y else nothing. also <? <=? >=? ==? and !=? x[..10]<?0\n\ |
1858 |
+&&/x 1 or 0 if x!=0 for all x values. ||/x similar &&/x[..100]>=0\n\ |
1859 |
+x,y x, then y. head-->next->(val,key)\n\ |
1860 |
+x=>y eval y for each x, setting '_' to x's values x[..50]=>_*_\n\ |
1861 |
+if(x) y C statements are operators. Also for(), while(), if() else\n\ |
1862 |
+x;y Evaluate and ignore x's value, then return y\n"); |
1863 |
+} |
1864 |
+ |
1865 |
+/* entry point into duel. s is the expression to evaluate */ |
1866 |
+ |
1867 |
+void duel_parse_and_eval(char *s) |
1868 |
+{ |
1869 |
+ static first=1 ; |
1870 |
+ if(first) { /* init stuff */ |
1871 |
+ duel_init_basic_ctypes(); |
1872 |
+ duel_printf("%s.%d, public domain debugging language. \"dl\" for help\n", |
1873 |
+ VERSION,PATCHLEVEL); |
1874 |
+ duel_redirectable_output_init(); |
1875 |
+ first=0 ; |
1876 |
+ } |
1877 |
+ if(!s || *s==0) { /* no input, give some help */ |
1878 |
+ duel_printf("\ |
1879 |
+Supported DUEL commands:\n\ |
1880 |
+duel help - give basic help (shortcut: dl ?)\n\ |
1881 |
+duel longhelp - give a longer help (dl ?\?)\n\ |
1882 |
+duel examples - show useful usage examples (dl ex)\n\ |
1883 |
+duel operators - operators summary (dl ops)\n\ |
1884 |
+duel aliases - show current aliases (dl alias)\n\ |
1885 |
+duel clear - clear all aliases\n\ |
1886 |
+duel debug - toggle duel debug mode\n"); |
1887 |
+ return ; |
1888 |
+ } |
1889 |
+ if(strcmp(s,"?")==0 || strcmp(s,"help")==0) { |
1890 |
+ help(); |
1891 |
+ return ; |
1892 |
+ } |
1893 |
+ if(strcmp(s,"?\?")==0 || strcmp(s,"longhelp")==0) { |
1894 |
+ longhelp(); |
1895 |
+ return ; |
1896 |
+ } |
1897 |
+ if(strcmp(s,"examples")==0 || strcmp(s,"ex")==0 ) { |
1898 |
+ examples(); |
1899 |
+ return ; |
1900 |
+ } |
1901 |
+ if(strcmp(s,"operators")==0 || strcmp(s,"ops")==0) { |
1902 |
+ operators(); |
1903 |
+ return ; |
1904 |
+ } |
1905 |
+ if(strcmp(s,"debug")==0) { /* turn debugging of duel itself */ |
1906 |
+ duel_debug= !duel_debug ; |
1907 |
+ duel_printf("duel debug mode %d\n",duel_debug); |
1908 |
+ return ; |
1909 |
+ } |
1910 |
+ if(strcmp(s,"clear")==0) { |
1911 |
+ duel_clear_aliases(); |
1912 |
+ duel_printf("Aliases table cleared\n"); |
1913 |
+ return ; |
1914 |
+ } |
1915 |
+ if(strcmp(s,"alias")==0 || strcmp(s,"aliases")==0) { |
1916 |
+ duel_show_aliases(); |
1917 |
+ return ; |
1918 |
+ } |
1919 |
+ if(setjmp(duel_abort_jmp)==0) { /* set abort point */ |
1920 |
+ if((root=duel_parse(s))!=NULL) { |
1921 |
+ tvalue v ; |
1922 |
+ duel_set_input_string(s); /* for src-location err management */ |
1923 |
+ duel_reset_eval(); |
1924 |
+ duel_redirectable_output_start(s); /* allow eval output to go to pipe */ |
1925 |
+ while(duel_eval(root,&v)) { |
1926 |
+ duel_print_value(&v); |
1927 |
+ duel_flush(); |
1928 |
+ } |
1929 |
+ duel_redirectable_output_end(); |
1930 |
+ } |
1931 |
+ } |
1932 |
+ duel_cleanup(0); |
1933 |
+} |
1934 |
+ |
1935 |
+ |
1936 |
+ |
1937 |
+ |
1938 |
+ |
1939 |
+ |
1940 |
+ |
1941 |
+ |
1942 |
+ |
1943 |
+ |
1944 |
--- gdb/duel/duel.h |
1945 |
+++ gdb/duel/duel.h |
1946 |
@@ -0,0 +1,35 @@ |
1947 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
1948 |
+/* Public domain code */ |
1949 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
1950 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
1951 |
+ |
1952 |
+/* duel.h - include file to be used with all duel source code. |
1953 |
+ * it defines important global constants & data types, as well as some |
1954 |
+ * global variables. prototypes should go in the duelprot.h file |
1955 |
+ */ |
1956 |
+ |
1957 |
+ |
1958 |
+/* common duel include files. I dunno why people don't like recursive |
1959 |
+ * includes, as long as it is consistent. Note only one level of recursion. |
1960 |
+ * the debugger module itself dont use this file, instead it includes what |
1961 |
+ * it needs directly. |
1962 |
+ * as for including "everything", unless one redefine some standard lib func, |
1963 |
+ * I feel safer including most standard lib files. It seems to prevent errors |
1964 |
+ * even if it garble the name space a bit. |
1965 |
+ */ |
1966 |
+ |
1967 |
+#include <stdio.h> |
1968 |
+#include <stdlib.h> |
1969 |
+#include <stddef.h> |
1970 |
+#include <string.h> |
1971 |
+#include <assert.h> |
1972 |
+#include <ctype.h> |
1973 |
+#include <limits.h> |
1974 |
+#include <math.h> |
1975 |
+/* global data and types */ |
1976 |
+ |
1977 |
+#include "global.h" |
1978 |
+ |
1979 |
+/* prototypes for all global functions follows */ |
1980 |
+ |
1981 |
+#include "proto.h" |
1982 |
--- gdb/duel/duel.pipe |
1983 |
+++ gdb/duel/duel.pipe |
1984 |
@@ -0,0 +1,107 @@ |
1985 |
+#!/usr/local/bin/perl |
1986 |
+# perl script opened as a pipe by duel |
1987 |
+# |
1988 |
+# duel(gdb), fork this program and feed it as stdin, the output from |
1989 |
+# evaluating expressions. the input is |
1990 |
+# $$$START: expr where expr is the expression being evaluted |
1991 |
+# $$$DONE end of results |
1992 |
+# $$$ABORT end of results due to error or interrupt |
1993 |
+# $$$SYM: s symbolic output 's' |
1994 |
+# $$$VAL: v value for previous symbolic output |
1995 |
+# |
1996 |
+# the output from this program is fed back into duel, which simply display |
1997 |
+# it. After DONE/ABORT, duel wait for a $$$DONE to get back, so it can |
1998 |
+# return to gdb's prompt. |
1999 |
+# |
2000 |
+# Duel expressions terminates after '|>', the text after which should be |
2001 |
+# processed by the pipe (a "pipe command" if you will). |
2002 |
+# There is no limit to what this program can do. Currently all it does |
2003 |
+# is provide all hex/ all decimal display of integers (|>hex and |>dec), |
2004 |
+# and provide "smart" output, on the same line, when the symbolic output |
2005 |
+# is the same as the values. |
2006 |
+# |
2007 |
+# Some examples of what can be done here: |
2008 |
+# |> sort -- will sort the output |
2009 |
+# |> sort? -- display a message if it was/wasnt sorted |
2010 |
+# |> uniq -- display only uniq values in output |
2011 |
+# |> uniq? -- display message if all output was uniq. |
2012 |
+# |> vals -- only display vals, ignore symbolic |
2013 |
+# |> syms -- only display symbolics, ignore vals |
2014 |
+# |> matrix -- Attempt to display in a matrix format |
2015 |
+# |> compress -- compress into single lines, eg |
2016 |
+# x[i].val=1\n x[i].name="me"\n |
2017 |
+# becomes: x[i] = { val=1, name="me" } |
2018 |
+# |> vector -- attempt to display as vector, eg |
2019 |
+# x[1]=5\bx[4]=3\nx[9]=2\nx[12]=8\n becomes: |
2020 |
+# i 1 4 9 12 |
2021 |
+# x[i] 5 3 2 8 |
2022 |
+# |> smart -- try to figure out one of the above formats... |
2023 |
+# |> plotxy -- plot (sym,val) using xgraph. can convert x[5] |
2024 |
+# symbol into '5' for the x-coord, etc. |
2025 |
+# |> stack -- output of frame(..frames_no).`*`, |
2026 |
+# which hasnt been implemented yet (* is regex), |
2027 |
+# to be formatted as a stack trace... |
2028 |
+# |
2029 |
+# the code below is very simple. A better organization will support |
2030 |
+# adding "functions" (commands) and specify for each command if the |
2031 |
+# function is called only after all values have been collected, or |
2032 |
+# for every value, if the command is active until unset, or just for |
2033 |
+# the specific line it was given on, what flags it set/reset, etc. |
2034 |
+ |
2035 |
+ |
2036 |
+$|=1 ; # flush output on every write to the pipe |
2037 |
+ |
2038 |
+%cmds = ("norm",1,"smart",1,"dec",1,"hex",1) ; |
2039 |
+$smart=0; |
2040 |
+$base=0 ; |
2041 |
+ |
2042 |
+while(<>) { |
2043 |
+ chop; study ; |
2044 |
+ if(/^\$\$\$START: /) { |
2045 |
+ if(/\|\>\s*([^"']*)$/) { # |> pipe-command |
2046 |
+ $_ = $1 ; |
2047 |
+ s/\s+$// ; # clean trailing spaces |
2048 |
+ if($cmds{$_}) { |
2049 |
+ printf "Pipe command '$_'\n" ; |
2050 |
+ $smart=0 if /norm/ ; |
2051 |
+ $smart=1 if /smart/ ; |
2052 |
+ $base=0 if /norm/ ; |
2053 |
+ $base=10 if /dec/ ; |
2054 |
+ $base=16 if /hex/ ; |
2055 |
+ } |
2056 |
+ else { printf "BAD PIP COMMAND '$_'\n" ; } |
2057 |
+ } |
2058 |
+ $same=0 ; |
2059 |
+ } |
2060 |
+ elsif(/^\$\$\$DONE$/) { |
2061 |
+ print "\n" if $same ; # go to next line if not on same |
2062 |
+ print "\$\$\$DONE\n" ; |
2063 |
+ } |
2064 |
+ elsif(/^\$\$\$ABORT$/) { |
2065 |
+ print "\n" if $same ; # go to next line if not on same |
2066 |
+ print "\$\$\$DONE\n" ; |
2067 |
+ } |
2068 |
+ elsif(/^\$\$\$SYM: (.*)$/) { |
2069 |
+ $sym = $1 ; |
2070 |
+ } |
2071 |
+ elsif(/^\$\$\$VAL: (.*)$/) { |
2072 |
+ $_ = $val = $1 ; |
2073 |
+ $_ = oct if($base==10 && /^0x[0-9a-z]*$/) ; |
2074 |
+ $_ = sprintf("0x%2.2x",$_) if($base==16 && /^[1-9]\d*$/) ; |
2075 |
+ if($smart && ( $sym eq $_ || $sym eq $val)) { |
2076 |
+ $sz= 3 + length ; |
2077 |
+ if($same+$sz > 75) { print "\n" ; $same=0 ; } |
2078 |
+ $same+=$sz ; |
2079 |
+ print "$_, " ; |
2080 |
+ } |
2081 |
+ else { |
2082 |
+ print "\n" if $same ; # go to next line if not on same |
2083 |
+ if($sym == $val) { print "$_\n" ; } |
2084 |
+ else { print "$sym = $_\n" ; } |
2085 |
+ $same=0 ; |
2086 |
+ } |
2087 |
+ } |
2088 |
+ else { |
2089 |
+ print "bad duel input to duel.pipe ignored: $_\n" ; |
2090 |
+ } |
2091 |
+} |
2092 |
--- gdb/duel/duelself.c |
2093 |
+++ gdb/duel/duelself.c |
2094 |
@@ -0,0 +1,209 @@ |
2095 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
2096 |
+/* Public domain code */ |
2097 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
2098 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
2099 |
+ |
2100 |
+/* self-debugger module, it contains all of duel's access to |
2101 |
+ * the outside world (like duelgdb.c), but is intended to work when duel |
2102 |
+ * is linked with the debuggee directly (not with the debugger!) |
2103 |
+ * if you link this with duel.a, you get a test suite of duel |
2104 |
+ * for the C program: (tsuite.c) |
2105 |
+ * |
2106 |
+ * int gint ; |
2107 |
+ * typedef unsigned int uint ; |
2108 |
+ * int main() { |
2109 |
+ * printf ; malloc ; / * include them in bin * / |
2110 |
+ * char *s="main string" ; |
2111 |
+ * } |
2112 |
+ * |
2113 |
+ * You could link this module with your own program and call it at |
2114 |
+ * "appropriate places", then ship the program with this code, and |
2115 |
+ * use duel at client's site when a crash occurs. However, reading in |
2116 |
+ * the symbol table and figuring out the active frames remains a problem. |
2117 |
+ */ |
2118 |
+ |
2119 |
+/* |
2120 |
+ * $Log: 10_all_gdb-6.6-duel.patch,v $ |
2121 |
+ * Revision 1.1 2007/12/29 21:06:06 vapier |
2122 |
+ * add DUEL support #199987 by Sergei Golubchik |
2123 |
+ * |
2124 |
+ * Revision 1.6 93/03/19 16:55:35 mg |
2125 |
+ * allow execution from within make |
2126 |
+ * |
2127 |
+ * Revision 1.5 93/03/12 05:47:29 mg |
2128 |
+ * *** empty log message *** |
2129 |
+ * |
2130 |
+ * Revision 1.4 93/02/04 00:05:10 mg |
2131 |
+ * avoid Header problems in self.out |
2132 |
+ * |
2133 |
+ * Revision 1.3 93/01/13 16:21:40 mg |
2134 |
+ * made sure printf is declared |
2135 |
+ * |
2136 |
+ * Revision 1.2 93/01/12 21:31:01 mg |
2137 |
+ * brought uptodate with duelgdb.c |
2138 |
+ * cleanup and set for release |
2139 |
+ * |
2140 |
+ */ |
2141 |
+/* include system dependent stuff here */ |
2142 |
+ |
2143 |
+#include "duel.h" |
2144 |
+ |
2145 |
+int main(int argc,char **argv); |
2146 |
+ |
2147 |
+FUNC void* duel_malloc(size_t size) |
2148 |
+{ |
2149 |
+ void *p=malloc(size); |
2150 |
+ if(p==0) duel_fatal("out of memory."); |
2151 |
+ return p; |
2152 |
+} |
2153 |
+ |
2154 |
+PROC duel_free(void *p) |
2155 |
+{ |
2156 |
+ free(p); |
2157 |
+} |
2158 |
+/* fetch n bytes from the target at the given memory address. |
2159 |
+ * the address to fetch from is given by (from). |
2160 |
+ * the value is stored at the 'to' location, which points to space for |
2161 |
+ * n bytes in the debugger. |
2162 |
+ * if the address can not be accessed, false is returned (if all ok, ret true) |
2163 |
+ */ |
2164 |
+ |
2165 |
+FUNC bool duel_get_target_bytes(ttarget_ptr from,void *to,size_t n) |
2166 |
+{ |
2167 |
+ duel_bcopy(to,from,n); |
2168 |
+ return TRUE ; |
2169 |
+} |
2170 |
+ |
2171 |
+/* store n bytes to the debuggee. reverse parms from above */ |
2172 |
+FUNC bool duel_put_target_bytes(ttarget_ptr to,void *from,size_t n) |
2173 |
+{ |
2174 |
+ duel_bcopy(to,from,n); |
2175 |
+ return TRUE ; |
2176 |
+} |
2177 |
+ |
2178 |
+/* fetch the value of a bitfield of a given structure. */ |
2179 |
+ |
2180 |
+FUNC bool duel_get_target_bitfield(ttarget_ptr struct_at,int bitpos, |
2181 |
+ int bitlen,void *to,tctype_kind tkind) |
2182 |
+{ |
2183 |
+ return FALSE ; /* not supported in duelself */ |
2184 |
+} |
2185 |
+ |
2186 |
+/* make a function call to the target. */ |
2187 |
+/* support only passing/returing sizeof(int) upto 5 paramaters */ |
2188 |
+PROC duel_target_func_call(tvalue *func, tvalue *parms[], |
2189 |
+ int parms_no,tvalue *rval) |
2190 |
+{ |
2191 |
+ int (*f)(); |
2192 |
+ int i ; |
2193 |
+ if(parms_no>5) duel_fatal("too many parms"); |
2194 |
+ if(sizeof(func->ctype->u.kid)!=sizeof(int) && |
2195 |
+ func->ctype->u.kid!=ctype_void ) duel_fatal("unsupported func parm"); |
2196 |
+ for(i=0 ; i<parms_no ; i++) { |
2197 |
+ if(parms[i]->val_kind!=VK_RVALUE || parms[i]->ctype->size!=sizeof(int)) |
2198 |
+ duel_fatal("unsupported paramater"); |
2199 |
+ } |
2200 |
+ f=(int (*)()) func->u.lvalue ; |
2201 |
+ switch(parms_no) { |
2202 |
+ case 0: |
2203 |
+ rval->u.rval_int= (*f)(); |
2204 |
+ break ; |
2205 |
+ case 1: |
2206 |
+ rval->u.rval_int= (*f)(parms[0]->u.rval_int); |
2207 |
+ break ; |
2208 |
+ case 2: |
2209 |
+ rval->u.rval_int= (*f)(parms[0]->u.rval_int,parms[1]->u.rval_int); |
2210 |
+ break ; |
2211 |
+ case 3: |
2212 |
+ rval->u.rval_int= (*f)(parms[0]->u.rval_int,parms[1]->u.rval_int, |
2213 |
+ parms[2]->u.rval_int); |
2214 |
+ break ; |
2215 |
+ case 4: |
2216 |
+ rval->u.rval_int= (*f)(parms[0]->u.rval_int,parms[1]->u.rval_int, |
2217 |
+ parms[2]->u.rval_int,parms[3]->u.rval_int); |
2218 |
+ break ; |
2219 |
+ case 5: |
2220 |
+ rval->u.rval_int= (*f)(parms[0]->u.rval_int,parms[1]->u.rval_int, |
2221 |
+ parms[2]->u.rval_int,parms[3]->u.rval_int,parms[4]->u.rval_int); |
2222 |
+ break ; |
2223 |
+ } |
2224 |
+ rval->val_kind=VK_RVALUE ; |
2225 |
+ rval->ctype=func->ctype->u.kid ; |
2226 |
+} |
2227 |
+ |
2228 |
+/* find debuggee variable. |
2229 |
+ * recognize main.s, gint, malloc, printf |
2230 |
+ */ |
2231 |
+ |
2232 |
+int gint ; /* global variable recognized */ |
2233 |
+char **main_s ; /* point to main's 's' */ |
2234 |
+ |
2235 |
+FUNC bool duel_get_target_variable(char *name, int frame_no, tvalue *v) |
2236 |
+{ |
2237 |
+ v->val_kind=VK_LVALUE ; |
2238 |
+ if(frame_no<=0 && strcmp(name,"s")==0) { |
2239 |
+ v->ctype=duel_mkctype_ptr(ctype_char); |
2240 |
+ v->u.lvalue = (void*) main_s ; |
2241 |
+ return TRUE ; |
2242 |
+ } |
2243 |
+ if(frame_no != -1) return FALSE ; |
2244 |
+ if(strcmp(name,"main")==0) { |
2245 |
+ v->ctype=duel_mkctype_func(ctype_void); |
2246 |
+ v->u.lvalue = (void*) main ; |
2247 |
+ return TRUE ; |
2248 |
+ } |
2249 |
+ if(strcmp(name,"malloc")==0) { |
2250 |
+ v->ctype=duel_mkctype_func(duel_mkctype_ptr(ctype_void)); |
2251 |
+ v->u.lvalue = (void*) malloc ; |
2252 |
+ return TRUE ; |
2253 |
+ } |
2254 |
+ if(strcmp(name,"printf")==0) { |
2255 |
+ if(0) printf(""); /* "declare" print */ |
2256 |
+ v->ctype=duel_mkctype_func(ctype_int); |
2257 |
+ v->u.lvalue = (void*) printf ; |
2258 |
+ return TRUE ; |
2259 |
+ } |
2260 |
+ if(strcmp(name,"gint")!=0) return FALSE ; |
2261 |
+ v->ctype= ctype_int ; /* type of this variable */ |
2262 |
+ v->u.lvalue= (void*) &gint ; /* address of variable */ |
2263 |
+ return TRUE ; |
2264 |
+} |
2265 |
+ |
2266 |
+ |
2267 |
+FUNC int duel_get_frames_number(void) |
2268 |
+{ |
2269 |
+ return 1 ; /* main */ |
2270 |
+} |
2271 |
+ |
2272 |
+ |
2273 |
+FUNC ttarget_ptr duel_get_function_for_frame(int frame_no) |
2274 |
+{ |
2275 |
+ if(frame_no==0) return (void*) main ; |
2276 |
+ else duel_fatal("bad frame number - internal err"); |
2277 |
+} |
2278 |
+ |
2279 |
+FUNC tctype* duel_get_target_typedef(char *name) |
2280 |
+{ |
2281 |
+ if(strcmp(name,"uint")==0) return ctype_uint ; |
2282 |
+ return NULL ; |
2283 |
+} |
2284 |
+ |
2285 |
+FUNC tctype* duel_get_target_struct_tag(char *name) { return 0 ; } |
2286 |
+FUNC tctype* duel_get_target_union_tag(char *name) { return 0 ; } |
2287 |
+FUNC tctype* duel_get_target_enum_tag(char *name) { return 0 ; } |
2288 |
+ |
2289 |
+int main(int argc,char **argv) |
2290 |
+{ |
2291 |
+ char *s="main string" ; |
2292 |
+ main_s = &s ; /* put s into the "symbol tbl" */ |
2293 |
+ |
2294 |
+ while(1) { |
2295 |
+ char in[120] ; |
2296 |
+ gets(in); |
2297 |
+ if(feof(stdin)) break ; |
2298 |
+ /* output & input are RCS'ed. avoid $Header in self.out, which is |
2299 |
+ * the input header, which RCS fix... which create mis matches */ |
2300 |
+ if(strncmp(in,"## $Header",10)==0) continue ; |
2301 |
+ printf("dl> %s\n",in); |
2302 |
+ if(in[0]==0 || in[0]=='#' && in[1]=='#') continue ; /* comments */ |
2303 |
+ duel_parse_and_eval(in); |
2304 |
+ } |
2305 |
+ return 0 ; /* to run in make */ |
2306 |
+} |
2307 |
--- gdb/duel/error.c |
2308 |
+++ gdb/duel/error.c |
2309 |
@@ -0,0 +1,114 @@ |
2310 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
2311 |
+/* Public domain code */ |
2312 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
2313 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
2314 |
+ |
2315 |
+/* display errors in a neat way */ |
2316 |
+ |
2317 |
+/* |
2318 |
+ * $Log: 10_all_gdb-6.6-duel.patch,v $ |
2319 |
+ * Revision 1.1 2007/12/29 21:06:06 vapier |
2320 |
+ * add DUEL support #199987 by Sergei Golubchik |
2321 |
+ * |
2322 |
+ * Revision 1.5 93/03/12 05:48:27 mg |
2323 |
+ * support output redirection |
2324 |
+ * |
2325 |
+ * Revision 1.4 93/01/12 21:35:31 mg |
2326 |
+ * cleanup and set for release |
2327 |
+ * |
2328 |
+ */ |
2329 |
+ |
2330 |
+#include "duel.h" |
2331 |
+ |
2332 |
+static tnode *curr_eval_node ; /* current node being evaluated */ |
2333 |
+static char *curr_inputstr ; /* current input string being eval */ |
2334 |
+ |
2335 |
+/* indicate the active node where an operator is now evaluated. |
2336 |
+ * if an error occurs, this marker is used to tell the user where |
2337 |
+ * the error is located. |
2338 |
+ * return previous setup to caller, so it can be restored. |
2339 |
+ */ |
2340 |
+ |
2341 |
+FUNC tnode* duel_set_eval_loc(tnode *n) |
2342 |
+{ |
2343 |
+ tnode *prev=curr_eval_node ; |
2344 |
+ curr_eval_node=n ; |
2345 |
+ return prev ; |
2346 |
+} |
2347 |
+ |
2348 |
+/* indicate the current input string which is evaluated |
2349 |
+ * (intended for future versions with multiple input strings) |
2350 |
+ */ |
2351 |
+ |
2352 |
+FUNC char* duel_set_input_string(char *s) |
2353 |
+{ |
2354 |
+ char *prev=curr_inputstr ; |
2355 |
+ curr_inputstr=s ; |
2356 |
+ return prev ; |
2357 |
+} |
2358 |
+/* display source position for errors, based on current node being eval'ed */ |
2359 |
+ |
2360 |
+LPROC print_src_pos(void) |
2361 |
+{ |
2362 |
+ int src_pos=0 ; |
2363 |
+ int i ; |
2364 |
+ if(curr_eval_node) src_pos=curr_eval_node->src_pos ; |
2365 |
+ duel_printf("Error: %s\n",curr_inputstr) ; |
2366 |
+ duel_printf(" ") ; |
2367 |
+ for(i=0 ; i<src_pos ; i++) duel_printf("-"); |
2368 |
+ duel_printf("^-- "); |
2369 |
+} |
2370 |
+ |
2371 |
+/* called for errors that are results of bad user input (syntax/sematics), |
2372 |
+ * e.g. an illegal variable name, etc |
2373 |
+ * the message is printed as a format string for 'op'. |
2374 |
+ * the error location in the source is printed based on the current eval node, |
2375 |
+ * and the value of the given operands are displayed. |
2376 |
+ */ |
2377 |
+ |
2378 |
+PROC duel_op_error(char *mesg,char *op,tvalue *v1,tvalue *v2) |
2379 |
+{ |
2380 |
+ char s[160] ; |
2381 |
+ |
2382 |
+ duel_redirectable_output_abort(); |
2383 |
+ print_src_pos(); |
2384 |
+ duel_printf(mesg,op); |
2385 |
+ duel_printf("\n"); |
2386 |
+ if(v1) { |
2387 |
+ duel_printf("operand%s ``%s'' ",(v2!=0)? "1":"",v1->symb_val); |
2388 |
+ duel_printf("\t-- type: "); |
2389 |
+ duel_print_type(v1->ctype,1); |
2390 |
+ duel_sprint_scalar_value(s,v1); |
2391 |
+ duel_printf("\n\t\t-- value: %s\n",s); |
2392 |
+ } |
2393 |
+ if(v2) { |
2394 |
+ duel_printf("operand%s ``%s'' ",(v1!=0)? "2":"",v2->symb_val); |
2395 |
+ duel_printf("\t-- type: "); |
2396 |
+ duel_print_type(v2->ctype,1); |
2397 |
+ duel_sprint_scalar_value(s,v2); |
2398 |
+ duel_printf("\n\t\t-- value: %s\n",s); |
2399 |
+ } |
2400 |
+ |
2401 |
+ duel_abort(); |
2402 |
+} |
2403 |
+ |
2404 |
+/* handle a genral error, no value (operand) is involved. |
2405 |
+ * location (node) is still displayed |
2406 |
+ */ |
2407 |
+ |
2408 |
+PROC duel_gen_error(char *mesg,char *arg1) |
2409 |
+{ |
2410 |
+ duel_redirectable_output_abort(); |
2411 |
+ print_src_pos(); |
2412 |
+ duel_printf(mesg,arg1); |
2413 |
+ duel_printf("\n"); |
2414 |
+ duel_abort(); |
2415 |
+} |
2416 |
+ |
2417 |
+/* handle fatal messages */ |
2418 |
+ |
2419 |
+PROC duel_fatal(char *msg) |
2420 |
+{ |
2421 |
+ duel_redirectable_output_abort(); |
2422 |
+ duel_printf("Fatal Duel error: %s\n",msg); |
2423 |
+ duel_abort(); |
2424 |
+} |
2425 |
+ |
2426 |
+ |
2427 |
--- gdb/duel/eval.c |
2428 |
+++ gdb/duel/eval.c |
2429 |
@@ -0,0 +1,834 @@ |
2430 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
2431 |
+/* Public domain code */ |
2432 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
2433 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
2434 |
+ |
2435 |
+/* this module is the most critical code, the recursive evaluation |
2436 |
+ */ |
2437 |
+ |
2438 |
+/* |
2439 |
+ * $Log: 10_all_gdb-6.6-duel.patch,v $ |
2440 |
+ * Revision 1.1 2007/12/29 21:06:06 vapier |
2441 |
+ * add DUEL support #199987 by Sergei Golubchik |
2442 |
+ * |
2443 |
+ * Revision 1.13 93/03/19 15:39:34 mg |
2444 |
+ * fixed bug in left->left symbolic, and long symbolics which caused crashes |
2445 |
+ * |
2446 |
+ * Revision 1.12 93/03/12 05:48:45 mg |
2447 |
+ * fixed sizeof(type) symbolic |
2448 |
+ * |
2449 |
+ * Revision 1.11 93/02/26 04:59:51 mg |
2450 |
+ * improved symbolic debugging of #/ |
2451 |
+ * |
2452 |
+ * Revision 1.10 93/02/03 21:47:41 mg |
2453 |
+ * fixed dot stack bug; fixed func-call last parm eval bug |
2454 |
+ * |
2455 |
+ * Revision 1.9 93/01/12 21:50:26 mg |
2456 |
+ * cleanup and set for release |
2457 |
+ * |
2458 |
+ * Revision 1.8 93/01/07 00:09:34 mg |
2459 |
+ * scope stack changes a bit. |
2460 |
+ * clear/aliases commands. |
2461 |
+ * func.x support, x.y etc force existance if y field of x., x=>y w/'_' |
2462 |
+ * allow fields in y for x@y, x pointer. |
2463 |
+ * fixed eval_node setup |
2464 |
+ * added &&/ ||/ |
2465 |
+ * |
2466 |
+ * |
2467 |
+ * Revision 1.7 93/01/03 07:29:23 mg |
2468 |
+ * function calls, error reporting, printing. |
2469 |
+ * |
2470 |
+ * Revision 1.6 92/12/24 23:33:48 mg |
2471 |
+ * frames support |
2472 |
+ * |
2473 |
+ * Revision 1.5 92/10/19 15:06:35 mg |
2474 |
+ * *** empty log message *** |
2475 |
+ * |
2476 |
+ * Revision 1.4 92/10/14 02:04:35 mg |
2477 |
+ * misc |
2478 |
+ * |
2479 |
+ * Revision 1.3 92/09/16 11:04:16 mg |
2480 |
+ * *** empty log message *** |
2481 |
+ * |
2482 |
+ * Revision 1.2 92/09/15 05:54:56 mg |
2483 |
+ * cosmetics and new ops: |
2484 |
+ * generic '.' and '_' support. x@y. '..x' and 'x..'. while(), for(), ?: |
2485 |
+ * |
2486 |
+ */ |
2487 |
+ |
2488 |
+#include "duel.h" |
2489 |
+ |
2490 |
+ |
2491 |
+ |
2492 |
+#define DOT_STACK_SIZE 100 /* dot stack size, maximum no. of dots in stmt */ |
2493 |
+ |
2494 |
+/* the scope eval stack. |
2495 |
+ * used for several purposes: to push _'s values (=>), to push structs |
2496 |
+ * and unions for x.y and x->y, and to push func/frame values fro frame(i).x |
2497 |
+ * and func.x/ |
2498 |
+ * realv is the real value for the left side operand. It is used for '_'. |
2499 |
+ * fieldv is the one to be used to fetch actual names. either: |
2500 |
+ * fieldv=realv (for x.y, frame(i).y), fieldv=*realv (for x->y), |
2501 |
+ * fieldv=func_frame(realv) (for func.x), or fieldv=0 (x=>y). |
2502 |
+ */ |
2503 |
+struct { |
2504 |
+ tvalue *realv ; /* actual value for x in x.y or x->y etc. used for _ */ |
2505 |
+ tvalue *fieldv; /* value to use for fetching fields, *realv for x->y */ |
2506 |
+ } dot_stack[DOT_STACK_SIZE] ; |
2507 |
+int dot_stack_top= -1 ; |
2508 |
+ |
2509 |
+PROC duel_reset_eval(void) /* reset evaluation states from previous eval */ |
2510 |
+{ |
2511 |
+ dot_stack_top= -1 ; /* reset stack */ |
2512 |
+} |
2513 |
+ |
2514 |
+/* try to find the given name on the dot_stack of structures. |
2515 |
+ * if found, return true and value in(v) else return false. |
2516 |
+ * the symbolic value is not set. |
2517 |
+ * if top_only, looks only at the top of the stack. |
2518 |
+ */ |
2519 |
+LFUNC bool find_dot_name(char *name,tvalue *v,bool top_only) |
2520 |
+{ |
2521 |
+ int i,j ; |
2522 |
+ tctype_field *f ; |
2523 |
+ tctype *t ; |
2524 |
+ tvalue *x; |
2525 |
+ |
2526 |
+ for(i=dot_stack_top ; i>=0 ; i--) { /* look at the stack[i] */ |
2527 |
+ if(top_only && i!=dot_stack_top) break ; /* consider only top of stk*/ |
2528 |
+ x=dot_stack[i].realv ; |
2529 |
+ if(name[0]=='_' && name[1]==0 || /* _ */ |
2530 |
+ name[1]=='_' && i==dot_stack_top-1 && name[2]==0 || /* __ */ |
2531 |
+ name[1]=='0'+dot_stack_top-i && name[2]==0) { /* _[0-9] */ |
2532 |
+ *v = *x ; |
2533 |
+ return TRUE ; |
2534 |
+ } |
2535 |
+ x=dot_stack[i].fieldv; |
2536 |
+ if(!x) continue ; |
2537 |
+ if(x->val_kind==VK_FVALUE) { |
2538 |
+ if(!duel_get_target_variable(name,x->u.fvalue,v)) continue ; |
2539 |
+ strcpy(v->symb_val,name); |
2540 |
+ return TRUE ; |
2541 |
+ } |
2542 |
+ t=x->ctype ; |
2543 |
+ if(!ctype_kind_struct_like(t)) continue ; |
2544 |
+ duel_assert(x->val_kind==VK_LVALUE); |
2545 |
+ for(j=0 ; j<t->u.f.fields_no ; j++) { /* look at field[j] of struct*/ |
2546 |
+ f= &t->u.f.fields[j] ; |
2547 |
+ if(strcmp(f->name,name)==0) goto found ; |
2548 |
+ } |
2549 |
+ } |
2550 |
+ return FALSE ; |
2551 |
+found: |
2552 |
+ v->ctype=f->ctype ; |
2553 |
+ strcpy(v->symb_val,name); |
2554 |
+ if(f->bitlen==0) { |
2555 |
+ v->u.lvalue=x->u.lvalue+f->bitpos/BITS_PER_BYTE ; |
2556 |
+ v->val_kind=VK_LVALUE ; |
2557 |
+ return TRUE ; |
2558 |
+ } |
2559 |
+ /* special care for a bitfield */ |
2560 |
+ if(f->ctype->type_kind!=CTK_INT && f->ctype->type_kind!=CTK_UINT) |
2561 |
+ duel_gen_error("bitfield '%s' must be int or unsigned",name); |
2562 |
+ v->val_kind=VK_BVALUE ; |
2563 |
+ v->u.bvalue.lvalue=x->u.lvalue ; |
2564 |
+ v->u.bvalue.bitpos=f->bitpos ; |
2565 |
+ v->u.bvalue.bitlen=f->bitlen ; |
2566 |
+ return TRUE ; |
2567 |
+} |
2568 |
+ |
2569 |
+/* find the value of a given symbolic name and |
2570 |
+ * return in in v |
2571 |
+ * if name is not found, aborts with an error |
2572 |
+ */ |
2573 |
+ |
2574 |
+LPROC duel_eval_name(char *name,tvalue *v) |
2575 |
+{ |
2576 |
+ tvalue *aval=duel_find_alias(name) ; /* find internal alias */ |
2577 |
+ if(aval!=NULL) *v= *aval ; |
2578 |
+ else |
2579 |
+ if(find_dot_name(name,v,FALSE)) return ; /* setup name itself */ |
2580 |
+ else |
2581 |
+ if(duel_get_target_variable(name,-1,v)); |
2582 |
+ else |
2583 |
+ if(strcmp(name,"frames_no")==0) { /* check special variables */ |
2584 |
+ v->val_kind=VK_RVALUE ; |
2585 |
+ v->ctype=ctype_int ; |
2586 |
+ v->u.rval_int=duel_get_frames_number(); |
2587 |
+ } |
2588 |
+ else duel_gen_error("variable '%s' not found",name); |
2589 |
+ strcpy(v->symb_val,name); |
2590 |
+} |
2591 |
+ |
2592 |
+ |
2593 |
+LPROC push_val(tval_list *l,tvalue *v) |
2594 |
+{ |
2595 |
+ tval_lcell *e = duel_malloc(sizeof(tval_lcell)); |
2596 |
+ e->val = *v ; |
2597 |
+ e->next=l->head ; |
2598 |
+ l->head=e ; |
2599 |
+ if(l->tail==0) l->tail=e ; |
2600 |
+} |
2601 |
+ |
2602 |
+LPROC append_val(tval_list *l,tvalue *v) |
2603 |
+{ |
2604 |
+ tval_lcell *e=duel_malloc(sizeof(tval_lcell)) ; |
2605 |
+ e->val = *v ; |
2606 |
+ e->next=0 ; |
2607 |
+ if(l->head==0) l->head=l->tail=e ; |
2608 |
+ else l->tail=l->tail->next=e ; |
2609 |
+} |
2610 |
+ |
2611 |
+/* push a whole val-list(ins) into (l) i.e. insert (ins) at the head of(l) |
2612 |
+ */ |
2613 |
+ |
2614 |
+LPROC push_val_list(tval_list *l,tval_list *ins) |
2615 |
+{ |
2616 |
+ if(ins->head==NULL) return ; /* inserted list is empty */ |
2617 |
+ if(l->head==NULL) { *l= *ins ; return ; } /* insert-into is empty */ |
2618 |
+ ins->tail->next=l->head ; |
2619 |
+ l->head=ins->head ; |
2620 |
+} |
2621 |
+ |
2622 |
+ |
2623 |
+/* remove first(top) element */ |
2624 |
+LFUNC bool pop_val(tval_list *l,tvalue *v) |
2625 |
+{ |
2626 |
+ tval_lcell *e=l->head ; |
2627 |
+ if(e==0) return(FALSE); |
2628 |
+ *v=e->val ; |
2629 |
+ l->head=e->next ; |
2630 |
+ return(TRUE); |
2631 |
+} |
2632 |
+/* compute the symbolic value of one iteration of a search (eg -->) operator. |
2633 |
+ * Normally, for (x) and (y) the result x->y is returned. |
2634 |
+ * But, if x === a-->next[[n]] and y === next, then we |
2635 |
+ * return a-->next[[m]] where m=n+1. |
2636 |
+ * Also, instead of returning x->y we return x-->y[[1]] |
2637 |
+ * |
2638 |
+ * note: this was not written for speed! I don't know if it takes |
2639 |
+ * a significant amount of time or not. |
2640 |
+ */ |
2641 |
+ |
2642 |
+LPROC set_search_symb_val(char *opcode,tvalue *xval,tvalue *yval) |
2643 |
+{ |
2644 |
+ char *x = xval->symb_val ; |
2645 |
+ char *y = yval->symb_val ; |
2646 |
+ int i,opl=strlen(opcode),xl=strlen(x),yl=strlen(y) ; |
2647 |
+ char s[3*VALUE_MAX_SYMBOLIC_SIZE]; |
2648 |
+ |
2649 |
+ if(yl+2<xl && strcmp(x+xl-yl,y)==0 && x[xl-yl-2]=='-' && x[xl-yl-1]=='>') |
2650 |
+ sprintf(s,"%-.*s%s%s[[2]]",xl-yl-2,x,opcode,y); |
2651 |
+ else { |
2652 |
+ for(i=xl-1 ; i>0 ; i--) /* see if we have op in x */ |
2653 |
+ if(strncmp(&x[i],opcode,opl)==0) break ; |
2654 |
+ if(i>0 && strncmp(&x[i+opl],y,yl)==0 && |
2655 |
+ x[i+opl+yl]=='[' && x[i+opl+yl+1]=='[' && x[xl-2]==']' && x[xl-1]==']'){ |
2656 |
+ /* x seems to be something like head-->next[1] */ |
2657 |
+ int j,val=0 ; |
2658 |
+ for(j=i+opl+yl+2 ; j<xl-2 ; j++) { |
2659 |
+ if(x[j]<'0' || x[j]>'9') goto simple ; |
2660 |
+ val=10*val+x[j]-'0' ; /* compute index */ |
2661 |
+ } |
2662 |
+ sprintf(s,"%-.*s[[%d]]",i+opl+yl,x,val+1); /* and re-create it */ |
2663 |
+ } |
2664 |
+ else { |
2665 |
+simple: /* we failed to find a x-->y[z] pattern, make new one */ |
2666 |
+ sprintf(s,"%s->%s",x,y); |
2667 |
+ } |
2668 |
+ } |
2669 |
+ s[VALUE_MAX_SYMBOLIC_SIZE-1]=0 ; /* chop as needed */ |
2670 |
+ strcpy(y,s); |
2671 |
+} |
2672 |
+ |
2673 |
+LPROC push_dot_stack(tvalue *realv,tvalue *fieldv) |
2674 |
+{ |
2675 |
+ if(dot_stack_top==DOT_STACK_SIZE) |
2676 |
+ duel_gen_error("expression too complex ('.' and '->' levels)",0); |
2677 |
+ dot_stack[++dot_stack_top].realv=realv ; |
2678 |
+ dot_stack[dot_stack_top].fieldv=fieldv ; |
2679 |
+} |
2680 |
+ |
2681 |
+LPROC pop_dot_stack(void) |
2682 |
+{ |
2683 |
+ duel_assert(dot_stack_top>=0); |
2684 |
+ dot_stack_top-- ; |
2685 |
+} |
2686 |
+ |
2687 |
+/* a simple fetch of a field. used mainly when printing |
2688 |
+ * v must be a struct with the given name field. value is returned in ret. |
2689 |
+ * return false if name not found. |
2690 |
+ */ |
2691 |
+ |
2692 |
+FUNC bool duel_get_dot_name(tvalue *v,char *name,tvalue *ret) |
2693 |
+{ |
2694 |
+ bool ok ; |
2695 |
+ push_dot_stack(v,v); |
2696 |
+ ok=find_dot_name(name,ret,TRUE); |
2697 |
+ pop_dot_stack(); |
2698 |
+ return ok ; |
2699 |
+} |
2700 |
+ |
2701 |
+/* evaluate x.y and similar "with" operators. Special care when y is a |
2702 |
+ * name and not an expression -- force y to be a direct field of x. |
2703 |
+ * y is the 'y' node. v is value to return. op is opcode for error reports |
2704 |
+ * (rv,fv) are values to push on the dot stack. rv is the real 'x' value, |
2705 |
+ * fv is the value of x to use for field lookup (fv= *rv for '->') |
2706 |
+ */ |
2707 |
+ |
2708 |
+LFUNC bool eval_dot(tnode *y,tvalue *v,char *op,tvalue *rv,tvalue *fv) |
2709 |
+{ |
2710 |
+ bool ok ; |
2711 |
+ push_dot_stack(rv,fv); |
2712 |
+ if(y->node_kind!=NK_NAME) ok=duel_eval(y,v); /* "with" style */ |
2713 |
+ else { /* x.y y simply name */ |
2714 |
+ if(++y->eval.level>1) { y->eval.level=0 ; ok=FALSE ; } |
2715 |
+ else { |
2716 |
+ ok=find_dot_name(y->name,v,TRUE); |
2717 |
+ if(!ok) duel_op_error("field not found in operator '%s'",op,rv,0); |
2718 |
+ } |
2719 |
+ } |
2720 |
+ pop_dot_stack(); |
2721 |
+ return ok ; |
2722 |
+} |
2723 |
+ |
2724 |
+ |
2725 |
+/* evaluate special operators like '-->' '?:' etc */ |
2726 |
+ |
2727 |
+/* get the next result of an sop val: |
2728 |
+ * DFS: init by pushing(x) |
2729 |
+ * Iterate: pop x, compute all x->y, push (reversed) |
2730 |
+ * out: x |
2731 |
+ |
2732 |
+ * POS: init by pushing(x), unmarked. |
2733 |
+ * Iterate: pop x, if marked return it. else push back, marked. |
2734 |
+ * compute all x->y, push (reversed) |
2735 |
+ * repeat until marked x is popped. |
2736 |
+ * out: poped x which is marked. |
2737 |
+ |
2738 |
+ * BFS: init by pushing(x) |
2739 |
+ * Iterate: get first(x), |
2740 |
+ * compute all x->y and put into queue. |
2741 |
+ * return x. |
2742 |
+ */ |
2743 |
+ |
2744 |
+/* fetch the next value in a DFS search on x-->y. y is given as a node |
2745 |
+ * and x is popped of the given list. Value is returned in v. |
2746 |
+ * note: the results from x->y are reversed when pushed on the list, |
2747 |
+ * this is so x-->(left,right) would return the left first (put last on |
2748 |
+ * the stack, even though it is computed first!) |
2749 |
+ * malloc problem: newl is kept locally, so in case of ^C while here, mem |
2750 |
+ * it points to will be lost. Normally only a few values |
2751 |
+ */ |
2752 |
+ |
2753 |
+LFUNC bool get_next_dfs_val(tval_list *l, tnode *y,tvalue *v) |
2754 |
+{ |
2755 |
+ tvalue child,x ; |
2756 |
+ tval_list newl ; |
2757 |
+ newl.head=0 ; |
2758 |
+ do { |
2759 |
+ if(!pop_val(l,v)) return(FALSE) ; |
2760 |
+ x= *v ; |
2761 |
+ duel_get_struct_ptr_val(&x,"x-->y"); |
2762 |
+ } while(x.u.lvalue==0) ; /* ignore null pointers */ |
2763 |
+ while(eval_dot(y,&child,"-->",v,&x)) { |
2764 |
+ set_search_symb_val("-->",&x,&child); /* makes x-->y[n] neatly */ |
2765 |
+ append_val(&newl,&child); /* append to childs list */ |
2766 |
+ } |
2767 |
+ push_val_list(l,&newl); /* append new childs to stack */ |
2768 |
+ return(TRUE); /* returns the popped value in v */ |
2769 |
+} |
2770 |
+ |
2771 |
+ |
2772 |
+/* stop the evaluation of the expression at node n. |
2773 |
+ * useful with operators like first(). |
2774 |
+ * each node keeps an internal state allowing it to produce the next value. |
2775 |
+ * this function resets those states. |
2776 |
+ * |
2777 |
+ * How: the internal state is kept in n->eval.level. we reset level to zero |
2778 |
+ * for the node and the subnodes. if the level is already zero, |
2779 |
+ * the node has already gone to the 'initial state', so the subnodes |
2780 |
+ * are not visited. |
2781 |
+ */ |
2782 |
+ |
2783 |
+LPROC stop_eval(tnode *n) |
2784 |
+{ |
2785 |
+ int i; |
2786 |
+ if(n==NULL || n->eval.level==0) return ; /* done! subnodes are also ok */ |
2787 |
+ n->eval.level=0 ; |
2788 |
+ for(i=0 ; i<NODE_MAX_KIDS ; i++) stop_eval(n->kids[i]); |
2789 |
+} |
2790 |
+ |
2791 |
+/* evaluate function paramaters. This recursive function should be called |
2792 |
+ * with the top node for the parms. Parms are parsed as "," operators. |
2793 |
+ * the function leaves the computed values "hanging" on v1 of each "," node. |
2794 |
+ * the last paramater is left at v2 of the function call itself (there isnt |
2795 |
+ * any other reasonable place!). |
2796 |
+ * 2nd paramater is the function call node, used for the last paramater. |
2797 |
+ */ |
2798 |
+ |
2799 |
+LFUNC bool eval_func_parms(tnode *n,tnode *fn) |
2800 |
+{ |
2801 |
+ tvalue *p= &n->eval.v1 ; |
2802 |
+ if(n->node_kind==NK_OP && n->op_kind==OPK_SBIN && n->op==',') { |
2803 |
+ while(n->eval.level==2 || duel_eval(n->kids[0],p)) { |
2804 |
+ n->eval.level=2 ; /* left side active parm in p */ |
2805 |
+ if(eval_func_parms(n->kids[1],fn)) goto ok; |
2806 |
+ n->eval.level=1 ; /*re-eval */ |
2807 |
+ } |
2808 |
+ return FALSE ; |
2809 |
+ } |
2810 |
+ else if(!duel_eval(n,p = &fn->eval.v2)) return FALSE; /* last paramater */ |
2811 |
+ok: |
2812 |
+ duel_standardize_func_parm(p); |
2813 |
+ return TRUE ; |
2814 |
+} |
2815 |
+ |
2816 |
+LFUNC bool eval_func_call(tnode *n,tvalue *v) |
2817 |
+{ |
2818 |
+ |
2819 |
+ tvalue *f= &n->eval.v1 ; |
2820 |
+ tvalue *parms[21]; |
2821 |
+ int i,parms_no ; |
2822 |
+ tnode *p ; |
2823 |
+ |
2824 |
+again: |
2825 |
+ if(n->kids[1]==NULL) { /* no parms */ |
2826 |
+ n->eval.level=1 ; |
2827 |
+ if(!duel_eval(n->kids[0],f)) return FALSE ; |
2828 |
+ } |
2829 |
+ else { |
2830 |
+ while(n->eval.level==2 || duel_eval(n->kids[0],f)) { |
2831 |
+ n->eval.level=2 ; /* function in f */ |
2832 |
+ if(eval_func_parms(n->kids[1],n)) goto ok; |
2833 |
+ n->eval.level=1 ; /*re-eval func */ |
2834 |
+ } |
2835 |
+ return FALSE ; |
2836 |
+ ok: ; |
2837 |
+ } |
2838 |
+ |
2839 |
+ if(f->ctype->type_kind!=CTK_FUNC) duel_op_error("bad function call",0,f,0); |
2840 |
+ |
2841 |
+ p=n->kids[1] ; /* collect paramaters now */ |
2842 |
+ parms_no=0 ; |
2843 |
+ while(p && p->node_kind==NK_OP && p->op_kind==OPK_SBIN && p->op==',') { |
2844 |
+ parms[parms_no++]= &p->eval.v1 ; |
2845 |
+ p=p->kids[1] ; |
2846 |
+ if(parms_no>=20) duel_op_error("too many paramaters",0,0,0); |
2847 |
+ } |
2848 |
+ if(p) parms[parms_no++]= &n->eval.v2 ; /* last paramater */ |
2849 |
+ |
2850 |
+ duel_target_func_call(f,parms,parms_no,v); |
2851 |
+ if(f->ctype->u.kid->type_kind==CTK_VOID) goto again ; /* no return vals */ |
2852 |
+ duel_set_symb_val(v,"%s(",f,0); |
2853 |
+ for(i=0 ; i<parms_no ; i++) |
2854 |
+ duel_set_symb_val(v,"%s%s,",v,parms[i]); |
2855 |
+ if(parms_no>0) v->symb_val[strlen(v->symb_val)-1]='\0' ; /*chop ',' tail*/ |
2856 |
+ strcat(v->symb_val,")"); |
2857 |
+ return TRUE ; |
2858 |
+} |
2859 |
+ |
2860 |
+ |
2861 |
+/* evaluate for special operators: those the produce more than one value, |
2862 |
+ * binary ones. ',' '..' etc |
2863 |
+ */ |
2864 |
+ |
2865 |
+LFUNC bool duel_eval_sbin(tnode *n,tvalue *v) |
2866 |
+{ |
2867 |
+ tval_list *vl = &n->eval.vlist ; |
2868 |
+ tvalue y,*v1= &n->eval.v1, *v2= &n->eval.v2 ; |
2869 |
+ tnode *kid0 = n->kids[0], *kid1 = n->kids[1] ; |
2870 |
+ int vi ; |
2871 |
+ bool ok ; |
2872 |
+#define lev n->eval.level |
2873 |
+ |
2874 |
+ duel_assert(n->node_kind==NK_OP && n->op_kind==OPK_SBIN); |
2875 |
+ switch(n->op) { |
2876 |
+ case OP_DECL: |
2877 |
+ duel_assert(kid0->node_kind==NK_NAME && kid1->node_kind==NK_CTYPE); |
2878 |
+ if(kid1->ctype->size<=0) duel_gen_error("illegal type size",0); |
2879 |
+ v->val_kind=VK_LVALUE ; |
2880 |
+ v->ctype=kid1->ctype ; |
2881 |
+ v->u.lvalue=duel_alloc_target_space(kid1->ctype->size); |
2882 |
+ strcpy(v->symb_val,kid0->name); |
2883 |
+ duel_set_alias(kid0->name,v); |
2884 |
+ break ; |
2885 |
+ case OP_DEF: |
2886 |
+ if(kid0->node_kind!=NK_NAME) |
2887 |
+ duel_gen_error("left side of := must be a simple var",0); |
2888 |
+ if(!duel_eval(kid1,v)) return FALSE ; |
2889 |
+ duel_set_alias(kid0->name,v); |
2890 |
+ return TRUE ; |
2891 |
+ case ',': |
2892 |
+ if(lev==1 && duel_eval(kid0,v)) return TRUE ; |
2893 |
+ lev=2 ; |
2894 |
+ return duel_eval(kid1,v); |
2895 |
+ case ';': |
2896 |
+ /*note: (x;) is not allowed in syntax, but is allowed here and |
2897 |
+ *means eval x, return nothing. used by parser, e.g. terminating ';' |
2898 |
+ *produces no side effects |
2899 |
+ */ |
2900 |
+ |
2901 |
+ if(lev==1) while(duel_eval(kid0,v)) ; /* eval all left size */ |
2902 |
+ lev=2 ; |
2903 |
+ return duel_eval(kid1,v); |
2904 |
+ break ; |
2905 |
+ case OP_IMP: /* a=>b for each _=eval(a) return eval(b) (with _ set) */ |
2906 |
+ if(lev>1) goto im2 ; |
2907 |
+ for(;;) { |
2908 |
+ if(!duel_eval(kid0,v1)) return FALSE ; |
2909 |
+ lev=2 ; |
2910 |
+ im2: push_dot_stack(v1,0); |
2911 |
+ ok=duel_eval(kid1,v); |
2912 |
+ pop_dot_stack(); |
2913 |
+ if(ok) return TRUE ; |
2914 |
+ } |
2915 |
+ case OP_IF: /* if(a) b return eval(b) for each eval(a)!=0 */ |
2916 |
+ if(lev>1) goto if2 ; |
2917 |
+ for(;;) { |
2918 |
+ if(!duel_eval(kid0,v)) return FALSE ; |
2919 |
+ if(!duel_mk_logical(v,"if(x)y")) continue ; |
2920 |
+ lev=2 ; |
2921 |
+ if2: if(duel_eval(kid1,v)) return TRUE ; |
2922 |
+ } |
2923 |
+ case OP_OR: /* a||b normal 'C' logical or */ |
2924 |
+ if(lev>1) goto or2 ; |
2925 |
+ for(;;) { |
2926 |
+ if(!duel_eval(kid0,v)) return FALSE ; |
2927 |
+ if(duel_mk_logical(v,"x||y")) {lev=1 ; return TRUE ;} |
2928 |
+ or2: if(duel_eval(kid1,v)) { |
2929 |
+ lev=2 ; |
2930 |
+ duel_mk_logical(v,"y||x"); |
2931 |
+ return TRUE ; |
2932 |
+ } |
2933 |
+ } |
2934 |
+ case OP_AND: /* a&&b normal 'C' logical and */ |
2935 |
+ if(lev>1) goto an2 ; |
2936 |
+ for(;;) { |
2937 |
+ if(!duel_eval(kid0,v)) return FALSE ; |
2938 |
+ if(!duel_mk_logical(v,"x&&y")) {lev=1 ; return TRUE ;} |
2939 |
+ an2: if(duel_eval(kid1,v)) { |
2940 |
+ lev=2 ; |
2941 |
+ duel_mk_logical(v,"y&&x"); |
2942 |
+ return TRUE ; |
2943 |
+ } |
2944 |
+ } |
2945 |
+ case '.': |
2946 |
+ if(lev>1) goto dt2 ; |
2947 |
+ for(;;) { |
2948 |
+ if(!duel_eval(kid0,v1)) return FALSE ; |
2949 |
+ *v2 = * v1 ; /* copy value for the lookup */ |
2950 |
+ if(ctype_kind_func_ptr_like(v1->ctype)) /* func.x */ |
2951 |
+ duel_find_func_frame(v2,"x.y"); |
2952 |
+ else |
2953 |
+ if(v1->val_kind!=VK_FVALUE) /* type check frame or struct*/ |
2954 |
+ duel_get_struct_val(v1,"x.y"); |
2955 |
+ lev=2 ; |
2956 |
+ dt2: if(!eval_dot(kid1,v,".",v1,v2)) continue ; |
2957 |
+ if(v->ctype!=v1->ctype || v->val_kind!=v1->val_kind || |
2958 |
+ v->u.lvalue != v1->u.lvalue || |
2959 |
+ strcmp(v->symb_val,v1->symb_val)!=0) /* check for x._ */ |
2960 |
+ duel_set_symb_val(v,"%s.%s",v1,v); |
2961 |
+ return TRUE ; |
2962 |
+ } |
2963 |
+ case OP_ARR: |
2964 |
+ if(lev>1) goto ar2 ; |
2965 |
+ for(;;) { |
2966 |
+ if(!duel_eval(kid0,v1)) return FALSE ; |
2967 |
+ *v2 = *v1 ; /* copy value for dereferencing */ |
2968 |
+ duel_get_struct_ptr_val(v2,"x->y"); |
2969 |
+ lev=2 ; |
2970 |
+ ar2: if(!eval_dot(kid1,v,"->",v1,v2)) continue ; |
2971 |
+ if(v->ctype!=v1->ctype || v->val_kind!=v1->val_kind || |
2972 |
+ v->u.lvalue != v1->u.lvalue || |
2973 |
+ strcmp(v->symb_val,v1->symb_val)!=0) /* check for x->_ */ |
2974 |
+ duel_set_symb_val(v,"%s->%s",v1,v); |
2975 |
+ return TRUE ; |
2976 |
+ } |
2977 |
+ case OP_TO: /* a..b Is it legal to have 1..(5,6) sure! */ |
2978 |
+ if(lev>1) goto to2 ; |
2979 |
+ do { |
2980 |
+ if(kid0 && !duel_eval(kid0,v1)) break ; |
2981 |
+ do { |
2982 |
+ if(kid1 && !duel_eval(kid1,v2)) break ; |
2983 |
+ to2: if(duel_do_op_to(kid0? v1:0,kid1? v2:0,++lev-2,v)) return TRUE; |
2984 |
+ } while(kid1); |
2985 |
+ } while(kid0) ; /* either one (kid0 null) or infinite iterations*/ |
2986 |
+ break ; |
2987 |
+ case OP_SEL: /* x[[y]] */ |
2988 |
+ if(lev==1) { lev=2 ; n->eval.counter= -1 ; } |
2989 |
+ if(!duel_eval(kid1,v1)) { |
2990 |
+ stop_eval(kid0); |
2991 |
+ return FALSE ; |
2992 |
+ } |
2993 |
+ vi=duel_get_posint_val(v1,"y[[x]]"); |
2994 |
+ if(vi<=n->eval.counter) { |
2995 |
+ /* v is smaller than previous v value, so reset x and |
2996 |
+ * start over. Example: \x[1,5,3] after \x[1], |
2997 |
+ * we continue to get [5]. but to get [3] we reset |
2998 |
+ * Alternatively, we could have kept a list of old |
2999 |
+ * generated values. |
3000 |
+ */ |
3001 |
+ stop_eval(kid0) ; |
3002 |
+ n->eval.counter= -1 ; |
3003 |
+ } |
3004 |
+ for( ; n->eval.counter<vi ; n->eval.counter++) |
3005 |
+ if(!duel_eval(kid0,v)) |
3006 |
+ duel_op_error("operator x of y[[x]] too large",0,v1,0); |
3007 |
+ return TRUE ; /* value is the last (v) computed */ |
3008 |
+ break ; |
3009 |
+ case '@': /* x@y - generate x stops when y true */ |
3010 |
+ if(!duel_eval(kid0,v)) return FALSE ; |
3011 |
+ if(kid1->node_kind==NK_CONST) { /* special case y constant */ |
3012 |
+ *v2=kid1->cnst ; |
3013 |
+ *v1= *v ; /* because 'apply_bin_op' destroy its args */ |
3014 |
+ duel_apply_bin_op(OP_EQ,v1,v2,&y); |
3015 |
+ if(y.u.rval_int) { stop_eval(kid0); return FALSE ; } |
3016 |
+ return TRUE ; |
3017 |
+ } |
3018 |
+ *v1 = *v ; /* allow fields in y of x@y for x struct ptr */ |
3019 |
+ if(ctype_kind_ptr_like(v->ctype) && |
3020 |
+ ctype_kind_struct_like(v->ctype->u.kid)) |
3021 |
+ duel_get_struct_ptr_val(v1,"x@y"); |
3022 |
+ |
3023 |
+ while(eval_dot(kid1,v2,"@",v,v1)) /* check &&/y */ |
3024 |
+ if(!duel_mk_logical(v2,"y@x")) { /* y==0, so dont stop x */ |
3025 |
+ stop_eval(kid1); |
3026 |
+ return TRUE ; |
3027 |
+ } |
3028 |
+ stop_eval(kid0); |
3029 |
+ break ; |
3030 |
+ case '#': /* x#i define variable i as counter for gen. x*/ |
3031 |
+ if(kid1->node_kind!=NK_NAME) |
3032 |
+ duel_gen_error("x#y 2rd operand must be a name",0); |
3033 |
+ if(!duel_eval(kid0,v)) return FALSE ; |
3034 |
+ if(lev==1) { lev=2 ; n->eval.counter= -1 ; } /* first time */ |
3035 |
+ y.val_kind=VK_RVALUE ; |
3036 |
+ y.ctype=ctype_int ; |
3037 |
+ y.u.rval_int= ++n->eval.counter ; |
3038 |
+ sprintf(y.symb_val,"%d",n->eval.counter); |
3039 |
+ duel_set_alias(kid1->name,&y); |
3040 |
+ return TRUE ; |
3041 |
+ break ; |
3042 |
+ case OP_DFS: /* x-->y */ |
3043 |
+ if(lev>1) goto df2 ; |
3044 |
+ for(;;) { |
3045 |
+ if(!duel_eval(kid0,v)) return FALSE ; |
3046 |
+ duel_free_val_list(vl); |
3047 |
+ push_val(vl,v); |
3048 |
+ lev=2 ; |
3049 |
+ df2: if(get_next_dfs_val(vl,kid1,v)) return TRUE ; |
3050 |
+ } |
3051 |
+ break ; |
3052 |
+ case OP_WHILE: /* while(a) b */ |
3053 |
+ if(lev==2) goto wh2 ; |
3054 |
+ for(;;) { |
3055 |
+ while(duel_eval(kid0,v)) /* check &&/a */ |
3056 |
+ if(!duel_mk_logical(v,"while(x)y")) { |
3057 |
+ stop_eval(kid0); |
3058 |
+ return FALSE ; |
3059 |
+ } |
3060 |
+ lev=2 ; |
3061 |
+ wh2: if(duel_eval(kid1,v)) return TRUE ; |
3062 |
+ } |
3063 |
+ default: duel_assert(0); |
3064 |
+ } |
3065 |
+ return FALSE ; |
3066 |
+#undef lev |
3067 |
+} |
3068 |
+ |
3069 |
+ |
3070 |
+ |
3071 |
+LFUNC bool duel_eval_tri(tnode *n,tvalue *v) |
3072 |
+{ |
3073 |
+#define lev n->eval.level |
3074 |
+ duel_assert(n->node_kind==NK_OP && n->op_kind==OPK_TRI); |
3075 |
+ switch(n->op) { |
3076 |
+ case OP_IF: /* if(a) b else c return eval(b) for each eval(a)!=0 |
3077 |
+ * and eval(c) for each eval(a)==0 (usu. (a) is one result*/ |
3078 |
+ if(lev>1) goto if2; |
3079 |
+ for(;;) { |
3080 |
+ if(!duel_eval(n->kids[0],v)) return FALSE ; |
3081 |
+ lev=(duel_mk_logical(v,"if(x) y else z")? 2:3) ; |
3082 |
+ if2: if(duel_eval(n->kids[lev-1],v)) return TRUE ; |
3083 |
+ } |
3084 |
+ case '?': /* a? b:c has the same semantics as if(a) b else c */ |
3085 |
+ if(lev>1) goto qm2; |
3086 |
+ for(;;) { |
3087 |
+ if(!duel_eval(n->kids[0],v)) return FALSE ; |
3088 |
+ lev=(duel_mk_logical(v,"x? y:z")? 2:3) ; |
3089 |
+ qm2: if(duel_eval(n->kids[lev-1],v)) return TRUE ; |
3090 |
+ } |
3091 |
+ default: duel_assert(0); |
3092 |
+ } |
3093 |
+ return FALSE ; |
3094 |
+#undef lev |
3095 |
+} |
3096 |
+ |
3097 |
+LFUNC bool duel_eval_quad(tnode *n,tvalue *v) |
3098 |
+{ |
3099 |
+#define lev n->eval.level |
3100 |
+ duel_assert(n->node_kind==NK_OP && n->op_kind==OPK_QUAD); |
3101 |
+ switch(n->op) { |
3102 |
+ case OP_FOR: /* for(a;b;c) d ; */ |
3103 |
+ if(lev==1) { lev=2 ; while(duel_eval(n->kids[0],v)); } |
3104 |
+ if(lev==3) goto fr3 ; |
3105 |
+ for(;;) { |
3106 |
+ while(duel_eval(n->kids[1],v)) /* check &&/b */ |
3107 |
+ if(!duel_mk_logical(v,"for(a;x;y)z")) { |
3108 |
+ stop_eval(n->kids[1]); |
3109 |
+ return FALSE ; |
3110 |
+ } |
3111 |
+ lev=3 ; |
3112 |
+ fr3: if(duel_eval(n->kids[3],v)) return TRUE ; |
3113 |
+ while(duel_eval(n->kids[2],v)); |
3114 |
+ } |
3115 |
+ default: duel_assert(0); |
3116 |
+ } |
3117 |
+ return FALSE ; |
3118 |
+#undef lev |
3119 |
+} |
3120 |
+ |
3121 |
+FUNC bool duel_eval(tnode *n,tvalue *v) |
3122 |
+{ |
3123 |
+ tvalue u,tmp ; |
3124 |
+ bool ok=FALSE ; |
3125 |
+ tnode *prev_loc ; |
3126 |
+ |
3127 |
+ if(!n) return FALSE ; |
3128 |
+ prev_loc=duel_set_eval_loc(n); /* set current eval node, save prev */ |
3129 |
+ if(n->eval.level==0) n->eval.level=1 ; /* indicate node is 'active' */ |
3130 |
+ |
3131 |
+ switch(n->node_kind) { |
3132 |
+ case NK_CONST: /* return a 'value' node made of this constant */ |
3133 |
+ if(n->eval.level==1) { |
3134 |
+ n->eval.level=2 ; |
3135 |
+ *v=n->cnst ; |
3136 |
+ ok=TRUE ; |
3137 |
+ } |
3138 |
+ break ; |
3139 |
+ case NK_NAME: |
3140 |
+ if(n->eval.level==1) { |
3141 |
+ n->eval.level=2 ; |
3142 |
+ duel_eval_name(n->name,v); |
3143 |
+ ok=TRUE ; |
3144 |
+ } |
3145 |
+ break ; |
3146 |
+ case NK_OP: |
3147 |
+ switch(n->op_kind) { |
3148 |
+ case OPK_SUNARY: /* special unary ops */ |
3149 |
+ if(n->op=='#') { |
3150 |
+ int count=0 ; |
3151 |
+ if(n->eval.level==1) { |
3152 |
+ while(duel_eval(n->kids[0],&u)) |
3153 |
+ if(count++ == 0) duel_set_symb_val(v,"#/(%s ...)",&u,0); |
3154 |
+ if(count == 0) duel_set_symb_val(v,"#/(empty)",0,0); |
3155 |
+ v->val_kind=VK_RVALUE ; |
3156 |
+ v->ctype=ctype_int ; |
3157 |
+ v->u.rval_int=count ; |
3158 |
+ n->eval.level=2 ; |
3159 |
+ ok=TRUE ; |
3160 |
+ } |
3161 |
+ } |
3162 |
+ else |
3163 |
+ if(n->op==OP_AND) { |
3164 |
+ if(n->eval.level==1) { int result=1 ; |
3165 |
+ while(duel_eval(n->kids[0],v)) { |
3166 |
+ if(!duel_mk_logical(v,"&&/x")) { |
3167 |
+ stop_eval(n->kids[0]); |
3168 |
+ result=0 ; |
3169 |
+ break ; |
3170 |
+ } |
3171 |
+ } |
3172 |
+ v->val_kind=VK_RVALUE ; |
3173 |
+ v->ctype=ctype_int ; |
3174 |
+ v->u.rval_int=result ; |
3175 |
+ sprintf(v->symb_val,"%d",result); |
3176 |
+ n->eval.level=2 ; |
3177 |
+ ok=TRUE ; |
3178 |
+ } |
3179 |
+ } |
3180 |
+ else |
3181 |
+ if(n->op==OP_OR) { |
3182 |
+ if(n->eval.level==1) { int result=0 ; |
3183 |
+ while(duel_eval(n->kids[0],v)) { |
3184 |
+ if(duel_mk_logical(v,"||/x")) { |
3185 |
+ stop_eval(n->kids[0]); |
3186 |
+ result=1 ; |
3187 |
+ break ; |
3188 |
+ } |
3189 |
+ } |
3190 |
+ v->val_kind=VK_RVALUE ; |
3191 |
+ v->ctype=ctype_int ; |
3192 |
+ v->u.rval_int=result ; |
3193 |
+ sprintf(v->symb_val,"%d",result); |
3194 |
+ n->eval.level=2 ; |
3195 |
+ ok=TRUE ; |
3196 |
+ } |
3197 |
+ } |
3198 |
+ else |
3199 |
+ if(n->op==OP_SIZ) { |
3200 |
+ if(n->eval.level==1) { |
3201 |
+ char *tname=n->kids[0]->ctype->name ; |
3202 |
+ duel_assert(n->kids[0]->node_kind==NK_CTYPE); |
3203 |
+ v->val_kind=VK_RVALUE ; |
3204 |
+ v->ctype=ctype_size_t ; |
3205 |
+ v->u.rval_size_t=n->kids[0]->ctype->size ; |
3206 |
+ n->eval.level=2 ; |
3207 |
+ if(tname==NULL || *tname=='\0') tname="T" ; /* cheating */ |
3208 |
+ sprintf(v->symb_val,"sizeof(%s)",tname); |
3209 |
+ ok=TRUE ; |
3210 |
+ } |
3211 |
+ } |
3212 |
+ else duel_assert(0); |
3213 |
+ break ; |
3214 |
+ case OPK_UNARY: |
3215 |
+ if(!duel_eval(n->kids[0],v)) break ; |
3216 |
+ duel_apply_unary_op(n->op,v); |
3217 |
+ ok=TRUE ; |
3218 |
+ break ; |
3219 |
+ case OPK_POST_UNARY: |
3220 |
+ if(!duel_eval(n->kids[0],v)) break ; |
3221 |
+ duel_apply_post_unary_op(n->op,v); |
3222 |
+ ok=TRUE ; |
3223 |
+ break ; |
3224 |
+ case OPK_BIN: /* a+b, compute and hold a, iterate on b, redo a */ |
3225 |
+ while(n->eval.level==2 || duel_eval(n->kids[0],&n->eval.v1)) { |
3226 |
+ n->eval.level=2 ; /* left side active op in vals[0] */ |
3227 |
+ while(duel_eval(n->kids[1],&u)) { |
3228 |
+ tmp= n->eval.v1 ; /* copy left val, it is destoryed*/ |
3229 |
+ ok=duel_apply_bin_op(n->op,&tmp,&u,v); |
3230 |
+ if(ok) goto done; |
3231 |
+ } |
3232 |
+ n->eval.level=1 ; /*left side val no longer valid, re-eval*/ |
3233 |
+ } |
3234 |
+ break ; |
3235 |
+ case OPK_SBIN: /* a,b etc, special ops */ |
3236 |
+ ok=duel_eval_sbin(n,v) ; |
3237 |
+ break ; |
3238 |
+ case OPK_TRI: |
3239 |
+ ok=duel_eval_tri(n,v) ; |
3240 |
+ break ; |
3241 |
+ case OPK_QUAD: |
3242 |
+ ok=duel_eval_quad(n,v) ; |
3243 |
+ break ; |
3244 |
+ case OPK_CAST: |
3245 |
+ duel_assert(n->kids[0]->node_kind==NK_CTYPE); |
3246 |
+ if(!duel_eval(n->kids[1],v)) break ; |
3247 |
+ duel_do_cast(n->kids[0]->ctype,v); |
3248 |
+ ok=TRUE ; |
3249 |
+ break ; |
3250 |
+ case OPK_ASSIGN: |
3251 |
+ duel_gen_error("modified assignment is not supported yet",0); |
3252 |
+ case OPK_FUNC: |
3253 |
+ ok=eval_func_call(n,v) ; |
3254 |
+ break ; |
3255 |
+ default: duel_assert(0); |
3256 |
+ } |
3257 |
+ break ; |
3258 |
+ default: duel_assert(0); |
3259 |
+ } |
3260 |
+done: |
3261 |
+ if(!ok) n->eval.level=0 ; /* no other val available */ |
3262 |
+ duel_set_eval_loc(prev_loc); |
3263 |
+ return ok ; |
3264 |
+} |
3265 |
+ |
3266 |
+ |
3267 |
--- gdb/duel/evalops.c |
3268 |
+++ gdb/duel/evalops.c |
3269 |
@@ -0,0 +1,1273 @@ |
3270 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
3271 |
+/* Public domain code */ |
3272 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
3273 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
3274 |
+ |
3275 |
+/* this module contains evalauation code for many standard operators, eg '+' |
3276 |
+ */ |
3277 |
+ |
3278 |
+/* |
3279 |
+ * $Log: 10_all_gdb-6.6-duel.patch,v $ |
3280 |
+ * Revision 1.1 2007/12/29 21:06:06 vapier |
3281 |
+ * add DUEL support #199987 by Sergei Golubchik |
3282 |
+ * |
3283 |
+ * Revision 1.14 93/03/19 15:40:17 mg |
3284 |
+ * fixed bug long symbolics handling |
3285 |
+ * |
3286 |
+ * Revision 1.13 93/03/12 05:50:01 mg |
3287 |
+ * uses tuint instead of uint, etc. |
3288 |
+ * |
3289 |
+ * Revision 1.12 93/02/26 05:00:13 mg |
3290 |
+ * fixed void pointers compare. ctype_voidptr is not unique! |
3291 |
+ * |
3292 |
+ * Revision 1.11 93/02/04 02:09:55 mg |
3293 |
+ * typo |
3294 |
+ * |
3295 |
+ * Revision 1.10 93/02/04 01:24:51 mg |
3296 |
+ * better error reports for "=" |
3297 |
+ * |
3298 |
+ * Revision 1.9 93/02/03 21:47:43 mg |
3299 |
+ * support "signed char" |
3300 |
+ * |
3301 |
+ * Revision 1.8 93/01/12 21:51:29 mg |
3302 |
+ * cleanup and set for release |
3303 |
+ * |
3304 |
+ * Revision 1.7 93/01/07 00:10:51 mg |
3305 |
+ * auto convert func to &func |
3306 |
+ * find a frame for a func |
3307 |
+ * |
3308 |
+ * |
3309 |
+ * Revision 1.6 93/01/03 07:30:02 mg |
3310 |
+ * function calls, error reporting, printing. |
3311 |
+ * |
3312 |
+ * Revision 1.5 92/12/24 23:34:47 mg |
3313 |
+ * frames support |
3314 |
+ * |
3315 |
+ * Revision 1.4 92/10/19 15:07:46 mg |
3316 |
+ * fvalue added (not ready yet), svalues dropped |
3317 |
+ * |
3318 |
+ * Revision 1.3 92/10/14 02:05:10 mg |
3319 |
+ * add print/{x} support |
3320 |
+ * |
3321 |
+ * Revision 1.2 92/09/15 05:48:57 mg |
3322 |
+ * support '..' new formats |
3323 |
+ * |
3324 |
+ */ |
3325 |
+ |
3326 |
+#include "duel.h" |
3327 |
+ |
3328 |
+/* |
3329 |
+ * This file is made up of three parts: |
3330 |
+ * (1) low-level functions that interact with the debugger/type system directly |
3331 |
+ * (2) mid-level functions that compute the result of simple operators like '+' |
3332 |
+ * (3) high-level functions that compute any binary/unary op. |
3333 |
+ * Only some of the functions in (1) are global, and all of the (3) are. |
3334 |
+ * this collection is in one file to allow a minimal of global symbols |
3335 |
+ * (for minimum collision with the debugger) |
3336 |
+ */ |
3337 |
+ |
3338 |
+ |
3339 |
+ |
3340 |
+/**************************************************************************** |
3341 |
+ A low-level set of functions follows. They interact with the type system |
3342 |
+ and the debugger/target's space directly: |
3343 |
+ get_storage_type_kind - retrieve ctype_kind, with special conversion for enums |
3344 |
+ get_rvalue - retrieve the rvalue of a variable/lvalue. |
3345 |
+ set_symb_val - set the symbolic value of a tvalue. |
3346 |
+ upgrade_small_int_types - figure out the type to upgrade to from char etc. |
3347 |
+ find_numeric_result_type - figure type of x+y where + is generic C op |
3348 |
+ convert_scalar_type - convert one scalar type to another |
3349 |
+ get_numeric_val - retrieve rvalue, making sure it is numeric |
3350 |
+ get_scalar_val - retrieve rvalue, making sure it is numeric or pointer |
3351 |
+ get_integral_val- retrieve rvalue, making sure it is an integer |
3352 |
+ get_int_val - retrieve rvalue, make sure it's an integer, return int val |
3353 |
+ get_pointer_val - retrieve rvalue, make sure it's a pointer. |
3354 |
+ ****************************************************************************/ |
3355 |
+ |
3356 |
+/* give the storage-type kind of a given type. |
3357 |
+ * this is the same type-kind as the type itslef, except in the case of enums |
3358 |
+ * where the type-kind of the storage will be CTK_INT etc (integral type) |
3359 |
+ * the storage type kind is set when the enum is created. |
3360 |
+ */ |
3361 |
+ |
3362 |
+LFUNC tctype_kind get_storage_type_kind(tctype *t) |
3363 |
+{ |
3364 |
+ if(t->type_kind!=CTK_ENUM) return t->type_kind ; |
3365 |
+ return t->u.e.real_type_kind ; |
3366 |
+} |
3367 |
+ |
3368 |
+/* try_get_rvalue -- make an rvalue of v. if v is already an rvalue, |
3369 |
+ * nothing is done. Else v is an b/lvalue, so its rvalue is fetched. |
3370 |
+ * special care: |
3371 |
+ * (1) Enums are fetched as int of same size. type stay enum! |
3372 |
+ * (2) Arrays and functions are made into pointers |
3373 |
+ * (3) Bitfields are converted to ints (debugger dependent) |
3374 |
+ * there are no rvalues of 'bitfield' type! |
3375 |
+ * return succ/fail for bad mem ref. the "real" function everyone calls is |
3376 |
+ * get_rvalue (this function is used only by printing functions to avoid |
3377 |
+ * chicken&egg problem of error reporting.) |
3378 |
+ */ |
3379 |
+ |
3380 |
+FUNC duel_try_get_rvalue(tvalue *v,char *op) |
3381 |
+{ |
3382 |
+ void *p ; |
3383 |
+ int n ; |
3384 |
+ bool ok; |
3385 |
+ if(v->val_kind == VK_RVALUE) return TRUE; |
3386 |
+ if(v->val_kind == VK_FVALUE) |
3387 |
+ duel_op_error("illegal type 'frame' for operand x of '%s'",op,v,0); |
3388 |
+ switch(get_storage_type_kind(v->ctype)) { |
3389 |
+ case CTK_CHAR: p= &v->u.rval_char ; n=sizeof(char) ;break ; |
3390 |
+ case CTK_SCHAR: p= &v->u.rval_schar ; n=sizeof(tschar) ;break ; |
3391 |
+ case CTK_UCHAR: p= &v->u.rval_uchar ; n=sizeof(tuchar) ;break ; |
3392 |
+ case CTK_USHORT: p= &v->u.rval_ushort ; n=sizeof(tushort) ;break ; |
3393 |
+ case CTK_SHORT: p= &v->u.rval_short ; n=sizeof(short) ;break ; |
3394 |
+ case CTK_INT: p= &v->u.rval_int ; n=sizeof(int) ;break ; |
3395 |
+ case CTK_UINT: p= &v->u.rval_uint ; n=sizeof(tuint) ;break ; |
3396 |
+ case CTK_LONG: p= &v->u.rval_long ; n=sizeof(long) ;break ; |
3397 |
+ case CTK_ULONG: p= &v->u.rval_ulong ; n=sizeof(tulong) ;break ; |
3398 |
+ case CTK_LONGLONG:p= &v->u.rval_longlong ; n=sizeof(long long) ;break ; |
3399 |
+ case CTK_ULONGLONG:p= &v->u.rval_ulonglong;n=sizeof(tulonglong) ;break ; |
3400 |
+ case CTK_FLOAT: p= &v->u.rval_float ; n=sizeof(float) ;break ; |
3401 |
+ case CTK_DOUBLE: p= &v->u.rval_double ; n=sizeof(double) ;break ; |
3402 |
+ case CTK_PTR: p= &v->u.rval_ptr ; n=sizeof(ttarget_ptr) ;break ; |
3403 |
+ case CTK_ARRAY: /* the lvalue becomes an rvalue, a real pointer! */ |
3404 |
+ duel_assert(v->val_kind==VK_LVALUE); /* duel exp rules */ |
3405 |
+ v->val_kind=VK_RVALUE ; |
3406 |
+ v->ctype=duel_mkctype_ptr(v->ctype->u.kid) ; |
3407 |
+ v->u.rval_ptr=v->u.lvalue ; |
3408 |
+ return TRUE; |
3409 |
+ case CTK_FUNC: /* makes it a pointer to a func*/ |
3410 |
+ duel_assert(v->val_kind==VK_LVALUE); /* duel exp rules */ |
3411 |
+ v->val_kind=VK_RVALUE ; |
3412 |
+ v->ctype=duel_mkctype_ptr(v->ctype) ; |
3413 |
+ v->u.rval_ptr=v->u.lvalue ; |
3414 |
+ return TRUE; |
3415 |
+ |
3416 |
+ case CTK_STRUCT: /* can't have an rval from struct? */ |
3417 |
+ case CTK_UNION: |
3418 |
+ /* enums were eliminated above */ |
3419 |
+ default: duel_assert(0); |
3420 |
+ } |
3421 |
+ if(v->val_kind == VK_BVALUE) { /* bitfield: lvalue+bitpos/len */ |
3422 |
+ tbvalue_info bv; |
3423 |
+ bv=v->u.bvalue ; |
3424 |
+ ok=duel_get_target_bitfield(bv.lvalue, bv.bitpos, bv.bitlen, p, |
3425 |
+ v->ctype->type_kind); |
3426 |
+ if(!ok) { v->u.bvalue=bv ; return FALSE ; } |
3427 |
+ } |
3428 |
+ else { |
3429 |
+ ttarget_ptr lv=v->u.lvalue ; |
3430 |
+ ok=duel_get_target_bytes(lv,p,n); /*fetch n debuggee bytes*/ |
3431 |
+ if(!ok) { v->u.lvalue=lv ; return FALSE ; } |
3432 |
+ } |
3433 |
+ |
3434 |
+ v->val_kind=VK_RVALUE ; |
3435 |
+ /* in remote debugging, one might need to swap byte order at this |
3436 |
+ * point. [remote debugging is not supported by duel v1.0] |
3437 |
+ */ |
3438 |
+ return TRUE ; |
3439 |
+} |
3440 |
+ |
3441 |
+ |
3442 |
+/* |
3443 |
+ * safe get_rvalue - produce error messages on memory access failer. |
3444 |
+ */ |
3445 |
+ |
3446 |
+LPROC get_rvalue(tvalue *v,char *op) |
3447 |
+{ |
3448 |
+ bool ok=duel_try_get_rvalue(v,op); |
3449 |
+ if(!ok) duel_op_error("illegal address for operand x of '%s'",op,v,0); |
3450 |
+} |
3451 |
+ |
3452 |
+/* put_rvalue: put the rvalue of v2 into the location in v1. |
3453 |
+ * types are assumed to be the same. |
3454 |
+ */ |
3455 |
+ |
3456 |
+LPROC put_rvalue(tvalue *v1,tvalue *v2,char *op) |
3457 |
+{ |
3458 |
+ void *p ; |
3459 |
+ int n ; |
3460 |
+ duel_assert(v1->val_kind!=VK_RVALUE); |
3461 |
+ duel_assert(v1->val_kind!=VK_FVALUE); |
3462 |
+ duel_assert(v2->val_kind==VK_RVALUE); |
3463 |
+ duel_assert(v1->ctype->size == v2->ctype->size); |
3464 |
+ switch(get_storage_type_kind(v2->ctype)) { |
3465 |
+ case CTK_CHAR: p= &v2->u.rval_char ; n=sizeof(char) ;break ; |
3466 |
+ case CTK_SCHAR: p= &v2->u.rval_schar ; n=sizeof(tschar) ;break ; |
3467 |
+ case CTK_UCHAR: p= &v2->u.rval_uchar ; n=sizeof(tuchar) ;break ; |
3468 |
+ case CTK_USHORT: p= &v2->u.rval_ushort ; n=sizeof(tushort) ;break ; |
3469 |
+ case CTK_SHORT: p= &v2->u.rval_short ; n=sizeof(short) ;break ; |
3470 |
+ case CTK_INT: p= &v2->u.rval_int ; n=sizeof(int) ;break ; |
3471 |
+ case CTK_UINT: p= &v2->u.rval_uint ; n=sizeof(tuint) ;break ; |
3472 |
+ case CTK_LONG: p= &v2->u.rval_long ; n=sizeof(long) ;break ; |
3473 |
+ case CTK_ULONG: p= &v2->u.rval_ulong ; n=sizeof(tulong) ;break ; |
3474 |
+ case CTK_LONGLONG: p= &v2->u.rval_longlong ; n=sizeof(long long);break ; |
3475 |
+ case CTK_ULONGLONG: p= &v2->u.rval_ulonglong ; n=sizeof(tulonglong);break ; |
3476 |
+ case CTK_FLOAT: p= &v2->u.rval_float ; n=sizeof(float) ;break ; |
3477 |
+ case CTK_DOUBLE: p= &v2->u.rval_double ; n=sizeof(double) ;break ; |
3478 |
+ case CTK_PTR: p= &v2->u.rval_ptr ; n=sizeof(ttarget_ptr) ;break ; |
3479 |
+ default: duel_assert(0); /* other types not supported as rvalues */ |
3480 |
+ } |
3481 |
+ if(v1->val_kind == VK_BVALUE) |
3482 |
+ duel_gen_error("assignment to bitfields is not yet supported",0); |
3483 |
+ else |
3484 |
+ if(!duel_put_target_bytes(v1->u.lvalue,p,n)) /*store n debuggee bytes*/ |
3485 |
+ duel_op_error("cant write memory for operand x of '%s'",op,v1,0); |
3486 |
+} |
3487 |
+ |
3488 |
+/* set the symbolic val for tvalue. input format is a sprintf, |
3489 |
+ * with v1,v2 being other values that show as '%s' in the format. |
3490 |
+ * v1,v2 can be zero if they are unused by the format. |
3491 |
+ */ |
3492 |
+PROC duel_set_symb_val(tvalue *r,char *format,tvalue *v1,tvalue *v2) |
3493 |
+{ |
3494 |
+ char s[3*VALUE_MAX_SYMBOLIC_SIZE]; |
3495 |
+ sprintf(s,format,v1->symb_val,v2->symb_val); |
3496 |
+ s[VALUE_MAX_SYMBOLIC_SIZE-1]=0 ; /* chop as needed */ |
3497 |
+ strcpy(r->symb_val,s); |
3498 |
+} |
3499 |
+ |
3500 |
+/* given a small int type (short,char,enum) return the upgraded (int or |
3501 |
+ * uint) type. Else return the original type |
3502 |
+ */ |
3503 |
+LFUNC tctype* upgrade_small_int_types(tctype *t) |
3504 |
+{ |
3505 |
+ switch(t->type_kind) { |
3506 |
+ case CTK_ENUM: |
3507 |
+ case CTK_CHAR: |
3508 |
+ case CTK_SCHAR: |
3509 |
+ case CTK_UCHAR: |
3510 |
+ case CTK_SHORT: |
3511 |
+ return ctype_int ; |
3512 |
+ case CTK_USHORT: |
3513 |
+ if(sizeof(tushort)==sizeof(int)) return ctype_uint ; |
3514 |
+ else return ctype_int ; |
3515 |
+ default: |
3516 |
+ return t ; |
3517 |
+ } |
3518 |
+} |
3519 |
+ |
3520 |
+/* find the type of the result of a generic numeric operation on |
3521 |
+ * v1,v2. This applies the standard C type upgrade rules. |
3522 |
+ * The type of the result is returned. |
3523 |
+ * r is setup so it can receive the result: an RVALUE of the specified |
3524 |
+ * type. Its symbolic value is also setup based on the symbolic value |
3525 |
+ * of v1 v2 and the operation op. |
3526 |
+ * Note: op is not used to figure out the numeric result, only |
3527 |
+ * the types of v1 and v2. As a side effect, the answer for x|y where |
3528 |
+ * y is a double will be given as double. it is up to the caller to |
3529 |
+ * verify that v1,v2 have meaningful types of this operation |
3530 |
+ * |
3531 |
+ */ |
3532 |
+ |
3533 |
+LFUNC tctype* find_numeric_result_type(tvalue *v1,tvalue *v2, |
3534 |
+ tvalue *r,char *op) |
3535 |
+{ |
3536 |
+ tctype *t1=upgrade_small_int_types(v1->ctype); /* upgrade to int etc */ |
3537 |
+ tctype *t2=upgrade_small_int_types(v2->ctype); |
3538 |
+ char s[80] ; |
3539 |
+ r->val_kind=VK_RVALUE ; |
3540 |
+ sprintf(s,"%%s%s%%s",op) ; /* eg, if op=">>" then s becomes "%s>>%s" */ |
3541 |
+ duel_set_symb_val(r,s,v1,v2); |
3542 |
+ |
3543 |
+ if(t1==ctype_double || t2==ctype_double) return r->ctype=ctype_double ; |
3544 |
+ if(t1==ctype_float || t2==ctype_float) return r->ctype=ctype_float ; |
3545 |
+ if(t1==ctype_ulonglong || t2==ctype_ulonglong) return r->ctype=ctype_ulonglong ; |
3546 |
+ if(t1==ctype_longlong || t2==ctype_longlong) return r->ctype=ctype_longlong ; |
3547 |
+ if(t1==ctype_ulong || t2==ctype_ulong) return r->ctype=ctype_ulong ; |
3548 |
+ if(sizeof(unsigned)==sizeof(long) && |
3549 |
+ (t1==ctype_long && t2==ctype_uint || |
3550 |
+ t1==ctype_uint && t2==ctype_long)) return r->ctype=ctype_ulong ; |
3551 |
+ if(t1==ctype_long || t2==ctype_long) return r->ctype=ctype_long ; |
3552 |
+ if(t1==ctype_uint || t2==ctype_uint) return r->ctype=ctype_uint ; |
3553 |
+ return r->ctype=ctype_int ; |
3554 |
+} |
3555 |
+ |
3556 |
+/* convert_to_fix assisting-macro: takes the val stored in v and put it |
3557 |
+ * into w. w is an lvalue with a 'fixed' type (t). |
3558 |
+ */ |
3559 |
+ |
3560 |
+#define convert_to_fix(v,w) \ |
3561 |
+ switch(get_storage_type_kind(v->ctype)) { \ |
3562 |
+ case CTK_CHAR: w (v->u.rval_char) ; break ; \ |
3563 |
+ case CTK_SCHAR: w (v->u.rval_schar) ; break ; \ |
3564 |
+ case CTK_UCHAR: w (v->u.rval_uchar) ; break ; \ |
3565 |
+ case CTK_USHORT: w (v->u.rval_ushort) ; break ; \ |
3566 |
+ case CTK_SHORT: w (v->u.rval_short) ; break ; \ |
3567 |
+ case CTK_INT: w (v->u.rval_int) ; break ; \ |
3568 |
+ case CTK_UINT: w (v->u.rval_uint) ; break ; \ |
3569 |
+ case CTK_LONG: w (v->u.rval_long) ; break ; \ |
3570 |
+ case CTK_ULONG: w (v->u.rval_ulong) ; break ; \ |
3571 |
+ case CTK_LONGLONG: w (v->u.rval_longlong) ; break ; \ |
3572 |
+ case CTK_ULONGLONG: w (v->u.rval_ulonglong) ; break ; \ |
3573 |
+ case CTK_FLOAT: w (v->u.rval_float) ; break ; \ |
3574 |
+ case CTK_DOUBLE: w (v->u.rval_double) ; break ; \ |
3575 |
+ case CTK_PTR: w (tptrsize_int) (v->u.rval_ptr) ; break ; \ |
3576 |
+ default: duel_assert(0); \ |
3577 |
+ } |
3578 |
+ |
3579 |
+ |
3580 |
+/* convert_scalar_type -- convert rvalue v to type t. |
3581 |
+ * uses convert_to_fix macro. In effect, this is a huge switch for |
3582 |
+ * all possible combinations of basic C types. |
3583 |
+ */ |
3584 |
+ |
3585 |
+LPROC convert_scalar_type(tvalue *v,tctype *t,char *op) |
3586 |
+{ |
3587 |
+ get_rvalue(v,op); |
3588 |
+ switch(get_storage_type_kind(t)) { |
3589 |
+ case CTK_CHAR: convert_to_fix(v,v->u.rval_char=(char)) ; break ; |
3590 |
+ case CTK_SCHAR: convert_to_fix(v,v->u.rval_schar=(tschar)) ; break ; |
3591 |
+ case CTK_UCHAR: convert_to_fix(v,v->u.rval_uchar=(tuchar)) ; break ; |
3592 |
+ case CTK_SHORT: convert_to_fix(v,v->u.rval_short=(short)) ; break ; |
3593 |
+ case CTK_USHORT: convert_to_fix(v,v->u.rval_ushort=(tushort)) ; break ; |
3594 |
+ case CTK_INT: convert_to_fix(v,v->u.rval_int=(int)) ; break ; |
3595 |
+ case CTK_UINT: convert_to_fix(v,v->u.rval_uint=(tuint)) ; break ; |
3596 |
+ case CTK_LONG: convert_to_fix(v,v->u.rval_long=(long)) ; break ; |
3597 |
+ case CTK_ULONG: convert_to_fix(v,v->u.rval_ulong=(tulong)) ; break ; |
3598 |
+ case CTK_LONGLONG: convert_to_fix(v,v->u.rval_longlong=(long long)) ; break ; |
3599 |
+ case CTK_ULONGLONG: convert_to_fix(v,v->u.rval_ulonglong=(tulonglong)) ; break ; |
3600 |
+ case CTK_FLOAT: convert_to_fix(v,v->u.rval_float=(float)) ; break ; |
3601 |
+ case CTK_DOUBLE: convert_to_fix(v,v->u.rval_double=(double)) ; break ; |
3602 |
+ case CTK_PTR: convert_to_fix(v, |
3603 |
+ v->u.rval_ptr=(ttarget_ptr)(tptrsize_int)) ; break ; |
3604 |
+ default: duel_assert(0); |
3605 |
+ } |
3606 |
+ v->ctype=t ; |
3607 |
+} |
3608 |
+ |
3609 |
+ |
3610 |
+/* verify v is numeric, get its rvalue converted to type tout or at least int*/ |
3611 |
+LPROC get_numeric_val(tvalue *v,char *op,tctype *tout) |
3612 |
+{ |
3613 |
+ if(!ctype_kind_numeric(v->ctype)) |
3614 |
+ duel_op_error("operand x of '%s' is not numeric",op,v,0); |
3615 |
+ if(!tout) tout=upgrade_small_int_types(v->ctype); /* upgrade to int etc */ |
3616 |
+ convert_scalar_type(v,tout,op); |
3617 |
+} |
3618 |
+ |
3619 |
+/*verify v is integral, get its rvalue converted to type tout or at least int*/ |
3620 |
+LPROC get_integral_val(tvalue *v,char *op,tctype *tout) |
3621 |
+{ |
3622 |
+ if(!ctype_kind_integral(v->ctype)) |
3623 |
+ duel_op_error("operand x of '%s' is not integral",op,v,0); |
3624 |
+ if(!tout) tout=upgrade_small_int_types(v->ctype); /* upgrade to int etc */ |
3625 |
+ convert_scalar_type(v,tout,op); |
3626 |
+} |
3627 |
+ |
3628 |
+/* verify v is integral, return its actual value as 'int' */ |
3629 |
+FUNC int duel_get_int_val(tvalue *v,char *op) |
3630 |
+{ |
3631 |
+ get_integral_val(v,op,ctype_int); |
3632 |
+ return v->u.rval_int ; |
3633 |
+} |
3634 |
+ |
3635 |
+/* verify v is numeric or pointer/array, upgrade type to at least int or ptr |
3636 |
+ and get the rvalue */ |
3637 |
+LPROC get_scalar_val(tvalue *v,char *op) |
3638 |
+{ |
3639 |
+ if(ctype_kind_ptr_like(v->ctype)) get_rvalue(v,op); |
3640 |
+ else { |
3641 |
+ tctype *t=upgrade_small_int_types(v->ctype); /* upgrade to int */ |
3642 |
+ if(!ctype_kind_numeric(v->ctype)) |
3643 |
+ duel_op_error("operand x of '%s' is not a scalar",op,v,0); |
3644 |
+ convert_scalar_type(v,t,op); |
3645 |
+ } |
3646 |
+} |
3647 |
+ |
3648 |
+LPROC get_pointer_val(tvalue *v,char *op,bool zero_ok) |
3649 |
+{ |
3650 |
+ if(ctype_kind_ptr_like(v->ctype)) get_rvalue(v,op); |
3651 |
+ else |
3652 |
+ if(zero_ok && v->ctype->type_kind==CTK_INT && |
3653 |
+ v->val_kind==VK_RVALUE && v->u.rval_int==0) { |
3654 |
+ v->ctype=ctype_voidptr ; |
3655 |
+ v->u.rval_ptr=0 ; |
3656 |
+ } |
3657 |
+ else duel_op_error("operand x of '%s' is not a pointer",op,v,0); |
3658 |
+} |
3659 |
+ |
3660 |
+/* copy one lvalue over the other. This copy is used for assignment, |
3661 |
+ * including the assignment of structures and unions. |
3662 |
+ * supports unlimited size and error reports when memory access fails. |
3663 |
+ */ |
3664 |
+ |
3665 |
+LPROC copy_lvalues(tvalue *v1,tvalue *v2,char *op) |
3666 |
+{ |
3667 |
+ size_t size ; |
3668 |
+ ttarget_ptr to=v1->u.lvalue,from=v2->u.lvalue ; |
3669 |
+ char buf[BUFSIZ] ; |
3670 |
+ duel_assert(v1->val_kind==VK_LVALUE && v2->val_kind==VK_LVALUE); |
3671 |
+ size=v1->ctype->size ; |
3672 |
+ duel_assert(v2->ctype->size==size); |
3673 |
+ while(size!=0) { |
3674 |
+ size_t chunk_size=((size>BUFSIZ)? BUFSIZ:size) ; |
3675 |
+ if(!duel_get_target_bytes(from,buf,chunk_size)) |
3676 |
+ duel_op_error("error reading memory (copy) in '%s'",op,v1,v2); |
3677 |
+ if(!duel_put_target_bytes(to,buf,chunk_size)) |
3678 |
+ duel_op_error("error writing memory (copy) in '%s'",op,v1,v2); |
3679 |
+ size-=chunk_size ; |
3680 |
+ to+=chunk_size ; |
3681 |
+ from+=chunk_size ; |
3682 |
+ } |
3683 |
+} |
3684 |
+ |
3685 |
+/* |
3686 |
+ * check that two values have "compatible" types. |
3687 |
+ * since structs compiled in different modules are each unique, |
3688 |
+ * we settle for comparing the number of references (array/ptr) |
3689 |
+ * and then make sure the same type-kind is used, with the same |
3690 |
+ * physical size. |
3691 |
+ * this allows, e.g. struct {short x,y } and struct {int x} |
3692 |
+ * to be considered equal. Possibly one could compare struct/union |
3693 |
+ * for member sizes (but not names?!). this however requires to keep |
3694 |
+ * track of self references and is not implemented here. |
3695 |
+ */ |
3696 |
+ |
3697 |
+LPROC duel_check_type_eq(tvalue *v1,tvalue *v2,char *op) |
3698 |
+{ |
3699 |
+ tctype *t1=v1->ctype, *t2=v2->ctype ; |
3700 |
+ if(ctype_kind_ptr_like(t1) && ctype_kind_ptr_like(t2) && /*(void*) match*/ |
3701 |
+ (t1->u.kid==ctype_void || t2->u.kid==ctype_void)) return; |
3702 |
+ |
3703 |
+ while(ctype_kind_ptr_like(t1) && ctype_kind_ptr_like(t2)) |
3704 |
+ t1=t1->u.kid, t2=t2->u.kid ; |
3705 |
+ if(t1==t2) return ; /* exact same type */ |
3706 |
+ if(t1->type_kind != t2->type_kind || t1->size != t2->size) |
3707 |
+ duel_op_error("incompatible types for op %s",op,v1,v2); |
3708 |
+} |
3709 |
+ |
3710 |
+ |
3711 |
+/************************************************************************** |
3712 |
+ a set of mid-level functions follow. These actually apply duel/C |
3713 |
+ operators to values |
3714 |
+ **************************************************************************/ |
3715 |
+ |
3716 |
+/* these do pointer+int addition/subtraction of v1,v2 and store result in r. |
3717 |
+ * NOTE: r's symbolic value is not set. |
3718 |
+ */ |
3719 |
+ |
3720 |
+LPROC add_offset_to_ptr(tvalue *v1,tvalue *v2,tvalue *r) |
3721 |
+{ |
3722 |
+ size_t len ; |
3723 |
+ get_pointer_val(v1,"x+y (ptr add)",FALSE); |
3724 |
+ get_integral_val(v2,"y+x (ptr add)",NULL); |
3725 |
+ r->val_kind=VK_RVALUE ; |
3726 |
+ r->ctype=v1->ctype ; |
3727 |
+ len=v1->ctype->u.kid->size ; |
3728 |
+ if(len==0) duel_op_error("unknown pointer object size for '+' op",0,v1,0); |
3729 |
+ switch(v2->ctype->type_kind) { |
3730 |
+ case CTK_INT: r->u.rval_ptr =v1->u.rval_ptr +len*v2->u.rval_int ;break ; |
3731 |
+ case CTK_UINT: r->u.rval_ptr =v1->u.rval_ptr +len*v2->u.rval_uint ;break ; |
3732 |
+ case CTK_LONG: r->u.rval_ptr =v1->u.rval_ptr +len*v2->u.rval_long ;break ; |
3733 |
+ case CTK_ULONG: r->u.rval_ptr =v1->u.rval_ptr +len*v2->u.rval_ulong;break ; |
3734 |
+ case CTK_LONGLONG: r->u.rval_ptr =v1->u.rval_ptr +len*v2->u.rval_longlong ;break ; |
3735 |
+ case CTK_ULONGLONG: r->u.rval_ptr =v1->u.rval_ptr +len*v2->u.rval_ulonglong;break ; |
3736 |
+ default: duel_assert(0); |
3737 |
+ } |
3738 |
+} |
3739 |
+ |
3740 |
+LPROC sub_offset_from_ptr(tvalue *v1,tvalue *v2,tvalue *r) |
3741 |
+{ |
3742 |
+ size_t len ; |
3743 |
+ get_pointer_val(v1,"x-y (ptr sub)",FALSE); |
3744 |
+ get_integral_val(v2,"y-x (ptr sub)",NULL); |
3745 |
+ r->val_kind=VK_RVALUE ; |
3746 |
+ r->ctype=v1->ctype ; |
3747 |
+ len=v1->ctype->u.kid->size ; |
3748 |
+ if(len==0) duel_op_error("unknown pointer object size for '-' op",0,v1,0); |
3749 |
+ switch(v2->ctype->type_kind) { |
3750 |
+ case CTK_INT: r->u.rval_ptr =v1->u.rval_ptr -len*v2->u.rval_int ;break ; |
3751 |
+ case CTK_UINT: r->u.rval_ptr =v1->u.rval_ptr -len*v2->u.rval_uint ;break ; |
3752 |
+ case CTK_LONG: r->u.rval_ptr =v1->u.rval_ptr -len*v2->u.rval_long ;break ; |
3753 |
+ case CTK_ULONG: r->u.rval_ptr =v1->u.rval_ptr -len*v2->u.rval_ulong;break ; |
3754 |
+ case CTK_LONGLONG: r->u.rval_ptr =v1->u.rval_ptr -len*v2->u.rval_longlong ;break ; |
3755 |
+ case CTK_ULONGLONG: r->u.rval_ptr =v1->u.rval_ptr -len*v2->u.rval_ulonglong;break ; |
3756 |
+ default: duel_assert(0); |
3757 |
+ } |
3758 |
+} |
3759 |
+ |
3760 |
+ |
3761 |
+/* do addition of v1,v2 and store result in r. |
3762 |
+ * NOTE: v1, v2 are destroyed! |
3763 |
+ */ |
3764 |
+LPROC do_op_add(tvalue *v1,tvalue *v2,tvalue *r) |
3765 |
+{ |
3766 |
+ tctype *t=find_numeric_result_type(v1,v2,r,"+"); |
3767 |
+ if(ctype_kind_ptr_like(v1->ctype)) { |
3768 |
+ get_integral_val(v2,"pointer+x",NULL); |
3769 |
+ add_offset_to_ptr(v1,v2,r); |
3770 |
+ return ; |
3771 |
+ } |
3772 |
+ if(ctype_kind_ptr_like(v2->ctype)) { |
3773 |
+ get_integral_val(v1,"x+pointer",NULL); |
3774 |
+ add_offset_to_ptr(v2,v1,r); |
3775 |
+ return ; |
3776 |
+ } |
3777 |
+ get_numeric_val(v1,"x+y",t); |
3778 |
+ get_numeric_val(v2,"y+x",t); |
3779 |
+ r->val_kind=VK_RVALUE ; |
3780 |
+ r->ctype=t ; |
3781 |
+ duel_set_symb_val(r,"%s+%s",v1,v2); |
3782 |
+ switch(t->type_kind) { |
3783 |
+ case CTK_INT: r->u.rval_int =v1->u.rval_int +v2->u.rval_int ;break ; |
3784 |
+ case CTK_UINT: r->u.rval_uint =v1->u.rval_uint +v2->u.rval_uint ;break ; |
3785 |
+ case CTK_LONG: r->u.rval_long =v1->u.rval_long +v2->u.rval_long ;break ; |
3786 |
+ case CTK_ULONG: r->u.rval_ulong=v1->u.rval_ulong +v2->u.rval_ulong ;break ; |
3787 |
+ case CTK_LONGLONG: r->u.rval_longlong =v1->u.rval_longlong +v2->u.rval_longlong ;break ; |
3788 |
+ case CTK_ULONGLONG: r->u.rval_ulonglong=v1->u.rval_ulonglong +v2->u.rval_ulonglong ;break ; |
3789 |
+ case CTK_FLOAT: r->u.rval_float=v1->u.rval_float +v2->u.rval_float ;break ; |
3790 |
+ case CTK_DOUBLE:r->u.rval_double=v1->u.rval_double+v2->u.rval_double;break; |
3791 |
+ default: duel_assert(0); |
3792 |
+ } |
3793 |
+} |
3794 |
+ |
3795 |
+/* do arithmeric subtraction of v1,v2 and store result in r. |
3796 |
+ * v1 and v2 should be of numeric type to begin with. |
3797 |
+ * NOTE: v1, v2 are destroyed! |
3798 |
+ */ |
3799 |
+LPROC do_op_subtract(tvalue *v1,tvalue *v2,tvalue *r) |
3800 |
+{ |
3801 |
+ tctype *t=find_numeric_result_type(v1,v2,r,"-"); |
3802 |
+ if(ctype_kind_ptr_like(v1->ctype)) { |
3803 |
+ if(ctype_kind_ptr_like(v2->ctype)) { |
3804 |
+ long len ; /* length must be signed to allow signed p-q result*/ |
3805 |
+ get_pointer_val(v1,"x-y",FALSE); |
3806 |
+ get_pointer_val(v2,"x-y",FALSE); |
3807 |
+ duel_check_type_eq(v1,v2,"- (ptr)"); |
3808 |
+ /* should compare pointer types */ |
3809 |
+ len=v1->ctype->u.kid->size ; |
3810 |
+ if(len<=0) |
3811 |
+ duel_op_error("illegal object size for op %s","- (ptr)",v1,v2); |
3812 |
+ r->ctype=ctype_ptrdiff_t ; |
3813 |
+ r->u.rval_ptrdiff_t= (v1->u.rval_ptr - v2->u.rval_ptr)/len ; |
3814 |
+ return ; |
3815 |
+ } |
3816 |
+ get_integral_val(v2,"pointer-x",NULL); |
3817 |
+ sub_offset_from_ptr(v1,v2,r); |
3818 |
+ return ; |
3819 |
+ } |
3820 |
+ get_numeric_val(v1,"x-y",t); |
3821 |
+ get_numeric_val(v2,"y-x",t); |
3822 |
+ switch(t->type_kind) { |
3823 |
+ case CTK_INT: r->u.rval_int =v1->u.rval_int - v2->u.rval_int ;break; |
3824 |
+ case CTK_UINT: r->u.rval_uint =v1->u.rval_uint - v2->u.rval_uint ;break; |
3825 |
+ case CTK_LONG: r->u.rval_long =v1->u.rval_long - v2->u.rval_long ;break; |
3826 |
+ case CTK_ULONG: r->u.rval_ulong=v1->u.rval_ulong - v2->u.rval_ulong ;break; |
3827 |
+ case CTK_LONGLONG: r->u.rval_longlong =v1->u.rval_longlong - v2->u.rval_longlong ;break; |
3828 |
+ case CTK_ULONGLONG: r->u.rval_ulonglong=v1->u.rval_ulonglong - v2->u.rval_ulonglong ;break; |
3829 |
+ case CTK_FLOAT: r->u.rval_float=v1->u.rval_float - v2->u.rval_float ;break; |
3830 |
+ case CTK_DOUBLE:r->u.rval_double=v1->u.rval_double-v2->u.rval_double;break; |
3831 |
+ default: duel_assert(0); |
3832 |
+ } |
3833 |
+} |
3834 |
+ |
3835 |
+/* compare values of v1 and v2, knowing that at least one is a frame-value |
3836 |
+ * type. Allows two fvals to be compared, or an fval to be compared |
3837 |
+ * to a func (this compares the func at the frame to the given func) |
3838 |
+ */ |
3839 |
+ |
3840 |
+LFUNC bool comp_bin_op_eq_fvals(tvalue *v1,tvalue *v2) |
3841 |
+{ |
3842 |
+ bool v1f=v1->val_kind == VK_FVALUE ; |
3843 |
+ bool v2f=v2->val_kind == VK_FVALUE ; |
3844 |
+ int frame_no ; |
3845 |
+ ttarget_ptr frame_func,p ; |
3846 |
+ if(v1f && v2f) return v1->u.fvalue == v2->u.fvalue ; /*cmp frames */ |
3847 |
+ if(v1f) { |
3848 |
+ frame_no = v1->u.fvalue ; |
3849 |
+ get_pointer_val(v2,"frame==x",FALSE) ; |
3850 |
+ if(v2->ctype->u.kid->type_kind!=CTK_FUNC) |
3851 |
+ duel_op_error("operand x of 'frame=x' not a func pointer",0,v2,0); |
3852 |
+ p=v2->u.rval_ptr ; |
3853 |
+ } |
3854 |
+ else { |
3855 |
+ frame_no = v2->u.fvalue ; |
3856 |
+ get_pointer_val(v1,"x==frame",FALSE) ; |
3857 |
+ if(v1->ctype->u.kid->type_kind!=CTK_FUNC) |
3858 |
+ duel_op_error("operand x of 'x==frame' not a func pointer",0,v1,0); |
3859 |
+ p=v1->u.rval_ptr ; |
3860 |
+ } |
3861 |
+ frame_func = duel_get_function_for_frame(frame_no); |
3862 |
+ return frame_func == p ; |
3863 |
+} |
3864 |
+ |
3865 |
+ |
3866 |
+/* compares of v1,v2 and store result in r. |
3867 |
+ * v1 and v2 should be of numeric/pointer type to begin with. |
3868 |
+ * NOTE: v1, v2 are destroyed! |
3869 |
+ */ |
3870 |
+ |
3871 |
+LPROC do_op_eq(tvalue *v1,tvalue *v2,tvalue *r) |
3872 |
+{ |
3873 |
+ tctype *t=find_numeric_result_type(v1,v2,r,"=="); |
3874 |
+ r->ctype=ctype_int ; |
3875 |
+ if(v1->val_kind==VK_FVALUE || v2->val_kind==VK_FVALUE) { |
3876 |
+ r->u.rval_int = comp_bin_op_eq_fvals(v1,v2); |
3877 |
+ return ; |
3878 |
+ } |
3879 |
+ if(ctype_kind_ptr_like(v1->ctype) || ctype_kind_ptr_like(v2->ctype)) { |
3880 |
+ get_pointer_val(v1,"x==y",TRUE); |
3881 |
+ get_pointer_val(v2,"y==x",TRUE); |
3882 |
+ duel_check_type_eq(v1,v2,"=="); |
3883 |
+ r->u.rval_int = v1->u.rval_ptr == v2->u.rval_ptr ; |
3884 |
+ return ; |
3885 |
+ } |
3886 |
+ get_numeric_val(v1,"x==y",t); |
3887 |
+ get_numeric_val(v2,"y==x",t); |
3888 |
+ switch(t->type_kind) { |
3889 |
+ case CTK_INT: r->u.rval_int=v1->u.rval_int == v2->u.rval_int ;break; |
3890 |
+ case CTK_UINT: r->u.rval_int=v1->u.rval_uint == v2->u.rval_uint ;break; |
3891 |
+ case CTK_LONG: r->u.rval_int=v1->u.rval_long == v2->u.rval_long ;break; |
3892 |
+ case CTK_ULONG: r->u.rval_int=v1->u.rval_ulong == v2->u.rval_ulong ;break; |
3893 |
+ case CTK_LONGLONG: r->u.rval_int=v1->u.rval_longlong == v2->u.rval_longlong ;break; |
3894 |
+ case CTK_ULONGLONG: r->u.rval_int=v1->u.rval_ulonglong == v2->u.rval_ulonglong ;break; |
3895 |
+ case CTK_FLOAT: r->u.rval_int=v1->u.rval_float == v2->u.rval_float ;break; |
3896 |
+ case CTK_DOUBLE:r->u.rval_int=v1->u.rval_double == v2->u.rval_double;break; |
3897 |
+ default: duel_assert(0); |
3898 |
+ } |
3899 |
+} |
3900 |
+ |
3901 |
+ |
3902 |
+/* compares of v1,v2 and store result in r. |
3903 |
+ * v1 and v2 should be of numeric/pointer type to begin with. |
3904 |
+ * NOTE: v1, v2 are destroyed! |
3905 |
+ */ |
3906 |
+#define mk_func_compare(func,op,sop,xysop,yxsop,nullok) \ |
3907 |
+LPROC func(tvalue *v1,tvalue *v2,tvalue *r) \ |
3908 |
+{ \ |
3909 |
+ tctype *t=find_numeric_result_type(v1,v2,r,sop); \ |
3910 |
+ r->ctype=ctype_int ; \ |
3911 |
+ \ |
3912 |
+ if(ctype_kind_ptr_like(v1->ctype) || ctype_kind_ptr_like(v2->ctype)) { \ |
3913 |
+ get_pointer_val(v1,xysop,nullok); \ |
3914 |
+ get_pointer_val(v2,yxsop,nullok); \ |
3915 |
+ duel_check_type_eq(v1,v2,sop); \ |
3916 |
+ r->u.rval_int = v1->u.rval_ptr op v2->u.rval_ptr ; \ |
3917 |
+ return ; \ |
3918 |
+ } \ |
3919 |
+ get_numeric_val(v1,xysop,t); \ |
3920 |
+ get_numeric_val(v2,yxsop,t); \ |
3921 |
+ switch(t->type_kind) { \ |
3922 |
+ case CTK_INT: r->u.rval_int=v1->u.rval_int op v2->u.rval_int ;break;\ |
3923 |
+ case CTK_UINT: r->u.rval_int=v1->u.rval_uint op v2->u.rval_uint ;break;\ |
3924 |
+ case CTK_LONG: r->u.rval_int=v1->u.rval_long op v2->u.rval_long ;break;\ |
3925 |
+ case CTK_ULONG: r->u.rval_int=v1->u.rval_ulong op v2->u.rval_ulong ;break;\ |
3926 |
+ case CTK_LONGLONG: r->u.rval_int=v1->u.rval_longlong op v2->u.rval_longlong ;break;\ |
3927 |
+ case CTK_ULONGLONG: r->u.rval_int=v1->u.rval_ulonglong op v2->u.rval_ulonglong ;break;\ |
3928 |
+ case CTK_FLOAT: r->u.rval_int=v1->u.rval_float op v2->u.rval_float ;break;\ |
3929 |
+ case CTK_DOUBLE:r->u.rval_int=v1->u.rval_double op v2->u.rval_double;break;\ |
3930 |
+ default: duel_assert(0); \ |
3931 |
+ } \ |
3932 |
+} |
3933 |
+ |
3934 |
+mk_func_compare(do_op_ne,!=,"!=","x!=y","y!=x",TRUE) |
3935 |
+mk_func_compare(do_op_ge,>=,">=","x>=y","y>=x",FALSE) |
3936 |
+mk_func_compare(do_op_le,<=,"<=","x<=y","y<=x",FALSE) |
3937 |
+mk_func_compare(do_op_ls,<, "<", "x<y", "y<x",FALSE) |
3938 |
+mk_func_compare(do_op_gt,>, ">", "x>y", "y>x",FALSE) |
3939 |
+#undef mk_func_compare |
3940 |
+ |
3941 |
+ |
3942 |
+/* do_compare_questionmark -- handle the <? >? etc ops */ |
3943 |
+ |
3944 |
+LFUNC bool do_compare_questionmark(topcode op,tvalue *v1,tvalue *v2,tvalue *r) |
3945 |
+{ |
3946 |
+ tvalue tmp ; |
3947 |
+ tmp= *v1 ; |
3948 |
+ switch(op) { |
3949 |
+ case OP_EQQ: do_op_eq(v1,v2,r); break ; |
3950 |
+ case OP_NEQ: do_op_ne(v1,v2,r); break ; |
3951 |
+ case OP_GEQ: do_op_ge(v1,v2,r); break ; |
3952 |
+ case OP_LEQ: do_op_le(v1,v2,r); break ; |
3953 |
+ case OP_LSQ: do_op_ls(v1,v2,r); break ; |
3954 |
+ case OP_GTQ: do_op_gt(v1,v2,r); break ; |
3955 |
+ } |
3956 |
+ if(r->u.rval_int==0) return FALSE ; |
3957 |
+ *r=tmp ; |
3958 |
+ return TRUE ; |
3959 |
+} |
3960 |
+ |
3961 |
+ |
3962 |
+ |
3963 |
+/* apply indirection of a pointer. |
3964 |
+ * this is easy, you just force the value to be an rvalue pointer, then |
3965 |
+ * make it into an lvalue with the pointed-to type. |
3966 |
+ * useful for (*x x[y] x->y etc) |
3967 |
+ * does not setup a symbolic value! |
3968 |
+ */ |
3969 |
+ |
3970 |
+ |
3971 |
+LPROC follow_pointer(tvalue *v,char *op,bool nonull) |
3972 |
+{ |
3973 |
+ get_pointer_val(v,op,FALSE); |
3974 |
+ if(nonull && v->u.rval_ptr == NULL) |
3975 |
+ duel_op_error("dereference NULL pointer x in '%s'",op,v,0); |
3976 |
+ v->val_kind=VK_LVALUE ; |
3977 |
+ v->u.lvalue=v->u.rval_ptr ; |
3978 |
+ v->ctype=v->ctype->u.kid ; |
3979 |
+} |
3980 |
+ |
3981 |
+PROC duel_get_struct_val(tvalue *v,char *op) |
3982 |
+{ |
3983 |
+ if(!ctype_kind_struct_like(v->ctype)) |
3984 |
+ duel_op_error("operand x of '%s' not a sturct/union",op,v,0); |
3985 |
+ duel_assert(v->val_kind==VK_LVALUE); |
3986 |
+} |
3987 |
+ |
3988 |
+PROC duel_get_struct_ptr_val(tvalue *v,char *op) |
3989 |
+{ |
3990 |
+ follow_pointer(v,op,FALSE); |
3991 |
+ if(!ctype_kind_struct_like(v->ctype)) |
3992 |
+ duel_op_error("operand x of '%s' not a pointer to sturct/union",op,v,0); |
3993 |
+} |
3994 |
+ |
3995 |
+FUNC int duel_get_posint_val(tvalue *v,char *op) |
3996 |
+{ |
3997 |
+ int x ; |
3998 |
+ x=duel_get_int_val(v,op); |
3999 |
+ if(x<0) duel_op_error("operand x of '%s' can not be negative",op,v,0); |
4000 |
+ return x ; |
4001 |
+} |
4002 |
+ |
4003 |
+/* indirection operator (*x) */ |
4004 |
+ |
4005 |
+LPROC do_op_indirection(tvalue *v) |
4006 |
+{ |
4007 |
+ follow_pointer(v,"*x",TRUE); |
4008 |
+ duel_set_symb_val(v,"*%s",v,0); |
4009 |
+} |
4010 |
+ |
4011 |
+/* address operator (&x) |
4012 |
+ * x must be an lvalue. it is converted into a pointer to the given type, |
4013 |
+ * an rvalue. |
4014 |
+ */ |
4015 |
+ |
4016 |
+LPROC do_op_address(tvalue *v) |
4017 |
+{ |
4018 |
+ if(v->val_kind != VK_LVALUE) |
4019 |
+ duel_op_error("operand x of '&x' is not a lvalue",0,v,0); |
4020 |
+ v->val_kind=VK_RVALUE ; |
4021 |
+ v->u.rval_ptr=v->u.lvalue ; |
4022 |
+ v->ctype=duel_mkctype_ptr(v->ctype); |
4023 |
+ duel_set_symb_val(v,"&%s",v,0); |
4024 |
+} |
4025 |
+ |
4026 |
+LPROC do_op_index(tvalue *v1,tvalue *v2,tvalue *r) |
4027 |
+{ |
4028 |
+ get_pointer_val(v1,"x[y]",FALSE); |
4029 |
+ get_integral_val(v2,"y[x]",NULL); |
4030 |
+ add_offset_to_ptr(v1,v2,r); |
4031 |
+ follow_pointer(r,"[]",TRUE); |
4032 |
+ duel_set_symb_val(r,"%s[%s]",v1,v2); |
4033 |
+} |
4034 |
+ |
4035 |
+ |
4036 |
+/* do arithmeric multiply of v1,v2 and store result in r. |
4037 |
+ * NOTE: v1, v2 are destroyed! |
4038 |
+ */ |
4039 |
+LPROC do_op_multiply(tvalue *v1,tvalue *v2,tvalue *r) |
4040 |
+{ |
4041 |
+ tctype *t=find_numeric_result_type(v1,v2,r,"*"); |
4042 |
+ get_numeric_val(v1,"x*y",t); |
4043 |
+ get_numeric_val(v2,"y*x",t); |
4044 |
+ r->val_kind=VK_RVALUE ; |
4045 |
+ r->ctype=t ; |
4046 |
+ duel_set_symb_val(r,"%s*%s",v1,v2); |
4047 |
+ switch(t->type_kind) { |
4048 |
+ case CTK_INT: r->u.rval_int =v1->u.rval_int * v2->u.rval_int ;break; |
4049 |
+ case CTK_UINT: r->u.rval_uint =v1->u.rval_uint * v2->u.rval_uint ;break; |
4050 |
+ case CTK_LONG: r->u.rval_long =v1->u.rval_long * v2->u.rval_long ;break; |
4051 |
+ case CTK_ULONG: r->u.rval_ulong =v1->u.rval_ulong * v2->u.rval_ulong;break; |
4052 |
+ case CTK_LONGLONG: r->u.rval_longlong =v1->u.rval_longlong * v2->u.rval_longlong ;break; |
4053 |
+ case CTK_ULONGLONG: r->u.rval_ulonglong =v1->u.rval_ulonglong * v2->u.rval_ulonglong;break; |
4054 |
+ case CTK_FLOAT: r->u.rval_float =v1->u.rval_float * v2->u.rval_float;break; |
4055 |
+ case CTK_DOUBLE:r->u.rval_double=v1->u.rval_double*v2->u.rval_double;break; |
4056 |
+ default: duel_assert(0); |
4057 |
+ } |
4058 |
+} |
4059 |
+ |
4060 |
+/* do numeric divide of v1,v2 and store result in r. |
4061 |
+ * v1 and v2 should be of numeric type to begin with. |
4062 |
+ * NOTE: v1, v2 are destroyed! |
4063 |
+ */ |
4064 |
+LPROC do_op_divide(tvalue *v1,tvalue *v2,tvalue *r) |
4065 |
+{ |
4066 |
+ tctype *t=find_numeric_result_type(v1,v2,r,"/"); |
4067 |
+ get_numeric_val(v1,"x/y",t); |
4068 |
+ get_numeric_val(v2,"y/x",t); |
4069 |
+ switch(t->type_kind) { |
4070 |
+ case CTK_INT: if(v2->u.rval_int==0) goto div_err; |
4071 |
+ r->u.rval_int =v1->u.rval_int / v2->u.rval_int ;break; |
4072 |
+ case CTK_UINT: if(v2->u.rval_uint==0) goto div_err; |
4073 |
+ r->u.rval_uint =v1->u.rval_uint / v2->u.rval_uint ;break; |
4074 |
+ case CTK_LONG: if(v2->u.rval_long==0) goto div_err; |
4075 |
+ r->u.rval_long =v1->u.rval_long / v2->u.rval_long ;break; |
4076 |
+ case CTK_ULONG: if(v2->u.rval_ulong==0) goto div_err; |
4077 |
+ r->u.rval_ulong =v1->u.rval_ulong/ v2->u.rval_ulong ;break; |
4078 |
+ case CTK_LONGLONG: if(v2->u.rval_longlong==0) goto div_err; |
4079 |
+ r->u.rval_longlong =v1->u.rval_longlong / v2->u.rval_longlong ;break; |
4080 |
+ case CTK_ULONGLONG: if(v2->u.rval_ulonglong==0) goto div_err; |
4081 |
+ r->u.rval_ulonglong =v1->u.rval_ulonglong/ v2->u.rval_ulonglong ;break; |
4082 |
+ case CTK_FLOAT: if(v2->u.rval_float==0.0) goto div_err; |
4083 |
+ r->u.rval_float =v1->u.rval_float/ v2->u.rval_float ;break; |
4084 |
+ case CTK_DOUBLE:if(v2->u.rval_double==0.0) goto div_err; |
4085 |
+ r->u.rval_double=v1->u.rval_double/v2->u.rval_double;break; |
4086 |
+ default: duel_assert(0); |
4087 |
+ } |
4088 |
+ return ; |
4089 |
+div_err: duel_op_error("division by zero",0,v1,v2); |
4090 |
+} |
4091 |
+ |
4092 |
+ |
4093 |
+/* do arithmeric reminder of v1,v2 and store result in r. |
4094 |
+ * NOTE: v1, v2 are destroyed! |
4095 |
+ */ |
4096 |
+LPROC do_op_reminder(tvalue *v1,tvalue *v2,tvalue *r) |
4097 |
+{ |
4098 |
+ tctype *t=find_numeric_result_type(v1,v2,r,"%"); |
4099 |
+ get_integral_val(v1,"x%y",t); |
4100 |
+ get_integral_val(v2,"y%x",t); |
4101 |
+ switch(t->type_kind) { |
4102 |
+ case CTK_INT: if(v2->u.rval_int==0) goto div_err; |
4103 |
+ r->u.rval_int = v1->u.rval_int % v2->u.rval_int ; break ; |
4104 |
+ case CTK_UINT: if(v2->u.rval_uint==0) goto div_err; |
4105 |
+ r->u.rval_uint = v1->u.rval_uint % v2->u.rval_uint ; break ; |
4106 |
+ case CTK_LONG: if(v2->u.rval_long==0) goto div_err; |
4107 |
+ r->u.rval_long = v1->u.rval_long % v2->u.rval_long ; break ; |
4108 |
+ case CTK_ULONG: if(v2->u.rval_ulong==0) goto div_err; |
4109 |
+ r->u.rval_ulong = v1->u.rval_ulong % v2->u.rval_ulong ; break ; |
4110 |
+ case CTK_LONGLONG: if(v2->u.rval_longlong==0) goto div_err; |
4111 |
+ r->u.rval_longlong = v1->u.rval_longlong % v2->u.rval_longlong ; break ; |
4112 |
+ case CTK_ULONGLONG: if(v2->u.rval_ulonglong==0) goto div_err; |
4113 |
+ r->u.rval_ulonglong = v1->u.rval_ulonglong % v2->u.rval_ulonglong ; break ; |
4114 |
+ default: duel_assert(0); |
4115 |
+ } |
4116 |
+ return ; |
4117 |
+div_err: duel_op_error("reminder modulo zero",0,v1,v2); |
4118 |
+} |
4119 |
+ |
4120 |
+/* do arithmeric or (bitwise) of v1,v2 and store result in r. |
4121 |
+ * NOTE: v1, v2 are destroyed! |
4122 |
+ */ |
4123 |
+LPROC do_op_or(tvalue *v1,tvalue *v2,tvalue *r) |
4124 |
+{ |
4125 |
+ tctype *t=find_numeric_result_type(v1,v2,r,"|"); |
4126 |
+ get_integral_val(v1,"x|y",t); |
4127 |
+ get_integral_val(v2,"y|x",t); |
4128 |
+ switch(t->type_kind) { |
4129 |
+ case CTK_INT: r->u.rval_int = v1->u.rval_int | v2->u.rval_int ; break; |
4130 |
+ case CTK_UINT: r->u.rval_uint = v1->u.rval_uint | v2->u.rval_uint ; break; |
4131 |
+ case CTK_LONG: r->u.rval_long = v1->u.rval_long | v2->u.rval_long ; break; |
4132 |
+ case CTK_ULONG:r->u.rval_ulong= v1->u.rval_ulong | v2->u.rval_ulong; break; |
4133 |
+ case CTK_LONGLONG: r->u.rval_longlong = v1->u.rval_longlong | v2->u.rval_longlong ; break; |
4134 |
+ case CTK_ULONGLONG:r->u.rval_ulonglong= v1->u.rval_ulonglong | v2->u.rval_ulonglong; break; |
4135 |
+ default: duel_assert(0); |
4136 |
+ } |
4137 |
+ return ; |
4138 |
+} |
4139 |
+ |
4140 |
+/* do arithmeric and (bitwise) of v1,v2 and store result in r. |
4141 |
+ * NOTE: v1, v2 are destroyed! |
4142 |
+ */ |
4143 |
+LPROC do_op_and(tvalue *v1,tvalue *v2,tvalue *r) |
4144 |
+{ |
4145 |
+ tctype *t=find_numeric_result_type(v1,v2,r,"&"); |
4146 |
+ get_integral_val(v1,"x&y",t); |
4147 |
+ get_integral_val(v2,"y&x",t); |
4148 |
+ switch(t->type_kind) { |
4149 |
+ case CTK_INT: r->u.rval_int = v1->u.rval_int & v2->u.rval_int ; break; |
4150 |
+ case CTK_UINT: r->u.rval_uint = v1->u.rval_uint & v2->u.rval_uint ; break; |
4151 |
+ case CTK_LONG: r->u.rval_long = v1->u.rval_long & v2->u.rval_long ; break; |
4152 |
+ case CTK_ULONG:r->u.rval_ulong= v1->u.rval_ulong & v2->u.rval_ulong; break; |
4153 |
+ case CTK_LONGLONG: r->u.rval_longlong = v1->u.rval_longlong & v2->u.rval_longlong ; break; |
4154 |
+ case CTK_ULONGLONG:r->u.rval_ulonglong= v1->u.rval_ulonglong & v2->u.rval_ulonglong; break; |
4155 |
+ default: duel_assert(0); |
4156 |
+ } |
4157 |
+} |
4158 |
+ |
4159 |
+/* do arithmeric xor (bitwise) of v1,v2 and store result in r. |
4160 |
+ * NOTE: v1, v2 are destroyed! |
4161 |
+ */ |
4162 |
+LPROC do_op_xor(tvalue *v1,tvalue *v2,tvalue *r) |
4163 |
+{ |
4164 |
+ |
4165 |
+ tctype *t=find_numeric_result_type(v1,v2,r,"^"); |
4166 |
+ get_integral_val(v1,"x^y",t); |
4167 |
+ get_integral_val(v2,"y^x",t); |
4168 |
+ switch(t->type_kind) { |
4169 |
+ case CTK_INT: r->u.rval_int = v1->u.rval_int ^ v2->u.rval_int ; break ; |
4170 |
+ case CTK_UINT: r->u.rval_uint = v1->u.rval_uint ^ v2->u.rval_uint ; break ; |
4171 |
+ case CTK_LONG: r->u.rval_long = v1->u.rval_long ^ v2->u.rval_long ; break ; |
4172 |
+ case CTK_ULONG:r->u.rval_ulong= v1->u.rval_ulong^ v2->u.rval_ulong; break ; |
4173 |
+ case CTK_LONGLONG: r->u.rval_longlong = v1->u.rval_longlong ^ v2->u.rval_longlong ; break ; |
4174 |
+ case CTK_ULONGLONG:r->u.rval_ulonglong= v1->u.rval_ulonglong ^ v2->u.rval_ulonglong; break ; |
4175 |
+ default: duel_assert(0); |
4176 |
+ } |
4177 |
+ return ; |
4178 |
+} |
4179 |
+ |
4180 |
+/* do arithmeric leftshift of v1,v2 and store result in r. |
4181 |
+ * v1 and v2 should be of numeric type to begin with. |
4182 |
+ * NOTE: v1, v2 are destroyed! |
4183 |
+ */ |
4184 |
+LPROC do_op_leftshift(tvalue *v1,tvalue *v2,tvalue *r) |
4185 |
+{ |
4186 |
+ int by; |
4187 |
+ get_integral_val(v1,"x<<y",NULL); |
4188 |
+ by=duel_get_int_val(v2,"y<<x"); |
4189 |
+ r->val_kind=VK_RVALUE ; |
4190 |
+ r->ctype=v1->ctype ; |
4191 |
+ duel_set_symb_val(r,"%s<<%s",v1,v2); |
4192 |
+ switch(v1->ctype->type_kind) { |
4193 |
+ case CTK_INT: r->u.rval_int = v1->u.rval_int << by ; break ; |
4194 |
+ case CTK_UINT: r->u.rval_uint = v1->u.rval_uint << by ; break ; |
4195 |
+ case CTK_LONG: r->u.rval_long = v1->u.rval_long << by ; break ; |
4196 |
+ case CTK_ULONG: r->u.rval_ulong = v1->u.rval_ulong << by ; break ; |
4197 |
+ case CTK_LONGLONG: r->u.rval_longlong = v1->u.rval_longlong << by ; break ; |
4198 |
+ case CTK_ULONGLONG: r->u.rval_ulonglong = v1->u.rval_ulonglong << by ; break ; |
4199 |
+ default: duel_assert(0); |
4200 |
+ } |
4201 |
+} |
4202 |
+ |
4203 |
+/* do arithmeric rightshift of v1,v2 and store result in r. |
4204 |
+ * v1 and v2 should be of numeric type to begin with. |
4205 |
+ * NOTE: v1, v2 are destroyed! |
4206 |
+ */ |
4207 |
+LPROC do_op_rightshift(tvalue *v1,tvalue *v2,tvalue *r) |
4208 |
+{ |
4209 |
+ int by ; |
4210 |
+ get_integral_val(v1,"x>>y",NULL); |
4211 |
+ by=duel_get_int_val(v2,"y>>x"); |
4212 |
+ r->val_kind=VK_RVALUE ; |
4213 |
+ r->ctype=v1->ctype ; |
4214 |
+ duel_set_symb_val(r,"%s>>%s",v1,v2); |
4215 |
+ switch(v1->ctype->type_kind) { |
4216 |
+ case CTK_INT: r->u.rval_int = v1->u.rval_int >> by ; break ; |
4217 |
+ case CTK_UINT: r->u.rval_uint = v1->u.rval_uint >> by ; break ; |
4218 |
+ case CTK_LONG: r->u.rval_long = v1->u.rval_long >> by ; break ; |
4219 |
+ case CTK_ULONG: r->u.rval_ulong = v1->u.rval_ulong >> by ; break ; |
4220 |
+ case CTK_LONGLONG: r->u.rval_longlong = v1->u.rval_longlong >> by ; break ; |
4221 |
+ case CTK_ULONGLONG: r->u.rval_ulonglong = v1->u.rval_ulonglong >> by ; break ; |
4222 |
+ default: duel_assert(0); |
4223 |
+ } |
4224 |
+} |
4225 |
+ |
4226 |
+/* do arithmeric not of v (!v) */ |
4227 |
+LPROC do_op_not(tvalue *v) |
4228 |
+{ |
4229 |
+ get_scalar_val(v,"!x"); |
4230 |
+ duel_set_symb_val(v,"!%s",v,0); |
4231 |
+ switch(v->ctype->type_kind) { |
4232 |
+ case CTK_PTR: v->u.rval_int = ! v->u.rval_ptr ; break ; |
4233 |
+ case CTK_INT: v->u.rval_int = ! v->u.rval_int ; break ; |
4234 |
+ case CTK_UINT: v->u.rval_int = ! v->u.rval_uint ; break ; |
4235 |
+ case CTK_LONG: v->u.rval_int = ! v->u.rval_long ; break ; |
4236 |
+ case CTK_ULONG: v->u.rval_int = ! v->u.rval_ulong ; break ; |
4237 |
+ case CTK_LONGLONG: v->u.rval_int = ! v->u.rval_longlong ; break ; |
4238 |
+ case CTK_ULONGLONG: v->u.rval_int = ! v->u.rval_ulonglong ; break ; |
4239 |
+ case CTK_FLOAT: v->u.rval_int = ! v->u.rval_float ; break ; |
4240 |
+ case CTK_DOUBLE: v->u.rval_int = ! v->u.rval_double ; break ; |
4241 |
+ default: duel_assert(0); |
4242 |
+ } |
4243 |
+ v->ctype=ctype_int ; /* always returns an int */ |
4244 |
+} |
4245 |
+ |
4246 |
+/* do bit-complement of v (~v) */ |
4247 |
+LPROC do_op_complement(tvalue *v) |
4248 |
+{ |
4249 |
+ get_integral_val(v,"~x",NULL); |
4250 |
+ duel_set_symb_val(v,"~%s",v,0); |
4251 |
+ switch(v->ctype->type_kind) { |
4252 |
+ case CTK_INT: v->u.rval_int = ~ v->u.rval_int ; break ; |
4253 |
+ case CTK_UINT: v->u.rval_uint = ~ v->u.rval_uint ; break ; |
4254 |
+ case CTK_LONG: v->u.rval_long = ~ v->u.rval_long ; break ; |
4255 |
+ case CTK_ULONG: v->u.rval_ulong = ~ v->u.rval_ulong ; break ; |
4256 |
+ case CTK_LONGLONG: v->u.rval_longlong = ~ v->u.rval_longlong ; break ; |
4257 |
+ case CTK_ULONGLONG: v->u.rval_ulonglong = ~ v->u.rval_ulonglong ; break ; |
4258 |
+ default: duel_assert(0); |
4259 |
+ } |
4260 |
+} |
4261 |
+ |
4262 |
+ /* do arithmeric minus of v (-v) */ |
4263 |
+LPROC do_op_minus(tvalue *v) |
4264 |
+{ |
4265 |
+ get_numeric_val(v,"-x",NULL); |
4266 |
+ duel_set_symb_val(v,"-%s",v,0); |
4267 |
+ switch(v->ctype->type_kind) { |
4268 |
+ case CTK_INT: v->u.rval_int = - v->u.rval_int ; break ; |
4269 |
+ case CTK_UINT: v->u.rval_uint = - v->u.rval_uint ; break ; |
4270 |
+ case CTK_LONG: v->u.rval_long = - v->u.rval_long ; break ; |
4271 |
+ case CTK_ULONG: v->u.rval_ulong = - v->u.rval_ulong ; break ; |
4272 |
+ case CTK_LONGLONG: v->u.rval_longlong = - v->u.rval_longlong ; break ; |
4273 |
+ case CTK_ULONGLONG: v->u.rval_ulonglong = - v->u.rval_ulonglong ; break ; |
4274 |
+ case CTK_FLOAT: v->u.rval_float = - v->u.rval_float ; break ; |
4275 |
+ case CTK_DOUBLE: v->u.rval_double= - v->u.rval_double ; break ; |
4276 |
+ default: duel_assert(0); |
4277 |
+ } |
4278 |
+} |
4279 |
+ |
4280 |
+/* do sizeif(exp) - simply return the size of the exp's type */ |
4281 |
+LPROC do_op_sizeofexp(tvalue *v) |
4282 |
+{ |
4283 |
+ v->val_kind=VK_RVALUE ; |
4284 |
+ v->u.rval_size_t=v->ctype->size ; |
4285 |
+ v->ctype=ctype_size_t ; |
4286 |
+ duel_set_symb_val(v,"sizeof(%s)",v,0); |
4287 |
+} |
4288 |
+ |
4289 |
+LPROC do_op_assignment(tvalue *v1,tvalue *v2,tvalue *r,char *op) |
4290 |
+{ |
4291 |
+ char xopy[10],yopx[10] ; |
4292 |
+ sprintf(xopy,"x%sy",op); |
4293 |
+ sprintf(yopx,"y%sx",op); |
4294 |
+ if(v1->val_kind!=VK_LVALUE && v1->val_kind!=VK_BVALUE) |
4295 |
+ duel_op_error("operand x is not an lvalue for operator '%s'",xopy,v1,0); |
4296 |
+ |
4297 |
+ if(ctype_kind_struct_like(v1->ctype)) { |
4298 |
+ duel_check_type_eq(v1,v2,xopy); |
4299 |
+ copy_lvalues(v1,v2,xopy); |
4300 |
+ *r= *v2 ; /* return the result as an lvalue. this means (x1=x2)=x3 |
4301 |
+ is legal for struct, unlike ansi-c. */ |
4302 |
+ return ; |
4303 |
+ } |
4304 |
+ if(ctype_kind_numeric(v1->ctype)) get_numeric_val(v2,yopx,v1->ctype); |
4305 |
+ else |
4306 |
+ if(v1->ctype->type_kind==CTK_PTR) { |
4307 |
+ get_pointer_val(v2,yopx,TRUE); |
4308 |
+ duel_check_type_eq(v1,v2,xopy); |
4309 |
+ } |
4310 |
+ else duel_op_error("bad operand x type for operator '%s'",xopy,v1,0); |
4311 |
+ put_rvalue(v1,v2,xopy); |
4312 |
+ *r= *v2 ; |
4313 |
+} |
4314 |
+ |
4315 |
+LPROC do_op_increment(tvalue *v,char *op,int inc,bool postfix) |
4316 |
+{ |
4317 |
+ tvalue lvalue_v,oldv ; |
4318 |
+ char s[80] ; |
4319 |
+ if(v->val_kind!=VK_LVALUE) |
4320 |
+ duel_op_error("operand of '%s' must be an lvalue",op,v,0); |
4321 |
+ lvalue_v= *v ; |
4322 |
+ if(v->ctype->type_kind==CTK_PTR) get_pointer_val(v,op,FALSE); |
4323 |
+ else get_integral_val(v,op,0); |
4324 |
+ oldv= *v ; |
4325 |
+ |
4326 |
+ switch(v->ctype->type_kind) { |
4327 |
+ case CTK_INT: v->u.rval_int += inc ; break ; |
4328 |
+ case CTK_UINT: v->u.rval_uint += inc ; break ; |
4329 |
+ case CTK_LONG: v->u.rval_long += inc ; break ; |
4330 |
+ case CTK_ULONG: v->u.rval_ulong += inc ; break ; |
4331 |
+ case CTK_LONGLONG: v->u.rval_longlong += inc ; break ; |
4332 |
+ case CTK_ULONGLONG: v->u.rval_ulonglong += inc ; break ; |
4333 |
+ case CTK_PTR: v->u.rval_ptr += inc*v->ctype->u.kid->size ; break; |
4334 |
+ default: duel_assert(0); |
4335 |
+ } |
4336 |
+ convert_scalar_type(v,lvalue_v.ctype,op); /* back to the original type */ |
4337 |
+ put_rvalue(&lvalue_v,v,op); |
4338 |
+ if(postfix) { /* if prefix, keep v and its sym val*/ |
4339 |
+ *v= oldv ; |
4340 |
+ convert_scalar_type(v,lvalue_v.ctype,op); /* back to original type */ |
4341 |
+ sprintf(s,"%%s%s",op); |
4342 |
+ duel_set_symb_val(v,s,v,0); |
4343 |
+ } |
4344 |
+} |
4345 |
+ |
4346 |
+/* unary op 'frame(n)' converts int n to a "frame type" */ |
4347 |
+LPROC do_op_frame(tvalue *v) |
4348 |
+{ |
4349 |
+ int f=duel_get_int_val(v,"frame(x)"); |
4350 |
+ if(f<0 || f>=duel_get_frames_number()) |
4351 |
+ duel_gen_error("Frame number too big",0); |
4352 |
+ v->val_kind=VK_FVALUE ; |
4353 |
+ v->ctype=ctype_int ; |
4354 |
+ v->u.fvalue=f ; |
4355 |
+ duel_set_symb_val(v,"frame(%s)",v,0); |
4356 |
+} |
4357 |
+ |
4358 |
+/* unary op '(x)'. this only add parenthesis to the symbolic value, if needed*/ |
4359 |
+ |
4360 |
+LPROC do_op_parenthesis(tvalue *v) |
4361 |
+{ |
4362 |
+ char *s=v->symb_val ; |
4363 |
+ int l=strlen(s); |
4364 |
+ if(s[0]=='(' && s[l-1]==')') return ; /* val is (x) dont make it ((x)) */ |
4365 |
+ while(*s!=0 && (isalnum(*s) || *s=='_')) s++ ; /* find first non alnum*/ |
4366 |
+ if(*s==0) return ; /* no need for (x) if x is a name or constant number */ |
4367 |
+ duel_set_symb_val(v,"(%s)",v,0); |
4368 |
+} |
4369 |
+ |
4370 |
+/*********************************************************************** |
4371 |
+ High-level functions, major entries to this module, evaluate a node |
4372 |
+ with a standard (single value) result |
4373 |
+ ***********************************************************************/ |
4374 |
+ |
4375 |
+ |
4376 |
+/* standardize a paramater to a function call according to the standard rules. |
4377 |
+ * we currently don't support union/struct paramater passing |
4378 |
+ */ |
4379 |
+ |
4380 |
+PROC duel_standardize_func_parm(tvalue *p) |
4381 |
+{ |
4382 |
+ /* convert paramater into "standard" function calling */ |
4383 |
+ if(ctype_kind_integral(p->ctype)) get_integral_val(p,"f()",NULL); |
4384 |
+ else |
4385 |
+ if(ctype_kind_numeric(p->ctype)) /* float, double to double */ |
4386 |
+ convert_scalar_type(p,ctype_double,"f()"); |
4387 |
+ else |
4388 |
+ if(ctype_kind_ptr_like(p->ctype)) get_pointer_val(p,"f()",FALSE); |
4389 |
+ else |
4390 |
+ duel_op_error("unsupported paramater type",0,p,0); |
4391 |
+} |
4392 |
+ |
4393 |
+ |
4394 |
+/* given a function (or pointer), find the first (top-most) frame that |
4395 |
+ * the function is active in, and return the FVALUE for it |
4396 |
+ */ |
4397 |
+PROC duel_find_func_frame(tvalue *v,char *op) |
4398 |
+{ |
4399 |
+ int i, frames_no=duel_get_frames_number(); |
4400 |
+ get_pointer_val(v,op,FALSE); |
4401 |
+ |
4402 |
+ for(i=0 ; i<frames_no ; i++) { |
4403 |
+ ttarget_ptr frame_func = duel_get_function_for_frame(i); |
4404 |
+ if(frame_func==v->u.rval_ptr) { |
4405 |
+ v->val_kind=VK_FVALUE ; |
4406 |
+ v->ctype=ctype_int ; |
4407 |
+ v->u.rval_int=i ; |
4408 |
+ return ; |
4409 |
+ } |
4410 |
+ } |
4411 |
+ duel_op_error("func x is not on the call stack for operator '%s'",op,v,0); |
4412 |
+} |
4413 |
+ |
4414 |
+ |
4415 |
+/* compute the n'th result of v1..v2 operator. |
4416 |
+ * result is returned in r, returns false if there isnt an nth result |
4417 |
+ * v1,v2 are converted to integer values (but can be used to call this |
4418 |
+ * function again. errors are reported if they arenot integral. |
4419 |
+ */ |
4420 |
+ |
4421 |
+FUNC bool duel_do_op_to(tvalue *v1,tvalue *v2,int n,tvalue *r) |
4422 |
+{ |
4423 |
+ int a,b,inc,x ; |
4424 |
+ char *p,*fmt ; |
4425 |
+ |
4426 |
+ if(!v1) { a=0 ; b=duel_get_int_val(v2,"..x")-1 ; } |
4427 |
+ else if(!v2) { a=duel_get_int_val(v1,"x.."); b=INT_MAX ; } |
4428 |
+ else { a=duel_get_int_val(v1,"x..y"); b=duel_get_int_val(v2,"x..y"); } |
4429 |
+ if(a<=b) inc=1 ; |
4430 |
+ else inc= -1 ; |
4431 |
+ x=a+n*inc ; |
4432 |
+ if(inc>0 && x>b || inc<0 && x<b) return FALSE ; |
4433 |
+ |
4434 |
+ r->val_kind=VK_RVALUE ; |
4435 |
+ r->ctype=ctype_int ; |
4436 |
+ r->u.rval_int=x ; |
4437 |
+ if(v1) p=v1->symb_val ; |
4438 |
+ else p=v2->symb_val ; |
4439 |
+ if( *p=='0' && p[1]=='x' || p[1]=='X') fmt="0x%x" ; |
4440 |
+ else if(*p=='0' && p[1]>='0' && p[1]<='7') fmt="0%o" ; |
4441 |
+ else if(*p=='\'' && isascii(x) && isprint(x)) fmt="'%c'" ; |
4442 |
+ else fmt="%d" ; |
4443 |
+ sprintf(r->symb_val,fmt,x); |
4444 |
+ return TRUE ; |
4445 |
+} |
4446 |
+ |
4447 |
+/* convert value to True/False and return it |
4448 |
+ * in case of an illegal operand, indicateds the operator is (op) |
4449 |
+ * main use: in operators '&&' '||' and 'if' |
4450 |
+ */ |
4451 |
+ |
4452 |
+FUNC bool duel_mk_logical(tvalue *v,char *op) |
4453 |
+{ |
4454 |
+ get_scalar_val(v,op); /* verify v is scalar */ |
4455 |
+ do_op_not(v); /* convert and force 0 or 1 */ |
4456 |
+ v->u.rval_int = !v->u.rval_int ; |
4457 |
+ sprintf(v->symb_val,"%d",v->u.rval_int); |
4458 |
+ return(v->u.rval_int); |
4459 |
+} |
4460 |
+ |
4461 |
+/* cast the value v into type t. */ |
4462 |
+ |
4463 |
+PROC duel_do_cast(tctype *tout,tvalue *v) |
4464 |
+{ |
4465 |
+ tctype *t=v->ctype ; |
4466 |
+ if(ctype_kind_scalar(t) && ctype_kind_scalar(tout)) { |
4467 |
+ if(tout->type_kind==CTK_ARRAY) |
4468 |
+ duel_gen_error("casting to an array type is illegal",0); |
4469 |
+ else convert_scalar_type(v,tout,"(cast) x"); |
4470 |
+ } |
4471 |
+ else duel_op_error("illegal type conversion in cast op",0,v,0); |
4472 |
+} |
4473 |
+ |
4474 |
+ |
4475 |
+/* apply unary oprand op to the given value. The original value is |
4476 |
+ * destoryed (of course) |
4477 |
+ */ |
4478 |
+ |
4479 |
+PROC duel_apply_unary_op(topcode op,tvalue *v) |
4480 |
+{ |
4481 |
+ switch(op) { |
4482 |
+ case '(': do_op_parenthesis(v); break ; |
4483 |
+ case '{': duel_sprint_scalar_value(v->symb_val,v);break ; |
4484 |
+ case '-': do_op_minus(v); break ; |
4485 |
+ case '!': do_op_not(v); break ; |
4486 |
+ case '*': do_op_indirection(v); break ; |
4487 |
+ case '~': do_op_complement(v); break ; |
4488 |
+ case '&': do_op_address(v); break ; |
4489 |
+ case OP_SIZ: do_op_sizeofexp(v); break ; |
4490 |
+ case OP_INC: do_op_increment(v,"++",1,FALSE); break ; |
4491 |
+ case OP_DEC: do_op_increment(v,"--",-1,FALSE); break ; |
4492 |
+ case OP_FRAME: do_op_frame(v); break ; |
4493 |
+ default: duel_assert(0); |
4494 |
+ } |
4495 |
+} |
4496 |
+ |
4497 |
+PROC duel_apply_post_unary_op(topcode op,tvalue *v) |
4498 |
+{ |
4499 |
+ switch(op) { |
4500 |
+ case OP_INC: do_op_increment(v,"++",1,TRUE); break ; |
4501 |
+ case OP_DEC: do_op_increment(v,"--",-1,TRUE); break ; |
4502 |
+ default: duel_assert(0); |
4503 |
+ } |
4504 |
+} |
4505 |
+ |
4506 |
+ |
4507 |
+/* apply_bin_op -- apply the operator op to the values v1 v2 and return |
4508 |
+ * the result in r. the bin op is a 'regular' one, like |
4509 |
+ * '+', '*', etc. in the C language. |
4510 |
+ * note: v1,v2 are destroyed |
4511 |
+ * returns: true if a value has been produced, false otherwise. |
4512 |
+ * (ops like '+' always return true. ops like '<=?' also return false) |
4513 |
+ */ |
4514 |
+ |
4515 |
+FUNC bool duel_apply_bin_op(topcode op,tvalue *v1,tvalue *v2,tvalue *r) |
4516 |
+{ |
4517 |
+ switch(op) { |
4518 |
+ case '[': do_op_index(v1,v2,r); break ; |
4519 |
+ case '+': do_op_add(v1,v2,r); break ; |
4520 |
+ case '-': do_op_subtract(v1,v2,r); break ; |
4521 |
+ case '*': do_op_multiply(v1,v2,r); break ; |
4522 |
+ case '/': do_op_divide(v1,v2,r); break ; |
4523 |
+ case '%': do_op_reminder(v1,v2,r); break ; |
4524 |
+ case '|': do_op_or(v1,v2,r); break; |
4525 |
+ case '&': do_op_and(v1,v2,r); break ; |
4526 |
+ case '^': do_op_xor(v1,v2,r); break ; |
4527 |
+ case OP_LSH: do_op_leftshift(v1,v2,r); break ; |
4528 |
+ case OP_RSH: do_op_rightshift(v1,v2,r); break ; |
4529 |
+ case OP_EQ: do_op_eq(v1,v2,r); break ; |
4530 |
+ case OP_NE: do_op_ne(v1,v2,r); break ; |
4531 |
+ case OP_GE: do_op_ge(v1,v2,r); break ; |
4532 |
+ case OP_LE: do_op_le(v1,v2,r); break ; |
4533 |
+ case '<': do_op_ls(v1,v2,r); break ; |
4534 |
+ case '>': do_op_gt(v1,v2,r); break ; |
4535 |
+ case OP_EQQ: |
4536 |
+ case OP_NEQ: |
4537 |
+ case OP_GEQ: |
4538 |
+ case OP_LEQ: |
4539 |
+ case OP_LSQ: |
4540 |
+ case OP_GTQ: return do_compare_questionmark(op,v1,v2,r); |
4541 |
+ case '=': do_op_assignment(v1,v2,r,"="); break ; |
4542 |
+ default: duel_assert(0); |
4543 |
+ } |
4544 |
+ return TRUE ; |
4545 |
+} |
4546 |
--- gdb/duel/global.h |
4547 |
+++ gdb/duel/global.h |
4548 |
@@ -0,0 +1,450 @@ |
4549 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
4550 |
+/* Public domain code */ |
4551 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
4552 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
4553 |
+ |
4554 |
+/* this include file contains global definitions for duel. All global info |
4555 |
+ * is shared thru this single file. |
4556 |
+ */ |
4557 |
+ |
4558 |
+/* |
4559 |
+ * $Log: 10_all_gdb-6.6-duel.patch,v $ |
4560 |
+ * Revision 1.1 2007/12/29 21:06:06 vapier |
4561 |
+ * add DUEL support #199987 by Sergei Golubchik |
4562 |
+ * |
4563 |
+ * Revision 1.12 93/03/12 05:50:35 mg |
4564 |
+ * uses tuint instead of uint, etc. |
4565 |
+ * |
4566 |
+ * Revision 1.11 93/02/27 06:03:26 mg |
4567 |
+ * added HP9000 support by not defining uint etc |
4568 |
+ * clean annoying enum {x,y,} warnings |
4569 |
+ * |
4570 |
+ * Revision 1.10 93/02/03 21:49:32 mg |
4571 |
+ * support "signed char" |
4572 |
+ * |
4573 |
+ * Revision 1.9 93/01/12 21:52:11 mg |
4574 |
+ * cleanup and set for release |
4575 |
+ * |
4576 |
+ * Revision 1.8 93/01/07 00:10:53 mg |
4577 |
+ * macros for func ptr auto-convert |
4578 |
+ * |
4579 |
+ * Revision 1.7 93/01/03 07:30:23 mg |
4580 |
+ * *** empty log message *** |
4581 |
+ * |
4582 |
+ * Revision 1.6 92/12/24 23:49:25 mg |
4583 |
+ * *** empty log message *** |
4584 |
+ * |
4585 |
+ * Revision 1.5 92/10/19 15:07:58 mg |
4586 |
+ * fvalue added (not ready yet), svalues dropped |
4587 |
+ * |
4588 |
+ * Revision 1.4 92/10/14 02:05:37 mg |
4589 |
+ * misc |
4590 |
+ * |
4591 |
+ * Revision 1.3 92/09/16 11:11:54 mg |
4592 |
+ * add builtin ctype_charptr |
4593 |
+ * |
4594 |
+ * Revision 1.2 92/09/15 05:47:49 mg |
4595 |
+ * some ops added |
4596 |
+ * |
4597 |
+ */ |
4598 |
+ |
4599 |
+ |
4600 |
+/* The following definitions are common programming tricks that I use |
4601 |
+ * in every program I write. I hope they are obvious. the FUNC/PROC |
4602 |
+ * constants are useful mainly when editing (to find a function def.) |
4603 |
+ * or when grep'ing on source files. DEF is set to "extern" by default, |
4604 |
+ * allowing declaration and definition of globals in one source. only |
4605 |
+ * duel.c should have #define DEF before including duel.h |
4606 |
+ */ |
4607 |
+ |
4608 |
+#define FUNC |
4609 |
+#define PROC void |
4610 |
+#define LPROC static void |
4611 |
+#define LFUNC static |
4612 |
+ |
4613 |
+#ifndef DEF |
4614 |
+#define DEF extern /* declare only, 'int x' become 'extern int x'*/ |
4615 |
+#endif |
4616 |
+ |
4617 |
+/* use simpler names for unsigned types, very common, |
4618 |
+ * too common, indeed, so I forced 't' as a prefix. |
4619 |
+ */ |
4620 |
+ |
4621 |
+typedef unsigned int tuint ; |
4622 |
+typedef unsigned char tuchar ; |
4623 |
+typedef unsigned short tushort ; |
4624 |
+typedef unsigned long tulong ; |
4625 |
+typedef unsigned long long tulonglong ; |
4626 |
+ |
4627 |
+typedef signed char tschar ; /* explicit signed char */ |
4628 |
+typedef int bool ; /* suppose to be just 0,1 */ |
4629 |
+#define FALSE 0 |
4630 |
+#define TRUE 1 |
4631 |
+ |
4632 |
+ /* these should be inline functions, they replace common lib func which |
4633 |
+ * change from system to system. |
4634 |
+ * duel_assert can be modified to call duel_fatal, so gdb itself isn't |
4635 |
+ * aborted because on an internal duel error. |
4636 |
+ */ |
4637 |
+ |
4638 |
+#define duel_assert(x) assert(x) |
4639 |
+#define duel_bzero(x,y) memset(x,0,y) |
4640 |
+#define duel_bcopy(x,y,s) memcpy(x,y,s) |
4641 |
+ |
4642 |
+ |
4643 |
+ |
4644 |
+/************* |
4645 |
+ Parsing: the expression is converted into a tree. |
4646 |
+ Each node of this tree is of 'tnode' type. |
4647 |
+ Nodes can be: |
4648 |
+ An operator (like '+', or ':=' or 'for') |
4649 |
+ A constant (numbers. Strings are pointers to space!) |
4650 |
+ A symbol. |
4651 |
+ A regular expression (really a symbol extention) |
4652 |
+ |
4653 |
+ The evaluation of any node results in: |
4654 |
+ 1. 'Environment': duel variables and their values |
4655 |
+ 2. symbolic expression which describe the computation |
4656 |
+ meaning: keep the parentethis. in the expression a<<(3+b) (even if not needed!) |
4657 |
+ 3. A type & value |
4658 |
+ |
4659 |
+ Values: |
4660 |
+ Values are always a fixed length area of bytes; Any C type is like that. |
4661 |
+**************/ |
4662 |
+ |
4663 |
+ |
4664 |
+/****** TYPES ******* |
4665 |
+ A type is described in the typical compiler's way, which is also gdb's |
4666 |
+ way. That is, a type is made of 'atomic' types, like 'pointer to', |
4667 |
+ 'array of', etc. Each atomic type is described by a 'ctype' node. Ctype |
4668 |
+ node points to other ctype nodes as required. For example, a ctype node |
4669 |
+ of 'array of' will point to the node 'int' for the 'C' type array of int. |
4670 |
+ [The name ctype is used to indicate the C language type; 'type' is too |
4671 |
+ generic a term] |
4672 |
+ Example: |
4673 |
+ char *(*f[])() ; |
4674 |
+ Here, f is an array of pointers to functions returning a pointer to char. |
4675 |
+ The type is described with the top node being of CTK_ARRAY type. It |
4676 |
+ points to a 'CTK_PTR' node, which points to a 'CTK_FUNC' node which |
4677 |
+ points to a 'CTK_PTR' node which points to a 'CTK_CHAR' node which has, |
4678 |
+ as size, 1. |
4679 |
+ |
4680 |
+ The size of a type is the number of bytes occupied by it. it is zero |
4681 |
+ for types like 'function'. An array of 10 integers will have as size |
4682 |
+ 10*sizeof(int) |
4683 |
+ |
4684 |
+ A note on UCHAR vs CHAR vs SCHAR: |
4685 |
+ Internally, duel supports all three forums (for aritmetic). |
4686 |
+ For output, only "char" types are considered ASCII, and will be displayed |
4687 |
+ as 'A' instead of "65", etc. The same is true for char[] and char*. |
4688 |
+ GDB doesn't really support "signed char", but some compilers do; |
4689 |
+ we convert "signed char" into just a "char" when the default char is signed. |
4690 |
+ This is only significant for output. |
4691 |
+ Maybe duel shouldn't support "char" at all, and force everything to be |
4692 |
+ "schar" or "uchar". I'm not sure. I prefer "char" as a distinct type |
4693 |
+ which implies "string" and uchar/schar as "integral". |
4694 |
+ ********************/ |
4695 |
+ |
4696 |
+typedef enum { /* 'C' Type atomic primitive Kinds (CTK_) */ |
4697 |
+ CTK_VOID, /* void type 'void' */ |
4698 |
+ CTK_CHAR, /* primitive types */ |
4699 |
+ CTK_SCHAR, /* signed char (ansi c) */ |
4700 |
+ CTK_UCHAR, /* note order is used in some macros */ |
4701 |
+ CTK_SHORT, |
4702 |
+ CTK_USHORT, |
4703 |
+ CTK_INT, |
4704 |
+ CTK_UINT, |
4705 |
+ CTK_LONG, |
4706 |
+ CTK_ULONG, |
4707 |
+ CTK_LONGLONG, |
4708 |
+ CTK_ULONGLONG, |
4709 |
+ CTK_FLOAT, |
4710 |
+ CTK_DOUBLE, |
4711 |
+ CTK_PTR, /* pointer '*' */ |
4712 |
+ CTK_ARRAY, /* array '[]' */ |
4713 |
+ CTK_FUNC, /* a function '()' */ |
4714 |
+ CTK_STRUCT, /* a sturcture 'struct{}' */ |
4715 |
+ CTK_UNION, /* a union 'union{}' */ |
4716 |
+ CTK_ENUM /* enum type 'enum{}' */ |
4717 |
+ } tctype_kind ; |
4718 |
+ |
4719 |
+typedef struct { /* a field (of struct) info */ |
4720 |
+ char *name ; /* field name */ |
4721 |
+ struct sctype *ctype ; /* field type */ |
4722 |
+ int bitpos, bitlen ; /* for bit fields only */ |
4723 |
+} tctype_field ; |
4724 |
+ |
4725 |
+typedef struct { /* an enumerator (constant of an enum) info */ |
4726 |
+ char *name ; /* enumerator name */ |
4727 |
+ int val ; /* value assigned to the name */ |
4728 |
+ /* question: ansi-C say cosnt fit in int?*/ |
4729 |
+} tctype_enumerator ; |
4730 |
+ |
4731 |
+ |
4732 |
+typedef struct sctype { /* a 'C' type description */ |
4733 |
+ tctype_kind type_kind ; |
4734 |
+ char *name ; /* named of this type, if any */ |
4735 |
+ size_t size ; /* size (total bytes) for this type */ |
4736 |
+ union { |
4737 |
+ struct sctype *kid ; /* pointer to next atomic type */ |
4738 |
+ struct { |
4739 |
+ int fields_no ; |
4740 |
+ tctype_field *fields ; /* union/struct fields */ |
4741 |
+ } f ; |
4742 |
+ struct { |
4743 |
+ tctype_kind real_type_kind ; /* the type used for storage of the enum */ |
4744 |
+ int enumerators_no ; |
4745 |
+ tctype_enumerator *enumerators ; /* enum's type enumerators list */ |
4746 |
+ } e; |
4747 |
+ } u ; |
4748 |
+ } tctype ; |
4749 |
+ |
4750 |
+ |
4751 |
+/**** BASIC C TYPES |
4752 |
+ these are initialized at run type to point to the basic C types. |
4753 |
+ basic types are never created again, e.g. pointer comparison with |
4754 |
+ these is sufficient to check type equality. |
4755 |
+ the voidptr is (void*) which is a basic type (what zero is converted |
4756 |
+ to when it is a pointer). |
4757 |
+ ptrdiff_t and size_t are actually pointing to their actualy types, |
4758 |
+ ie. normally point to ctype_int. |
4759 |
+ ****/ |
4760 |
+ |
4761 |
+DEF tctype *ctype_int, *ctype_uint, *ctype_short, *ctype_ushort, |
4762 |
+ *ctype_char, *ctype_schar, *ctype_uchar, |
4763 |
+ *ctype_long, *ctype_ulong, *ctype_longlong, *ctype_ulonglong, |
4764 |
+ *ctype_float, *ctype_double, |
4765 |
+ *ctype_void, *ctype_charptr, |
4766 |
+ *ctype_voidptr,*ctype_ptrdiff_t,*ctype_size_t ; |
4767 |
+ |
4768 |
+/* type checking macros */ |
4769 |
+ |
4770 |
+/** tell if type is a struct or union */ |
4771 |
+#define ctype_kind_struct_like(t) ((t)->type_kind==CTK_STRUCT || \ |
4772 |
+ (t)->type_kind==CTK_UNION) |
4773 |
+ |
4774 |
+/** tell if type is a pointer or can be made one (array, func) */ |
4775 |
+#define ctype_kind_ptr_like(t) ((t)->type_kind==CTK_PTR || \ |
4776 |
+ (t)->type_kind==CTK_ARRAY || (t)->type_kind==CTK_FUNC) |
4777 |
+/* tell if type is numeric */ |
4778 |
+#define ctype_kind_numeric(t) (((t)->type_kind>=CTK_CHAR && \ |
4779 |
+ (t)->type_kind<=CTK_DOUBLE) || (t)->type_kind==CTK_ENUM) |
4780 |
+ |
4781 |
+/* tell if type is integral */ |
4782 |
+#define ctype_kind_integral(t) ((t)->type_kind>=CTK_CHAR && \ |
4783 |
+ (t)->type_kind<=CTK_ULONG || (t)->type_kind==CTK_ENUM) |
4784 |
+ |
4785 |
+/* tell if type fits into fixed memory size (void not included) */ |
4786 |
+#define ctype_kind_scalar(t) (ctype_kind_numeric(t) || ctype_kind_ptr_like(t)) |
4787 |
+ |
4788 |
+/* tell if type is a "base" ie can't have kids */ |
4789 |
+ |
4790 |
+#define ctype_kind_base(t) ((t)->type_kind>=CTK_VOID && \ |
4791 |
+ (t)->type_kind<=CTK_DOUBLE) |
4792 |
+ |
4793 |
+/* tell if a type is a function pointer or like a func ptr (ie a func!) */ |
4794 |
+#define ctype_kind_func_ptr_like(t) ((t)->type_kind==CTK_FUNC || \ |
4795 |
+ (t)->type_kind==CTK_PTR && t->u.kid->type_kind==CTK_FUNC) |
4796 |
+ |
4797 |
+ |
4798 |
+/***** VALUES |
4799 |
+ used to keep information when evaluating an expression. A value is |
4800 |
+ either: |
4801 |
+ 1) a right-value, which is represented in a fixed number of bytes that |
4802 |
+ actually contain its value. Example: result of '+' operation. |
4803 |
+ 2) a left-value. This is a reference to the actual value, which |
4804 |
+ resides in the debuggee's address space. |
4805 |
+ 3) a special-value. This contains a long value specifying a special |
4806 |
+ target location (e.g. register) from which values can be fetched |
4807 |
+ or written to. However, special-values can not be manipulated (i.e |
4808 |
+ have an offset added to them, as done to an lvalue struct). |
4809 |
+ |
4810 |
+ Note that the operation '*x' starts with x as an lvalue - a pointer to |
4811 |
+ x is kept. Then, '*x' is executed, fetching the value of x and creating |
4812 |
+ another lvalue, which points to where x has pointed to! This allows |
4813 |
+ &*x to be executed, as well as *x=1 or &x[1] ... |
4814 |
+ When the value of an lvalue is actually needed, it must be fetched |
4815 |
+ from the debugge's space. |
4816 |
+ *****/ |
4817 |
+ |
4818 |
+#define VALUE_MAX_CONST_SIZE 8 |
4819 |
+#define VALUE_MAX_SYMBOLIC_SIZE 128 |
4820 |
+ |
4821 |
+typedef long tptrsize_int ; /* type so that |
4822 |
+ tptrsize x; char *p ; |
4823 |
+ p == (char*) (tptrsize) p |
4824 |
+ */ |
4825 |
+ |
4826 |
+ /* type that represent a target address space location. */ |
4827 |
+ |
4828 |
+typedef char* ttarget_ptr ; /* pointer to target's address */ |
4829 |
+ |
4830 |
+typedef struct { |
4831 |
+ ttarget_ptr lvalue ; /* pointer to target's location of struct*/ |
4832 |
+ int bitpos,bitlen ; /* as specified in the field info of stuct*/ |
4833 |
+ } tbvalue_info ; |
4834 |
+ |
4835 |
+typedef enum { |
4836 |
+ VK_RVALUE, /* this value represent a constant, in the rval_ union */ |
4837 |
+ VK_LVALUE, /* this value represent a left-value. address in lvalue*/ |
4838 |
+ VK_BVALUE, /* a bit-field lvalue, given as point and bitpos/bitlen*/ |
4839 |
+ VK_FVALUE /* a frame, fvalue contains it number */ |
4840 |
+ } tval_kind ; |
4841 |
+ |
4842 |
+typedef struct { |
4843 |
+ tval_kind val_kind ; |
4844 |
+ tctype *ctype ; /* type of this value */ |
4845 |
+ union { |
4846 |
+ ttarget_ptr lvalue ; /* location in target of the value */ |
4847 |
+ tbvalue_info bvalue ; /* location in target of a bitfield */ |
4848 |
+ int fvalue ; /* a frame number (0 = top of stack) */ |
4849 |
+ char rval_char ; |
4850 |
+ tschar rval_schar ; |
4851 |
+ tuchar rval_uchar ; |
4852 |
+ short rval_short ; |
4853 |
+ tushort rval_ushort ; |
4854 |
+ int rval_int ; |
4855 |
+ tuint rval_uint ; |
4856 |
+ long rval_long ; |
4857 |
+ tulong rval_ulong ; |
4858 |
+ long long rval_longlong ; |
4859 |
+ tulonglong rval_ulonglong ; |
4860 |
+ float rval_float ; |
4861 |
+ double rval_double ; |
4862 |
+ ttarget_ptr rval_ptr ; |
4863 |
+ ptrdiff_t rval_ptrdiff_t ; /* Synonyms to one of the above fields! */ |
4864 |
+ size_t rval_size_t ; /* normally these are simply = rval_int */ |
4865 |
+ } u ; |
4866 |
+ char symb_val[VALUE_MAX_SYMBOLIC_SIZE]; |
4867 |
+ } tvalue ; |
4868 |
+ |
4869 |
+ |
4870 |
+typedef struct sval_lcell { /* a cell on a linked-list containing a tvalue*/ |
4871 |
+ tvalue val ; |
4872 |
+ struct sval_lcell *next ; |
4873 |
+ } tval_lcell ; |
4874 |
+ |
4875 |
+typedef struct { /* a linked list of tvalue's */ |
4876 |
+ tval_lcell *head ; |
4877 |
+ tval_lcell *tail ; |
4878 |
+} tval_list ; |
4879 |
+ |
4880 |
+/**** OP CODES **** |
4881 |
+ Opcodes are divided into groups, or 'kinds'. For example, all the |
4882 |
+ C regular unary operators, binary operators, etc. |
4883 |
+ An opcode is defined by its 'kind' and actual value. The value is, |
4884 |
+ in most cases, a single char. For example, the C plus operator is |
4885 |
+ defined as op_kind=OPK_BIN and op='+'. The C operator '+=' is |
4886 |
+ defined as op_kind=OPK_ASSIGN and op='+'. |
4887 |
+ some operators are uniquely identified by type alone (e.g. func call). |
4888 |
+ In the lexer there is a table of actual operators as tokens, and |
4889 |
+ the kind & value assigned to each. |
4890 |
+ Several opertors use more than one char, and are defined below. |
4891 |
+ the OPK_SBIN, etc kinds are special in the sense that A op B isn't |
4892 |
+ computed in the normal way of the C language (i.e. compute both sides, |
4893 |
+ then apply the operator). Such operators include ',' '&&', etc. |
4894 |
+ **********/ |
4895 |
+typedef enum { |
4896 |
+ /* '+' '-' etc are used directly and have their ascii value */ |
4897 |
+ OP_LSH = 300, /* '<<' */ |
4898 |
+ OP_RSH = 301, /* '>>' */ |
4899 |
+ OP_INC = 302, /* '++' */ |
4900 |
+ OP_DEC = 303, /* '--' */ |
4901 |
+ OP_ARR = 304, /* '->' */ |
4902 |
+ OP_AND = 305, /* '&&' */ |
4903 |
+ OP_OR = 306, /* '||' */ |
4904 |
+ OP_EQ = 307, /* '==' */ |
4905 |
+ OP_GE = 308, /* '>=' */ |
4906 |
+ OP_LE = 309, /* '<=' */ |
4907 |
+ OP_NE = 310, /* '!=' */ |
4908 |
+ OP_SIZ = 311, /* 'sizeof' */ |
4909 |
+ OP_TO = 312, /* '..' */ |
4910 |
+ OP_EQQ = 313, /* '==?' */ |
4911 |
+ OP_NEQ = 314, /* '!=?' */ |
4912 |
+ OP_GEQ = 315, /* '>=?' */ |
4913 |
+ OP_LEQ = 316, /* '<=?' */ |
4914 |
+ OP_GTQ = 317, /* '>?' */ |
4915 |
+ OP_LSQ = 318, /* '<?' */ |
4916 |
+ OP_IMP = 319, /* '=>' */ |
4917 |
+ OP_IF = 320, /* if() */ |
4918 |
+ OP_DEF = 321, /* ':=' */ |
4919 |
+ OP_DFS = 322, /* '-->' */ |
4920 |
+ OP_BFS = 323, /* '->>' */ |
4921 |
+ OP_POS = 324, /* '>--' */ |
4922 |
+ OP_IOS = 325, /* '->-' */ |
4923 |
+ OP_SEL = 326, /*'x[[y]]'*/ |
4924 |
+ OP_FOR = 327, /*for(;;)'*/ |
4925 |
+ OP_WHILE= 328, /*while() */ |
4926 |
+ OP_DECL = 329, /* var decl*/ |
4927 |
+ OP_FRAME= 330 /* frame(i)*/ |
4928 |
+ } topcode ; |
4929 |
+ |
4930 |
+/**** OPCODE KINDS ****/ |
4931 |
+ |
4932 |
+typedef enum { /* the kind of the opcode, 'OPK_' = OPcode Kind */ |
4933 |
+ OPK_UNARY =0, /* regular unary operator */ |
4934 |
+ OPK_SUNARY =1, /* special unary operator (sizeof) */ |
4935 |
+ OPK_POST_UNARY =2, /* post unary operator (x++ etc) */ |
4936 |
+ OPK_BIN =3, /* regular binary operator */ |
4937 |
+ OPK_SBIN =4, /* special binary operator */ |
4938 |
+ OPK_TRI =5, /* trinary (eg ?:) operator */ |
4939 |
+ OPK_QUAD =6, /* quad (e.g.for(;;)) operator */ |
4940 |
+ OPK_ASSIGN =7, /* assignment ie =, +=, -= etc */ |
4941 |
+ OPK_FUNC =8, /* function call. 2nd kid made of ',' kids for parms */ |
4942 |
+ OPK_CAST =9, /* type cast. 2nd kid convert to type in 1st kid */ |
4943 |
+ OPK_NUM_OF =10 /* number of OPK_* op kinds */ |
4944 |
+ } top_kind ; |
4945 |
+ |
4946 |
+ |
4947 |
+/**** NODE KINDS ****/ |
4948 |
+ |
4949 |
+typedef enum { /* the kind of node */ |
4950 |
+ NK_OP, /* contain an operator */ |
4951 |
+ NK_CONST, /* contains a constant */ |
4952 |
+ NK_NAME, /* contains a name/symbol */ |
4953 |
+ NK_CTYPE /* contain a 'C' type */ |
4954 |
+ } tnode_kind ; |
4955 |
+ |
4956 |
+#define NODE_MAX_KIDS 4 /* maximum no of kids per node */ |
4957 |
+#define NODE_MAX_SYM_LEN 50 /* maximum length for a symbol */ |
4958 |
+ |
4959 |
+/* the following structure is used to store one node of the expression tree. |
4960 |
+ * It contains two parts: (a) information to describe the node and (b) |
4961 |
+ * information used during the evaluation of the node. |
4962 |
+ * |
4963 |
+ * This structure could/should be optimized with ugly unions (e.g., for |
4964 |
+ * a node describing a constant(node_kind==NK_CONST) there is no need for |
4965 |
+ * the op, kids or any eval stuff!). However, only few nodes (less than 100?) |
4966 |
+ * are expected to be in memory at any time (how complex can a user |
4967 |
+ * expression be?). Hence, for clarity, no unions where used. |
4968 |
+ * |
4969 |
+ * All nodes have kids in the typical way. the opcode OPK_FUNC node is tricky: |
4970 |
+ * see parsing - the commas are handled as operators and not as part of the |
4971 |
+ * syntax. when a func call is evaluated, the top comma nodes are used to |
4972 |
+ * separate the arguments (this hack prevents complex parsing and complex tnode |
4973 |
+ * with variable num of kids, which would force the kids[] to be malloc etc.) |
4974 |
+ */ |
4975 |
+ |
4976 |
+typedef struct snode { /* a single node on an expression tree */ |
4977 |
+ tnode_kind node_kind ; /* what kind of note this is */ |
4978 |
+ /* NK_OP node info: op_kind,op,kids */ |
4979 |
+ int src_pos ; /* starting source code location (op etc) */ |
4980 |
+ top_kind op_kind ; /* opcode type (unary,bin etc) */ |
4981 |
+ topcode op ; /* actual opcode: '-' for both unary&bin '-'*/ |
4982 |
+ struct snode *kids[NODE_MAX_KIDS] ; /* pointers to node's kids */ |
4983 |
+ tvalue cnst ; /* NK_CONST info - constant value */ |
4984 |
+ char *name ; /* NK_NAME info - variable name */ |
4985 |
+ tctype *ctype ; /* NK_CTYPE info - a type */ |
4986 |
+ |
4987 |
+ struct { /* information used during node evaluation */ |
4988 |
+ int level ; /* evaluation level (0=none, 1=left in x etc)*/ |
4989 |
+ tvalue v1,v2 ; /* keep last computed operands, etc */ |
4990 |
+ tval_list vlist ; /* value list for node (used in --> etc ops) */ |
4991 |
+ int counter ; /* used for counting */ |
4992 |
+ } eval ; |
4993 |
+ } tnode ; |
4994 |
+ |
4995 |
+ |
4996 |
+DEF bool duel_debug ; /* debugging duel-itself mode */ |
4997 |
+DEF bool duel_output_pipe_style ; /* pipe-style output of values */ |
4998 |
+ |
4999 |
+/* this things are machine dependent stuff */ |
5000 |
+ |
5001 |
+#define BITS_PER_BYTE 8 /* no of bits in (char) (right. try '9' :-) */ |
5002 |
--- gdb/duel/internals.doc |
5003 |
+++ gdb/duel/internals.doc |
5004 |
@@ -0,0 +1,129 @@ |
5005 |
+DUEL 1.0x INTERNALS |
5006 |
+This documents some of the basics internal info, and might help porting |
5007 |
+duel. Incomplete and probably badly written. sorry. |
5008 |
+ |
5009 |
+Entry points and modules |
5010 |
+-------------------------- |
5011 |
+duel_eval_and_parse is entry point into duel, in duel.c |
5012 |
+duel_parse in parse.y does all parsing |
5013 |
+duel_eval in eval.c makes the evaluation |
5014 |
+evalop.c contains low-level evaluation |
5015 |
+misc.c contains misc stuff |
5016 |
+types.c type create/manage |
5017 |
+output.c all output goes thru duel_printf |
5018 |
+output2.c same as output, but support sending eval output to a pipe, |
5019 |
+ like the duel.pipe perl script. |
5020 |
+print.c all output of values is done here |
5021 |
+eval.c high level evaluation code (generators) |
5022 |
+evalops.c low level evaluation code (operators) |
5023 |
+error.c handle erros, display error info "nicely" |
5024 |
+ |
5025 |
+start reading the code from duel.c, then global.h, then eval.c. |
5026 |
+eval.c is hairy, especially the state-keeping code. The goto's are |
5027 |
+intentional, they convey control better than other constructs. |
5028 |
+ |
5029 |
+Types |
5030 |
+------ |
5031 |
+A relatively straight-forward system, if you have read code of real C |
5032 |
+compilers. A type is a "graph" with each node being a base type or |
5033 |
+a composition of other types. see global.h and types.c |
5034 |
+ |
5035 |
+Value system |
5036 |
+------------- |
5037 |
+also pretty simple, either an LVALUE, which have u.lvalue point to it, |
5038 |
+or an RVALUE, so u.rval_type contains the actual value. There is also |
5039 |
+a special BVALUE hack to hold lvalued bitfields, which is only useful |
5040 |
+is someone implements modifying a bitfield. and there is an FVALUE, which |
5041 |
+is just stored in u.rval_int but has the special value type (it was either |
5042 |
+this or add a new TYPE, i preferred a new value). |
5043 |
+Note the there is no "register" type support. You must read register variables |
5044 |
+as rvalues (duelgdb.c does that). I don't think it is essential, since |
5045 |
+gdb can be used directly to modify such values (this might be a |
5046 |
+problem in watchpoint/cond.breaks however). Also cc -g don't usually keep |
5047 |
+stuff in registers. We could add "SVALUE" for these. |
5048 |
+Bitfields are a pain, but bvalue is really needed, eg for x[..100].bitfield=0 |
5049 |
+ |
5050 |
+Memory allocation |
5051 |
+----------------- |
5052 |
+go through duel_malloc/duel_free. |
5053 |
+Memory is allocated only for (a) a new node, while parsing, (b) a value pushed |
5054 |
+on stack for x-->y operator (c) duel aliases. |
5055 |
+It is always safe to call duel_free_nodes which free everything except |
5056 |
+for aliases. |
5057 |
+Memory spill can occur in asynchronous interrupts (^C), but they at most |
5058 |
+reflect items moved from one list to another. This isn't too bad. |
5059 |
+ |
5060 |
+Interrupts |
5061 |
+---------- |
5062 |
+Duel ignores the issues of interrupts, but is written so it can be |
5063 |
+interrupted at any time. Naturally, some memory could be lost if an |
5064 |
+operation is interrupted, since Duel does not setup critical sections. |
5065 |
+However, interrupts will no result in bad internal structures, so it is |
5066 |
+safe to call duel_free_nodes after an interrupt. |
5067 |
+duelgdb.c implements exactly that - interrupts at all times, and cleanup |
5068 |
+using duel_free_nodes. |
5069 |
+ |
5070 |
+Parsing |
5071 |
+-------- |
5072 |
+yacc is pretty weak, especially when I tried complex ops like x\y#z |
5073 |
+(as a single, 3 val op!). I have up on such things and the syntax is |
5074 |
+pretty clean. Things to watch for are the semicolon nonsense, |
5075 |
+especially with optional-expressions (as in for(a;b;c);), the T hack |
5076 |
+for user types (only fix is to delay decision on (x)(y) till runtime |
5077 |
+or make clearer rules (consider something; (x)(y), do you parse x as a type |
5078 |
+and ignore the possible x:=printf in "something", etc), and the use of "," |
5079 |
+regular op and nodes for function parameters (the parser knows only about |
5080 |
+a single parameter, an exp!). |
5081 |
+ |
5082 |
+Search ops |
5083 |
+----------- |
5084 |
+Straight forward stacking in dfs_... in eval.c |
5085 |
+Note things are put in reversed, so root-->(left,right) does what you |
5086 |
+expect. Also linked-lists could be greatly optimized. |
5087 |
+The functionality for ->> (BFS) is already in, all you need is to |
5088 |
+make the stack into a queue by pushing from the other side (really append) |
5089 |
+ |
5090 |
+Multi-expressions |
5091 |
+-------------------- |
5092 |
+As far as I know, you could save root (in duel.h) and use it to evaluate |
5093 |
+as often as needed (e.g for breakpoints/watchpoints), the internals |
5094 |
+of the nodes hold all eval info. You must reset the expression |
5095 |
+with eval_stop, if u dont eval it to the last value. Also make sure you |
5096 |
+cleanup the dot stack. Aliases (in misc.c) could become scoped, of course. |
5097 |
+ |
5098 |
+Interface to the debugger |
5099 |
+------------------------- |
5100 |
+ |
5101 |
+What DUEL needs: |
5102 |
+1. A way to access the symbol table for variable names, types, etc. |
5103 |
+2. A way to access the value of a variable, both for read and writes. |
5104 |
+3. A way to call debuggee functions. |
5105 |
+4. A way to get locals of frame n |
5106 |
+5. misc functions, eg memory alloc, entery/exit code |
5107 |
+ |
5108 |
+In practice, you will probably take duelgdb.c and modify it until you |
5109 |
+get the "right thing" for your debugger. |
5110 |
+NOTE: duelgdb.c was written from scratch and has *no* GNU code in it. |
5111 |
+ |
5112 |
+The most complex issue is types - you must pass names in a tvalue, |
5113 |
+which include a tctype (the C reminds one of a "C" type, not just 'type' |
5114 |
+which is ambiguous). The code to convert gdb types into duel types is |
5115 |
+typical. Watch out for recursive struct pointers (the hash table handles |
5116 |
+these problems), and for partial types, e.g. pointer to struct which |
5117 |
+contains no fields (size zero!). |
5118 |
+ |
5119 |
+You can return a BVALUE an LVALUE (preferred) or an RVALUE for a name |
5120 |
+lookup. use RVALUE for names found in registers, and return the actual |
5121 |
+value. |
5122 |
+ |
5123 |
+if a frame number is given for symbol lookup, only local variables |
5124 |
+allocated in that frame should be returned. (else return none. don't |
5125 |
+return a global if it exist with the same name, this will make the dot |
5126 |
+stack compute things wrong). |
5127 |
+ |
5128 |
+Node that this doesnt help with scoping problems (for duel)- e.g. |
5129 |
+you can't do myfunc.x if x is a static variable in myfunc. There needs to |
5130 |
+be a more complex & general way in the language to specify this (i.e. |
5131 |
+specify a source location in which the variable is visible, AND a frame |
5132 |
+to use if the value is kept on a frame) frame(n).(scope(file,line).x)? |
5133 |
+ |
5134 |
--- gdb/duel/misc.c |
5135 |
+++ gdb/duel/misc.c |
5136 |
@@ -0,0 +1,145 @@ |
5137 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
5138 |
+/* Public domain code */ |
5139 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
5140 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
5141 |
+ |
5142 |
+/* misc function/library-like */ |
5143 |
+ |
5144 |
+/* |
5145 |
+ * $Log: 10_all_gdb-6.6-duel.patch,v $ |
5146 |
+ * Revision 1.1 2007/12/29 21:06:06 vapier |
5147 |
+ * add DUEL support #199987 by Sergei Golubchik |
5148 |
+ * |
5149 |
+ * Revision 1.5 93/03/12 05:51:00 mg |
5150 |
+ * support output redirection |
5151 |
+ * |
5152 |
+ * Revision 1.4 93/01/13 16:22:09 mg |
5153 |
+ * allow malloc to return int (is a mini symbol on SUN) |
5154 |
+ * |
5155 |
+ * Revision 1.3 93/01/12 21:52:43 mg |
5156 |
+ * moved aliases mgmt here |
5157 |
+ * cleanup and set for release |
5158 |
+ * |
5159 |
+ */ |
5160 |
+ |
5161 |
+#include "duel.h" |
5162 |
+ |
5163 |
+/* like strncpy, but put a zero at to[len] anyway. |
5164 |
+ * are copied (hence taking len+1 bytes |
5165 |
+ */ |
5166 |
+ |
5167 |
+FUNC char* strncpyz(char *to,char *from,size_t len) |
5168 |
+{ |
5169 |
+ strncpy(to,from,len); |
5170 |
+ to[len]=0 ; |
5171 |
+ return to ; |
5172 |
+} |
5173 |
+ |
5174 |
+/* allocate n bytes in the target's space. Used for storing constant |
5175 |
+ * strings when they are parsed, and for variables declaration |
5176 |
+ * note: on SUN (and others?) gdb claims malloc to return an integer. we |
5177 |
+ * accept this (silly but probably no harm done) |
5178 |
+ */ |
5179 |
+ |
5180 |
+FUNC ttarget_ptr duel_alloc_target_space(size_t n) |
5181 |
+{ |
5182 |
+ tvalue p,f,r,*parms[1] ; |
5183 |
+ |
5184 |
+ p.val_kind=VK_RVALUE ; /* mk n into a value, to pass as parm */ |
5185 |
+ p.ctype=ctype_int ; |
5186 |
+ p.u.rval_int=n ; |
5187 |
+ parms[0]= &p ; |
5188 |
+ |
5189 |
+ if(!duel_get_target_variable("malloc",-1,&f) || |
5190 |
+ f.ctype->type_kind!=CTK_FUNC || |
5191 |
+ f.ctype->u.kid->type_kind!=CTK_INT && f.ctype->u.kid->type_kind!=CTK_PTR) |
5192 |
+ duel_fatal("malloc() function returning a pointer required in target"); |
5193 |
+ |
5194 |
+ duel_target_func_call(&f,parms,1,&r); |
5195 |
+ if(r.u.rval_ptr==NULL) duel_fatal("target's malloc() failed"); |
5196 |
+ return r.u.rval_ptr ; |
5197 |
+} |
5198 |
+ |
5199 |
+PROC duel_free_val_list(tval_list *l) /*free a val list and mark list empty */ |
5200 |
+{ |
5201 |
+ tval_lcell *cell,*next ; |
5202 |
+ for(cell=l->head ; cell!=NULL ; cell=next ) { |
5203 |
+ next=cell->next ; |
5204 |
+ duel_free(cell); |
5205 |
+ } |
5206 |
+ l->head=l->tail=NULL ; |
5207 |
+} |
5208 |
+ |
5209 |
+/* free all the memory allocated in the parse tree from node */ |
5210 |
+ |
5211 |
+PROC duel_free_nodes(tnode *n) |
5212 |
+{ |
5213 |
+ int i; |
5214 |
+ if(!n) return ; |
5215 |
+ for(i=0 ; i<NODE_MAX_KIDS ; i++) |
5216 |
+ duel_free_nodes(n->kids[i]); |
5217 |
+ duel_free_val_list(&n->eval.vlist); |
5218 |
+ duel_free(n); |
5219 |
+} |
5220 |
+ |
5221 |
+ |
5222 |
+ |
5223 |
+/* Aliases management */ |
5224 |
+ |
5225 |
+typedef struct sduel_var { /* an alias */ |
5226 |
+ char *name ; |
5227 |
+ tvalue val ; |
5228 |
+ struct sduel_var *next ; |
5229 |
+ } tduel_var ; |
5230 |
+tduel_var *duel_vars_head ; |
5231 |
+ |
5232 |
+/* find the value of a duel variable, if exist (else return null */ |
5233 |
+ |
5234 |
+FUNC tvalue* duel_find_alias(char *name) |
5235 |
+{ |
5236 |
+ tduel_var *p ; |
5237 |
+ for(p=duel_vars_head ; p ; p=p->next) { |
5238 |
+ if(strcmp(name,p->name)==0) return(&p->val); |
5239 |
+ } |
5240 |
+ return NULL ; |
5241 |
+} |
5242 |
+ |
5243 |
+/* set a value of a duel alias. Create var as needed */ |
5244 |
+ |
5245 |
+PROC duel_set_alias(char *name,tvalue *v) |
5246 |
+{ |
5247 |
+ tduel_var *p ; |
5248 |
+ tvalue *found = duel_find_alias(name) ; |
5249 |
+ if(found!=NULL) *found= *v ; |
5250 |
+ else { |
5251 |
+ p=duel_malloc(sizeof(tduel_var)) ; |
5252 |
+ p->next=duel_vars_head ; |
5253 |
+ p->val= *v ; |
5254 |
+ p->name=name ; |
5255 |
+ duel_vars_head=p ; |
5256 |
+ } |
5257 |
+} |
5258 |
+ |
5259 |
+PROC duel_clear_aliases(void) /* clear all defined aliases */ |
5260 |
+{ |
5261 |
+ tduel_var *p=duel_vars_head ; |
5262 |
+ while(p) { |
5263 |
+ tduel_var *q=p ; |
5264 |
+ p=p->next ; |
5265 |
+ duel_free(q); |
5266 |
+ } |
5267 |
+ duel_vars_head=0 ; |
5268 |
+} |
5269 |
+ |
5270 |
+PROC duel_show_aliases(void) |
5271 |
+{ |
5272 |
+ tduel_var *p ; |
5273 |
+ if(!duel_vars_head) duel_printf("No aliases defined\n"); |
5274 |
+ else { |
5275 |
+ duel_printf("Aliases table:\n"); |
5276 |
+ for(p=duel_vars_head ; p ; p=p->next) { |
5277 |
+ duel_printf("%s: ",p->name); |
5278 |
+ duel_print_value(&p->val); |
5279 |
+ } |
5280 |
+ } |
5281 |
+} |
5282 |
+ |
5283 |
+ |
5284 |
+ |
5285 |
--- gdb/duel/output.c |
5286 |
+++ gdb/duel/output.c |
5287 |
@@ -0,0 +1,53 @@ |
5288 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
5289 |
+/* Public domain code */ |
5290 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
5291 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
5292 |
+ |
5293 |
+/* This module supports i/o for duel. Normally output goes to stdout, |
5294 |
+ * but it could be piped out instead. |
5295 |
+ * this module support minimal duel output w/o pipes. output2.c which |
5296 |
+ * support piped i/o is still an alpha version. |
5297 |
+ */ |
5298 |
+ |
5299 |
+#include <stdarg.h> /* for duel_printf */ |
5300 |
+#include "duel.h" |
5301 |
+ |
5302 |
+/* output functions: |
5303 |
+ * duel_printf all duel output goes thru this - like printf() |
5304 |
+ * duel_flush used by duel to flush the output. |
5305 |
+ */ |
5306 |
+ |
5307 |
+PROC duel_printf(char *fmt, ...) /* like printf, but for duel output */ |
5308 |
+{ |
5309 |
+ va_list args; |
5310 |
+ va_start(args, fmt); |
5311 |
+ vfprintf(stdout,fmt,args); |
5312 |
+ va_end(args); |
5313 |
+} |
5314 |
+ |
5315 |
+PROC duel_flush(void) /* flush out output from duel */ |
5316 |
+{ |
5317 |
+ fflush(stdout); |
5318 |
+} |
5319 |
+ |
5320 |
+/* tells us the output is "directable" now. s is the expression |
5321 |
+ * being evaluated for this */ |
5322 |
+ |
5323 |
+PROC duel_redirectable_output_start(char *s) |
5324 |
+{ |
5325 |
+ if(s) duel_flush(); /* if(s) is always true. prevents warnings ...*/ |
5326 |
+} |
5327 |
+ |
5328 |
+PROC duel_redirectable_output_end(void) |
5329 |
+{ |
5330 |
+ duel_flush(); |
5331 |
+} |
5332 |
+ |
5333 |
+PROC duel_redirectable_output_abort(void) |
5334 |
+{ |
5335 |
+ duel_flush(); |
5336 |
+} |
5337 |
+ |
5338 |
+PROC duel_redirectable_output_init(void) |
5339 |
+{ |
5340 |
+} |
5341 |
--- gdb/duel/output2.c |
5342 |
+++ gdb/duel/output2.c |
5343 |
@@ -0,0 +1,141 @@ |
5344 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
5345 |
+/* Public domain code */ |
5346 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
5347 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
5348 |
+ |
5349 |
+/* This module supports i/o for duel. Normally output goes to stdout, |
5350 |
+ * but it could be piped out instead. |
5351 |
+ * Still alpha version. |
5352 |
+ * HOW: if file duel.pipe exists, it is opened with stdin/out piped |
5353 |
+ * here. results of expressions evaluations are sent to the pipe |
5354 |
+ * with $$$START $$$END $$$ABORT and $$$SYM/$$$VAL. The pipe's |
5355 |
+ * output is passed back here and is printed to stdout until |
5356 |
+ * a $$$DONE is received. The pipe is normally a perl script, |
5357 |
+ * that can processes the output at a symbolic level. |
5358 |
+ */ |
5359 |
+ |
5360 |
+#include <stdarg.h> /* for duel_printf */ |
5361 |
+#include <sys/types.h> /* for stat() */ |
5362 |
+#include <sys/stat.h> /* " */ |
5363 |
+#include <fcntl.h> /* for popen impl. */ |
5364 |
+#include <signal.h> /* " */ |
5365 |
+ |
5366 |
+#include "duel.h" |
5367 |
+ |
5368 |
+/* output functions: |
5369 |
+ * duel_printf all duel output goes thru this - like printf() |
5370 |
+ * duel_flush used by duel to flush the output. |
5371 |
+ * duel_redirectable_output_start(s) - indicate start of output for exp s that |
5372 |
+ * can be redirected to a pipe. |
5373 |
+ * duel_redirectable_output_end() - indicate end of that output. |
5374 |
+ * duel_redirectable_output_abort() - indicate output was aborted (error,intr) |
5375 |
+ * |
5376 |
+ * duel_redirectable_output_init() - called to init at first duel use. |
5377 |
+ */ |
5378 |
+ |
5379 |
+static FILE *duel_outf = stdout ; /* current output stream */ |
5380 |
+static FILE *poutf,*pinf ; /* pipe i/o streams */ |
5381 |
+ |
5382 |
+#define PIPE_CMD "./duel.pipe" /* command to pipe into */ |
5383 |
+ |
5384 |
+bool bidir_popen(void) |
5385 |
+{ |
5386 |
+ int pout[2],pin[2]; /* pin[0] is my input, pout[1] my output */ |
5387 |
+ int pid; |
5388 |
+ struct stat s ; |
5389 |
+ |
5390 |
+ if(stat(PIPE_CMD,&s)!=0 || !(s.st_mode & S_IEXEC)) return FALSE; |
5391 |
+ if (pipe(pout) < 0 || pipe(pin) < 0) return FALSE ; |
5392 |
+ |
5393 |
+ if ((pid = fork()) == 0) { |
5394 |
+ signal(SIGINT, SIG_IGN); |
5395 |
+ signal(SIGQUIT, SIG_IGN); |
5396 |
+ dup2(pout[0],0); dup2(pin[1],1); |
5397 |
+ close(pin[0]); close(pin[1]); close(pout[0]); close(pout[1]); |
5398 |
+ execl(PIPE_CMD, PIPE_CMD, NULL); |
5399 |
+ _exit(127); |
5400 |
+ } |
5401 |
+ close(pout[0]); close(pin[1]); |
5402 |
+ if (pid == -1) return FALSE; |
5403 |
+ pinf =fdopen(pin[0], "r"); |
5404 |
+ poutf=fdopen(pout[1],"w"); |
5405 |
+ if(fcntl(pin[0],F_SETFL,O_NDELAY) < 0) return FALSE ; |
5406 |
+ return pinf!=NULL && poutf!=NULL ; |
5407 |
+} |
5408 |
+ |
5409 |
+ |
5410 |
+PROC duel_printf(char *fmt, ...) /* like printf, but for duel output */ |
5411 |
+{ |
5412 |
+ va_list args; |
5413 |
+ va_start(args, fmt); |
5414 |
+ vfprintf(duel_outf,fmt,args); |
5415 |
+ va_end(args); |
5416 |
+} |
5417 |
+ |
5418 |
+PROC duel_flush(void) /* flush out output from duel */ |
5419 |
+{ |
5420 |
+ char s[256]; |
5421 |
+ fflush(duel_outf); |
5422 |
+ while(pinf && fgets(s,sizeof(s),pinf)) /* note pinf is non blocking */ |
5423 |
+ printf("%s",s); |
5424 |
+} |
5425 |
+ |
5426 |
+LPROC duel_waitpipe(bool abort) /* wait for pipe to finish working */ |
5427 |
+{ |
5428 |
+ char s[256]; |
5429 |
+ if(abort) duel_printf("$$$ABORT\n"); /* write termination mesg */ |
5430 |
+ else duel_printf("$$$DONE\n"); |
5431 |
+ fflush(duel_outf); |
5432 |
+ fcntl(fileno(pinf),F_SETFL,0); /* restore blocking for pipe */ |
5433 |
+ while(fgets(s,sizeof(s),pinf)!=NULL && strcmp(s,"$$$DONE\n")!=0) |
5434 |
+ if(!abort) printf("%s",s); |
5435 |
+ fcntl(fileno(pinf),F_SETFL,O_NDELAY); |
5436 |
+ if(abort) printf("\n"); |
5437 |
+} |
5438 |
+ |
5439 |
+/* tells us the output is "directable" now. s is the expression |
5440 |
+ * being evaluated for this */ |
5441 |
+ |
5442 |
+PROC duel_redirectable_output_start(char *s) |
5443 |
+{ |
5444 |
+ duel_flush(); |
5445 |
+ if(poutf) { |
5446 |
+ duel_flush(); |
5447 |
+ duel_outf=poutf ; |
5448 |
+ duel_output_pipe_style=1 ; |
5449 |
+ duel_printf("$$$START: %s\n",s); |
5450 |
+ duel_flush(); |
5451 |
+ } |
5452 |
+} |
5453 |
+ |
5454 |
+PROC duel_redirectable_output_end(void) |
5455 |
+{ |
5456 |
+ duel_flush(); |
5457 |
+ if(poutf && duel_outf == poutf) { |
5458 |
+ duel_waitpipe(FALSE); |
5459 |
+ duel_outf=stdout ; |
5460 |
+ duel_output_pipe_style=0 ; |
5461 |
+ } |
5462 |
+} |
5463 |
+ |
5464 |
+PROC duel_redirectable_output_abort(void) |
5465 |
+{ |
5466 |
+ if(poutf && duel_outf == poutf) { |
5467 |
+ duel_waitpipe(TRUE); |
5468 |
+ duel_outf=stdout ; |
5469 |
+ duel_output_pipe_style=0 ; |
5470 |
+ } |
5471 |
+ duel_flush(); |
5472 |
+} |
5473 |
+ |
5474 |
+PROC duel_redirectable_output_init(void) |
5475 |
+{ |
5476 |
+ /* open the duel pipe, if available. Verify that duel.pipe |
5477 |
+ * as an existing executable, because popen() does not, and can |
5478 |
+ * later fail with pipe signal! |
5479 |
+ */ |
5480 |
+ if(bidir_popen()) { |
5481 |
+ duel_printf("Duel results directed to pipe \"duel.pipe\"\n"); |
5482 |
+ } |
5483 |
+ else poutf=pinf=NULL ; |
5484 |
+} |
5485 |
--- gdb/duel/parse.y |
5486 |
+++ gdb/duel/parse.y |
5487 |
@@ -0,0 +1,940 @@ |
5488 |
+%{ |
5489 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
5490 |
+/* Public domain code */ |
5491 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
5492 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
5493 |
+ |
5494 |
+/* this module contains the duel parser, in yacc, plus a simple lexer. |
5495 |
+ * the lexer is slow, but duel expressions are tiny. |
5496 |
+ * the parsing generate an AST with essentially no type checking. |
5497 |
+ * names are only looked up when the refer explicitly to types. This forces |
5498 |
+ * the use of "T" before user types. You can't parse (x)(y) correctly, if |
5499 |
+ * you want the node to contain "cast" or "func", without knowing the x is |
5500 |
+ * not a type. (It is interesting to note that (x *)(y) is clearly a cast, |
5501 |
+ * but it can not be parsed without a context sensitive grammer!). |
5502 |
+ * |
5503 |
+ * Version 1.1 now accept (x) as a type cast, so (print)("hi") fails, but |
5504 |
+ * (uint)z is ok. Also accepted is (uint*)z. T is still required in sizeof |
5505 |
+ * and in variable declarations. A side effect was making "sizeof x" illegal |
5506 |
+ * (since then sizeof(x)-1 was parsed sizeof((x)-1) with (x) a cast), so |
5507 |
+ * now sizeof(x) must be used. Note that in C, sizoef(x)++ is acceptable, |
5508 |
+ * and the '++' operate on x (which is optimized out!) This can be confusing. |
5509 |
+ * |
5510 |
+ * yacc is also not smart enough to recognize e.g. "if(e) e ; else e" as |
5511 |
+ * a special case (redundent ';'). I hacked this in the lexer. It should |
5512 |
+ * reduce the trouble with C->duel coding. (It can also be done for {e1}e2, |
5513 |
+ * in some speical cases, e.g. if e2 is a keyword, or a name or a unary op, |
5514 |
+ * but this can confuse some people, e.g. in {i}[5], so I left it alone.) |
5515 |
+ * Finally, the %/ operator is accepted as "#/" and "%%" as "#", to those |
5516 |
+ * who wish to keep gdb with # comments. |
5517 |
+ * memory: nodes are alloc'ed dynamically. a parsing error loose so-far |
5518 |
+ * allocated nodes, which is normally acceptable (yyerror can probably hack |
5519 |
+ * into the yacc stack to release them.) |
5520 |
+ */ |
5521 |
+ |
5522 |
+/* |
5523 |
+ * $Log: 10_all_gdb-6.6-duel.patch,v $ |
5524 |
+ * Revision 1.1 2007/12/29 21:06:06 vapier |
5525 |
+ * add DUEL support #199987 by Sergei Golubchik |
5526 |
+ * |
5527 |
+ * Revision 1.14 93/03/17 11:04:12 mg |
5528 |
+ * fixed (t*)x bug, was parsed as (t**)x |
5529 |
+ * |
5530 |
+ * Revision 1.13 93/03/12 06:15:09 mg |
5531 |
+ * modified unary's a bit - cosmetics |
5532 |
+ * support (x)y as type cast |
5533 |
+ * support (x*)y as type cast |
5534 |
+ * replace sizeof exp with sizeof(exp) to prevent clash with above |
5535 |
+ * more cosmetics, including yyerror abort, tuint for uint. |
5536 |
+ * takes anything after |> to be comment (pipe command really) |
5537 |
+ * |
5538 |
+ * |
5539 |
+ * Revision 1.12 93/02/27 06:06:09 mg |
5540 |
+ * added signed char parsing. |
5541 |
+ * |
5542 |
+ * Revision 1.11 93/02/23 19:15:38 mg |
5543 |
+ * improved escaped char support |
5544 |
+ * |
5545 |
+ * Revision 1.10 93/02/03 21:49:34 mg |
5546 |
+ * bug fix - yyerror calls now abort parsing (eg called from lex) |
5547 |
+ * |
5548 |
+ * Revision 1.9 93/01/12 21:53:07 mg |
5549 |
+ * cleanup and set for release |
5550 |
+ * |
5551 |
+ * Revision 1.8 93/01/07 00:14:33 mg |
5552 |
+ * add &&/ ||/ |
5553 |
+ * fixed parsing of trailing ';' was a mess. |
5554 |
+ * ignore ';' before 'else' and '}' w/warning. |
5555 |
+ * |
5556 |
+ * Revision 1.7 93/01/03 07:31:01 mg |
5557 |
+ * error reporting |
5558 |
+ * |
5559 |
+ * Revision 1.6 92/12/24 23:35:50 mg |
5560 |
+ * began src pos support |
5561 |
+ * |
5562 |
+ * Revision 1.5 92/10/19 15:08:02 mg |
5563 |
+ * frames() added; bug fixed |
5564 |
+ * |
5565 |
+ * Revision 1.4 92/10/14 02:06:32 mg |
5566 |
+ * misc/change casting parsing/variable def. |
5567 |
+ * |
5568 |
+ * Revision 1.3 92/09/16 11:09:39 mg |
5569 |
+ * add typedef/struct support, const strings |
5570 |
+ * cleanup s/r conflict by setting ELSE to a token. explained some stuff in |
5571 |
+ * comments. |
5572 |
+ * |
5573 |
+ * Revision 1.2 92/09/15 06:10:46 mg |
5574 |
+ * cosmetics and new ops: x@y, for() while() ..x and x.. |
5575 |
+ * generic '.' and '_' support. x@y. '..x' and 'x..'. while(), for(), ?: |
5576 |
+ * |
5577 |
+ */ |
5578 |
+ |
5579 |
+#include "duel.h" |
5580 |
+ |
5581 |
+static char *inputstr ; /* pointer to string being parsed */ |
5582 |
+static char *lexptr ; /* current lexer pointer into input str */ |
5583 |
+static tnode *root ; /* result of parsing stored here */ |
5584 |
+ |
5585 |
+/* pick unique names for globals of yacc. gdb has other parsers! */ |
5586 |
+#define yyparse duel_yyparse |
5587 |
+#define yylex duel_yylex |
5588 |
+#define yyerror duel_yyerror |
5589 |
+#define yylval duel_yylval |
5590 |
+#define yychar duel_yychar |
5591 |
+#define yydebug duel_yydebug |
5592 |
+#define yypact duel_yypact |
5593 |
+#define yyr1 duel_yyr1 |
5594 |
+#define yyr2 duel_yyr2 |
5595 |
+#define yydef duel_yydef |
5596 |
+#define yychk duel_yychk |
5597 |
+#define yypgo duel_yypgo |
5598 |
+#define yyact duel_yyact |
5599 |
+#define yyexca duel_yyexca |
5600 |
+#define yyerrflag duel_yyerrflag |
5601 |
+#define yynerrs duel_yynerrs |
5602 |
+#define yyps duel_yyps |
5603 |
+#define yypv duel_yypv |
5604 |
+#define yys duel_yys |
5605 |
+#define yystate duel_yystate |
5606 |
+#define yytmp duel_yytmp |
5607 |
+#define yyv duel_yyv |
5608 |
+#define yyval duel_yyval |
5609 |
+#define yylloc duel_yylloc |
5610 |
+ |
5611 |
+typedef struct { /* token info for operators */ |
5612 |
+ int src_pos ; /* source position */ |
5613 |
+ topcode opcode ; /* opcode */ |
5614 |
+ } topinfo ; |
5615 |
+ |
5616 |
+typedef struct { /* token info for symbols */ |
5617 |
+ int src_pos ; /* source position */ |
5618 |
+ char *name ; /* symbol */ |
5619 |
+ } tnameinfo ; |
5620 |
+ |
5621 |
+/* these are used as operators to mknode_... when source location is unknown*/ |
5622 |
+static topinfo seq_op = { -1,';' } ; /* sequencing operator, src pos unkown */ |
5623 |
+static topinfo decl_op = { -1,OP_DECL } ; /* declare var op, src pos unkown */ |
5624 |
+ |
5625 |
+/* local prototypes. */ |
5626 |
+LPROC yyerror(char *msg); |
5627 |
+LFUNC int yylex (void); |
5628 |
+ |
5629 |
+LPROC push_type(char desc) ; |
5630 |
+LPROC push_type_int(char desc,tnode *n) ; |
5631 |
+LFUNC bool pop_type(char *desc,int *size); |
5632 |
+ |
5633 |
+LFUNC tnode* mknode_op(top_kind,topinfo opinfo,tnode*,tnode*,tnode*,tnode*); |
5634 |
+LFUNC tnode* mknode_const(int src_pos,tctype *ctype); |
5635 |
+LFUNC tnode* mknode_ctype(tctype *ctype); |
5636 |
+LFUNC tnode* mknode_name(tnameinfo nameinfo); |
5637 |
+LFUNC tnode* mknode_modified_ctype(tctype *base); |
5638 |
+ |
5639 |
+#define mknode_post_unary(op,n) (mknode_op(OPK_POST_UNARY,op,n, 0, 0,0)) |
5640 |
+#define mknode_unary(op,n) (mknode_op(OPK_UNARY, op,n, 0, 0,0)) |
5641 |
+#define mknode_sunary(op,n) (mknode_op(OPK_SUNARY, op,n, 0, 0,0)) |
5642 |
+#define mknode_bin(op,n1,n2) (mknode_op(OPK_BIN, op,n1,n2,0,0)) |
5643 |
+#define mknode_sbin(op,n1,n2) (mknode_op(OPK_SBIN, op,n1,n2,0,0)) |
5644 |
+#define mknode_tri(op,n1,n2,n3) (mknode_op(OPK_TRI, op,n1,n2,n3,0)) |
5645 |
+ |
5646 |
+static tctype *decl_tbase ; /* used for variables decl */ |
5647 |
+ |
5648 |
+/* #define YYDEBUG 1 */ |
5649 |
+ |
5650 |
+%} |
5651 |
+ |
5652 |
+%union |
5653 |
+ { |
5654 |
+ tnode *node ; /* node pointer for constructed exp tree */ |
5655 |
+ tctype *ctype; /* type for type nodes */ |
5656 |
+ tnameinfo nameinfo ; /* a name/symbol + src position */ |
5657 |
+ topinfo opinfo; /* keyword/operator + source position */ |
5658 |
+ } |
5659 |
+ |
5660 |
+%type <node> start duel_inp duel_exp exp type nameexp sm_exp oexp |
5661 |
+%type <node> all_decls vars_decl var_decl name_decl1 name_decl |
5662 |
+%type <ctype> typebase |
5663 |
+%type <nameinfo> name |
5664 |
+ |
5665 |
+%token <node> T_CONST |
5666 |
+%token <nameinfo> T_SYM |
5667 |
+%token <opinfo> T_ASSIGN T_DEFVAR |
5668 |
+ |
5669 |
+ |
5670 |
+%token <opinfo> T_CHAR T_INT T_SHORT T_LONG T_UNSIGNED T_FLOAT T_DOUBLE T_VOID |
5671 |
+%token <opinfo> T_STRUCT T_UNION T_ENUM T_SIZEOF T_TYPEDEF_INDICATOR T_SIGNED |
5672 |
+ |
5673 |
+%token <opinfo> T_IF T_ELSE T_FOR T_WHILE |
5674 |
+%token <opinfo> ';' ',' '=' '?' '|' '^' '&' '<' '>' '+' '-' '*' '/' '%' |
5675 |
+%token <opinfo> '.' '[' ']' '(' ')' '{' '}' '#' '@' '!' '~' |
5676 |
+%token <opinfo> T_OR T_AND T_RSH T_LSH T_INC T_DEC T_COUNT T_FRAME T_TO |
5677 |
+%token <opinfo> T_DFS T_BFS T_ARROW T_OSEL T_CSEL T_IMP T_ANDL T_ORL |
5678 |
+%token <opinfo> T_EQ T_NE T_EQQ T_NEQ T_LE T_GE T_LSQ T_GTQ T_LEQ T_GEQ |
5679 |
+ |
5680 |
+%left ';' |
5681 |
+%right STMT T_ELSE |
5682 |
+%right T_IMP |
5683 |
+%right ',' |
5684 |
+%right '=' T_ASSIGN T_DEFVAR |
5685 |
+%right '?' |
5686 |
+%left T_OR T_ORL |
5687 |
+%left T_AND T_ANDL |
5688 |
+%left '|' |
5689 |
+%left '^' |
5690 |
+%left '&' |
5691 |
+%left T_EQ T_NE T_EQQ T_NEQ |
5692 |
+%left '<' '>' T_LE T_GE T_LSQ T_GTQ T_LEQ T_GEQ |
5693 |
+%nonassoc T_TO |
5694 |
+%left T_LSH T_RSH |
5695 |
+%left '+' '-' |
5696 |
+%left '*' '/' '%' |
5697 |
+%right UNARY '!' '~' T_INC T_DEC T_COUNT T_FRAME |
5698 |
+%left T_DFS T_BFS T_POS T_ARROW '.' '[' ']' '(' ')' '{' '}' '#' '@' T_OSEL T_CSEL |
5699 |
+%% |
5700 |
+ |
5701 |
+start : duel_inp { root=$1 ; } |
5702 |
+ ; |
5703 |
+ |
5704 |
+duel_inp : all_decls |
5705 |
+ | all_decls ';' |
5706 |
+ | all_decls ';' duel_exp { $$=mknode_sbin($2,$1,$3);} |
5707 |
+ | duel_exp |
5708 |
+ ; |
5709 |
+duel_exp : sm_exp |
5710 |
+ | sm_exp ';' { $$=mknode_sbin($2,$1,0); } |
5711 |
+ ; |
5712 |
+all_decls: vars_decl |
5713 |
+ | all_decls ';' vars_decl { $$=mknode_sbin($2,$1,$3); } |
5714 |
+ ; |
5715 |
+ |
5716 |
+vars_decl: typebase { decl_tbase=$1 ; } var_decl { $$=$3 ; } |
5717 |
+ ; |
5718 |
+var_decl : name_decl1 |
5719 |
+ | var_decl ',' name_decl1 { $$=mknode_sbin(seq_op,$1,$3); } |
5720 |
+ ; |
5721 |
+ |
5722 |
+name_decl1: name_decl { $$=mknode_sbin(decl_op,$1, |
5723 |
+ mknode_modified_ctype(decl_tbase)); } |
5724 |
+ ; |
5725 |
+ |
5726 |
+name_decl : '(' name_decl ')' { $$=$2 ; } |
5727 |
+ | '(' name_decl ')' '(' ')' { $$=$2 ; push_type('('); } |
5728 |
+ | '*' name_decl { $$=$2 ; push_type('*'); } |
5729 |
+ | name_decl '[' T_CONST ']' { $$=$1 ; push_type_int('[',$3); } |
5730 |
+ | nameexp |
5731 |
+ ; |
5732 |
+ |
5733 |
+/* Statements - not really, these are expressions too! |
5734 |
+ Notes: for(;;) oexp - will create lots of shift/reduce conflicts, |
5735 |
+ 'for(;;;)' and 'for(;;) exp' are specified |
5736 |
+ instead and yacc handle this as a "standard" s/r. |
5737 |
+ the only diff is yacc dont complain on these! |
5738 |
+ if() - same comments as above, plus, we prevent meaningless |
5739 |
+ if's like in C: ' if(x); else;' - a useless statement. |
5740 |
+ */ |
5741 |
+exp : T_IF '(' exp ')' exp %prec STMT { $$=mknode_tri($1,$3,$5,0); } |
5742 |
+ | T_IF '(' exp ')' exp T_ELSE %prec STMT |
5743 |
+ { $$=mknode_tri($1,$3,$5,0); } |
5744 |
+ | T_IF '(' exp ')' T_ELSE exp %prec STMT |
5745 |
+ { $$=mknode_tri($1,$3,0,$6); } |
5746 |
+ | T_IF '(' exp ')' exp T_ELSE exp %prec STMT |
5747 |
+ { $$=mknode_tri($1,$3,$5,$7); } |
5748 |
+ |
5749 |
+ | T_FOR '(' oexp ';' exp ';' oexp ')' exp %prec STMT |
5750 |
+ { $$=mknode_op(OPK_QUAD,$1,$3,$5,$7,$9); } |
5751 |
+ | T_FOR '(' oexp ';' exp ';' oexp ')' %prec STMT |
5752 |
+ { $$=mknode_op(OPK_QUAD,$1,$3,$5,$7,0); } |
5753 |
+ | T_WHILE '(' exp ')' exp %prec STMT |
5754 |
+ { $$=mknode_sbin($1,$3,$5); } |
5755 |
+ | T_WHILE '(' exp ')' %prec STMT |
5756 |
+ { $$=mknode_sbin($1,$3,0); } |
5757 |
+ ; |
5758 |
+ |
5759 |
+/* Expressions */ |
5760 |
+ |
5761 |
+exp : '*' exp %prec UNARY { $$=mknode_unary( $1,$2); } |
5762 |
+ | '&' exp %prec UNARY { $$=mknode_unary( $1,$2); } |
5763 |
+ | '-' exp %prec UNARY { $$=mknode_unary( $1,$2); } |
5764 |
+ | '!' exp { $$=mknode_unary( $1,$2); } |
5765 |
+ | '~' exp { $$=mknode_unary( $1,$2); } |
5766 |
+ | T_COUNT exp { $$=mknode_sunary($1,$2); } |
5767 |
+ | T_ANDL exp { $$=mknode_sunary($1,$2); } |
5768 |
+ | T_ORL exp { $$=mknode_sunary($1,$2); } |
5769 |
+ | T_INC exp { $$=mknode_unary( $1,$2); } |
5770 |
+ | T_DEC exp { $$=mknode_unary( $1,$2); } |
5771 |
+ | exp T_INC { $$=mknode_post_unary($2,$1); } |
5772 |
+ | exp T_DEC { $$=mknode_post_unary($2,$1); } |
5773 |
+ | T_SIZEOF '(' type ')' { $$=mknode_sunary($1,$3); } |
5774 |
+ | T_SIZEOF '(' exp ')' { $$=mknode_unary($1,$3); } |
5775 |
+ | T_FRAME '(' exp ')' %prec UNARY { $$=mknode_unary( $1,$3); } |
5776 |
+ ; |
5777 |
+ |
5778 |
+exp : exp T_DFS exp { $$=mknode_sbin($2,$1,$3); } |
5779 |
+ | exp T_BFS exp { $$=mknode_sbin($2,$1,$3); } |
5780 |
+ |
5781 |
+ | exp '#' nameexp { $$=mknode_sbin($2,$1,$3); } |
5782 |
+ | exp '@' exp { $$=mknode_sbin($2,$1,$3); } |
5783 |
+ | exp T_ARROW exp { $$=mknode_sbin($2,$1,$3); } |
5784 |
+ | exp '.' exp { $$=mknode_sbin($2,$1,$3); } |
5785 |
+ | exp '[' exp ']' { $$=mknode_bin( $2,$1,$3); } |
5786 |
+ | exp T_OSEL exp T_CSEL { $$=mknode_sbin($2,$1,$3); } |
5787 |
+ | exp '(' oexp ')' %prec '.' { $$=mknode_op(OPK_FUNC,$2,$1,$3,0,0); } |
5788 |
+ | '(' sm_exp ')' { $$=mknode_unary($1,$2); } |
5789 |
+ | '{' sm_exp '}' { $$=mknode_unary($1,$2); } |
5790 |
+ ; |
5791 |
+ |
5792 |
+exp : '(' type ')' exp %prec UNARY |
5793 |
+ { $$=mknode_op(OPK_CAST,$1,$2,$4,0,0); } |
5794 |
+/* HACKS to handle the most common cast cases with a typedef, without |
5795 |
+ * requiring a 'T'. This code breaks (printf)("hi"), which returns the |
5796 |
+ * error "printf not a typedef", but otherwise it works ok. |
5797 |
+ * It might be confusing since "(uint *)p" works but "(uint (*)())p" wont, |
5798 |
+ * but it seems that (uint*)p, (uint)x are the most common, and users get |
5799 |
+ * confused w/o them. |
5800 |
+ * The code below works essentially with context-sensitive parsing! |
5801 |
+ * see the hacked %prec for nameexp which prevents yacc s/r warning! |
5802 |
+ */ |
5803 |
+ | '(' name ')' exp %prec UNARY { |
5804 |
+ tctype *t=duel_get_target_typedef($2.name); |
5805 |
+ if(t==NULL) yyerror("not a typedef name"); |
5806 |
+ $$=mknode_op(OPK_CAST,$1,mknode_ctype(t),$4,0,0); } |
5807 |
+ | '(' name '*' type_mod ')' exp %prec UNARY { |
5808 |
+ tctype *t=duel_get_target_typedef($2.name); |
5809 |
+ if(t==NULL) yyerror("not a typedef name"); |
5810 |
+ push_type('*'); |
5811 |
+ $$=mknode_op(OPK_CAST,$1,mknode_modified_ctype(t),$6,0,0); } |
5812 |
+ ; |
5813 |
+ |
5814 |
+ /* Bin ops in decreasing precedence order: */ |
5815 |
+ |
5816 |
+exp : exp '*' exp { $$=mknode_bin($2,$1,$3); } |
5817 |
+ | exp '/' exp { $$=mknode_bin($2,$1,$3); } |
5818 |
+ | exp '%' exp { $$=mknode_bin($2,$1,$3); } |
5819 |
+ | exp '+' exp { $$=mknode_bin($2,$1,$3); } |
5820 |
+ | exp '-' exp { $$=mknode_bin($2,$1,$3); } |
5821 |
+ | exp T_LSH exp { $$=mknode_bin($2,$1,$3); } |
5822 |
+ | exp T_RSH exp { $$=mknode_bin($2,$1,$3); } |
5823 |
+ | exp T_EQ exp { $$=mknode_bin($2,$1,$3); } |
5824 |
+ | exp T_NE exp { $$=mknode_bin($2,$1,$3); } |
5825 |
+ | exp T_EQQ exp { $$=mknode_bin($2,$1,$3); } |
5826 |
+ | exp T_NEQ exp { $$=mknode_bin($2,$1,$3); } |
5827 |
+ | exp T_LE exp { $$=mknode_bin($2,$1,$3); } |
5828 |
+ | exp T_GE exp { $$=mknode_bin($2,$1,$3); } |
5829 |
+ | exp T_LEQ exp { $$=mknode_bin($2,$1,$3); } |
5830 |
+ | exp T_GEQ exp { $$=mknode_bin($2,$1,$3); } |
5831 |
+ | exp '<' exp { $$=mknode_bin($2,$1,$3); } |
5832 |
+ | exp '>' exp { $$=mknode_bin($2,$1,$3); } |
5833 |
+ | exp T_LSQ exp { $$=mknode_bin($2,$1,$3); } |
5834 |
+ | exp T_GTQ exp { $$=mknode_bin($2,$1,$3); } |
5835 |
+ | exp '&' exp { $$=mknode_bin($2,$1,$3); } |
5836 |
+ | exp '|' exp { $$=mknode_bin($2,$1,$3); } |
5837 |
+ | exp '^' exp { $$=mknode_bin($2,$1,$3); } |
5838 |
+ | exp T_AND exp { $$=mknode_sbin($2,$1,$3); } |
5839 |
+ | exp T_OR exp { $$=mknode_sbin($2,$1,$3); } |
5840 |
+ ; |
5841 |
+ |
5842 |
+exp : exp '?' exp ':' exp %prec '?' |
5843 |
+ { $$=mknode_tri($2,$1,$3,$5); } |
5844 |
+ ; |
5845 |
+ |
5846 |
+exp : exp '=' exp { $$=mknode_bin($2,$1,$3); } |
5847 |
+ | exp T_ASSIGN exp { $$=mknode_op(OPK_ASSIGN,$2, $1,$3,0,0); } |
5848 |
+ |nameexp T_DEFVAR exp { $$=mknode_sbin($2,$1,$3); } |
5849 |
+ ; |
5850 |
+ |
5851 |
+ /* generating expressions */ |
5852 |
+ |
5853 |
+exp : exp T_TO exp { $$=mknode_sbin($2,$1,$3); } |
5854 |
+ | T_TO exp { $$=mknode_sbin($1, 0,$2); } |
5855 |
+ | exp T_TO { $$=mknode_sbin($2,$1, 0); } |
5856 |
+ | exp ',' exp { $$=mknode_sbin($2,$1,$3); } |
5857 |
+ | exp T_IMP exp { $$=mknode_sbin($2,$1,$3); } |
5858 |
+ ; |
5859 |
+ |
5860 |
+sm_exp : sm_exp ';' exp { $$=mknode_sbin($2,$1,$3); } |
5861 |
+ | exp |
5862 |
+ ; |
5863 |
+ |
5864 |
+oexp : exp /* optional expression, eg in for() */ |
5865 |
+ | { $$=0 ; } |
5866 |
+ ; |
5867 |
+ |
5868 |
+exp : T_CONST ; |
5869 |
+exp : nameexp ; |
5870 |
+ /* convert a string input (name) into an expression. |
5871 |
+ * precedence of '+' is a hack to make the special case |
5872 |
+ * of (x*)(y) parsed as a cast, without shift/reduce conflict |
5873 |
+ *(this would work the same w/o the '+' but gives warning) |
5874 |
+ */ |
5875 |
+nameexp : name %prec '+' { $$=mknode_name($1) ; } ; |
5876 |
+ |
5877 |
+type : typebase type_mod { $$=mknode_modified_ctype($1); } |
5878 |
+ ; |
5879 |
+/* type_mod has no value. bison warning is meaningless. I cant find a way |
5880 |
+ * to shut it up |
5881 |
+ */ |
5882 |
+type_mod: '(' type_mod ')' |
5883 |
+ | '(' type_mod ')' '(' ')' { push_type('('); } |
5884 |
+ | '*' type_mod { push_type('*'); } |
5885 |
+ | type_mod '[' T_CONST ']' { push_type_int('[',$3); } |
5886 |
+ | |
5887 |
+ ; |
5888 |
+ |
5889 |
+ |
5890 |
+/* note that names are evaluated at runtime. hence (name)(x) is ambigious |
5891 |
+ * as either a function call or a cast. |
5892 |
+ * We could identify a typedef 'name' as such and return a special token from |
5893 |
+ * the lexr, but this will make 'x.(5+y)' illegal if y is both a field and |
5894 |
+ * a typedef (Note that gdb's own code include such things). |
5895 |
+ * |
5896 |
+ * there is a complex solution, that keeps the the casting as a syntax tree, |
5897 |
+ * and compute ctype at runtime, too. However, we want to compute all types at |
5898 |
+ * parse time. Out solution forces the reserved word T_TYPEDEF_INDICATOR to |
5899 |
+ * appear before any typedef name. (the reserved word is normally just 'T') |
5900 |
+ * example: instead of '(list *) x' use in duel: '(T list *) x' |
5901 |
+ */ |
5902 |
+ |
5903 |
+typebase: T_TYPEDEF_INDICATOR name { |
5904 |
+ $$=duel_get_target_typedef($2.name); |
5905 |
+ if($$==NULL) { |
5906 |
+ tvalue v; |
5907 |
+ if(duel_get_target_variable($2.name,-1,&v)) $$=v.ctype; |
5908 |
+ else yyerror("not a typedef name"); |
5909 |
+ } |
5910 |
+ } |
5911 |
+ ; |
5912 |
+ |
5913 |
+typebase: T_CHAR { $$ = ctype_char; } |
5914 |
+ | T_SIGNED T_CHAR { $$ = ctype_schar; } |
5915 |
+ | T_UNSIGNED T_CHAR { $$ = ctype_uchar; } |
5916 |
+ | T_INT { $$ = ctype_int; } |
5917 |
+ | T_UNSIGNED { $$ = ctype_uint; } |
5918 |
+ | T_UNSIGNED T_INT { $$ = ctype_uint; } |
5919 |
+ | T_LONG { $$ = ctype_long; } |
5920 |
+ | T_LONG T_INT { $$ = ctype_long; } |
5921 |
+ | T_UNSIGNED T_LONG { $$ = ctype_ulong; } |
5922 |
+ | T_UNSIGNED T_LONG T_INT { $$ = ctype_ulong; } |
5923 |
+ | T_LONG T_LONG { $$ = ctype_longlong; } |
5924 |
+ | T_LONG T_LONG T_INT { $$ = ctype_longlong; } |
5925 |
+ | T_UNSIGNED T_LONG T_LONG { $$ = ctype_ulonglong; } |
5926 |
+ | T_UNSIGNED T_LONG T_LONG T_INT { $$ = ctype_ulonglong; } |
5927 |
+ | T_SHORT { $$ = ctype_short; } |
5928 |
+ | T_SHORT T_INT { $$ = ctype_short; } |
5929 |
+ | T_UNSIGNED T_SHORT { $$ = ctype_ushort; } |
5930 |
+ | T_UNSIGNED T_SHORT T_INT { $$ = ctype_ushort; } |
5931 |
+ | T_FLOAT { $$ = ctype_float ; } |
5932 |
+ | T_DOUBLE { $$ = ctype_double; } |
5933 |
+ | T_VOID { $$ = ctype_void; } |
5934 |
+ | T_STRUCT name |
5935 |
+ { $$ = duel_get_target_struct_tag($2.name); |
5936 |
+ if($$==NULL) yyerror("not a struct tag"); } |
5937 |
+ | T_UNION name |
5938 |
+ { $$ = duel_get_target_union_tag($2.name); |
5939 |
+ if($$==NULL) yyerror("not a union tag"); } |
5940 |
+ | T_ENUM name |
5941 |
+ { $$ = duel_get_target_enum_tag($2.name); |
5942 |
+ if($$==NULL) yyerror("not an enum tag"); } |
5943 |
+ ; |
5944 |
+ |
5945 |
+name : T_SYM ; |
5946 |
+%% |
5947 |
+ |
5948 |
+static struct stoken { /* all opcodes we recognize */ |
5949 |
+ char *opstr ; /* op code as a string */ |
5950 |
+ int token ; /* token to return to yacc */ |
5951 |
+ int opcode ; /* opcode value associated with the token */ |
5952 |
+ } tokens[] = { /* the special tokens, longer ones 1st! */ |
5953 |
+ {">>=",T_ASSIGN, OP_RSH}, |
5954 |
+ {"<<=",T_ASSIGN, OP_LSH}, |
5955 |
+ {"-->",T_DFS, OP_DFS}, |
5956 |
+ {"->>",T_BFS, OP_BFS}, |
5957 |
+ {"==?", T_EQQ, OP_EQQ}, |
5958 |
+ {"!=?", T_NEQ, OP_NEQ}, |
5959 |
+ {"<=?", T_LEQ, OP_LEQ}, |
5960 |
+ {">=?", T_GEQ, OP_GEQ}, |
5961 |
+ {"&&/", T_ANDL, OP_AND}, |
5962 |
+ {"||/", T_ORL, OP_OR}, |
5963 |
+ |
5964 |
+ {"<?", T_LSQ, OP_LSQ}, |
5965 |
+ {">?", T_GTQ, OP_GTQ}, |
5966 |
+ {"#/", T_COUNT, '#' }, |
5967 |
+ {"%/", T_COUNT, '#' }, /* gdb insists to recognize # as start of comma!*/ |
5968 |
+ {"%%", '#', '#' }, /* same. so %/ for #/ and %% for #. not doc!*/ |
5969 |
+ {"+=", T_ASSIGN, '+'}, |
5970 |
+ {"-=", T_ASSIGN, '-'}, |
5971 |
+ {"*=", T_ASSIGN, '*'}, |
5972 |
+ {"/=", T_ASSIGN, '/'}, |
5973 |
+ {"%=", T_ASSIGN, '%'}, |
5974 |
+ {"|=", T_ASSIGN, '|'}, |
5975 |
+ {"&=", T_ASSIGN, '&'}, |
5976 |
+ {"^=", T_ASSIGN, '^'}, |
5977 |
+ {":=", T_DEFVAR,OP_DEF}, |
5978 |
+ {"++", T_INC, OP_INC }, |
5979 |
+ {"--", T_DEC, OP_DEC }, |
5980 |
+ {"->", T_ARROW, OP_ARR }, |
5981 |
+ {"&&", T_AND, OP_AND }, |
5982 |
+ {"||", T_OR, OP_OR }, |
5983 |
+ {"<<", T_LSH, OP_LSH }, |
5984 |
+ {">>", T_RSH, OP_RSH }, |
5985 |
+ {"==", T_EQ, OP_EQ }, |
5986 |
+ {"!=", T_NE, OP_NE }, |
5987 |
+ {"<=", T_LE, OP_LE }, |
5988 |
+ {">=", T_GE, OP_GE }, |
5989 |
+ {"..", T_TO, OP_TO }, |
5990 |
+ {"=>", T_IMP, OP_IMP }, |
5991 |
+ {"[[", T_OSEL, OP_SEL }, |
5992 |
+ {"]]", T_CSEL, OP_SEL }, |
5993 |
+ }; |
5994 |
+ |
5995 |
+static struct skeyword { /* all keywords we recognize */ |
5996 |
+ char *keyword_str ; /* keyword as a string */ |
5997 |
+ int token ; /* token to return to yacc */ |
5998 |
+ topcode opcode ; /* opcode associated w/keyword */ |
5999 |
+ } keywords[] = { |
6000 |
+ {"if", T_IF , OP_IF}, |
6001 |
+ {"else", T_ELSE }, |
6002 |
+ {"for", T_FOR , OP_FOR}, |
6003 |
+ {"while", T_WHILE , OP_WHILE}, |
6004 |
+ {"sizeof", T_SIZEOF , OP_SIZ}, |
6005 |
+ {"frame", T_FRAME , OP_FRAME}, |
6006 |
+ |
6007 |
+ {"T", T_TYPEDEF_INDICATOR }, |
6008 |
+ {"struct", T_STRUCT }, |
6009 |
+ {"union", T_UNION }, |
6010 |
+ {"enum", T_ENUM }, |
6011 |
+ |
6012 |
+ {"unsigned",T_UNSIGNED }, |
6013 |
+ {"signed", T_SIGNED }, |
6014 |
+ {"short", T_SHORT }, |
6015 |
+ {"long", T_LONG }, |
6016 |
+ {"char", T_CHAR }, |
6017 |
+ {"int", T_INT }, |
6018 |
+ {"double", T_DOUBLE }, |
6019 |
+ {"float", T_FLOAT }, |
6020 |
+ {"void", T_VOID }, |
6021 |
+ } ; |
6022 |
+ |
6023 |
+ |
6024 |
+LFUNC tnode* duel_lex_int(void) /* parse next token as integer num */ |
6025 |
+{ |
6026 |
+ tnode *n ; |
6027 |
+ tulonglong val=0 ; |
6028 |
+ char *p=lexptr ; |
6029 |
+ bool is_l=0,is_u=0 ; |
6030 |
+ int base=10 ; |
6031 |
+ int src_pos=lexptr-inputstr ; |
6032 |
+ |
6033 |
+ if(*p=='0') { /* figure out the base */ |
6034 |
+ p++ ; |
6035 |
+ if(*p=='x' || *p=='X') base=16,p++ ; |
6036 |
+ else |
6037 |
+ if(isdigit(*p)) base=8 ; /* avoid having '0' as a base 8 (uint) */ |
6038 |
+ } |
6039 |
+ |
6040 |
+ while(isdigit(*p) || base==16 && isxdigit(*p)) { /* get the value */ |
6041 |
+ val*=base ; |
6042 |
+ if(isupper(*p)) val+= *p-'A'+10 ; |
6043 |
+ else if(islower(*p)) val+= *p-'a'+10 ; |
6044 |
+ else val+= *p-'0' ; |
6045 |
+ p++ ; |
6046 |
+ } |
6047 |
+ for (;*p;p++) { /* yuk. figure 0L etc */ |
6048 |
+ if (*p == 'l' || *p == 'L') is_l++; |
6049 |
+ else if(*p == 'u' || *p == 'U') is_u++; |
6050 |
+ else break; |
6051 |
+ } |
6052 |
+ is_u=is_u || base!=10 ; |
6053 |
+ |
6054 |
+ if((is_l>1 && is_u) || (long long) val < 0 || ((tulong) val != val && is_u)) { |
6055 |
+ n=mknode_const(src_pos,ctype_ulonglong); |
6056 |
+ n->cnst.u.rval_ulonglong=val ; |
6057 |
+ } |
6058 |
+ else |
6059 |
+ if(is_l>1 || (tulong) val != val) { |
6060 |
+ n=mknode_const(src_pos,ctype_longlong) ; |
6061 |
+ n->cnst.u.rval_longlong=(long long) val ; |
6062 |
+ } |
6063 |
+ else |
6064 |
+ if((is_l && is_u) || (long) val < 0 || ((tuint) val != val && is_u)) { |
6065 |
+ n=mknode_const(src_pos,ctype_ulong); |
6066 |
+ n->cnst.u.rval_ulong=val ; |
6067 |
+ } |
6068 |
+ else |
6069 |
+ if(is_l || (tuint) val != val) { |
6070 |
+ n=mknode_const(src_pos,ctype_long) ; |
6071 |
+ n->cnst.u.rval_long=(long) val ; |
6072 |
+ } |
6073 |
+ else |
6074 |
+ if(is_u || (int) val < 0) { |
6075 |
+ n=mknode_const(src_pos,ctype_uint) ; |
6076 |
+ n->cnst.u.rval_uint=(tuint) val ; |
6077 |
+ } |
6078 |
+ else { |
6079 |
+ n=mknode_const(src_pos,ctype_int) ; |
6080 |
+ n->cnst.u.rval_int=(int) val ; |
6081 |
+ } |
6082 |
+ strncpyz(n->cnst.symb_val,lexptr,p-lexptr); /* save the symbolic val*/ |
6083 |
+ lexptr=p ; |
6084 |
+ return n ; |
6085 |
+} |
6086 |
+ |
6087 |
+LFUNC tnode* duel_lex_float(void) /* parse next token as float num */ |
6088 |
+{ |
6089 |
+ tnode *n=0 ; |
6090 |
+ char *p=lexptr ; |
6091 |
+ double val ; |
6092 |
+ char c,tmpc ; |
6093 |
+ bool ok=TRUE; |
6094 |
+ int src_pos = lexptr - inputstr ; |
6095 |
+ |
6096 |
+ /* this is disgusting.. why isnt there a lib call to recognize floats?! */ |
6097 |
+ while(isdigit(*p)) p++ ; |
6098 |
+ if(*p=='.') p++ ; |
6099 |
+ while(isdigit(*p)) p++ ; |
6100 |
+ if(*p=='e' || *p=='E') { |
6101 |
+ p++ ; |
6102 |
+ if(*p=='+' || *p=='-') p++ ; |
6103 |
+ if(!isdigit(*p)) ok=FALSE ; /* force digit (scanf allows 1e-.2 ?!) */ |
6104 |
+ while(isdigit(*p)) p++ ; |
6105 |
+ } |
6106 |
+ tmpc= *p ; *p=0 ; |
6107 |
+ ok=ok && sscanf(lexptr,"%lf%c",&val,&c)==1 ; |
6108 |
+ *p=tmpc ; |
6109 |
+ if(!ok) yyerror("Invalid float constant."); |
6110 |
+ |
6111 |
+ n=mknode_const(src_pos,ctype_double); |
6112 |
+ n->cnst.u.rval_double=val ; |
6113 |
+ strncpyz(n->cnst.symb_val,lexptr,p-lexptr); /* save the symbolic val*/ |
6114 |
+ lexptr=p ; |
6115 |
+ return(n); |
6116 |
+} |
6117 |
+ |
6118 |
+/* parse_escaped_char -- parse an escaped char (e.g. '\n'). |
6119 |
+ * lexptr expected to point to text right after the '\'. |
6120 |
+ * return: actual char value (e.g. 012 if 'n' or '012' is found.) |
6121 |
+ * lexptr is advanced after the espaced char. |
6122 |
+ */ |
6123 |
+ |
6124 |
+LFUNC char parse_escaped_char(void) |
6125 |
+{ |
6126 |
+ char retc ; |
6127 |
+ switch(lexptr[0]) { |
6128 |
+ /*case 'a': retc='\a' ; break ; /* some compilers don't support it. */ |
6129 |
+ case 'b': retc='\b' ; break ; |
6130 |
+ case 'f': retc='\f' ; break ; |
6131 |
+ case 'n': retc='\n' ; break ; |
6132 |
+ case 'r': retc='\r' ; break ; |
6133 |
+ case 't': retc='\t' ; break ; |
6134 |
+ case 'v': retc='\v' ; break ; |
6135 |
+ case 'x': yyerror("hex char const not yet suppported"); |
6136 |
+ case '0': case '1': case '2': case '3': |
6137 |
+ retc= lexptr[0] - '0' ; |
6138 |
+ if(lexptr[1]>='0' && lexptr[1]<='7') |
6139 |
+ retc= retc* 010 + *++lexptr - '0' ; |
6140 |
+ if(lexptr[1]>='0' && lexptr[1]<='7') |
6141 |
+ retc= retc* 010 + *++lexptr - '0' ; |
6142 |
+ break ; |
6143 |
+ default: retc=lexptr[0] ; /* default also takes care of '\'' '\\' */ |
6144 |
+ } |
6145 |
+ lexptr++ ; |
6146 |
+ return retc ; |
6147 |
+} |
6148 |
+ |
6149 |
+/* FUNC yylex -- return the next token to yacc. |
6150 |
+ * GLOBALS: lexptr point to the string we are parsing next. it is updated. |
6151 |
+ */ |
6152 |
+ |
6153 |
+LFUNC int yylex (void) |
6154 |
+{ |
6155 |
+ int c,i,src_pos ; |
6156 |
+ char *p ; |
6157 |
+ |
6158 |
+ for(c= *lexptr; c==' ' || c=='\t' || c=='\n' ; c= *++lexptr); /* skip blank*/ |
6159 |
+ |
6160 |
+ src_pos = lexptr - inputstr ; /* current char being parsed */ |
6161 |
+ yylval.opinfo.src_pos = src_pos ; |
6162 |
+ |
6163 |
+ if(*lexptr=='\0' || strncmp(lexptr,"|>",2)==0) return 0 ; /* end of expr */ |
6164 |
+ |
6165 |
+ for (i = 0; i < sizeof(tokens)/sizeof(struct stoken) ; i++) { |
6166 |
+ int l=strlen(tokens[i].opstr) ; /* check next token vs table */ |
6167 |
+ if(strncmp(lexptr,tokens[i].opstr,l)==0) { |
6168 |
+ lexptr+=l ; |
6169 |
+ yylval.opinfo.opcode = tokens[i].opcode; |
6170 |
+ return tokens[i].token ; |
6171 |
+ } |
6172 |
+ } |
6173 |
+ |
6174 |
+ switch (c = *lexptr) { |
6175 |
+ case '\'': /* char constant, but stored as int (ansi-c) */ |
6176 |
+ p=lexptr++ ; |
6177 |
+ c = *lexptr++ ; |
6178 |
+ if (c == '\\') c=parse_escaped_char(); |
6179 |
+ if( *lexptr++ != '\'') yyerror("Invalid character constant."); |
6180 |
+ yylval.node=mknode_const(src_pos,ctype_int) ; |
6181 |
+ yylval.node->cnst.u.rval_int=c ; |
6182 |
+ strncpyz(yylval.node->cnst.symb_val,p,lexptr-p); /*save the symbol. val*/ |
6183 |
+ return T_CONST ; |
6184 |
+ |
6185 |
+ case '0': /* chk hex */ |
6186 |
+ if(lexptr[1]=='x' || lexptr[1]=='X') { |
6187 |
+ yylval.node=duel_lex_int(); |
6188 |
+ return T_CONST ; |
6189 |
+ } |
6190 |
+ /* fall thru for other numbers */ |
6191 |
+ case '1': case '2': case '3': /* decimal or floating point number */ |
6192 |
+ case '4': case '5': case '6': case '7': case '8': case '9': |
6193 |
+ for(p=lexptr ; *p>='0' && *p<='9' ; p++ ) ; /*find next non digit*/ |
6194 |
+ if(*p=='.' && p[1]!='.' || *p=='e' || *p=='E') |
6195 |
+ yylval.node=duel_lex_float(); |
6196 |
+ else yylval.node=duel_lex_int(); |
6197 |
+ return T_CONST ; |
6198 |
+ |
6199 |
+ case '(': case ')': |
6200 |
+ case '<': case '>': |
6201 |
+ case '[': case ']': |
6202 |
+ case '{': case '}': |
6203 |
+ case '+': case '-': case '*': case '/': case '%': |
6204 |
+ case '|': case '&': case '^': case '~': case '!': |
6205 |
+ case ',': case '?': case ':': case '=': |
6206 |
+ case '.': case '@': case '$': case '#': case '`': case '\\': |
6207 |
+ lexptr++; |
6208 |
+ yylval.opinfo.opcode=c ; |
6209 |
+ return c; |
6210 |
+ case ';': { /* hack, ignore ';' before '}' and else. for C compatability*/ |
6211 |
+ char *save_lexptr= ++lexptr ; |
6212 |
+ int tok=yylex() ; /* hack, call myself for next token */ |
6213 |
+ if(tok=='}' || tok==T_ELSE) { |
6214 |
+ duel_printf("warning: useless ';' ignored\n"); |
6215 |
+ return tok ; |
6216 |
+ } |
6217 |
+ /* else restore position and return the ';' */ |
6218 |
+ lexptr=save_lexptr ; |
6219 |
+ yylval.opinfo.opcode=';' ; |
6220 |
+ yylval.opinfo.src_pos = src_pos ; |
6221 |
+ return ';'; |
6222 |
+ } |
6223 |
+ case '"': { |
6224 |
+ char s[512] ; |
6225 |
+ size_t len=0 ; |
6226 |
+ ttarget_ptr dptr ; |
6227 |
+ tnode *n ; |
6228 |
+ |
6229 |
+ p=lexptr++ ; |
6230 |
+ while((c= *lexptr++)!='"') { |
6231 |
+ if (c == '\\') c=parse_escaped_char(); |
6232 |
+ s[len++]=c ; |
6233 |
+ } |
6234 |
+ s[len++]=0 ; |
6235 |
+ dptr=duel_alloc_target_space(len); |
6236 |
+ duel_put_target_bytes(dptr,s,len); |
6237 |
+ |
6238 |
+ n=mknode_const(src_pos,ctype_charptr); |
6239 |
+ n->cnst.u.rval_ptr=dptr ; |
6240 |
+ len=lexptr-p ; |
6241 |
+ if(len>60) len=60 ; |
6242 |
+ strncpyz(n->cnst.symb_val,p,len); /* save the symbolic val*/ |
6243 |
+ yylval.node=n ; |
6244 |
+ return T_CONST ; |
6245 |
+ } |
6246 |
+ } |
6247 |
+ |
6248 |
+ if(c != '_' && !isalpha(c)) |
6249 |
+ yyerror ("Invalid character in expression."); |
6250 |
+ |
6251 |
+ p=lexptr ; |
6252 |
+ do { c= *++lexptr ; } while(c=='_' || isalnum(c)); |
6253 |
+ |
6254 |
+ for (i = 0; i < sizeof(keywords)/sizeof(struct skeyword) ; i++) { |
6255 |
+ int l=strlen(keywords[i].keyword_str) ; /* check next token vs keywords*/ |
6256 |
+ if(l==lexptr-p && strncmp(p,keywords[i].keyword_str,l)==0) { |
6257 |
+ yylval.opinfo.opcode=keywords[i].opcode ; |
6258 |
+ return keywords[i].token ; |
6259 |
+ } |
6260 |
+ } |
6261 |
+ |
6262 |
+ /* the symbol/name found is not a reserved word, so return it as a T_SYM |
6263 |
+ */ |
6264 |
+ |
6265 |
+ i=lexptr-p ; /* length of string found (symbol/name) */ |
6266 |
+ yylval.nameinfo.src_pos=src_pos ; |
6267 |
+ yylval.nameinfo.name=duel_malloc(i+1); |
6268 |
+ strncpyz(yylval.nameinfo.name,p,i); |
6269 |
+ return T_SYM; |
6270 |
+} |
6271 |
+ |
6272 |
+LPROC yyerror(char *msg) |
6273 |
+{ |
6274 |
+ int i,n=lexptr-inputstr ; |
6275 |
+ duel_printf("%s\n",inputstr); |
6276 |
+ for(i=0 ; i<n ; i++) duel_printf("-"); |
6277 |
+ duel_printf("^ %s\n",msg); |
6278 |
+ duel_abort(); /* terminate parsing. some callers depend on this*/ |
6279 |
+} |
6280 |
+ |
6281 |
+/*************************************************************************/ |
6282 |
+/* utility functions used to parse the expression and build it as a tree */ |
6283 |
+/*************************************************************************/ |
6284 |
+ |
6285 |
+/* mknode_op -- make a tree node of type op with given opcode and kids |
6286 |
+ */ |
6287 |
+ |
6288 |
+LFUNC tnode* mknode_op(top_kind op_kind,topinfo opinfo, |
6289 |
+ tnode *k1,tnode *k2,tnode *k3,tnode *k4) |
6290 |
+{ |
6291 |
+ tnode *n ; |
6292 |
+ duel_assert(opinfo.opcode>' '); |
6293 |
+ n=(tnode *) duel_malloc(sizeof(tnode)); |
6294 |
+ duel_bzero((char*) n,sizeof(tnode)); |
6295 |
+ n->node_kind=NK_OP ; |
6296 |
+ n->op_kind=op_kind ; |
6297 |
+ n->op=opinfo.opcode ; |
6298 |
+ n->src_pos=opinfo.src_pos ; |
6299 |
+ n->kids[0]=k1 ; n->kids[1]=k2 ; n->kids[2]=k3 ; n->kids[3]=k4 ; |
6300 |
+ return n ; |
6301 |
+} |
6302 |
+ |
6303 |
+ |
6304 |
+ /* mknode_const -- make a constant node for the given type. |
6305 |
+ */ |
6306 |
+ |
6307 |
+LFUNC tnode* mknode_const(int src_pos,tctype *ctype) |
6308 |
+{ |
6309 |
+ tnode *n ; |
6310 |
+ n=(tnode *) duel_malloc(sizeof(tnode)); |
6311 |
+ duel_bzero((char*) n,sizeof(tnode)); |
6312 |
+ n->node_kind=NK_CONST ; |
6313 |
+ n->src_pos=src_pos ; |
6314 |
+ n->cnst.val_kind=VK_RVALUE ; |
6315 |
+ n->cnst.ctype=ctype ; |
6316 |
+ return n ; |
6317 |
+} |
6318 |
+ |
6319 |
+ /* mknode_ctype -- make a node of the given c-type. |
6320 |
+ */ |
6321 |
+ |
6322 |
+LFUNC tnode* mknode_ctype(tctype *ctype) |
6323 |
+{ |
6324 |
+ tnode *n ; |
6325 |
+ n=(tnode *) duel_malloc(sizeof(tnode)); |
6326 |
+ duel_bzero((char*) n,sizeof(tnode)); |
6327 |
+ n->node_kind=NK_CTYPE ; |
6328 |
+ n->ctype=ctype ; |
6329 |
+ return n ; |
6330 |
+} |
6331 |
+ |
6332 |
+ /* mknode_name -- make a node of the given name/symbol. |
6333 |
+ * input is pointer to the saved name (on heap) |
6334 |
+ */ |
6335 |
+ |
6336 |
+LFUNC tnode* mknode_name(tnameinfo nameinfo) |
6337 |
+{ |
6338 |
+ tnode *n ; |
6339 |
+ n=(tnode *) duel_malloc(sizeof(tnode)); |
6340 |
+ duel_bzero((char*) n,sizeof(tnode)); |
6341 |
+ n->node_kind=NK_NAME ; |
6342 |
+ n->name=nameinfo.name ; |
6343 |
+ n->src_pos=nameinfo.src_pos ; |
6344 |
+ return n ; |
6345 |
+} |
6346 |
+ |
6347 |
+/* In order to parse C types, which are 'reversed' in the parser, a stack |
6348 |
+ * is used to push abstract declarators, e.g. in (*)() we first push a func |
6349 |
+ * indicator '(' and then push a pointer indicator '*'. for arrays we push |
6350 |
+ * a '[' and the array size. |
6351 |
+ * This stack is popped and a ctype is constructed at the end of the |
6352 |
+ * abstract type parsing. The following functions implement the stack |
6353 |
+ */ |
6354 |
+ |
6355 |
+typedef struct stype_desc { /* stack of type descriptors is made of these */ |
6356 |
+ char desc ; |
6357 |
+ int size ; |
6358 |
+ struct stype_desc *next ; /* next on stack */ |
6359 |
+ } ttype_desc ; |
6360 |
+ |
6361 |
+ttype_desc *top = 0 ; |
6362 |
+ |
6363 |
+ |
6364 |
+LPROC push_type(char desc) /* put desc on the types stack */ |
6365 |
+{ |
6366 |
+ ttype_desc *p = (ttype_desc* ) duel_malloc(sizeof(ttype_desc)); |
6367 |
+ p->desc=desc ; |
6368 |
+ p->size=0 ; |
6369 |
+ p->next=top ; |
6370 |
+ top=p ; |
6371 |
+} |
6372 |
+ |
6373 |
+/* push_type_int -- same as push_type but also set the size parameter, which |
6374 |
+ * is given as a constant node (which is expected to be int) |
6375 |
+ */ |
6376 |
+ |
6377 |
+LPROC push_type_int(char desc,tnode *n) |
6378 |
+{ |
6379 |
+ duel_assert(n->node_kind==NK_CONST); |
6380 |
+ if(n->cnst.ctype != ctype_int || |
6381 |
+ n->cnst.u.rval_int <=0 ) duel_gen_error("Illegal array size",0); |
6382 |
+ push_type(desc); |
6383 |
+ top->size=n->cnst.u.rval_int ; |
6384 |
+} |
6385 |
+ |
6386 |
+LFUNC bool pop_type(char *desc,int *size) /* pop item from stack. */ |
6387 |
+{ |
6388 |
+ ttype_desc *p = top ; |
6389 |
+ if(p==0) return FALSE ; |
6390 |
+ *desc=p->desc ; |
6391 |
+ *size=p->size ; |
6392 |
+ top=p->next ; |
6393 |
+ duel_free(p) ; |
6394 |
+ return TRUE ; |
6395 |
+} |
6396 |
+ |
6397 |
+ |
6398 |
+/* abstract type-modifiers were pushed on a stack. Retrieve |
6399 |
+ * them (reversed) creating type nodes as we go |
6400 |
+ * input: base type (e.g. 'long'). |
6401 |
+ * returns: node of the modified type. |
6402 |
+ * modification is based on the stack of things pushed while parsing. |
6403 |
+ */ |
6404 |
+ |
6405 |
+LFUNC tnode* mknode_modified_ctype(tctype *base) |
6406 |
+{ |
6407 |
+ int size; |
6408 |
+ char tdesc ; /* descriptor of abs decl eg '*' */ |
6409 |
+ tctype *t=base ; /* type under construction */ |
6410 |
+ |
6411 |
+ while(pop_type(&tdesc,&size)) /* pop next abs decl */ |
6412 |
+ switch (tdesc) { |
6413 |
+ case '*': t=duel_mkctype_ptr(t); break ; |
6414 |
+ case '(': t=duel_mkctype_func(t); break ; |
6415 |
+ case '[': t=duel_mkctype_array(t,size); break ; |
6416 |
+ } |
6417 |
+ return mknode_ctype(t) ; |
6418 |
+} |
6419 |
+ |
6420 |
+/* entry point for parsing. the given expression is parsed into the given |
6421 |
+ * node as root. |
6422 |
+ */ |
6423 |
+ |
6424 |
+FUNC tnode* duel_parse(char *s) |
6425 |
+{ |
6426 |
+ lexptr=inputstr=s ; |
6427 |
+ top=0 ; /* reset the types stack */ |
6428 |
+ if(duel_yyparse()) root=NULL ; |
6429 |
+ return root ; |
6430 |
+} |
6431 |
--- gdb/duel/patchlevel.h |
6432 |
+++ gdb/duel/patchlevel.h |
6433 |
@@ -0,0 +1,7 @@ |
6434 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
6435 |
+/* Public domain code */ |
6436 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
6437 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
6438 |
+ |
6439 |
+#define PATCHLEVEL 4 |
6440 |
+#define VERSION "DUEL 1.20" |
6441 |
--- gdb/duel/print.c |
6442 |
+++ gdb/duel/print.c |
6443 |
@@ -0,0 +1,300 @@ |
6444 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
6445 |
+/* Public domain code */ |
6446 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
6447 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
6448 |
+ |
6449 |
+/* handle value/type printing */ |
6450 |
+ |
6451 |
+/* |
6452 |
+ * $Log: 10_all_gdb-6.6-duel.patch,v $ |
6453 |
+ * Revision 1.1 2007/12/29 21:06:06 vapier |
6454 |
+ * add DUEL support #199987 by Sergei Golubchik |
6455 |
+ * |
6456 |
+ * Revision 1.9 93/03/12 06:01:00 mg |
6457 |
+ * cosmetics: tuint for uint, etc. |
6458 |
+ * display union like structs |
6459 |
+ * suport piped output |
6460 |
+ * note for all pointers if illegal, better handling of string bad pointers |
6461 |
+ * |
6462 |
+ * Revision 1.8 93/02/27 06:06:50 mg |
6463 |
+ * removed usage of fabs() so -lm is not required in gdb's linking (HP9000) |
6464 |
+ * |
6465 |
+ * Revision 1.7 93/02/26 05:00:42 mg |
6466 |
+ * fixed display of *p for void *p |
6467 |
+ * |
6468 |
+ * Revision 1.6 93/02/23 20:57:56 mg |
6469 |
+ * *** empty log message *** |
6470 |
+ * |
6471 |
+ * Revision 1.5 93/02/23 19:16:00 mg |
6472 |
+ * improved escaped char support |
6473 |
+ * |
6474 |
+ * Revision 1.4 93/02/03 21:54:49 mg |
6475 |
+ * support "signed char" |
6476 |
+ * |
6477 |
+ * Revision 1.3 93/01/12 21:53:45 mg |
6478 |
+ * cleanup and set for release |
6479 |
+ * |
6480 |
+ * Revision 1.2 93/01/07 00:14:34 mg |
6481 |
+ * print union name |
6482 |
+ * |
6483 |
+ * Revision 1.1 93/01/03 07:31:55 mg |
6484 |
+ * Initial revision |
6485 |
+ * |
6486 |
+ */ |
6487 |
+ |
6488 |
+#include "duel.h" |
6489 |
+ |
6490 |
+/* print type information (no new lines) |
6491 |
+ * parm 'expand' controls expansion level for structs & unions. normally 1. |
6492 |
+ */ |
6493 |
+ |
6494 |
+PROC duel_print_type(tctype *t,int expand) |
6495 |
+{ |
6496 |
+ int i ; |
6497 |
+ tctype *kid=t->u.kid ; |
6498 |
+ |
6499 |
+ switch(t->type_kind) { |
6500 |
+ case CTK_VOID: duel_printf("void ") ; break ; |
6501 |
+ case CTK_CHAR: duel_printf("char ") ; break ; |
6502 |
+ case CTK_SCHAR: duel_printf("schar ") ; break ; |
6503 |
+ case CTK_UCHAR: duel_printf("uchar ") ; break ; |
6504 |
+ case CTK_USHORT: duel_printf("ushort ") ; break ; |
6505 |
+ case CTK_SHORT: duel_printf("short ") ; break ; |
6506 |
+ case CTK_INT: duel_printf("int ") ; break ; |
6507 |
+ case CTK_UINT: duel_printf("uint ") ; break ; |
6508 |
+ case CTK_LONG: duel_printf("long ") ; break ; |
6509 |
+ case CTK_ULONG: duel_printf("ulong ") ; break ; |
6510 |
+ case CTK_LONGLONG: duel_printf("longong ") ; break ; |
6511 |
+ case CTK_ULONGLONG: duel_printf("ulonglong ") ; break ; |
6512 |
+ case CTK_FLOAT: duel_printf("float ") ; break ; |
6513 |
+ case CTK_DOUBLE: duel_printf("double ") ; break ; |
6514 |
+ case CTK_ENUM: duel_printf("enum %s ",t->name); break ; |
6515 |
+ |
6516 |
+ case CTK_PTR: |
6517 |
+ if(ctype_kind_base(kid)) { |
6518 |
+ duel_print_type(kid,0); |
6519 |
+ duel_printf("* "); |
6520 |
+ } |
6521 |
+ else { |
6522 |
+ duel_printf("ptr to "); |
6523 |
+ duel_print_type(kid,expand-1) ; |
6524 |
+ } |
6525 |
+ break ; |
6526 |
+ case CTK_ARRAY: { |
6527 |
+ int n=t->size ; |
6528 |
+ if(kid->size>0) n/=kid->size ; |
6529 |
+ |
6530 |
+ if(ctype_kind_base(kid)) { |
6531 |
+ duel_print_type(kid,0); |
6532 |
+ duel_printf("[%d] ",n); |
6533 |
+ } |
6534 |
+ else { |
6535 |
+ duel_printf("array [%d] of ",n); |
6536 |
+ duel_print_type(kid,expand) ; |
6537 |
+ } |
6538 |
+ } |
6539 |
+ break ; |
6540 |
+ case CTK_FUNC: duel_printf("func returning "); |
6541 |
+ duel_print_type(kid,expand); |
6542 |
+ break ; |
6543 |
+ case CTK_STRUCT: |
6544 |
+ if(expand <= 0) { |
6545 |
+ duel_printf("struct %s ",t->name); |
6546 |
+ break ; |
6547 |
+ } |
6548 |
+ duel_printf("struct %s { ",t->name) ; |
6549 |
+ for(i=0 ; i<t->u.f.fields_no ; i++) { |
6550 |
+ tctype_field *f= &t->u.f.fields[i] ; |
6551 |
+ duel_print_type(f->ctype,expand-1); |
6552 |
+ duel_printf("%s ",f->name); |
6553 |
+ if(f->bitlen != 0) duel_printf(":%d ",f->bitlen); |
6554 |
+ duel_printf("; "); |
6555 |
+ } |
6556 |
+ duel_printf("} ; "); |
6557 |
+ break ; |
6558 |
+ case CTK_UNION: duel_printf("union %s",t->name) ; break ; |
6559 |
+ default: duel_assert(0); |
6560 |
+ } |
6561 |
+} |
6562 |
+ |
6563 |
+/* display char 'c' in a "neat" way, e.g. c='\n' is displayed as such, |
6564 |
+ * etc. Special case for c==quote (normally ' or "), we add '\\' |
6565 |
+ * return a pointer to a static string which is overriden each call etc |
6566 |
+ */ |
6567 |
+char *neat_char(char c,char quote) |
6568 |
+{ |
6569 |
+ static char s[8] ; |
6570 |
+ switch(c) { |
6571 |
+ case '\0': strcpy(s,"\\0"); break ; |
6572 |
+ case '\n': strcpy(s,"\\n"); break ; |
6573 |
+ case '\r': strcpy(s,"\\r"); break ; |
6574 |
+ case '\t': strcpy(s,"\\t"); break ; |
6575 |
+ case '\\': strcpy(s,"\\\\"); break ; |
6576 |
+ default: |
6577 |
+ if(!isprint(c) || !isascii(c)) sprintf(s,"\\%3.3o",c & 0377); |
6578 |
+ else |
6579 |
+ if(c==quote) sprintf(s,"\\%c",c); |
6580 |
+ else sprintf(s,"%c",c); |
6581 |
+ } |
6582 |
+ return s ; |
6583 |
+} |
6584 |
+ |
6585 |
+/* print the given scalar value into string s. |
6586 |
+ * for none-scalar values, print the lval's address. |
6587 |
+ * note: v's value is not modified. |
6588 |
+ */ |
6589 |
+ |
6590 |
+PROC duel_sprint_scalar_value(char *s,tvalue *v) |
6591 |
+{ |
6592 |
+ bool ok ; |
6593 |
+ tvalue rval ; /* copy of v, but as an rval */ |
6594 |
+ rval = *v ; |
6595 |
+ if(v->val_kind==VK_FVALUE) { |
6596 |
+ sprintf(s,"frame(%d)",v->u.fvalue); |
6597 |
+ return ; |
6598 |
+ } |
6599 |
+ if(v->val_kind==VK_LVALUE) { |
6600 |
+ char tmpstr[256],*m="" ; /* tmpstr= temporary for check, m= message */ |
6601 |
+ int sz = v->ctype->size ; /* size of object ref. */ |
6602 |
+ if(sz<1) sz=1 ; |
6603 |
+ if(sz>256) sz=256 ; |
6604 |
+ /* check for null and bad (try read sz bytes at addr ) references */ |
6605 |
+ if(v->u.lvalue==NULL || |
6606 |
+ !duel_get_target_bytes(v->u.lvalue,tmpstr,sz)) m=" [ILLEGAL]" ; |
6607 |
+ |
6608 |
+ switch(v->ctype->type_kind) { |
6609 |
+ case CTK_VOID: sprintf(s,"void @%p%s",v->u.lvalue,m); return; |
6610 |
+ case CTK_STRUCT: sprintf(s,"struct @%p%s",v->u.lvalue,m); return; |
6611 |
+ case CTK_UNION: sprintf(s,"union @%p%s",v->u.lvalue,m); return; |
6612 |
+ case CTK_FUNC: sprintf(s,"func @%p%s",v->u.lvalue,m) ; return; |
6613 |
+ case CTK_ARRAY: |
6614 |
+ if(*m!='\0' || v->ctype->u.kid!=ctype_char) { |
6615 |
+ sprintf(s,"array @%p%s",v->u.lvalue,m); |
6616 |
+ return; |
6617 |
+ } |
6618 |
+ } |
6619 |
+ /* convert scalar type to rvalue */ |
6620 |
+ if(!duel_try_get_rvalue(&rval,"")) { |
6621 |
+ sprintf(s,"ref @%p [ILLEGAL]",v->u.lvalue,m); |
6622 |
+ return ; |
6623 |
+ } |
6624 |
+ } |
6625 |
+ else |
6626 |
+ if(v->val_kind==VK_BVALUE) { |
6627 |
+ if(!duel_try_get_rvalue(&rval,"")) { |
6628 |
+ sprintf(s,"ref @%p [ILLEGAL]",v->u.bvalue.lvalue); |
6629 |
+ return ; |
6630 |
+ } |
6631 |
+ } |
6632 |
+ |
6633 |
+ switch(rval.ctype->type_kind) { /* handle rvalues */ |
6634 |
+ case CTK_VOID: sprintf(s,"void") ; break ; |
6635 |
+ case CTK_CHAR: sprintf(s,"'%s'",neat_char(rval.u.rval_char,'\''));break; |
6636 |
+ case CTK_SHORT: sprintf(s,"%d", rval.u.rval_short) ; break ; |
6637 |
+ case CTK_INT: sprintf(s,"%d", rval.u.rval_int) ; break ; |
6638 |
+ case CTK_LONG: sprintf(s,"%ldL", rval.u.rval_long) ; break ; |
6639 |
+ case CTK_LONGLONG: sprintf(s,"%lldLL", rval.u.rval_longlong) ; break ; |
6640 |
+ case CTK_SCHAR: if(rval.u.rval_schar==0) sprintf(s,"'\\0'"); |
6641 |
+ else sprintf(s,"%d", rval.u.rval_schar) ; break ; |
6642 |
+ case CTK_UCHAR: if(rval.u.rval_uchar==0) sprintf(s,"'\\0'"); |
6643 |
+ else sprintf(s,"'\\x%d'", rval.u.rval_uchar) ; break ; |
6644 |
+ case CTK_USHORT: if(rval.u.rval_ushort==0) sprintf(s,"0"); |
6645 |
+ else sprintf(s,"0x%x", rval.u.rval_ushort) ; break ; |
6646 |
+ case CTK_UINT: if(rval.u.rval_uint==0) sprintf(s,"0"); |
6647 |
+ else sprintf(s,"0x%x", rval.u.rval_uint) ; break ; |
6648 |
+ case CTK_ULONG: if(rval.u.rval_ulong==0L) sprintf(s,"0"); |
6649 |
+ else sprintf(s,"0x%lxUL", rval.u.rval_ulong) ; break ; |
6650 |
+ case CTK_ULONGLONG: if(rval.u.rval_ulonglong==0L) sprintf(s,"0"); |
6651 |
+ else sprintf(s,"0x%llxULL", rval.u.rval_ulonglong) ; break ; |
6652 |
+ case CTK_FLOAT: rval.u.rval_double=rval.u.rval_float ; |
6653 |
+ case CTK_DOUBLE: { double x=rval.u.rval_double ; |
6654 |
+ if(x >= -1e-6 && x <= 1e-6 || x >= 1e8 || x <= -1e8) |
6655 |
+ sprintf(s,"%.4le",x); /* standard 'e' fmt */ |
6656 |
+ else { /* fixed point removing trailing '0'*/ |
6657 |
+ int l; |
6658 |
+ sprintf(s,"%.8lf",x); |
6659 |
+ l=strlen(s)-1; |
6660 |
+ while(s[l]=='0' && s[l-1]!='.') s[l--]=0 ; |
6661 |
+ } |
6662 |
+ } |
6663 |
+ break ; |
6664 |
+ case CTK_PTR: |
6665 |
+ if(rval.u.rval_ptr==NULL) sprintf(s,"NULL"); |
6666 |
+ else { |
6667 |
+ char sval[41]; |
6668 |
+ bool ok=duel_get_target_bytes(rval.u.lvalue,sval,1); |
6669 |
+ if(ok && rval.ctype->u.kid==ctype_char) { |
6670 |
+ int i ; |
6671 |
+ duel_get_target_bytes(rval.u.lvalue,sval,41); |
6672 |
+ strcpy(s,"\""); |
6673 |
+ for(i=0 ; i<40 && sval[i]!='\0' ; i++) |
6674 |
+ strcat(s,neat_char(sval[i],'"')); |
6675 |
+ if(sval[i]=='\0') strcat(s,"\""); |
6676 |
+ else strcat(s,"...\""); |
6677 |
+ } |
6678 |
+ else sprintf(s,"@%p%s",rval.u.rval_ptr,ok? "":" [ILLEGAL]"); |
6679 |
+ } |
6680 |
+ break ; |
6681 |
+ case CTK_ENUM: { |
6682 |
+ int i, n=rval.ctype->u.e.enumerators_no ; |
6683 |
+ tctype_enumerator *e=rval.ctype->u.e.enumerators ; |
6684 |
+ int val=duel_get_int_val(v,""); |
6685 |
+ for(i=0 ; i<n ; i++) |
6686 |
+ if(e[i].val == val) { strcpy(s,e[i].name); return ;} |
6687 |
+ sprintf(s,"%d",val); |
6688 |
+ } |
6689 |
+ break ; |
6690 |
+ default: duel_assert(0); |
6691 |
+ } |
6692 |
+} |
6693 |
+ |
6694 |
+/* print the given value, symbolic+val. Handles structures */ |
6695 |
+ |
6696 |
+PROC duel_print_value(tvalue *v) |
6697 |
+{ |
6698 |
+ tctype *t=v->ctype ; |
6699 |
+ int i ; |
6700 |
+ bool topipe=duel_output_pipe_style ; |
6701 |
+ char s[160]; |
6702 |
+ |
6703 |
+ duel_printf(topipe? "$$$SYM: %s\n":"%s",v->symb_val); |
6704 |
+ |
6705 |
+ if(duel_debug && !topipe) { |
6706 |
+ duel_printf("`` %s '' ",v->symb_val); |
6707 |
+ duel_printf("{ "); |
6708 |
+ duel_print_type(v->ctype,2); |
6709 |
+ duel_printf("} "); |
6710 |
+ if(v->val_kind==VK_LVALUE) { |
6711 |
+ duel_printf("lval @%p",v->u.lvalue); |
6712 |
+ } |
6713 |
+ else |
6714 |
+ if(v->val_kind==VK_BVALUE) { |
6715 |
+ duel_printf("bval @%p [%d,%d]",v->u.bvalue.lvalue,v->u.bvalue.bitpos, |
6716 |
+ v->u.bvalue.bitlen); |
6717 |
+ } |
6718 |
+ duel_printf("\n"); |
6719 |
+ } |
6720 |
+ |
6721 |
+ duel_sprint_scalar_value(s,v); |
6722 |
+ if(v->val_kind==VK_LVALUE && strstr(s,"ILLEGAL")==NULL) { |
6723 |
+ switch(t->type_kind) { |
6724 |
+ case CTK_UNION: |
6725 |
+ case CTK_STRUCT: |
6726 |
+ duel_printf(topipe? "$$$VAL: { " : " = { "); |
6727 |
+ for(i=0 ; i<t->u.f.fields_no ; i++) { |
6728 |
+ tvalue u ; |
6729 |
+ char *name=t->u.f.fields[i].name ; |
6730 |
+ duel_get_dot_name(v,name,&u); |
6731 |
+ duel_sprint_scalar_value(s,&u); |
6732 |
+ duel_printf("%s = %s",name,s) ; |
6733 |
+ if(i < t->u.f.fields_no-1) duel_printf(", "); |
6734 |
+ } |
6735 |
+ duel_printf(" }\n"); |
6736 |
+ return ; |
6737 |
+ case CTK_ARRAY: ; /* not handled except for char[] as scalar*/ |
6738 |
+ } |
6739 |
+ } |
6740 |
+ |
6741 |
+ if(topipe) duel_printf("$$$VAL: %s",s); |
6742 |
+ else |
6743 |
+ if(strcmp(v->symb_val,s)!=0) duel_printf(" = %s",s); |
6744 |
+ duel_printf("\n"); |
6745 |
+} |
6746 |
+ |
6747 |
--- gdb/duel/proto.h |
6748 |
+++ gdb/duel/proto.h |
6749 |
@@ -0,0 +1,101 @@ |
6750 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
6751 |
+/* Public domain code */ |
6752 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
6753 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
6754 |
+ |
6755 |
+/* prototypes for all of duel's global functions */ |
6756 |
+ |
6757 |
+FUNC tctype* duel_mkctype_ptr(tctype *t); |
6758 |
+FUNC tctype* duel_mkctype_func(tctype *t); |
6759 |
+FUNC tctype* duel_mkctype_array(tctype *t,int size); |
6760 |
+FUNC tctype* duel_mkctype_struct(char *name,size_t size,int fields_no, |
6761 |
+ bool is_union); |
6762 |
+PROC duel_mkctype_struct_field(tctype *t,int field_no,char *name, |
6763 |
+ int bitpos,int bitlen, tctype *fctype); |
6764 |
+FUNC tctype* duel_mkctype_enum(char *name,tctype_kind real_type_kind, |
6765 |
+ size_t size,int enumerators_no); |
6766 |
+PROC duel_mkctype_enumerator(tctype *t,int enumerator_no,char *name,int val); |
6767 |
+ |
6768 |
+PROC duel_init_basic_ctypes(void); |
6769 |
+ |
6770 |
+PROC duel_print_value(tvalue *v); |
6771 |
+PROC duel_print_type(tctype *t,int expand); |
6772 |
+PROC duel_sprint_scalar_value(char *s,tvalue *v); |
6773 |
+ |
6774 |
+ |
6775 |
+PROC duel_fatal(char *msg); |
6776 |
+PROC duel_abort(void); |
6777 |
+PROC duel_cleanup(void *); |
6778 |
+ |
6779 |
+FUNC tnode* duel_parse(char *s); |
6780 |
+ |
6781 |
+ |
6782 |
+PROC duel_reset_eval(void); |
6783 |
+FUNC bool duel_eval(tnode *n,tvalue *v); |
6784 |
+FUNC bool duel_get_dot_name(tvalue *v,char *name,tvalue *ret); |
6785 |
+ |
6786 |
+FUNC tnode* duel_set_eval_loc(tnode *n); |
6787 |
+FUNC char* duel_set_input_string(char *s); |
6788 |
+PROC duel_op_error(char *mesg,char *op,tvalue *v1,tvalue *v2); |
6789 |
+PROC duel_gen_error(char *mesg,char *arg1); |
6790 |
+ |
6791 |
+PROC duel_parse_and_eval(char *s); |
6792 |
+ |
6793 |
+FUNC bool duel_try_get_rvalue(tvalue *v,char *op); |
6794 |
+PROC duel_standardize_func_parm(tvalue *p); |
6795 |
+FUNC bool duel_do_op_to(tvalue *v1,tvalue *v2,int n,tvalue *r); |
6796 |
+PROC duel_do_cast(tctype *tout,tvalue *v); |
6797 |
+FUNC bool duel_mk_logical(tvalue *v,char *op); |
6798 |
+PROC duel_set_symb_val(tvalue *r,char *format,tvalue *v1,tvalue *v2); |
6799 |
+PROC duel_get_struct_val(tvalue *v,char *op); |
6800 |
+PROC duel_get_struct_ptr_val(tvalue *v,char *op); |
6801 |
+FUNC int duel_get_int_val(tvalue *v,char *op); |
6802 |
+FUNC int duel_get_posint_val(tvalue *v,char *op); |
6803 |
+PROC duel_apply_unary_op(topcode op,tvalue *v); |
6804 |
+PROC duel_apply_post_unary_op(topcode op,tvalue *v); |
6805 |
+FUNC bool duel_apply_bin_op(topcode op,tvalue *v1,tvalue *v2,tvalue *r); |
6806 |
+PROC duel_find_func_frame(tvalue *v,char *op); |
6807 |
+ |
6808 |
+/* output management */ |
6809 |
+ |
6810 |
+PROC duel_printf(char *fmt, ...); |
6811 |
+PROC duel_flush(void); |
6812 |
+PROC duel_redirectable_output_start(char *); |
6813 |
+PROC duel_redirectable_output_end(void); |
6814 |
+PROC duel_redirectable_output_abort(void); |
6815 |
+PROC duel_redirectable_output_init(void); |
6816 |
+ |
6817 |
+/* debugger dependent functions */ |
6818 |
+ |
6819 |
+FUNC void* duel_malloc(size_t size); |
6820 |
+PROC duel_free(void *); |
6821 |
+ |
6822 |
+FUNC bool duel_get_target_bytes(ttarget_ptr from,void *to,size_t n); |
6823 |
+FUNC bool duel_put_target_bytes(ttarget_ptr to,void *from,size_t n); |
6824 |
+ |
6825 |
+FUNC bool duel_get_target_bitfield(ttarget_ptr struct_at,int bitpos, |
6826 |
+ int bitlen,void *to,tctype_kind tkind); |
6827 |
+FUNC bool duel_get_target_variable(char *name, int frame_no, tvalue *v); |
6828 |
+FUNC tctype* duel_get_target_typedef(char *name); |
6829 |
+FUNC tctype* duel_get_target_struct_tag(char *name); |
6830 |
+FUNC tctype* duel_get_target_union_tag(char *name); |
6831 |
+FUNC tctype* duel_get_target_enum_tag(char *name); |
6832 |
+FUNC ttarget_ptr duel_alloc_target_space(size_t n); |
6833 |
+ |
6834 |
+FUNC int duel_get_frames_number(void); |
6835 |
+FUNC ttarget_ptr duel_get_function_for_frame(int frame_no); |
6836 |
+PROC duel_target_func_call(tvalue *func, tvalue *parms[], |
6837 |
+ int parms_no,tvalue *ret); |
6838 |
+ |
6839 |
+/* prototypes for misc functions */ |
6840 |
+ |
6841 |
+FUNC char* strncpyz(char *to,char *from,size_t len); |
6842 |
+ |
6843 |
+PROC duel_free_val_list(tval_list *l); |
6844 |
+PROC duel_free_nodes(tnode *); |
6845 |
+ |
6846 |
+FUNC tvalue* duel_find_alias(char *name); |
6847 |
+PROC duel_set_alias(char *name,tvalue *v); |
6848 |
+PROC duel_clear_aliases(void); |
6849 |
+PROC duel_show_aliases(void); |
6850 |
+ |
6851 |
--- gdb/duel/tsuite.c |
6852 |
+++ gdb/duel/tsuite.c |
6853 |
@@ -0,0 +1,64 @@ |
6854 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
6855 |
+/* Public domain code */ |
6856 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
6857 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
6858 |
+ |
6859 |
+/* this is a test program to be used with tsuite.gdb */ |
6860 |
+ |
6861 |
+#include <stdlib.h> |
6862 |
+#include <stdio.h> |
6863 |
+#include <string.h> |
6864 |
+ |
6865 |
+int gint ; |
6866 |
+typedef unsigned int uint ; |
6867 |
+ |
6868 |
+struct { int a,b ; char *name ; } emp[100] ; |
6869 |
+enum { MIKI, DAVE, ELA } us ; |
6870 |
+struct snode { int code ; struct snode *left,*right ; } ; |
6871 |
+typedef struct snode tnode ; |
6872 |
+ |
6873 |
+/* amazing, but DEC compiled strcmp such that gdb thinks it returns void */ |
6874 |
+int mystrcmp(s,t) char *s; char *t; { return strcmp(s,t); } |
6875 |
+ |
6876 |
+void main() |
6877 |
+{ |
6878 |
+ char *s="main string" ; |
6879 |
+ FILE *out=stdout ; /* stdout is not a variable on some machines */ |
6880 |
+ /* will use fflush(out) from debugger */ |
6881 |
+ int i ; |
6882 |
+ tnode *root,*p,**q ; |
6883 |
+ |
6884 |
+ for(i=0 ; i<100 ; i++) { |
6885 |
+ emp[i].a=i ; emp[i].b=i*i ; |
6886 |
+ emp[i].name=(char*) malloc(10); |
6887 |
+ sprintf(emp[i].name,"emp%3.3d",i); |
6888 |
+ } |
6889 |
+ emp[53].a=76 ; /* bug */ |
6890 |
+ emp[36].b-- ; /* bug */ |
6891 |
+ emp[74].name[3]='5' ; /* another bug */ |
6892 |
+ |
6893 |
+ root=(tnode*) malloc(sizeof(tnode)); |
6894 |
+ root->left=root->right=0 ; |
6895 |
+ root->code=5000 ; |
6896 |
+ for(i=1 ; i<10000 ; i++) { /* insert elements into tree */ |
6897 |
+ int code=((i*997*1013)>>10)%11000 ; /* "fixed" "random" generaor */ |
6898 |
+ if(code<0) code= -code ; |
6899 |
+ p=root ; |
6900 |
+ while(p) { |
6901 |
+ if(p->code==code) break ; |
6902 |
+ if(p->code<code) q= &p->right, p=p->right ; |
6903 |
+ else q= &p->left, p=p->left ; |
6904 |
+ } |
6905 |
+ if(p==0) { |
6906 |
+ p=(tnode*) malloc(sizeof(tnode)); |
6907 |
+ p->code=code ; |
6908 |
+ if(i>8680) p->code+=(i<9210)? 1:-1 ; /* bug */ |
6909 |
+ p->left=p->right=0 ; |
6910 |
+ *q=p ; |
6911 |
+ } |
6912 |
+ } |
6913 |
+ |
6914 |
+ printf("trivial tsuite program\n"); |
6915 |
+ printf("trivial tsuite program\n"); |
6916 |
+} |
6917 |
+ |
6918 |
--- gdb/duel/tsuite.gdb |
6919 |
+++ gdb/duel/tsuite.gdb |
6920 |
@@ -0,0 +1,126 @@ |
6921 |
+set prompt |
6922 |
+## DUEL - A Very High Level Debugging Langauge. |
6923 |
+## Public domain code |
6924 |
+## Written by Michael Golan mg@××××××××××××.edu |
6925 |
+##$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $ |
6926 |
+## |
6927 |
+## test suite for duel, can be used with duelself or gdb |
6928 |
+## |
6929 |
+file tsuite |
6930 |
+b 60 |
6931 |
+b 61 |
6932 |
+r |
6933 |
+## check constants |
6934 |
+dl (1..5)*(2,(double) 2/3) |
6935 |
+## declare array x, set it, search it |
6936 |
+dl int x[100] ; |
6937 |
+dl x[0..99]= -1 ; |
6938 |
+dl x[i:=20..40]=2+i*i ; |
6939 |
+dl x[20..23,38..40] |
6940 |
+dl x[..100] >=? 33*33 <=? 35*35 |
6941 |
+dl x[..100]=> ((_>=33*33) & (_<= 35*35)) ==? 1 |
6942 |
+dl (*(x+(7..9)))++ |
6943 |
+dl y:= &x[7] ; |
6944 |
+dl y[0..2] |
6945 |
+dl x+7 == y |
6946 |
+dl (x[..99]>?0)@(_>100) |
6947 |
+dl printf("%d\n",1..10); |
6948 |
+dl printf("x is: "); printf("%d, ",x[0..99]>? 0); printf("\n");fflush(out); |
6949 |
+dl int j ; for(j=0 ; j<100 ; j++) if(x[j]>37*37) printf("x[%d]=%d\n",j,x[j]);fflush(out); |
6950 |
+dl printf("%d\n",1..5); |
6951 |
+## check void type |
6952 |
+dl void *p |
6953 |
+dl p = &p |
6954 |
+dl p,*p |
6955 |
+## errors |
6956 |
+dl 1e+++3 |
6957 |
+dl i=4 ; |
6958 |
+dl x=6 ; |
6959 |
+dl x++ ; |
6960 |
+dl --i ; |
6961 |
+## cleanup |
6962 |
+dl alias |
6963 |
+dl clear |
6964 |
+## access some variables |
6965 |
+dl s |
6966 |
+dl s[4..8] |
6967 |
+dl s[6..]@0 |
6968 |
+dl l:=#/s[0..]@0 |
6969 |
+dl s[l-2..l] |
6970 |
+dl gint |
6971 |
+dl gint++ |
6972 |
+dl gint++ |
6973 |
+dl --gint |
6974 |
+dl gint |
6975 |
+dl main.s |
6976 |
+dl ++main.s |
6977 |
+dl main ==? main |
6978 |
+dl main == main |
6979 |
+dl frames_no |
6980 |
+dl frame(0).s |
6981 |
+dl frame(0).(gint+0) |
6982 |
+dl sizeof(gint) |
6983 |
+dl sizeof(T uint) |
6984 |
+dl sizeof(T uint*) |
6985 |
+dl sizeof(T emp) |
6986 |
+dl sizeof(emp) |
6987 |
+dl sizeof(emp[0]) |
6988 |
+dl (uint)-1 |
6989 |
+dl (uint*)(gint=gint-9) |
6990 |
+dl *(uint*)&gint |
6991 |
+dl T uint myuint ; myuint = -1 |
6992 |
+## some errors |
6993 |
+dl frame(0).gint |
6994 |
+dl frame(0).(gint) |
6995 |
+dl frame(0).ha |
6996 |
+dl sizeof(uint) |
6997 |
+dl sizeof gint |
6998 |
+dl main == printf |
6999 |
+dl main+1 |
7000 |
+dl main > printf |
7001 |
+dl printf+3 |
7002 |
+dl T int x |
7003 |
+dl uint y |
7004 |
+dl T uint z = 5 |
7005 |
+## finally, do some serious checks using the bugs in the programs |
7006 |
+dl emp[4] |
7007 |
+dl emp[k:=..100].a !=? k |
7008 |
+dl (emp[k:=..100].a !=? k)[[0]] ; emp[{k}] |
7009 |
+dl emp[k:=..100].if(a!=k) _ |
7010 |
+dl emp[k:=..100].b !=? k*k |
7011 |
+dl emp[k:=..100].if(b!=k*k) _,{k}*{k} |
7012 |
+dl emp[k:=..100]=>if(_.b!=k*k) _,{k}*{k} |
7013 |
+dl char s[80]; |
7014 |
+dl ..100 => (sprintf(s,"emp%3.3d",_) ; emp[_].name[0..]@0#j !=? s[j]) |
7015 |
+dl ..100 => (sprintf(s,"emp%3.3d",_) ; mystrcmp(emp[_].name,s)!=?0) |
7016 |
+dl ..100 => (sprintf(s,"emp%3.3d",_) ; emp[_].name=>if(mystrcmp(_,s))_) |
7017 |
+## now, lets try some pointers and --> stuff! |
7018 |
+dl root-->left[[..8]]->code |
7019 |
+dl root-->(left,right)[[..30]]->code |
7020 |
+dl #/root-->(left,right) |
7021 |
+dl root->(left,right) => #/_-->(left,right) |
7022 |
+dl root->(left->left,left->right,right->left,right->right)=> #/_-->(left,right) |
7023 |
+## this cause very long symbolic vals, core dump/bad results before duel 1.10.3 |
7024 |
+dl #/(root+0000000000000000000000000000000000000000000000000000)-->(left,right) |
7025 |
+## compute min, max, check for dups, no-show |
7026 |
+dl root-->left[[#/root-->left-1]]->code |
7027 |
+dl root-->right[[#/root-->right-1]]->code |
7028 |
+dl int codes[11000] ; codes[..11000]=0 ; codes[root-->(left,right)->code]++ ; |
7029 |
+dl codes[..11000] >? 1 |
7030 |
+dl (codes[..11000] ==? 0 )[[..10]] |
7031 |
+dl (..11000 => if(!codes[_]) _)[[..10]] |
7032 |
+## check consistency |
7033 |
+dl root-->(left,right)->((left!=?0)->code >=? code, (right!=?0)->code <=? code) |
7034 |
+dl root-->(left,right)->((left!=?0)->code>=code, (right!=?0)->code<=code)==?1 |
7035 |
+dl (1000..=>if(&&/( 2,3.._-1 =>__%_)) _)[[..10]] |
7036 |
+## enums |
7037 |
+dl ELA |
7038 |
+dl (T us) 1 |
7039 |
+dl us=1 ; us |
7040 |
+dl MIKI..ELA |
7041 |
+## more errors |
7042 |
+dl emp[0]=us |
7043 |
+dl emp=us |
7044 |
+dl us=emp |
7045 |
+## the end |
7046 |
+ |
7047 |
--- gdb/duel/tsuite.gdb.out |
7048 |
+++ gdb/duel/tsuite.gdb.out |
7049 |
@@ -0,0 +1,293 @@ |
7050 |
+GDB is free software and you are welcome to distribute copies of it |
7051 |
+ under certain conditions; type "show copying" to see the conditions. |
7052 |
+There is absolutely no warranty for GDB; type "show warranty" for details. |
7053 |
+GDB 4.8, Copyright 1993 Free Software Foundation, Inc. |
7054 |
+(gdb) Reading symbols from tsuite...done. |
7055 |
+ Breakpoint 1 at 0x400518: file tsuite.c, line 60. |
7056 |
+ Note: breakpoint 1 also set at pc 0x400518. |
7057 |
+Breakpoint 2 at 0x400518: file tsuite.c, line 61. |
7058 |
+ Starting program: /tmp_mnt/n/fs/grad2/mg/duel/tsuite/tsuite |
7059 |
+ |
7060 |
+Breakpoint 1, main () at tsuite.c:61 |
7061 |
+61 printf("trivial tsuite program\n"); |
7062 |
+ DUEL 1.10.4, public domain debugging language. "dl" for help |
7063 |
+1*2 = 2 |
7064 |
+1*(2/3) = 0.66666667 |
7065 |
+2*2 = 4 |
7066 |
+2*(2/3) = 1.33333333 |
7067 |
+3*2 = 6 |
7068 |
+3*(2/3) = 2.0 |
7069 |
+4*2 = 8 |
7070 |
+4*(2/3) = 2.66666667 |
7071 |
+5*2 = 10 |
7072 |
+5*(2/3) = 3.33333333 |
7073 |
+ x[20] = 402 |
7074 |
+x[21] = 443 |
7075 |
+x[22] = 486 |
7076 |
+x[23] = 531 |
7077 |
+x[38] = 1446 |
7078 |
+x[39] = 1523 |
7079 |
+x[40] = 1602 |
7080 |
+ x[33] = 1091 |
7081 |
+x[34] = 1158 |
7082 |
+ (x[33]>=33*33)&(x[33]<=35*35) = 1 |
7083 |
+(x[34]>=33*33)&(x[34]<=35*35) = 1 |
7084 |
+ (*(x+7))++ = -1 |
7085 |
+(*(x+8))++ = -1 |
7086 |
+(*(x+9))++ = -1 |
7087 |
+ y[0] = 0 |
7088 |
+y[1] = 0 |
7089 |
+y[2] = 0 |
7090 |
+ x+7==y = 1 |
7091 |
+ 1 |
7092 |
+2 |
7093 |
+3 |
7094 |
+4 |
7095 |
+5 |
7096 |
+6 |
7097 |
+7 |
7098 |
+8 |
7099 |
+9 |
7100 |
+10 |
7101 |
+x is: 402, 443, 486, 531, 578, 627, 678, 731, 786, 843, 902, 963, 1026, 1091, 1158, 1227, 1298, 1371, 1446, 1523, 1602, |
7102 |
+ x[37]=1371 |
7103 |
+x[38]=1446 |
7104 |
+x[39]=1523 |
7105 |
+x[40]=1602 |
7106 |
+ &p = @10020020 |
7107 |
+ p = @10020020 |
7108 |
+*p = void @10020020 |
7109 |
+ 1e+++3 |
7110 |
+^ Invalid float constant. |
7111 |
+ Error: i=4 ; |
7112 |
+ -^-- operand x is not an lvalue for operator 'x=y' |
7113 |
+operand ``i'' -- type: int |
7114 |
+ -- value: 40 |
7115 |
+ Error: x=6 ; |
7116 |
+ -^-- bad operand x type for operator 'x=y' |
7117 |
+operand ``x'' -- type: int [100] |
7118 |
+ -- value: array @1001f000 |
7119 |
+ Error: x++ ; |
7120 |
+ -^-- operand x of '++' is not integral |
7121 |
+operand ``x'' -- type: int [100] |
7122 |
+ -- value: array @1001f000 |
7123 |
+ Error: --i ; |
7124 |
+ ^-- operand of '--' must be an lvalue |
7125 |
+operand ``i'' -- type: int |
7126 |
+ -- value: 40 |
7127 |
+ Aliases table: |
7128 |
+p: p = @10020020 |
7129 |
+j: j = 100 |
7130 |
+y: &x[7] = @1001f01c |
7131 |
+i: 40 |
7132 |
+x: x = array @1001f000 |
7133 |
+ Aliases table cleared |
7134 |
+ s = "main string" |
7135 |
+ s[4] = ' ' |
7136 |
+s[5] = 's' |
7137 |
+s[6] = 't' |
7138 |
+s[7] = 'r' |
7139 |
+s[8] = 'i' |
7140 |
+ s[6] = 't' |
7141 |
+s[7] = 'r' |
7142 |
+s[8] = 'i' |
7143 |
+s[9] = 'n' |
7144 |
+s[10] = 'g' |
7145 |
+ #/(s[0] ...) = 11 |
7146 |
+ s[9] = 'n' |
7147 |
+s[10] = 'g' |
7148 |
+s[11] = '\0' |
7149 |
+ gint = 0 |
7150 |
+ gint++ = 0 |
7151 |
+ gint++ = 1 |
7152 |
+ gint = 1 |
7153 |
+ gint = 1 |
7154 |
+ main.s = "main string" |
7155 |
+ main.s = "ain string" |
7156 |
+ main = func @004001f0 |
7157 |
+ main==main = 1 |
7158 |
+ frames_no = 1 |
7159 |
+ frame(0).s = "ain string" |
7160 |
+ frame(0).(gint+0) = 1 |
7161 |
+ sizeof(gint) = 0x4 |
7162 |
+ sizeof(unsigned int) = 0x4 |
7163 |
+ sizeof(T) = 0x4 |
7164 |
+ sizeof(T) = 0x4b0 |
7165 |
+ sizeof(emp) = 0x4b0 |
7166 |
+ sizeof(emp[0]) = 0xc |
7167 |
+ -1 = 0xffffffff |
7168 |
+ (gint-9) = @fffffff8 [ILLEGAL] |
7169 |
+ *&gint = 0xfffffff8 |
7170 |
+ -1 = 0xffffffff |
7171 |
+ Error: frame(0).gint |
7172 |
+ --------^-- field not found in operator '.' |
7173 |
+operand ``frame(0)'' -- type: int |
7174 |
+ -- value: frame(0) |
7175 |
+ frame(0).(gint) |
7176 |
+---------------^ syntax error |
7177 |
+ Error: frame(0).ha |
7178 |
+ --------^-- field not found in operator '.' |
7179 |
+operand ``frame(0)'' -- type: int |
7180 |
+ -- value: frame(0) |
7181 |
+ Error: sizeof(uint) |
7182 |
+ -------^-- variable 'uint' not found |
7183 |
+ sizeof gint |
7184 |
+-----------^ syntax error |
7185 |
+ Error: main == printf |
7186 |
+ -----^-- incompatible types for op == |
7187 |
+operand1 ``main'' -- type: ptr to func returning void |
7188 |
+ -- value: @004001f0 |
7189 |
+operand2 ``printf'' -- type: ptr to func returning int |
7190 |
+ -- value: @00400ca0 |
7191 |
+ Error: main+1 |
7192 |
+ ----^-- unknown pointer object size for '+' op |
7193 |
+operand ``main'' -- type: ptr to func returning void |
7194 |
+ -- value: @004001f0 |
7195 |
+ Error: main > printf |
7196 |
+ -----^-- incompatible types for op > |
7197 |
+operand1 ``main'' -- type: ptr to func returning void |
7198 |
+ -- value: @004001f0 |
7199 |
+operand2 ``printf'' -- type: ptr to func returning int |
7200 |
+ -- value: @00400ca0 |
7201 |
+ Error: printf+3 |
7202 |
+ ------^-- unknown pointer object size for '+' op |
7203 |
+operand ``printf'' -- type: ptr to func returning int |
7204 |
+ -- value: @00400ca0 |
7205 |
+ T int x |
7206 |
+-----^ syntax error |
7207 |
+ uint y |
7208 |
+------^ syntax error |
7209 |
+ T uint z = 5 |
7210 |
+----------^ syntax error |
7211 |
+ emp[4] = { a = 4, b = 16, name = "emp004" } |
7212 |
+ emp[53].a = 76 |
7213 |
+ emp[53] = { a = 76, b = 2809, name = "emp053" } |
7214 |
+ emp[53] = { a = 76, b = 2809, name = "emp053" } |
7215 |
+ emp[36].b = 1295 |
7216 |
+ emp[36] = { a = 36, b = 1295, name = "emp036" } |
7217 |
+emp[36].36*36 = 1296 |
7218 |
+ emp[36] = { a = 36, b = 1295, name = "emp036" } |
7219 |
+36*36 = 1296 |
7220 |
+ (emp[74].name[3]) = '5' |
7221 |
+ (mystrcmp(emp[74].name,s)) = 5 |
7222 |
+ (emp[74].name) = "emp574" |
7223 |
+ root->code = 5000 |
7224 |
+root->left->code = 986 |
7225 |
+root-->left[[2]]->code = 835 |
7226 |
+root-->left[[3]]->code = 684 |
7227 |
+root-->left[[4]]->code = 533 |
7228 |
+root-->left[[5]]->code = 383 |
7229 |
+root-->left[[6]]->code = 232 |
7230 |
+root-->left[[7]]->code = 81 |
7231 |
+ root->code = 5000 |
7232 |
+root->left->code = 986 |
7233 |
+root-->left[[2]]->code = 835 |
7234 |
+root-->left[[3]]->code = 684 |
7235 |
+root-->left[[4]]->code = 533 |
7236 |
+root-->left[[5]]->code = 383 |
7237 |
+root-->left[[6]]->code = 232 |
7238 |
+root-->left[[7]]->code = 81 |
7239 |
+root-->left[[8]]->code = 12 |
7240 |
+root-->left[[9]]->code = 2 |
7241 |
+root-->left[[9]]->right->code = 5 |
7242 |
+root-->left[[9]]->right->left->code = 4 |
7243 |
+root-->left[[9]]-->right[[2]]->code = 11 |
7244 |
+root-->left[[9]]-->right[[2]]->left->code = 8 |
7245 |
+root-->left[[9]]-->right[[2]]-->left[[2]]->code = 7 |
7246 |
+root-->left[[9]]-->right[[2]]->left->right->code = 10 |
7247 |
+root-->left[[8]]->right->code = 24 |
7248 |
+root-->left[[8]]->right->left->code = 15 |
7249 |
+root-->left[[8]]->right-->left[[2]]->code = 14 |
7250 |
+root-->left[[8]]->right->left->right->code = 17 |
7251 |
+root-->left[[8]]->right->left->right->left->code = 16 |
7252 |
+root-->left[[8]]->right->left-->right[[2]]->code = 23 |
7253 |
+root-->left[[8]]->right->left-->right[[2]]->left->code = 20 |
7254 |
+root-->left[[8]]->right->left-->right[[2]]-->left[[2]]->code = 19 |
7255 |
+root-->left[[8]]->right->left-->right[[2]]->left->right->code = 22 |
7256 |
+root-->left[[8]]->right->left-->right[[2]]->left->right->left->code = 21 |
7257 |
+root-->left[[8]]-->right[[2]]->code = 36 |
7258 |
+root-->left[[8]]-->right[[2]]->left->code = 27 |
7259 |
+root-->left[[8]]-->right[[2]]->left->right->code = 35 |
7260 |
+root-->left[[8]]-->right[[2]]->left->right->left->code = 32 |
7261 |
+ #/(root ...) = 7144 |
7262 |
+ #/(root->left ...) = 3249 |
7263 |
+#/(root->right ...) = 3894 |
7264 |
+ #/(root->(left->left) ...) = 641 |
7265 |
+#/(root->(left->right) ...) = 2607 |
7266 |
+#/(root->(right->left) ...) = 595 |
7267 |
+#/(root->(right->right) ...) = 3298 |
7268 |
+ #/((root+0000000000000000000000000000000000000000000000000000) ...) = 7144 |
7269 |
+ root-->left[[9]]->code = 2 |
7270 |
+ root-->right[[14]]->code = 10999 |
7271 |
+ codes[2122] = 2 |
7272 |
+codes[2308] = 2 |
7273 |
+codes[5081] = 2 |
7274 |
+codes[5267] = 2 |
7275 |
+codes[8040] = 2 |
7276 |
+codes[9026] = 2 |
7277 |
+codes[9363] = 2 |
7278 |
+ (codes[0]) = 0 |
7279 |
+(codes[1]) = 0 |
7280 |
+(codes[3]) = 0 |
7281 |
+(codes[6]) = 0 |
7282 |
+(codes[9]) = 0 |
7283 |
+(codes[13]) = 0 |
7284 |
+(codes[18]) = 0 |
7285 |
+(codes[25]) = 0 |
7286 |
+(codes[26]) = 0 |
7287 |
+(codes[29]) = 0 |
7288 |
+ 0 |
7289 |
+1 |
7290 |
+3 |
7291 |
+6 |
7292 |
+9 |
7293 |
+13 |
7294 |
+18 |
7295 |
+25 |
7296 |
+26 |
7297 |
+29 |
7298 |
+ root->left-->right[[2]]-->left[[6]]->right->left-->right[[5]]->left->right->left->(right->code) = 2122 |
7299 |
+root->left-->right[[2]]-->left[[5]]-->right[[3]]->left->right->left->right->(left->code) = 2308 |
7300 |
+root->right-->left[[6]]->right->left-->right[[5]]->left->right->left->(right->code) = 5081 |
7301 |
+root->right-->left[[5]]-->right[[3]]->left->right->left->right->(left->code) = 5267 |
7302 |
+root-->right[[4]]-->left[[6]]->right->left-->right[[5]]->left->right->left->(right->code) = 8040 |
7303 |
+root-->right[[5]]-->left[[6]]->right->left-->right[[5]]->left->right->left->(right->code) = 9026 |
7304 |
+root-->right[[5]]-->left[[4]]-->right[[3]]->left->right->left->right->(left->code) = 9363 |
7305 |
+ root->left-->right[[2]]-->left[[6]]->right->left-->right[[5]]->left->right->left->(right->code<=code) = 1 |
7306 |
+root->left-->right[[2]]-->left[[5]]-->right[[3]]->left->right->left->right->(left->code>=code) = 1 |
7307 |
+root->right-->left[[6]]->right->left-->right[[5]]->left->right->left->(right->code<=code) = 1 |
7308 |
+root->right-->left[[5]]-->right[[3]]->left->right->left->right->(left->code>=code) = 1 |
7309 |
+root-->right[[4]]-->left[[6]]->right->left-->right[[5]]->left->right->left->(right->code<=code) = 1 |
7310 |
+root-->right[[5]]-->left[[6]]->right->left-->right[[5]]->left->right->left->(right->code<=code) = 1 |
7311 |
+root-->right[[5]]-->left[[4]]-->right[[3]]->left->right->left->right->(left->code>=code) = 1 |
7312 |
+ 1009 |
7313 |
+1013 |
7314 |
+1019 |
7315 |
+1021 |
7316 |
+1031 |
7317 |
+1033 |
7318 |
+1039 |
7319 |
+1049 |
7320 |
+1051 |
7321 |
+1061 |
7322 |
+ ELA |
7323 |
+ 1 = DAVE |
7324 |
+ us = DAVE |
7325 |
+ 0 |
7326 |
+1 |
7327 |
+2 |
7328 |
+ Error: emp[0]=us |
7329 |
+ ------^-- incompatible types for op x=y |
7330 |
+operand1 ``emp[0]'' -- type: struct .F13 { int a ; int b ; char * name ; } ; |
7331 |
+ -- value: struct @10001510 |
7332 |
+operand2 ``us'' -- type: enum .F14 |
7333 |
+ -- value: DAVE |
7334 |
+ Error: emp=us |
7335 |
+ ---^-- bad operand x type for operator 'x=y' |
7336 |
+operand ``emp'' -- type: array [100] of struct .F13 { int a ; int b ; char * name ; } ; |
7337 |
+ -- value: array @10001510 |
7338 |
+ Error: us=emp |
7339 |
+ --^-- operand x of 'y=x' is not numeric |
7340 |
+operand ``emp'' -- type: array [100] of struct .F13 { int a ; int b ; char * name ; } ; |
7341 |
+ -- value: array @10001510 |
7342 |
+ |
7343 |
--- gdb/duel/tsuite.self |
7344 |
+++ gdb/duel/tsuite.self |
7345 |
@@ -0,0 +1,111 @@ |
7346 |
+## DUEL - A Very High Level Debugging Langauge. |
7347 |
+## Public domain code |
7348 |
+## Written by Michael Golan mg@××××××××××××.edu |
7349 |
+## $Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $ |
7350 |
+ |
7351 |
+## |
7352 |
+## test suite for duel, can be used with duelself or gdb |
7353 |
+## |
7354 |
+ |
7355 |
+## check constants |
7356 |
+(1..5)*(2,(double) 2/3) |
7357 |
+ |
7358 |
+## declare array x, set it, search it |
7359 |
+ |
7360 |
+int x[100] ; |
7361 |
+x[0..99]= -1 ; |
7362 |
+x[i:=20..40]=2+i*i ; |
7363 |
+x[20..23,38..40] |
7364 |
+x[..100] >=? 33*33 <=? 35*35 |
7365 |
+x[..100]=> ((_>=33*33) & (_<= 35*35)) ==? 1 |
7366 |
+x |
7367 |
+x+5 |
7368 |
+*(x+7..9)++ |
7369 |
+*(x+(7..9))++ |
7370 |
+(*(x+(7..9)))++ |
7371 |
+y:= &x[7] ; |
7372 |
+y[0..2] |
7373 |
+x+7 == y |
7374 |
+(x[..99]>?0)@(_>500) |
7375 |
+ |
7376 |
+printf("x is: "); printf("%d, ",x[0..99]>? 0); printf("\n"); |
7377 |
+int j ; for(j=0 ; j<100 ; j++) if(x[j]>37*37) printf("x[%d]=%d\n",j,x[j]); |
7378 |
+ |
7379 |
+printf("%d, ",1..5); printf("\n"); |
7380 |
+ |
7381 |
+## check void type |
7382 |
+void *p |
7383 |
+p = &p |
7384 |
+p,*p |
7385 |
+ |
7386 |
+## errors |
7387 |
+ |
7388 |
+1e++4 |
7389 |
+& &x |
7390 |
+i=4 ; |
7391 |
+x=6 ; |
7392 |
+x++ ; |
7393 |
+--i ; |
7394 |
+ |
7395 |
+## cleanup |
7396 |
+ |
7397 |
+alias |
7398 |
+clear |
7399 |
+ |
7400 |
+## access some variables |
7401 |
+s |
7402 |
+s[3..7] |
7403 |
+s[5..]@0 |
7404 |
+l:=#/s[0..]@0 |
7405 |
+s[l-2..l] |
7406 |
+ |
7407 |
+gint |
7408 |
+gint++ |
7409 |
+gint++ |
7410 |
+--gint |
7411 |
+gint |
7412 |
+main.s |
7413 |
+main.s++ |
7414 |
+main.s++ |
7415 |
+ |
7416 |
+main |
7417 |
+printf |
7418 |
+main ==? main |
7419 |
+main == main |
7420 |
+ |
7421 |
+frames_no |
7422 |
+frame(0).s |
7423 |
+ |
7424 |
+## gint is a global, not local fro main in frame 0 |
7425 |
+frame(0).gint |
7426 |
+## but when we eval (expr) under frame 0 scope, we find it ok. |
7427 |
+frame(0).(gint) |
7428 |
+ |
7429 |
+T uint myuint ; myuint = -1 |
7430 |
+ |
7431 |
+sizeof(int) |
7432 |
+sizeof(long) |
7433 |
+sizeof(int *) |
7434 |
+sizeof(signed char*) |
7435 |
+sizeof() |
7436 |
+sizeof(gint) |
7437 |
+sizeof gint |
7438 |
+sizeof gint+1 |
7439 |
+## some errors |
7440 |
+ |
7441 |
+main == main |
7442 |
+main == printf |
7443 |
+ |
7444 |
+main+1 |
7445 |
+malloc[4] |
7446 |
+printf+3 |
7447 |
+ |
7448 |
+T int x |
7449 |
+int x |
7450 |
+uint y |
7451 |
+T uint y = 5 |
7452 |
+T uint y |
7453 |
+ |
7454 |
+## the end |
7455 |
+ |
7456 |
+ |
7457 |
--- gdb/duel/tsuite.self.out |
7458 |
+++ gdb/duel/tsuite.self.out |
7459 |
@@ -0,0 +1,263 @@ |
7460 |
+dl> ## DUEL - A Very High Level Debugging Langauge. |
7461 |
+dl> ## Public domain code |
7462 |
+dl> ## Written by Michael Golan mg@××××××××××××.edu |
7463 |
+dl> |
7464 |
+dl> ## |
7465 |
+dl> ## test suite for duel, can be used with duelself or gdb |
7466 |
+dl> ## |
7467 |
+dl> |
7468 |
+dl> ## check constants |
7469 |
+dl> (1..5)*(2,(double) 2/3) |
7470 |
+DUEL 1.10.4, public domain debugging language. "dl" for help |
7471 |
+1*2 = 2 |
7472 |
+1*(2/3) = 0.66666667 |
7473 |
+2*2 = 4 |
7474 |
+2*(2/3) = 1.33333333 |
7475 |
+3*2 = 6 |
7476 |
+3*(2/3) = 2.0 |
7477 |
+4*2 = 8 |
7478 |
+4*(2/3) = 2.66666667 |
7479 |
+5*2 = 10 |
7480 |
+5*(2/3) = 3.33333333 |
7481 |
+dl> |
7482 |
+dl> ## declare array x, set it, search it |
7483 |
+dl> |
7484 |
+dl> int x[100] ; |
7485 |
+dl> x[0..99]= -1 ; |
7486 |
+dl> x[i:=20..40]=2+i*i ; |
7487 |
+dl> x[20..23,38..40] |
7488 |
+x[20] = 402 |
7489 |
+x[21] = 443 |
7490 |
+x[22] = 486 |
7491 |
+x[23] = 531 |
7492 |
+x[38] = 1446 |
7493 |
+x[39] = 1523 |
7494 |
+x[40] = 1602 |
7495 |
+dl> x[..100] >=? 33*33 <=? 35*35 |
7496 |
+x[33] = 1091 |
7497 |
+x[34] = 1158 |
7498 |
+dl> x[..100]=> ((_>=33*33) & (_<= 35*35)) ==? 1 |
7499 |
+(x[33]>=33*33)&(x[33]<=35*35) = 1 |
7500 |
+(x[34]>=33*33)&(x[34]<=35*35) = 1 |
7501 |
+dl> x |
7502 |
+x = array @10014000 |
7503 |
+dl> x+5 |
7504 |
+x+5 = @10014014 |
7505 |
+dl> *(x+7..9)++ |
7506 |
+Error: *(x+7..9)++ |
7507 |
+ -----^-- operand x of 'x..y' is not integral |
7508 |
+operand ``x+7'' -- type: int * |
7509 |
+ -- value: @1001401c |
7510 |
+dl> *(x+(7..9))++ |
7511 |
+Error: *(x+(7..9))++ |
7512 |
+ -----------^-- operand of '++' must be an lvalue |
7513 |
+operand ``(x+7)'' -- type: int * |
7514 |
+ -- value: @1001401c |
7515 |
+dl> (*(x+(7..9)))++ |
7516 |
+(*(x+7))++ = -1 |
7517 |
+(*(x+8))++ = -1 |
7518 |
+(*(x+9))++ = -1 |
7519 |
+dl> y:= &x[7] ; |
7520 |
+dl> y[0..2] |
7521 |
+y[0] = 0 |
7522 |
+y[1] = 0 |
7523 |
+y[2] = 0 |
7524 |
+dl> x+7 == y |
7525 |
+x+7==y = 1 |
7526 |
+dl> (x[..99]>?0)@(_>500) |
7527 |
+(x[20]) = 402 |
7528 |
+(x[21]) = 443 |
7529 |
+(x[22]) = 486 |
7530 |
+dl> |
7531 |
+dl> printf("x is: "); printf("%d, ",x[0..99]>? 0); printf("\n"); |
7532 |
+x is: 402, 443, 486, 531, 578, 627, 678, 731, 786, 843, 902, 963, 1026, 1091, 1158, 1227, 1298, 1371, 1446, 1523, 1602, |
7533 |
+dl> int j ; for(j=0 ; j<100 ; j++) if(x[j]>37*37) printf("x[%d]=%d\n",j,x[j]); |
7534 |
+x[37]=1371 |
7535 |
+x[38]=1446 |
7536 |
+x[39]=1523 |
7537 |
+x[40]=1602 |
7538 |
+dl> |
7539 |
+dl> printf("%d, ",1..5); printf("\n"); |
7540 |
+1, 2, 3, 4, 5, |
7541 |
+dl> |
7542 |
+dl> ## check void type |
7543 |
+dl> void *p |
7544 |
+dl> p = &p |
7545 |
+&p = @10012138 |
7546 |
+dl> p,*p |
7547 |
+p = @10012138 |
7548 |
+*p = void @10012138 |
7549 |
+dl> |
7550 |
+dl> ## errors |
7551 |
+dl> |
7552 |
+dl> 1e++4 |
7553 |
+1e++4 |
7554 |
+^ Invalid float constant. |
7555 |
+dl> & &x |
7556 |
+Error: & &x |
7557 |
+ ^-- operand x of '&x' is not a lvalue |
7558 |
+operand ``&x'' -- type: ptr to int [100] |
7559 |
+ -- value: @10014000 |
7560 |
+dl> i=4 ; |
7561 |
+Error: i=4 ; |
7562 |
+ -^-- operand x is not an lvalue for operator 'x=y' |
7563 |
+operand ``i'' -- type: int |
7564 |
+ -- value: 40 |
7565 |
+dl> x=6 ; |
7566 |
+Error: x=6 ; |
7567 |
+ -^-- bad operand x type for operator 'x=y' |
7568 |
+operand ``x'' -- type: int [100] |
7569 |
+ -- value: array @10014000 |
7570 |
+dl> x++ ; |
7571 |
+Error: x++ ; |
7572 |
+ -^-- operand x of '++' is not integral |
7573 |
+operand ``x'' -- type: int [100] |
7574 |
+ -- value: array @10014000 |
7575 |
+dl> --i ; |
7576 |
+Error: --i ; |
7577 |
+ ^-- operand of '--' must be an lvalue |
7578 |
+operand ``i'' -- type: int |
7579 |
+ -- value: 40 |
7580 |
+dl> |
7581 |
+dl> ## cleanup |
7582 |
+dl> |
7583 |
+dl> alias |
7584 |
+Aliases table: |
7585 |
+p: p = @10012138 |
7586 |
+j: j = 100 |
7587 |
+y: &x[7] = @1001401c |
7588 |
+i: 40 |
7589 |
+x: x = array @10014000 |
7590 |
+dl> clear |
7591 |
+Aliases table cleared |
7592 |
+dl> |
7593 |
+dl> ## access some variables |
7594 |
+dl> s |
7595 |
+s = "main string" |
7596 |
+dl> s[3..7] |
7597 |
+s[3] = 'n' |
7598 |
+s[4] = ' ' |
7599 |
+s[5] = 's' |
7600 |
+s[6] = 't' |
7601 |
+s[7] = 'r' |
7602 |
+dl> s[5..]@0 |
7603 |
+s[5] = 's' |
7604 |
+s[6] = 't' |
7605 |
+s[7] = 'r' |
7606 |
+s[8] = 'i' |
7607 |
+s[9] = 'n' |
7608 |
+s[10] = 'g' |
7609 |
+dl> l:=#/s[0..]@0 |
7610 |
+#/(s[0] ...) = 11 |
7611 |
+dl> s[l-2..l] |
7612 |
+s[9] = 'n' |
7613 |
+s[10] = 'g' |
7614 |
+s[11] = '\0' |
7615 |
+dl> |
7616 |
+dl> gint |
7617 |
+gint = 0 |
7618 |
+dl> gint++ |
7619 |
+gint++ = 0 |
7620 |
+dl> gint++ |
7621 |
+gint++ = 1 |
7622 |
+dl> --gint |
7623 |
+gint = 1 |
7624 |
+dl> gint |
7625 |
+gint = 1 |
7626 |
+dl> main.s |
7627 |
+main.s = "main string" |
7628 |
+dl> main.s++ |
7629 |
+main.s++ = "main string" |
7630 |
+dl> main.s++ |
7631 |
+main.s++ = "ain string" |
7632 |
+dl> |
7633 |
+dl> main |
7634 |
+main = func @00400918 |
7635 |
+dl> printf |
7636 |
+printf = func @004112b0 |
7637 |
+dl> main ==? main |
7638 |
+main = func @00400918 |
7639 |
+dl> main == main |
7640 |
+main==main = 1 |
7641 |
+dl> |
7642 |
+dl> frames_no |
7643 |
+frames_no = 1 |
7644 |
+dl> frame(0).s |
7645 |
+frame(0).s = "in string" |
7646 |
+dl> |
7647 |
+dl> ## gint is a global, not local fro main in frame 0 |
7648 |
+dl> frame(0).gint |
7649 |
+Error: frame(0).gint |
7650 |
+ --------^-- field not found in operator '.' |
7651 |
+operand ``frame(0)'' -- type: int |
7652 |
+ -- value: frame(0) |
7653 |
+dl> ## but when we eval (expr) under frame 0 scope, we find it ok. |
7654 |
+dl> frame(0).(gint) |
7655 |
+frame(0).(gint) |
7656 |
+---------------^ syntax error |
7657 |
+dl> |
7658 |
+dl> T uint myuint ; myuint = -1 |
7659 |
+-1 = 0xffffffff |
7660 |
+dl> |
7661 |
+dl> sizeof(int) |
7662 |
+sizeof(int) = 0x4 |
7663 |
+dl> sizeof(long) |
7664 |
+sizeof(long) = 0x4 |
7665 |
+dl> sizeof(int *) |
7666 |
+sizeof(T) = 0x4 |
7667 |
+dl> sizeof(signed char*) |
7668 |
+sizeof(T) = 0x4 |
7669 |
+dl> sizeof() |
7670 |
+sizeof() |
7671 |
+--------^ syntax error |
7672 |
+dl> sizeof(gint) |
7673 |
+sizeof(gint) = 0x4 |
7674 |
+dl> sizeof gint |
7675 |
+sizeof gint |
7676 |
+-----------^ syntax error |
7677 |
+dl> sizeof gint+1 |
7678 |
+sizeof gint+1 |
7679 |
+-----------^ syntax error |
7680 |
+dl> ## some errors |
7681 |
+dl> |
7682 |
+dl> main == main |
7683 |
+main==main = 1 |
7684 |
+dl> main == printf |
7685 |
+Error: main == printf |
7686 |
+ -----^-- incompatible types for op == |
7687 |
+operand1 ``main'' -- type: ptr to func returning void |
7688 |
+ -- value: @00400918 |
7689 |
+operand2 ``printf'' -- type: ptr to func returning int |
7690 |
+ -- value: @004112b0 |
7691 |
+dl> |
7692 |
+dl> main+1 |
7693 |
+Error: main+1 |
7694 |
+ ----^-- unknown pointer object size for '+' op |
7695 |
+operand ``main'' -- type: ptr to func returning void |
7696 |
+ -- value: @00400918 |
7697 |
+dl> malloc[4] |
7698 |
+Error: malloc[4] |
7699 |
+ ------^-- unknown pointer object size for '+' op |
7700 |
+operand ``malloc'' -- type: ptr to func returning void * |
7701 |
+ -- value: @00411310 |
7702 |
+dl> printf+3 |
7703 |
+Error: printf+3 |
7704 |
+ ------^-- unknown pointer object size for '+' op |
7705 |
+operand ``printf'' -- type: ptr to func returning int |
7706 |
+ -- value: @004112b0 |
7707 |
+dl> |
7708 |
+dl> T int x |
7709 |
+T int x |
7710 |
+-----^ syntax error |
7711 |
+dl> int x |
7712 |
+dl> uint y |
7713 |
+uint y |
7714 |
+------^ syntax error |
7715 |
+dl> T uint y = 5 |
7716 |
+T uint y = 5 |
7717 |
+----------^ syntax error |
7718 |
+dl> T uint y |
7719 |
+dl> |
7720 |
+dl> ## the end |
7721 |
+dl> |
7722 |
+dl> |
7723 |
--- gdb/duel/types.c |
7724 |
+++ gdb/duel/types.c |
7725 |
@@ -0,0 +1,202 @@ |
7726 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
7727 |
+/* Public domain code */ |
7728 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
7729 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
7730 |
+ |
7731 |
+/* this module contains the duel type system management |
7732 |
+ */ |
7733 |
+ |
7734 |
+/* |
7735 |
+ * $Log: 10_all_gdb-6.6-duel.patch,v $ |
7736 |
+ * Revision 1.1 2007/12/29 21:06:06 vapier |
7737 |
+ * add DUEL support #199987 by Sergei Golubchik |
7738 |
+ * |
7739 |
+ * Revision 1.8 93/03/12 06:01:50 mg |
7740 |
+ * use tuint for uint etc |
7741 |
+ * |
7742 |
+ * Revision 1.7 93/02/03 21:55:26 mg |
7743 |
+ * support "signed char" |
7744 |
+ * |
7745 |
+ * Revision 1.6 93/01/12 21:54:25 mg |
7746 |
+ * cleanup and set for release |
7747 |
+ * |
7748 |
+ * Revision 1.5 93/01/03 07:31:24 mg |
7749 |
+ * *** empty log message *** |
7750 |
+ * |
7751 |
+ * Revision 1.4 92/10/19 15:09:28 mg |
7752 |
+ * support zero fields/enumerators because gdb have them sometimes. |
7753 |
+ * |
7754 |
+ * Revision 1.3 92/10/14 02:07:00 mg |
7755 |
+ * misc |
7756 |
+ * |
7757 |
+ * Revision 1.2 92/09/16 11:11:43 mg |
7758 |
+ * added builtin charptr type |
7759 |
+ * |
7760 |
+ */ |
7761 |
+ |
7762 |
+#include "duel.h" |
7763 |
+ |
7764 |
+FUNC tctype* duel_mkctype_ptr(tctype *t) |
7765 |
+{ |
7766 |
+ tctype *n ; |
7767 |
+ n=(tctype *) duel_malloc(sizeof(tctype)); |
7768 |
+ duel_bzero((char*) n,sizeof(tctype)); |
7769 |
+ n->type_kind=CTK_PTR ; |
7770 |
+ n->size=sizeof(void*); |
7771 |
+ n->u.kid=t ; |
7772 |
+ return n ; |
7773 |
+} |
7774 |
+ |
7775 |
+FUNC tctype* duel_mkctype_func(tctype *t) |
7776 |
+{ |
7777 |
+ tctype *n ; |
7778 |
+ n=(tctype *) duel_malloc(sizeof(tctype)); |
7779 |
+ duel_bzero((char*) n,sizeof(tctype)); |
7780 |
+ n->size=0 ; |
7781 |
+ n->type_kind=CTK_FUNC ; |
7782 |
+ n->u.kid=t ; |
7783 |
+ return n ; |
7784 |
+} |
7785 |
+ |
7786 |
+/* create a struct or union type. The fields are not set here, but |
7787 |
+ * filled individually with the next function |
7788 |
+ * note the having zero fields is supported. This shouldnt be legal in C |
7789 |
+ * but compilers allow pointer to sturct w/o every specifying the struct. |
7790 |
+ * this is especially true for gdb itself! |
7791 |
+ */ |
7792 |
+ |
7793 |
+FUNC tctype* duel_mkctype_struct(char *name,size_t size,int fields_no, |
7794 |
+ bool is_union) |
7795 |
+{ |
7796 |
+ tctype *n ; |
7797 |
+ n=(tctype *) duel_malloc(sizeof(tctype)); |
7798 |
+ duel_bzero((char*) n,sizeof(tctype)); |
7799 |
+ n->name=name ; |
7800 |
+ n->size=size ; |
7801 |
+ if(is_union) n->type_kind=CTK_UNION ; |
7802 |
+ else n->type_kind=CTK_STRUCT ; |
7803 |
+ n->u.f.fields_no=fields_no ; |
7804 |
+ if(fields_no==0) n->u.f.fields=NULL ; |
7805 |
+ else { |
7806 |
+ n->u.f.fields=(tctype_field *) duel_malloc(fields_no*sizeof(tctype_field)); |
7807 |
+ duel_bzero((char*) n->u.f.fields,fields_no*sizeof(tctype_field)); |
7808 |
+ } |
7809 |
+ return n ; |
7810 |
+} |
7811 |
+ |
7812 |
+/* insert field (field_no) into sturct/union (t), with type fctype |
7813 |
+ */ |
7814 |
+PROC duel_mkctype_struct_field(tctype *t,int field_no,char *name, |
7815 |
+ int bitpos,int bitlen, tctype *fctype) |
7816 |
+{ |
7817 |
+ tctype_field *f ; |
7818 |
+ duel_assert(t->type_kind==CTK_STRUCT || t->type_kind==CTK_UNION); |
7819 |
+ duel_assert(field_no>=0 && field_no <= t->u.f.fields_no); |
7820 |
+ f= &t->u.f.fields[field_no] ; |
7821 |
+ f->name=name ; |
7822 |
+ f->bitpos=bitpos ; |
7823 |
+ f->bitlen=bitlen ; |
7824 |
+ f->ctype=fctype ; |
7825 |
+} |
7826 |
+ |
7827 |
+/* create an enum type. The enumerators are not set here, but |
7828 |
+ * filled individually with the next function |
7829 |
+ * again like sturct, we support zero enums. I am not sure its needed, |
7830 |
+ * but better safe than sorry. |
7831 |
+ */ |
7832 |
+ |
7833 |
+FUNC tctype* duel_mkctype_enum(char *name,tctype_kind real_type_kind, |
7834 |
+ size_t size,int enumerators_no) |
7835 |
+{ |
7836 |
+ tctype *n ; |
7837 |
+ n=(tctype *) duel_malloc(sizeof(tctype)); |
7838 |
+ duel_bzero((char*) n,sizeof(tctype)); |
7839 |
+ n->name=name ; |
7840 |
+ n->size=size ; |
7841 |
+ n->type_kind=CTK_ENUM ; |
7842 |
+ n->u.e.real_type_kind=real_type_kind ; |
7843 |
+ n->u.e.enumerators_no=enumerators_no ; |
7844 |
+ if(enumerators_no==0) n->u.e.enumerators=NULL ; |
7845 |
+ else { |
7846 |
+ n->u.e.enumerators= (tctype_enumerator *) |
7847 |
+ duel_malloc(enumerators_no*sizeof(tctype_enumerator)); |
7848 |
+ duel_bzero((char*) n->u.e.enumerators, |
7849 |
+ enumerators_no*sizeof(tctype_enumerator)); |
7850 |
+ } |
7851 |
+ return n ; |
7852 |
+} |
7853 |
+ |
7854 |
+ |
7855 |
+/* insert enumerator (enumerator_no_ into an enum type (t), with given name/val |
7856 |
+ */ |
7857 |
+PROC duel_mkctype_enumerator(tctype *t,int enumerator_no,char *name,int val) |
7858 |
+{ |
7859 |
+ tctype_enumerator *e ; |
7860 |
+ duel_assert(t->type_kind==CTK_ENUM); |
7861 |
+ duel_assert(enumerator_no>=0 && enumerator_no <= t->u.e.enumerators_no); |
7862 |
+ e= &t->u.e.enumerators[enumerator_no] ; |
7863 |
+ e->name=name ; |
7864 |
+ e->val=val ; |
7865 |
+} |
7866 |
+ |
7867 |
+FUNC tctype* duel_mkctype_array(tctype *t,int size) |
7868 |
+{ |
7869 |
+ tctype *n ; |
7870 |
+ if(t->size==0) duel_gen_error("array of a type of zero size is illegal",0); |
7871 |
+ if(size<=0) duel_gen_error("array of size zero or negative is illegal",0); |
7872 |
+ n=(tctype *) duel_malloc(sizeof(tctype)); |
7873 |
+ duel_bzero((char*) n,sizeof(tctype)); |
7874 |
+ n->type_kind=CTK_ARRAY ; |
7875 |
+ n->size=size*t->size ; |
7876 |
+ n->u.kid=t ; |
7877 |
+ return n ; |
7878 |
+} |
7879 |
+ |
7880 |
+ |
7881 |
+LFUNC tctype* init_basic_ctype(tctype_kind tk,char *name,size_t size) |
7882 |
+{ |
7883 |
+ tctype *p = duel_malloc(sizeof(tctype)); |
7884 |
+ p->type_kind=tk ; |
7885 |
+ p->name=name ; |
7886 |
+ p->size=size ; |
7887 |
+ return p ; |
7888 |
+} |
7889 |
+ |
7890 |
+PROC duel_init_basic_ctypes(void) |
7891 |
+{ |
7892 |
+ ctype_void= init_basic_ctype(CTK_VOID, "void", 0); |
7893 |
+ |
7894 |
+ ctype_char =init_basic_ctype(CTK_CHAR, "char", sizeof(char)); |
7895 |
+ ctype_short =init_basic_ctype(CTK_SHORT, "short",sizeof(short)); |
7896 |
+ ctype_int =init_basic_ctype(CTK_INT, "int", sizeof(int)); |
7897 |
+ ctype_long =init_basic_ctype(CTK_LONG, "long", sizeof(long)); |
7898 |
+ ctype_longlong=init_basic_ctype(CTK_LONGLONG,"long long", sizeof(long long)); |
7899 |
+ |
7900 |
+ ctype_schar =init_basic_ctype(CTK_SCHAR, "signed char", sizeof(tschar)); |
7901 |
+ ctype_uchar =init_basic_ctype(CTK_UCHAR, "unsigned char", sizeof(tuchar)); |
7902 |
+ ctype_ushort =init_basic_ctype(CTK_USHORT, "unsigned short",sizeof(tushort)); |
7903 |
+ ctype_uint =init_basic_ctype(CTK_UINT, "unsigned int", sizeof(tuint)); |
7904 |
+ ctype_ulong =init_basic_ctype(CTK_ULONG, "unsigned long", sizeof(tulong)); |
7905 |
+ ctype_ulonglong=init_basic_ctype(CTK_ULONG, "unsigned long long", sizeof(tulonglong)); |
7906 |
+ |
7907 |
+ ctype_double=init_basic_ctype(CTK_DOUBLE, "double", sizeof(double)); |
7908 |
+ ctype_float =init_basic_ctype(CTK_FLOAT, "float", sizeof(float)); |
7909 |
+ |
7910 |
+ ctype_voidptr=duel_mkctype_ptr(ctype_void); |
7911 |
+ ctype_charptr=duel_mkctype_ptr(ctype_char); |
7912 |
+ /* find and set the special types. |
7913 |
+ * support only a signed ptrdiff; size_t/ptrdiff must both be int or long |
7914 |
+ */ |
7915 |
+ { ptrdiff_t p ; size_t s ; |
7916 |
+ p= -1 ; s= -1 ; |
7917 |
+ if(p>0) duel_gen_error("bad ptrdiff_t - unsigned",0); |
7918 |
+ |
7919 |
+ if(sizeof(p)==sizeof(int)) ctype_ptrdiff_t=ctype_int ; |
7920 |
+ else if(sizeof(p)==sizeof(long)) ctype_ptrdiff_t=ctype_long ; |
7921 |
+ else duel_gen_error("bad ptrdiff_t size",0); |
7922 |
+ |
7923 |
+ if(sizeof(s)==sizeof(int)) ctype_size_t= (s<0)? ctype_int:ctype_uint ; |
7924 |
+ else |
7925 |
+ if(sizeof(s)==sizeof(long)) ctype_size_t= (s<0)? ctype_long:ctype_ulong ; |
7926 |
+ else duel_gen_error("bad size_t size",0); |
7927 |
+ } |
7928 |
+} |
7929 |
+ |
7930 |
+ |
7931 |
--- gdb/duel/wishlist.doc |
7932 |
+++ gdb/duel/wishlist.doc |
7933 |
@@ -0,0 +1,160 @@ |
7934 |
+ |
7935 |
+ += -= etc operators |
7936 |
+ initialize variables e.g. int x=0 , maybe even scopes |
7937 |
+ set declared var to zero. |
7938 |
+ allow x++ for aliases as a special case. |
7939 |
+ x->?y or x?->y to be like (x!=?0)->y OR x?? or ??x as (x!=?0) |
7940 |
+ |
7941 |
+ +/ */ &/ |/ ^/ ==/ !=/ </ >/ <=/ >=/ |
7942 |
+ src(location) as scope |
7943 |
+ istype(type,x) to check type of x |
7944 |
+ ?x to check for x in current scope |
7945 |
+ conditional break points, watchpoints |
7946 |
+ better type checking of structs. |
7947 |
+ bitfield assignment |
7948 |
+ better builtin commands, help |
7949 |
+ output formatting, duel/xodus, more general out(v) |
7950 |
+ duel macros/functions |
7951 |
+ \x and \\x |
7952 |
+ check array bounds |
7953 |
+ x->>y x->-y x>--y |
7954 |
+ check cycles in --> expansion |
7955 |
+ ..:+ ..:- |
7956 |
+ print types, do so better |
7957 |
+ |
7958 |
+DUEL.PIPE - make it general purpose |
7959 |
+------------------------------------ |
7960 |
+see duel.pipe for some details. |
7961 |
+should be made general purpose, so it is easy to modify/add functions. |
7962 |
+many basic functions can be writted - sort, uniq, matrix, vector, |
7963 |
+compress, etc. |
7964 |
+ |
7965 |
+Checking for cycles in --> expansion |
7966 |
+------------------------------------ |
7967 |
+One can easily add code to handle head-->(next!=?head), as well as |
7968 |
+head-->(next!=?_). If you don't know what these do, you should RTFM again :-) |
7969 |
+ |
7970 |
+You can also keep all pointers that have been expanded already, |
7971 |
+hence detecting any kind of cycle. However, what to do in |
7972 |
+such cases is debatable. Some users would like to see |
7973 |
+cycles terminate expansion quietly, while others will want a fatal error |
7974 |
+to be produced. This could be handled by an operator like x-->?y which |
7975 |
+would indicate that cycles are ok and expansion should terminate quietly, |
7976 |
+while x-->y produce an error on cycles. |
7977 |
+ |
7978 |
+Another idea is to have _cyc defined inside -->, to allow the user to |
7979 |
+do something about cycles, e.g. head-->(if(!_cyc) next). There are |
7980 |
+several ways to manage _cyc: a boolean, or equal to head; true if |
7981 |
+this is already a cycle, or a function cyc(next), which return true if |
7982 |
+next would cycle, or return next unles it would cycle, etc. |
7983 |
+This last one seems to handle most cases: |
7984 |
+head-->(cyc(left),cyc(right)) - return tree, igoring cycles |
7985 |
+head-->(cyc(0),left,right) - like head->(left,right), but mention of cyc |
7986 |
+ which by itself does nothing, cause general |
7987 |
+ cycle detection as errors |
7988 |
+as above, but left!=?_ - detect general cycles, pointer to self ok |
7989 |
+ |
7990 |
+While we adding cyc(), we can also add _depth to indicate current depth, |
7991 |
+e.g. head-->(if(_depth<6) (left,right)) -- expand only to depth 6 |
7992 |
+and also acceess to the current path with _path(i), _path(0)=_ and |
7993 |
+_path(_depth-1)=head |
7994 |
+head-->(cyc(0), if(! ||/_path(.._deapth)==left) left, ...) |
7995 |
+ which avoids cycles "in the path" |
7996 |
+ |
7997 |
+If you an strong opinion on this subject, or a better idea, lemme know! |
7998 |
+ |
7999 |
+Other expansions: x->>y x->-y x>--y |
8000 |
+------------------------------------ |
8001 |
+x-->y applies DFS (Depth First Search). Another useful expansion would be |
8002 |
+BFS (Breath First Search). It is simple to implement - y's values should |
8003 |
+be put on a queue instead of a stack, and the code in place has been written |
8004 |
+with this in mind (eval.c). |
8005 |
+Others will probably want a post-order or in-order search instead of preorder |
8006 |
+search as done by x-->y. I am not sure this is important enough to merit |
8007 |
+new operators, but ->- for inorder and >-- for post order are reserved. |
8008 |
+These, too, should be easy to implement, but it is very unclear that the |
8009 |
+added complexity to the language is worth it. If you really need such |
8010 |
+operators, lemme know. |
8011 |
+ |
8012 |
+Increment count for x..y (x..y:+z and x..y:-z) |
8013 |
+------------------------------------------------ |
8014 |
+The x..y operator could be extended to support an increment or decrement |
8015 |
+value. This would allow 1..n to be written as 1..n:+1 so when n==0 it |
8016 |
+will not produce the surprising 1,0 results. |
8017 |
+However, 0..10:+2 could also be written as (0..5)*2, so it is unclear |
8018 |
+that such operators are really needed (maybe just x..+y, x..-y to force |
8019 |
+the direction). |
8020 |
+ |
8021 |
+ |
8022 |
+Duel functions / print procedures |
8023 |
+------------------------------------- |
8024 |
+the command: dl define x expr |
8025 |
+will define x to be duel procedure for expression expr. |
8026 |
+x can then be used like an alias (indeed, it will probably be kept in |
8027 |
+the alias table with a special value). x evaluation returns multiple |
8028 |
+values. |
8029 |
+There is no need parameters, since emp.x would call "x" using the implicit |
8030 |
+parameter "_" set as emp. the expression for x is essentially put into |
8031 |
+the code for the execution. Having no parameters (except implicit ones) |
8032 |
+make it easier to document, use etc. |
8033 |
+ |
8034 |
+Such functions (macros?) are most useful for output. e.g. |
8035 |
+dl define empout val_type,a, u.if(val_type==0) code*6,name else code,z |
8036 |
+dl emp.empout |
8037 |
+will produce output for |
8038 |
+ struct { |
8039 |
+ int val_type,code ; |
8040 |
+ char a; |
8041 |
+ union { char *name ; double z ; } u |
8042 |
+ } emp ; |
8043 |
+ |
8044 |
+the empout procedure can be defined just once, and used to output such |
8045 |
+unions as needed. |
8046 |
+ |
8047 |
+The next step is to call such functions automatically for output and |
8048 |
+for expansion. We add syntax like dl define out(type) expr |
8049 |
+ |
8050 |
+then whenever an expression of the given type is to be printed, this |
8051 |
+code is evaluated instead, e.g.: |
8052 |
+dl define out(struct emp) ... |
8053 |
+dl emp ## this calls the above out code for the output. |
8054 |
+ |
8055 |
+We can also expand expressions by calling the right function, e.g. |
8056 |
+The operator "\" calls a function to expand a specific type: |
8057 |
+dl define \(struct list *) (_-->next) |
8058 |
+dl if(\head#i == \head#j && i<j) \head[[i,j]] |
8059 |
+ |
8060 |
+instead of writing this code (find non unique elements of linked list): |
8061 |
+ if(head-->next#i == head-->next#j && i<j) head-->next[[i,j]] |
8062 |
+ |
8063 |
+Both printing and expansion occurs automatically based on TYPE. |
8064 |
+It is unclear if the an array is allowed to be expanded by a pointer |
8065 |
+type expansion or not (i.e. is \(int *) to expand "int x[40]"). |
8066 |
+this might require an extension to types allowing \(int [n]) which matches |
8067 |
+any int array and set n for the specific bound. Types could be extended |
8068 |
+in a similar way, e.g. \(type **) _[0..]@0 |
8069 |
+which expands any array of pointers (e.g. argv). |
8070 |
+This can quickly require scope-nesting for local aliases/variables. |
8071 |
+ |
8072 |
+As before, it is unclear what of these is useful. Unless people depends on |
8073 |
+duel heavily, and write such "output/expansion" functions for the project, |
8074 |
+the features are useless (who is going to use this interactively?) |
8075 |
+ |
8076 |
+Regular expressions for names. $xxx and `xxx` |
8077 |
+---------------------------------------------- |
8078 |
+this allows things like emp.`value_*` to return all the value_something |
8079 |
+fields. it is really useful with structs, especially if a grep-style hat (^) |
8080 |
+is supported. Obviously extends to func.rexp, to show all locals, etc, |
8081 |
+which will make it possible to write a stack-trace display in duel. |
8082 |
+ |
8083 |
+exact semantics (e.g. what is matched and how) unclear. |
8084 |
+ |
8085 |
+ |
8086 |
+Nicer #/ |
8087 |
+--------- |
8088 |
+ |
8089 |
+hash[..1024] => #/_-->next >? 2 |
8090 |
+ |
8091 |
+it is probably best if #/(exp) constructed (exp) as symbolic before it |
8092 |
+gets the values. or maybe, yes, best is #/(e) symbolic is #/(e1..en) |
8093 |
+where e1 is the first return symbolc, en the last. |
8094 |
--- gdb/duelgdb.c |
8095 |
+++ gdb/duelgdb.c |
8096 |
@@ -0,0 +1,694 @@ |
8097 |
+/* DUEL - A Very High Level Debugging Langauge. */ |
8098 |
+/* Public domain code */ |
8099 |
+/* Written by Michael Golan mg@××××××××××××.edu */ |
8100 |
+/*$Header: /var/cvsroot/gentoo/src/patchsets/gdb/6.7.1/10_all_gdb-6.6-duel.patch,v 1.1 2007/12/29 21:06:06 vapier Exp $*/ |
8101 |
+ |
8102 |
+/* debugger dependent module, it contains all of duel's access to |
8103 |
+ * the outside world (debuggee, symbol table, etc) |
8104 |
+ */ |
8105 |
+ |
8106 |
+/* |
8107 |
+ * $Log: 10_all_gdb-6.6-duel.patch,v $ |
8108 |
+ * Revision 1.1 2007/12/29 21:06:06 vapier |
8109 |
+ * add DUEL support #199987 by Sergei Golubchik |
8110 |
+ * |
8111 |
+ * Revision 1.30 08/11/14 23:14:00 serg |
8112 |
+ * ported to gdb 6.6.2, glibc 2.5 |
8113 |
+ * |
8114 |
+ * Revision 1.20 93/03/20 10:35:48 mg |
8115 |
+ * fixed system("date")... didnt work on OS/2 |
8116 |
+ * |
8117 |
+ * Revision 1.19 93/03/13 03:28:49 mg |
8118 |
+ * bug fixed frame(0).unknown_name caused a crash |
8119 |
+ * bug fixed duel didnt support enum of length zero but turns out gdb tables |
8120 |
+ * have such things (specifically, for some gdb internals!) |
8121 |
+ * |
8122 |
+ * Revision 1.18 93/03/12 05:43:22 mg |
8123 |
+ * Version 1.10 - tuint instead of uint etc, fixed gdb48 recognis. problem |
8124 |
+ * |
8125 |
+ * Revision 1.17 93/02/27 06:01:01 mg |
8126 |
+ * improved unsigned char default machines support, |
8127 |
+ * convert explicit uchar into "char" if they are the same. |
8128 |
+ * |
8129 |
+ * Revision 1.16 93/02/23 19:11:10 mg |
8130 |
+ * beauty changes + gdb4.8 support |
8131 |
+ * |
8132 |
+ * Revision 1.15 93/02/04 02:09:18 mg |
8133 |
+ * fixed enum enum names |
8134 |
+ * |
8135 |
+ * Revision 1.14 93/02/04 00:54:26 mg |
8136 |
+ * arr. fixed. |
8137 |
+ * |
8138 |
+ * Revision 1.13 93/02/03 21:54:14 mg |
8139 |
+ * create duel.out unless compiling with NO_DUEL_OUT |
8140 |
+ * |
8141 |
+ * Revision 1.12 93/02/03 21:46:33 mg |
8142 |
+ * fixed problems with null gdb type names. |
8143 |
+ * support "signed char" |
8144 |
+ * |
8145 |
+ * Revision 1.11 93/01/21 21:22:15 mg |
8146 |
+ * *** empty log message *** |
8147 |
+ * |
8148 |
+ * Revision 1.10 93/01/13 16:19:33 mg |
8149 |
+ * support mini symbol table lookup (malloc, printf on SUN didnt work) |
8150 |
+ * |
8151 |
+ * Revision 1.9 93/01/12 21:30:04 mg |
8152 |
+ * cleanup and set for release |
8153 |
+ * |
8154 |
+ * Revision 1.8 93/01/06 23:59:21 mg |
8155 |
+ * new memory alloc/release. moved target's malloc into duel code |
8156 |
+ * allow ^c to work, fixed help, fixed variable lookup for specific frame. |
8157 |
+ * |
8158 |
+ * Revision 1.7 93/01/03 07:27:11 mg |
8159 |
+ * support function calls! |
8160 |
+ * |
8161 |
+ * Revision 1.6 92/12/24 23:33:13 mg |
8162 |
+ * frames support |
8163 |
+ * |
8164 |
+ * Revision 1.5 92/10/19 15:06:29 mg |
8165 |
+ * made lcc happy |
8166 |
+ * no svalues |
8167 |
+ * new registers support and way of getting vars. |
8168 |
+ * these are temporary changes, new frames supports soon |
8169 |
+ * |
8170 |
+ * Revision 1.4 92/10/14 02:03:53 mg |
8171 |
+ * misc/gdb4.6/duel vars using malloc |
8172 |
+ * |
8173 |
+ * Revision 1.3 92/09/16 11:06:22 mg |
8174 |
+ * a lot more functions: get typedef/tags, alloc debuggee mem. +cosmetics |
8175 |
+ * |
8176 |
+ * Revision 1.2 92/09/15 05:37:28 mg |
8177 |
+ * fix enum size bug. added headers |
8178 |
+ * |
8179 |
+ */ |
8180 |
+ |
8181 |
+ |
8182 |
+#include <stddef.h> /* used for ptrdiff_t and size_t */ |
8183 |
+#include <stdio.h> |
8184 |
+#include <string.h> |
8185 |
+#include <time.h> /* for time/ctime stamping of duel.out */ |
8186 |
+#include <assert.h> |
8187 |
+ |
8188 |
+#include "defs.h" |
8189 |
+#include "symtab.h" |
8190 |
+#include "gdbtypes.h" |
8191 |
+#include "gdbcore.h" |
8192 |
+#include "frame.h" |
8193 |
+#include "target.h" |
8194 |
+#include "value.h" |
8195 |
+#include "symfile.h" |
8196 |
+#include "objfiles.h" |
8197 |
+#include "gdbcmd.h" |
8198 |
+#include "call-cmds.h" |
8199 |
+#include "infcall.h" |
8200 |
+ |
8201 |
+#include "duel/global.h" |
8202 |
+#include "duel/proto.h" |
8203 |
+ |
8204 |
+/* all output goes thru here */ |
8205 |
+ |
8206 |
+#include <stdarg.h> |
8207 |
+ |
8208 |
+PROC duel_printf(char *fmt, ...) /* like printf, but for duel output */ |
8209 |
+{ |
8210 |
+ va_list args; |
8211 |
+ va_start(args, fmt); |
8212 |
+ vprintf_filtered(fmt,args); |
8213 |
+ va_end(args); |
8214 |
+} |
8215 |
+ |
8216 |
+PROC duel_flush(void) |
8217 |
+{ /* not yet. only really needed for redirections */ |
8218 |
+} |
8219 |
+ |
8220 |
+PROC duel_redirectable_output_start(char *s) |
8221 |
+{ |
8222 |
+} |
8223 |
+ |
8224 |
+PROC duel_redirectable_output_end(void) |
8225 |
+{ |
8226 |
+} |
8227 |
+ |
8228 |
+PROC duel_redirectable_output_abort(void) |
8229 |
+{ |
8230 |
+} |
8231 |
+ |
8232 |
+PROC duel_redirectable_output_init(void) |
8233 |
+{ |
8234 |
+} |
8235 |
+ |
8236 |
+/* all duel memory allocations go thru here */ |
8237 |
+ |
8238 |
+FUNC void* duel_malloc(size_t size) |
8239 |
+{ |
8240 |
+ void *p ; |
8241 |
+ immediate_quit-- ; /* disable ^C while xmalloc */ |
8242 |
+ p=xmalloc(size); /* gdb's malloc, incl zero return chk */ |
8243 |
+ immediate_quit++ ; |
8244 |
+ QUIT ; /* check if ^C while xmalloc called */ |
8245 |
+ return p ; |
8246 |
+} |
8247 |
+ |
8248 |
+PROC duel_free(void *p) |
8249 |
+{ |
8250 |
+ immediate_quit-- ; |
8251 |
+ free(p); |
8252 |
+ immediate_quit++ ; |
8253 |
+ QUIT ; |
8254 |
+} |
8255 |
+ |
8256 |
+/* fetch n bytes from the target at the given memory address. |
8257 |
+ * the address to fetch from is given by (from). |
8258 |
+ * the value is stored at the 'to' location, which points to space for |
8259 |
+ * n bytes in the debugger. |
8260 |
+ * if the address can not be accessed, false is returned (if all ok, ret true) |
8261 |
+ */ |
8262 |
+ |
8263 |
+FUNC bool duel_get_target_bytes(ttarget_ptr from,void *to,size_t n) |
8264 |
+{ |
8265 |
+ return target_read_memory((CORE_ADDR)from,to,n)==0; |
8266 |
+} |
8267 |
+ |
8268 |
+/* store n bytes to the debuggee. reverse parms from above */ |
8269 |
+FUNC bool duel_put_target_bytes(ttarget_ptr to,void *from,size_t n) |
8270 |
+{ |
8271 |
+ return target_write_memory((CORE_ADDR)to,from,n)==0; |
8272 |
+} |
8273 |
+ |
8274 |
+/* fetch the value of a bitfield of a given structure. |
8275 |
+ * struct_at - a pointer to the structure |
8276 |
+ * bitpos - the position of the field, in bits (as given in the type) |
8277 |
+ * bitlen - the length of the field in bits |
8278 |
+ * to - pointer to tuint where value will be stored. |
8279 |
+ * tkind - the type kind of the field (used to do sign extention if needed) |
8280 |
+ * note: I'm unaware of any compiler with bitfields that are not int/tuint. |
8281 |
+ */ |
8282 |
+ |
8283 |
+FUNC bool duel_get_target_bitfield(ttarget_ptr struct_at,int bitpos, |
8284 |
+ int bitlen,void *to,tctype_kind tkind) |
8285 |
+{ |
8286 |
+ tuint bits ; |
8287 |
+ duel_assert(tkind==CTK_INT || tkind==CTK_UINT); |
8288 |
+ if(!duel_get_target_bytes(struct_at+bitpos/8,&bits,sizeof(bits))) |
8289 |
+ return FALSE; |
8290 |
+ |
8291 |
+ /* now, move the field to the 'bottom' of bits, by shifting right */ |
8292 |
+ bitpos%=8 ; /* fix it to a bit offset inside the 'bits' */ |
8293 |
+ if (BITS_BIG_ENDIAN) /* defined by gdb's src code */ |
8294 |
+ bits >>= (sizeof(bits)*8-bitpos-bitlen) ; |
8295 |
+ else |
8296 |
+ bits >>= bitpos ; |
8297 |
+ |
8298 |
+ /* finally chop down 'bits' to only bitlen significant bits, |
8299 |
+ * or sign-extend it if output field is 'int' and the sign is 1. |
8300 |
+ * ~0 is all ones, shift it to have bitlen zeros. Complement to get |
8301 |
+ * a bitlen string of 1's in the low-order bits. Common ugly hacks. |
8302 |
+ * Note: this code assume 2's complement |
8303 |
+ */ |
8304 |
+ |
8305 |
+ if(tkind==CTK_INT && (bits & 1<<(bitlen-1))) /* int field, negative sign */ |
8306 |
+ bits|= ~0<<bitlen ; /*sign extend */ |
8307 |
+ else bits&= ~(~0<<bitlen) ; /* clear all bits above the sign bit */ |
8308 |
+ *(tuint*) to= bits ; |
8309 |
+ |
8310 |
+ return TRUE ; |
8311 |
+} |
8312 |
+ |
8313 |
+LFUNC struct type* duel_convert_type_to_gdb(tctype *ct); |
8314 |
+LFUNC tctype* duel_convert_type_from_gdb(struct type *gv); |
8315 |
+ |
8316 |
+/* convert gdb value into duel's. Used to fetch const, registers, func ret val |
8317 |
+ * and convert a symbol into a reference. |
8318 |
+ * otherwise, duel access target's memory directly. |
8319 |
+ */ |
8320 |
+ |
8321 |
+LPROC duel_convert_value_from_gdb(struct value *gv, tvalue *dv) |
8322 |
+{ |
8323 |
+ dv->ctype=duel_convert_type_from_gdb(value_type(gv)); |
8324 |
+ if(VALUE_LVAL(gv) == lval_memory) { |
8325 |
+ dv->val_kind=VK_LVALUE ; |
8326 |
+ dv->u.lvalue= (ttarget_ptr) VALUE_ADDRESS(gv) ; /*address of variable*/ |
8327 |
+ } |
8328 |
+ else |
8329 |
+ if(ctype_kind_scalar(dv->ctype) && (VALUE_LVAL(gv) == not_lval || |
8330 |
+ VALUE_LVAL(gv) == lval_register)) { |
8331 |
+ dv->val_kind=VK_RVALUE ; |
8332 |
+ duel_bcopy(&dv->u,value_contents_raw(gv),dv->ctype->size); |
8333 |
+ } |
8334 |
+ else |
8335 |
+ duel_fatal("unsupported value type returned by gdb"); |
8336 |
+} |
8337 |
+ |
8338 |
+ |
8339 |
+/* helper function converts duel values to gdb's values. used only to make |
8340 |
+ * function calls to the target, so current support is weak. |
8341 |
+ * gdb thinks long=int=pointers, so we go along with that. |
8342 |
+ * To support arbitrary types like struct/union, we can probably fake it |
8343 |
+ * by making a gdb lvalue. but i am not sure how/what |
8344 |
+ */ |
8345 |
+ |
8346 |
+LFUNC struct value *convert_duel_val_to_gdb_val(tvalue *v) |
8347 |
+{ |
8348 |
+ struct value *gv ; |
8349 |
+ if(v->val_kind!=VK_RVALUE) return 0 ; /* cant handle lvals */ |
8350 |
+ switch(v->ctype->type_kind) { |
8351 |
+/* duel standardize func parms, so this code is not required. if this |
8352 |
+ * function is used for more than func parms, as its name implies, we will |
8353 |
+ * need to do better than this. |
8354 |
+ * there is no gdb "builtin_type_signed_char", so we assume char |
8355 |
+ case CTK_CHAR: |
8356 |
+ gv=value_from_longest(builtin_type_char,v->u.rval_char); break; |
8357 |
+ case CTK_SCHAR: |
8358 |
+ gv=value_from_longest(builtin_type_char,v->u.rval_schar); break; |
8359 |
+ case CTK_UCHAR: |
8360 |
+ gv=value_from_longest(builtin_type_unsigned_char,v->u.rval_char); break; |
8361 |
+ case CTK_USHORT: |
8362 |
+ gv=value_from_longest(builtin_type_unsigned_short,v->u.rval_ushort);break; |
8363 |
+ case CTK_SHORT: |
8364 |
+ gv=value_from_longest(builtin_type_unsigned_short,v->u.rval_short);break; |
8365 |
+*/ |
8366 |
+ case CTK_INT: |
8367 |
+ gv=value_from_longest(builtin_type_int, v->u.rval_int); break; |
8368 |
+ case CTK_UINT: |
8369 |
+ gv=value_from_longest(builtin_type_unsigned_int, v->u.rval_uint) ; break ; |
8370 |
+ case CTK_LONG: |
8371 |
+ gv=value_from_longest(builtin_type_long, v->u.rval_long) ; break ; |
8372 |
+ case CTK_ULONG: |
8373 |
+ gv=value_from_longest(builtin_type_unsigned_long,v->u.rval_ulong); break ; |
8374 |
+ case CTK_LONGLONG: |
8375 |
+ gv=value_from_longest(builtin_type_long_long, v->u.rval_longlong) ; break ; |
8376 |
+ case CTK_ULONGLONG: |
8377 |
+ gv=value_from_longest(builtin_type_unsigned_long_long,v->u.rval_ulonglong); break ; |
8378 |
+ case CTK_FLOAT: |
8379 |
+ gv=value_from_double(builtin_type_float, v->u.rval_float) ; break ; |
8380 |
+ case CTK_DOUBLE: |
8381 |
+ gv=value_from_double(builtin_type_double, v->u.rval_double) ; break ; |
8382 |
+ case CTK_PTR: |
8383 |
+ gv=value_from_longest(lookup_pointer_type(builtin_type_void), |
8384 |
+ (long) v->u.rval_ptr) ;break ; |
8385 |
+ default: duel_assert(0); |
8386 |
+ } |
8387 |
+ return gv ; |
8388 |
+} |
8389 |
+ |
8390 |
+/* make a function call to the target. |
8391 |
+ * this is the only case where we convert duel tvalue into gdb's values. |
8392 |
+ * gdb thinks long=int=pointers, so we go along with that. |
8393 |
+ */ |
8394 |
+ |
8395 |
+PROC duel_target_func_call(tvalue *func, tvalue *parms[], |
8396 |
+ int parms_no,tvalue *rval) |
8397 |
+{ |
8398 |
+ struct value *gfunc, *grval, *gparms[20] ; |
8399 |
+ int i ; |
8400 |
+ struct type *gftype ; |
8401 |
+ |
8402 |
+ duel_assert(func->val_kind==VK_LVALUE); |
8403 |
+ for(i=0 ; i<parms_no ; i++) { |
8404 |
+ gparms[i]=convert_duel_val_to_gdb_val(parms[i]) ; |
8405 |
+ if(gparms[i]==NULL) |
8406 |
+ duel_op_error("unsupported func call parm type",0,parms[i],0); |
8407 |
+ } |
8408 |
+ gftype =duel_convert_type_to_gdb(func->ctype); |
8409 |
+ if(!gftype) duel_op_error("unsupported func return parm type",0,func,0); |
8410 |
+ gftype = lookup_pointer_type(gftype); |
8411 |
+ if(!gftype) |
8412 |
+ duel_op_error("unsupproted func return type",0,func,0); |
8413 |
+ |
8414 |
+ gfunc = value_from_longest(gftype,(LONGEST) func->u.lvalue); |
8415 |
+ |
8416 |
+ grval=call_function_by_hand(gfunc,parms_no,gparms); |
8417 |
+ if(func->ctype->u.kid->type_kind==CTK_VOID) return ; /* no return val*/ |
8418 |
+ duel_convert_value_from_gdb(grval,rval); |
8419 |
+} |
8420 |
+ |
8421 |
+ |
8422 |
+ |
8423 |
+#define TYPE_HASH_SIZE (1024*128) |
8424 |
+#define type_hash_func(t) ( (((long)t&0xffff) + (((long)t>>16)&0xffff)) \ |
8425 |
+ % TYPE_HASH_SIZE ) |
8426 |
+struct { |
8427 |
+ struct type *t ; /* gdb type ptr */ |
8428 |
+ tctype *ct ; /* duel type ptr */ |
8429 |
+} duel_thash[TYPE_HASH_SIZE] ; |
8430 |
+ |
8431 |
+LPROC duel_add_hash(struct type *t, tctype *ct) |
8432 |
+{ |
8433 |
+ int start,i=type_hash_func(t); |
8434 |
+ start=i ; |
8435 |
+ do { |
8436 |
+ if(duel_thash[i].t==0) { |
8437 |
+ duel_thash[i].t=t ; |
8438 |
+ duel_thash[i].ct=ct ; |
8439 |
+ return ; |
8440 |
+ } |
8441 |
+ if(duel_thash[i].t==t) { |
8442 |
+ if(duel_thash[i].ct==ct) return ; |
8443 |
+ duel_fatal("type hash table inconsistency "); |
8444 |
+ } |
8445 |
+ i= (i+1)%TYPE_HASH_SIZE ; |
8446 |
+ } while(i!=start); |
8447 |
+ duel_fatal("type hash table is full"); |
8448 |
+} |
8449 |
+ |
8450 |
+LFUNC tctype* duel_find_hash(struct type *t) |
8451 |
+{ |
8452 |
+ int start,i=type_hash_func(t); |
8453 |
+ start=i ; |
8454 |
+ do { |
8455 |
+ if(duel_thash[i].t==0) break ; |
8456 |
+ if(duel_thash[i].t==t) return duel_thash[i].ct ; |
8457 |
+ i= (i+1)%TYPE_HASH_SIZE ; |
8458 |
+ } while(i!=start); |
8459 |
+ return NULL ; |
8460 |
+} |
8461 |
+ |
8462 |
+/* a simple conversion back to gdb types, used only for target func calls */ |
8463 |
+/* this is a hack and based on the assumption that the type was first |
8464 |
+ * converted FROM gdb to duel. (turn out to be false for int func from |
8465 |
+ * minimal symbols, so we do this as a special case.) |
8466 |
+ */ |
8467 |
+LFUNC struct type* duel_convert_type_to_gdb(tctype *ct) |
8468 |
+{ |
8469 |
+ int i ; |
8470 |
+ for(i=0 ; i<TYPE_HASH_SIZE ; i++) |
8471 |
+ if(duel_thash[i].ct==ct) return duel_thash[i].t ; |
8472 |
+ |
8473 |
+ if(ct->type_kind==CTK_FUNC && ct->u.kid->type_kind==CTK_INT) |
8474 |
+ return lookup_function_type (builtin_type_int); |
8475 |
+ return NULL ; |
8476 |
+} |
8477 |
+ |
8478 |
+#define INTTYPE_CHAR 1 |
8479 |
+#define INTTYPE_SHORT 2 |
8480 |
+#define INTTYPE_INT 0 |
8481 |
+#define INTTYPE_LONG 4 |
8482 |
+#define INTTYPE_SIGNED 0 |
8483 |
+#define INTTYPE_UNSIGNED 16 |
8484 |
+ |
8485 |
+struct { char *name; int len; int codetype; } name_to_codetype[]= |
8486 |
+{ {"char", 4, INTTYPE_CHAR }, |
8487 |
+ {"short", 5, INTTYPE_SHORT }, |
8488 |
+ {"int", 3, INTTYPE_INT }, |
8489 |
+ {"long", 4, INTTYPE_LONG }, |
8490 |
+ {"signed", 6, INTTYPE_SIGNED }, |
8491 |
+ {"unsigned", 8, INTTYPE_UNSIGNED }, |
8492 |
+ {0,0,0} |
8493 |
+}; |
8494 |
+ |
8495 |
+ /* given a gdb type t, return an equivalent duel type */ |
8496 |
+ |
8497 |
+LFUNC tctype* duel_convert_type_from_gdb(struct type *t) |
8498 |
+{ |
8499 |
+ tctype *ct=duel_find_hash(t); |
8500 |
+ if(ct) return ct ; |
8501 |
+ |
8502 |
+ if (duel_debug) |
8503 |
+ duel_printf("gdb type: {%d, %s}\n", TYPE_CODE(t), TYPE_NAME(t)); |
8504 |
+ |
8505 |
+ switch (TYPE_CODE (t)) { |
8506 |
+ case TYPE_CODE_BOOL: |
8507 |
+ if(strcmp(TYPE_NAME(t),"bool")==0) ct=ctype_uchar ; /* XXX HACK */ |
8508 |
+ break; |
8509 |
+ case TYPE_CODE_INT: { |
8510 |
+ int i, type=0; |
8511 |
+ char *s=TYPE_NAME(t); |
8512 |
+ while (*s) |
8513 |
+ for (i=0; name_to_codetype[i].name; i++) { |
8514 |
+ if (strncmp(s,name_to_codetype[i].name,name_to_codetype[i].len) == 0) { |
8515 |
+ s+=name_to_codetype[i].len; |
8516 |
+ if (*s == ' ') s++; |
8517 |
+ type+= name_to_codetype[i].codetype; |
8518 |
+ break; |
8519 |
+ } |
8520 |
+ } |
8521 |
+ if(type == INTTYPE_CHAR) ct=ctype_char ; |
8522 |
+ else if(type == INTTYPE_CHAR + INTTYPE_UNSIGNED) ct=ctype_uchar ; |
8523 |
+ else if(type == INTTYPE_SHORT) ct=ctype_short ; |
8524 |
+ else if(type == INTTYPE_SHORT + INTTYPE_UNSIGNED) ct=ctype_ushort ; |
8525 |
+ else if(type == INTTYPE_INT) ct=ctype_int ; |
8526 |
+ else if(type == INTTYPE_UNSIGNED) ct=ctype_uint ; |
8527 |
+ else if(type == INTTYPE_LONG) ct=ctype_long ; |
8528 |
+ else if(type == INTTYPE_UNSIGNED + INTTYPE_LONG) ct=ctype_ulong ; |
8529 |
+ else if(type == INTTYPE_LONG + INTTYPE_LONG) ct=ctype_longlong ; |
8530 |
+ else if(type == INTTYPE_UNSIGNED + INTTYPE_LONG + INTTYPE_LONG) ct=ctype_ulonglong ; |
8531 |
+ break; |
8532 |
+ } |
8533 |
+ case TYPE_CODE_FLT: |
8534 |
+ if(strcmp(TYPE_NAME(t),"float")==0) ct=ctype_float ; |
8535 |
+ else |
8536 |
+ if(strcmp(TYPE_NAME(t),"double")==0) ct=ctype_double ; |
8537 |
+ break; |
8538 |
+ case TYPE_CODE_VOID: |
8539 |
+ if(strcmp(TYPE_NAME(t),"void")==0) ct=ctype_void ; |
8540 |
+ break; |
8541 |
+ case TYPE_CODE_PTR: |
8542 |
+ case TYPE_CODE_REF: |
8543 |
+ { |
8544 |
+ /* the pointer might get defined when converting the target, so |
8545 |
+ * check the hashing again (reason: self-referencing structs) |
8546 |
+ */ |
8547 |
+ tctype *target=duel_convert_type_from_gdb(TYPE_TARGET_TYPE(t)); |
8548 |
+ if((ct=duel_find_hash(t))==NULL) ct=duel_mkctype_ptr(target); |
8549 |
+ } |
8550 |
+ break ; |
8551 |
+ case TYPE_CODE_FUNC: |
8552 |
+ ct=duel_mkctype_func(duel_convert_type_from_gdb(TYPE_TARGET_TYPE(t))); |
8553 |
+ break ; |
8554 |
+ case TYPE_CODE_ARRAY: |
8555 |
+ { int n=TYPE_LENGTH(TYPE_TARGET_TYPE(t)); |
8556 |
+ if(n!=0) n=TYPE_LENGTH(t)/n; |
8557 |
+ ct=duel_mkctype_array( |
8558 |
+ duel_convert_type_from_gdb(TYPE_TARGET_TYPE(t)),n); |
8559 |
+ } |
8560 |
+ break; |
8561 |
+ case TYPE_CODE_STRUCT: |
8562 |
+ case TYPE_CODE_UNION: |
8563 |
+ { int i,n=TYPE_NFIELDS(t); |
8564 |
+ char *name=TYPE_NAME(t); |
8565 |
+ if(name == NULL) name="" ; /* duel can't handle null ptr! */ |
8566 |
+ if(strncmp(name,"struct ",7)==0) name+=7 ; |
8567 |
+ if(strncmp(name,"union ",6)==0) name+=6 ; |
8568 |
+ ct=duel_mkctype_struct(name,TYPE_LENGTH(t),n, |
8569 |
+ TYPE_CODE(t)==TYPE_CODE_UNION); |
8570 |
+ duel_add_hash(t,ct); /* so a pointer to myself is recognized */ |
8571 |
+ for(i=0 ; i<n ; i++) |
8572 |
+ duel_mkctype_struct_field(ct,i,TYPE_FIELD_NAME(t,i), |
8573 |
+ TYPE_FIELD_BITPOS(t,i), TYPE_FIELD_BITSIZE(t,i), |
8574 |
+ duel_convert_type_from_gdb(TYPE_FIELD_TYPE(t,i))); |
8575 |
+ } |
8576 |
+ break ; |
8577 |
+ case TYPE_CODE_ENUM: |
8578 |
+ /* TYPE_LENGTH(t) tell how big it is. I assume signed integral types. |
8579 |
+ * it is unclear if gdb supports unsigned enums and how |
8580 |
+ * (e.g. enum { x=0,y=250 } stored in uchar |
8581 |
+ * FIELDS contain the tags, BITPOS is the assigned value. |
8582 |
+ */ |
8583 |
+ { int i,n=TYPE_NFIELDS(t),len=TYPE_LENGTH(t); |
8584 |
+ char *name=TYPE_NAME(t); |
8585 |
+ tctype_kind k ; |
8586 |
+ if(name==NULL) name="" ; /* duel can't handle null ptr */ |
8587 |
+ if(strncmp(name,"enum ",5)==0) name+=5 ; |
8588 |
+ /* select 'real' stored type. note order important if short==int. |
8589 |
+ * long is not allowed as far as I know ANSI C (enums are conv. to int) |
8590 |
+ * Amazingly, some internal gdb struct (sym) can have an enum of |
8591 |
+ * size zero (enum language, gdb4.8). We allow this as int but warn. |
8592 |
+ * gdb> p sizeof(sym->ginfo.lang_specific.language) gives zero |
8593 |
+ */ |
8594 |
+ if(len==0) { |
8595 |
+ duel_printf("Warning: enum %s is size zero. assumed int\n",name); |
8596 |
+ len=sizeof(int); |
8597 |
+ } |
8598 |
+ if(len==sizeof(int)) k=CTK_INT ; |
8599 |
+ else if(len==sizeof(short)) k=CTK_SHORT ; |
8600 |
+ else if(len==sizeof(char)) k=CTK_CHAR ; |
8601 |
+ else duel_assert(0); |
8602 |
+ |
8603 |
+ ct=duel_mkctype_enum(name,k,len,n); |
8604 |
+ for(i=0 ; i<n ; i++) |
8605 |
+ duel_mkctype_enumerator(ct,i,TYPE_FIELD_NAME(t,i), |
8606 |
+ TYPE_FIELD_BITPOS(t,i)); |
8607 |
+ } |
8608 |
+ break ; |
8609 |
+ case TYPE_CODE_TYPEDEF: |
8610 |
+ ct=duel_convert_type_from_gdb(check_typedef(t)); |
8611 |
+ break ; |
8612 |
+ case TYPE_CODE_UNDEF: |
8613 |
+ break; |
8614 |
+ } |
8615 |
+ if(ct==0) duel_fatal("unsupported C type returned by gdb"); |
8616 |
+ duel_add_hash(t,ct); |
8617 |
+ return ct ; |
8618 |
+} |
8619 |
+ |
8620 |
+/* optimize frame access so frame(100..0) doesnt start the search from 0 |
8621 |
+ * everytime. similar to selected_frame etc, but we dont want to mess up |
8622 |
+ * gdb's own frame setup (for up/down/print etc) |
8623 |
+ * this optimization should have been part of gdb, not here. |
8624 |
+ * ie. duel_select_frame should be a simple fast gdb call. |
8625 |
+ * we dont optimze going to frame 7 from frame 5 etc, this isn't typical. |
8626 |
+ * set last/tot frames to -2 to assure recomputeations (-1 is not good enuf) |
8627 |
+ */ |
8628 |
+ |
8629 |
+static struct frame_info * last_frame ; /* last frame pointer we used */ |
8630 |
+static int last_frame_no ; /* last frame number we used */ |
8631 |
+static int tot_frames_no ; /* tot number of frames */ |
8632 |
+ |
8633 |
+LFUNC struct frame_info * duel_select_frame(int frame_no) |
8634 |
+{ |
8635 |
+ struct frame_info * frame ; |
8636 |
+ if(last_frame_no==frame_no) frame=last_frame ; |
8637 |
+ else |
8638 |
+ if(last_frame_no==frame_no-1) frame=get_prev_frame(last_frame); |
8639 |
+ else |
8640 |
+ if(last_frame_no==frame_no+1) frame=get_next_frame(last_frame); |
8641 |
+ else { |
8642 |
+ int count=frame_no ; |
8643 |
+ frame=get_current_frame(); |
8644 |
+ while (frame && --count >= 0) |
8645 |
+ frame = get_prev_frame (frame); |
8646 |
+ } |
8647 |
+ duel_assert(frame); /* callee should have checked frames no*/ |
8648 |
+ last_frame = frame ; |
8649 |
+ last_frame_no = frame_no ; |
8650 |
+ return frame ; |
8651 |
+} |
8652 |
+ |
8653 |
+FUNC bool duel_get_target_variable(char *name, int frame_no, tvalue *v) |
8654 |
+{ |
8655 |
+ struct symbol *sym; |
8656 |
+ struct frame_info * frame ; |
8657 |
+ struct block *blk ; |
8658 |
+ int len ; |
8659 |
+ struct value *gv ; /* gdb value */ |
8660 |
+ |
8661 |
+ if(frame_no== -1) { /* use the user selected frame and block */ |
8662 |
+ frame = get_selected_frame("Error!") ; |
8663 |
+ blk = get_selected_block(0) ; |
8664 |
+ } |
8665 |
+ else { |
8666 |
+ frame=duel_select_frame(frame_no) ; |
8667 |
+ blk = get_frame_block(frame, 0); |
8668 |
+ } |
8669 |
+ sym = lookup_symbol (name, blk, VAR_DOMAIN,0,0); |
8670 |
+ if(!sym) { /* look up the symbol that has no debug info*/ |
8671 |
+ struct minimal_symbol *m ; |
8672 |
+ if(frame_no != -1) return FALSE ; /* only locals looked up- not found*/ |
8673 |
+ m=lookup_minimal_symbol (name,NULL, 0); /* find printf, malloc etc */ |
8674 |
+ if(m == NULL) return FALSE ; |
8675 |
+ v->val_kind=VK_LVALUE ; |
8676 |
+#ifdef SYMBOL_LANGUAGE |
8677 |
+ /* in gdb4.8 the mini table changed. I use the existance of the above |
8678 |
+ * #define symbol as hack to indicate gdb.4.8 */ |
8679 |
+ v->u.lvalue=(ttarget_ptr) SYMBOL_VALUE_ADDRESS(m); |
8680 |
+#else |
8681 |
+ v->u.lvalue=(ttarget_ptr) m->address ; |
8682 |
+#endif |
8683 |
+ /* guess it is an int if it is a data type, an int func if text */ |
8684 |
+ if(m->type == mst_data || m->type == mst_bss) v->ctype=ctype_int ; |
8685 |
+ else |
8686 |
+ if(m->type == mst_text) v->ctype=duel_mkctype_func(ctype_int); |
8687 |
+ else return FALSE ; |
8688 |
+ return TRUE ; |
8689 |
+ } |
8690 |
+ if(SYMBOL_CLASS(sym)==LOC_TYPEDEF) return FALSE ; |
8691 |
+ /* if frame specificed, allow only local variables to be found */ |
8692 |
+ if(frame_no!= -1 && (SYMBOL_CLASS(sym)==LOC_STATIC || |
8693 |
+ SYMBOL_CLASS(sym)==LOC_BLOCK || SYMBOL_CLASS(sym)==LOC_CONST)) return FALSE; |
8694 |
+ gv=read_var_value(sym,frame); |
8695 |
+ if(gv==0) return FALSE ; /* frame not found or illegal */ |
8696 |
+ duel_convert_value_from_gdb(gv,v); |
8697 |
+ return TRUE ; |
8698 |
+} |
8699 |
+ |
8700 |
+ |
8701 |
+/* return the total number of frames on the stack */ |
8702 |
+ |
8703 |
+FUNC int duel_get_frames_number(void) |
8704 |
+{ |
8705 |
+ int n ; |
8706 |
+ struct frame_info * frame ; |
8707 |
+ if(tot_frames_no!= -2) return tot_frames_no ; |
8708 |
+ frame=get_current_frame(); |
8709 |
+ for(n=0 ; frame ; n++) |
8710 |
+ frame = get_prev_frame (frame); |
8711 |
+ return tot_frames_no=n ; |
8712 |
+} |
8713 |
+ |
8714 |
+FUNC ttarget_ptr duel_get_function_for_frame(int frame_no) |
8715 |
+{ |
8716 |
+ struct frame_info * frame=duel_select_frame(frame_no); |
8717 |
+ struct symbol *sym = get_frame_function(frame); |
8718 |
+ struct value *val = read_var_value(sym,frame); |
8719 |
+ duel_assert(val!=0 && VALUE_LVAL(val) == lval_memory); |
8720 |
+ |
8721 |
+ return (ttarget_ptr) VALUE_ADDRESS(val) ; |
8722 |
+} |
8723 |
+ |
8724 |
+FUNC tctype* duel_get_target_typedef(char *name) |
8725 |
+{ |
8726 |
+ struct symbol *sym; |
8727 |
+ sym = lookup_symbol (name, get_selected_block(0), VAR_DOMAIN,0,0); |
8728 |
+ if(!sym || SYMBOL_CLASS(sym)!=LOC_TYPEDEF) { |
8729 |
+ sym = lookup_symbol (name, 0, VAR_DOMAIN, 0,0); |
8730 |
+ if(!sym || SYMBOL_CLASS(sym)!=LOC_TYPEDEF) return NULL ; |
8731 |
+ } |
8732 |
+ return duel_convert_type_from_gdb(SYMBOL_TYPE(sym)); |
8733 |
+} |
8734 |
+ |
8735 |
+FUNC tctype* duel_get_target_struct_tag(char *name) |
8736 |
+{ |
8737 |
+ struct symbol *sym; |
8738 |
+ sym = lookup_symbol (name, get_selected_block(0), STRUCT_DOMAIN,0,0); |
8739 |
+ if(!sym || TYPE_CODE(SYMBOL_TYPE(sym))!=TYPE_CODE_STRUCT) { |
8740 |
+ sym = lookup_symbol (name, 0, STRUCT_DOMAIN, 0,0); |
8741 |
+ if(!sym || TYPE_CODE(SYMBOL_TYPE(sym))!=TYPE_CODE_STRUCT) return NULL ; |
8742 |
+ } |
8743 |
+ return duel_convert_type_from_gdb(SYMBOL_TYPE(sym)); |
8744 |
+} |
8745 |
+ |
8746 |
+FUNC tctype* duel_get_target_union_tag(char *name) |
8747 |
+{ |
8748 |
+ struct symbol *sym; |
8749 |
+ sym = lookup_symbol (name, get_selected_block(0), STRUCT_DOMAIN,0,0); |
8750 |
+ if(!sym || TYPE_CODE(SYMBOL_TYPE(sym))!=TYPE_CODE_UNION) { |
8751 |
+ sym = lookup_symbol (name, 0, STRUCT_DOMAIN, 0,0); |
8752 |
+ if(!sym || TYPE_CODE(SYMBOL_TYPE(sym))!=TYPE_CODE_UNION) return NULL ; |
8753 |
+ } |
8754 |
+ return duel_convert_type_from_gdb(SYMBOL_TYPE(sym)); |
8755 |
+} |
8756 |
+ |
8757 |
+FUNC tctype* duel_get_target_enum_tag(char *name) |
8758 |
+{ |
8759 |
+ struct symbol *sym; |
8760 |
+ sym = lookup_symbol (name, get_selected_block(0), STRUCT_DOMAIN,0,0); |
8761 |
+ if(!sym || TYPE_CODE(SYMBOL_TYPE(sym))!=TYPE_CODE_ENUM) { |
8762 |
+ sym = lookup_symbol (name, 0, STRUCT_DOMAIN, 0,0); |
8763 |
+ if(!sym || TYPE_CODE(SYMBOL_TYPE(sym))!=TYPE_CODE_ENUM) return NULL ; |
8764 |
+ } |
8765 |
+ return duel_convert_type_from_gdb(SYMBOL_TYPE(sym)); |
8766 |
+} |
8767 |
+ |
8768 |
+/* |
8769 |
+ * entry point from gdb. |
8770 |
+ * produce help in gdb's format, or call duel enter point. |
8771 |
+ * we allow ^c to quit immidiatly, and setup memory release cleanup. |
8772 |
+ */ |
8773 |
+ |
8774 |
+void duel_command(char *exp,int from_tty) |
8775 |
+{ |
8776 |
+ last_frame_no = -2 ; /* recompute frame location on each dl command */ |
8777 |
+ tot_frames_no = -2 ; |
8778 |
+ |
8779 |
+ make_cleanup(duel_cleanup, 0); /* clear all allocated mem */ |
8780 |
+ immediate_quit++ ; |
8781 |
+ duel_parse_and_eval(exp); |
8782 |
+ immediate_quit-- ; |
8783 |
+} |
8784 |
+ |
8785 |
+void |
8786 |
+_initialize_duel() |
8787 |
+{ |
8788 |
+ add_com ("duel", class_vars, duel_command, |
8789 |
+"Evaluate Duel expressions. Duel is a very high level debugging language.\n\ |
8790 |
+\"dl help\" for help.\n"); |
8791 |
+ add_com_alias ("dl", "duel", class_vars, 1); |
8792 |
+ |
8793 |
+} |
8794 |
|
8795 |
|
8796 |
|
8797 |
1.1 src/patchsets/gdb/6.7.1/11_all_gdb-6.6-duel-integrate.patch |
8798 |
|
8799 |
file : http://sources.gentoo.org/viewcvs.py/gentoo/src/patchsets/gdb/6.7.1/11_all_gdb-6.6-duel-integrate.patch?rev=1.1&view=markup |
8800 |
plain: http://sources.gentoo.org/viewcvs.py/gentoo/src/patchsets/gdb/6.7.1/11_all_gdb-6.6-duel-integrate.patch?rev=1.1&content-type=text/plain |
8801 |
|
8802 |
Index: 11_all_gdb-6.6-duel-integrate.patch |
8803 |
=================================================================== |
8804 |
--- gdb/Makefile.in |
8805 |
+++ gdb/Makefile.in |
8806 |
@@ -116,6 +116,9 @@ |
8807 |
# Where is the "-liberty" library? Typically in ../libiberty. |
8808 |
LIBIBERTY = ../libiberty/libiberty.a |
8809 |
|
8810 |
+# Where is the DUEL library ? Always in duel/src |
8811 |
+DUEL=duel/duel.a |
8812 |
+ |
8813 |
# Where is the BFD library? Typically in ../bfd. |
8814 |
BFD_DIR = ../bfd |
8815 |
BFD = $(BFD_DIR)/libbfd.a |
8816 |
@@ -383,9 +386,9 @@ |
8817 |
CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) \ |
8818 |
$(XM_CLIBS) $(TM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ \ |
8819 |
$(LIBICONV) $(LIBEXPAT) \ |
8820 |
- $(LIBIBERTY) $(WIN32LIBS) |
8821 |
+ $(LIBIBERTY) $(WIN32LIBS) $(DUEL) |
8822 |
CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \ |
8823 |
- $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) |
8824 |
+ $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(DUEL) |
8825 |
|
8826 |
ADD_FILES = $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES) |
8827 |
ADD_DEPS = $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES) |
8828 |
@@ -561,7 +564,7 @@ |
8829 |
ui-out.c utils.c ui-file.h ui-file.c \ |
8830 |
user-regs.c \ |
8831 |
valarith.c valops.c valprint.c value.c varobj.c vec.c \ |
8832 |
- wrapper.c \ |
8833 |
+ wrapper.c duelgdb.c \ |
8834 |
xml-tdesc.c xml-support.c |
8835 |
|
8836 |
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c |
8837 |
@@ -948,7 +951,7 @@ |
8838 |
dwarf2expr.o dwarf2loc.o dwarf2-frame.o \ |
8839 |
ada-lang.o c-lang.o f-lang.o objc-lang.o \ |
8840 |
ui-out.o cli-out.o \ |
8841 |
- varobj.o vec.o wrapper.o \ |
8842 |
+ varobj.o vec.o wrapper.o duelgdb.o \ |
8843 |
jv-lang.o jv-valprint.o jv-typeprint.o \ |
8844 |
m2-lang.o p-lang.o p-typeprint.o p-valprint.o \ |
8845 |
scm-exp.o scm-lang.o scm-valprint.o \ |
8846 |
@@ -971,7 +974,7 @@ |
8847 |
|
8848 |
TSOBS = inflow.o |
8849 |
|
8850 |
-SUBDIRS = @subdirs@ |
8851 |
+SUBDIRS = @subdirs@ duel |
8852 |
|
8853 |
# For now, shortcut the "configure GDB for fewer languages" stuff. |
8854 |
YYFILES = c-exp.c \ |
8855 |
@@ -3238,4 +3241,7 @@ |
8856 |
$(gdb_curses_h) $(gdb_assert_h) |
8857 |
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/tui/tui-winsource.c |
8858 |
|
8859 |
+$(DUEL): |
8860 |
+ $(MAKE) -C duel |
8861 |
+ |
8862 |
### end of the gdb Makefile.in. |
8863 |
|
8864 |
|
8865 |
|
8866 |
-- |
8867 |
gentoo-commits@g.o mailing list |