improve the SB-EXT:GC docstring(s)
[sbcl.git] / src / runtime / parse.c
1 /* parsing for LDB monitor */
2
3 /*
4  * This software is part of the SBCL system. See the README file for
5  * more information.
6  *
7  * This software is derived from the CMU CL system, which was
8  * written at Carnegie Mellon University and released into the
9  * public domain. The software is in the public domain and is
10  * provided with absolutely no warranty. See the COPYING and CREDITS
11  * files for more information.
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <ctype.h>
17 #include <signal.h>
18
19 #include "sbcl.h"
20 #include "runtime.h"
21
22 #if defined(LISP_FEATURE_SB_LDB)
23
24 #include "globals.h"
25 #include "vars.h"
26 #include "parse.h"
27 #include "os.h"
28 #include "interrupt.h"
29 #include "lispregs.h"
30 #include "monitor.h"
31 #include "validate.h"
32 #include "arch.h"
33 #include "search.h"
34 #include "thread.h"
35 #include "pseudo-atomic.h"
36
37 #include "genesis/simple-fun.h"
38 #include "genesis/fdefn.h"
39 #include "genesis/symbol.h"
40 #include "genesis/static-symbols.h"
41
42 static void skip_ws(char **ptr)
43 {
44     while (**ptr <= ' ' && **ptr != '\0')
45         (*ptr)++;
46 }
47
48 static boolean string_to_long(char *token, long *value)
49 {
50     int base, digit;
51     long num;
52     char *ptr;
53
54     if (token == 0)
55         return 0;
56
57     if (token[0] == '0')
58         if (token[1] == 'x') {
59             base = 16;
60             token += 2;
61         }
62         else {
63             base = 8;
64             token++;
65         }
66     else if (token[0] == '#') {
67         switch (token[1]) {
68             case 'x':
69             case 'X':
70                 base = 16;
71                 token += 2;
72                 break;
73             case 'o':
74             case 'O':
75                 base = 8;
76                 token += 2;
77                 break;
78             default:
79                 return 0;
80         }
81     }
82     else
83         base = 10;
84
85     num = 0;
86     ptr = token;
87     while (*ptr != '\0') {
88         if (*ptr >= 'a' && *ptr <= 'f')
89             digit = *ptr + 10 - 'a';
90         else if (*ptr >= 'A' && *ptr <= 'F')
91             digit = *ptr + 10 - 'A';
92         else if (*ptr >= '0' && *ptr <= '9')
93             digit = *ptr - '0';
94         else
95             return 0;
96         if (digit < 0 || digit >= base)
97             return 0;
98
99         ptr++;
100         num = num * base + digit;
101     }
102
103     *value = num;
104     return 1;
105 }
106
107 static boolean lookup_variable(char *name, lispobj *result)
108 {
109     struct var *var = lookup_by_name(name);
110
111     if (var == NULL)
112         return 0;
113     else {
114         *result = var_value(var);
115         return 1;
116     }
117 }
118
119
120 boolean more_p(ptr)
121 char **ptr;
122 {
123     skip_ws(ptr);
124
125     if (**ptr == '\0')
126         return 0;
127     else
128         return 1;
129 }
130
131 char *parse_token(ptr)
132 char **ptr;
133 {
134     char *token;
135
136     skip_ws(ptr);
137
138     if (**ptr == '\0')
139         return NULL;
140
141     token = *ptr;
142
143     while (**ptr > ' ')
144         (*ptr)++;
145
146     if (**ptr != '\0') {
147         **ptr = '\0';
148         (*ptr)++;
149     }
150
151     return token;
152 }
153
154 #if 0
155 static boolean number_p(token)
156 char *token;
157 {
158     char *okay;
159
160     if (token == NULL)
161         return 0;
162
163     okay = "abcdefABCDEF987654321d0";
164
165     if (token[0] == '0')
166         if (token[1] == 'x' || token[1] == 'X')
167             token += 2;
168         else {
169             token++;
170             okay += 14;
171         }
172     else if (token[0] == '#') {
173         switch (token[1]) {
174             case 'x':
175             case 'X':
176                 break;
177             case 'o':
178             case 'O':
179                 okay += 14;
180                 break;
181             default:
182                 return 0;
183         }
184     }
185     else
186         okay += 12;
187
188     while (*token != '\0')
189         if (index(okay, *token++) == NULL)
190             return 0;
191     return 1;
192 }
193 #endif
194
195 long parse_number(ptr)
196 char **ptr;
197 {
198     char *token = parse_token(ptr);
199     long result;
200
201     if (token == NULL) {
202         printf("expected a number\n");
203         throw_to_monitor();
204     }
205     else if (string_to_long(token, &result))
206         return result;
207     else {
208         printf("invalid number: ``%s''\n", token);
209         throw_to_monitor();
210     }
211     return 0;
212 }
213
214 char *parse_addr(ptr)
215 char **ptr;
216 {
217     char *token = parse_token(ptr);
218     lispobj result;
219
220     if (token == NULL) {
221         printf("expected an address\n");
222         throw_to_monitor();
223     }
224     else if (token[0] == '$') {
225         if (!lookup_variable(token+1, &result)) {
226             printf("unknown variable: ``%s''\n", token);
227             throw_to_monitor();
228         }
229         result &= ~7;
230     }
231     else {
232         long value;
233         if (!string_to_long(token, &value)) {
234             printf("invalid number: ``%s''\n", token);
235             throw_to_monitor();
236         }
237         result = (value & ~3);
238     }
239
240     if (!is_valid_lisp_addr((os_vm_address_t)result)) {
241         printf("invalid Lisp-level address: %p\n", (void *)result);
242         throw_to_monitor();
243     }
244
245     return (char *)result;
246 }
247
248 static boolean lookup_symbol(char *name, lispobj *result)
249 {
250     int count;
251     lispobj *headerptr;
252
253     /* Search static space. */
254     headerptr = (lispobj *)STATIC_SPACE_START;
255     count =
256         (lispobj *)SymbolValue(STATIC_SPACE_FREE_POINTER,0) -
257         (lispobj *)STATIC_SPACE_START;
258     if (search_for_symbol(name, &headerptr, &count)) {
259         *result = make_lispobj(headerptr,OTHER_POINTER_LOWTAG);
260         return 1;
261     }
262
263     /* Search dynamic space. */
264 #if defined(LISP_FEATURE_GENCGC)
265     headerptr = (lispobj *)DYNAMIC_SPACE_START;
266     count = (lispobj *)get_alloc_pointer() - headerptr;
267 #else
268     headerptr = (lispobj *)current_dynamic_space;
269     count = dynamic_space_free_pointer - headerptr;
270 #endif
271
272     if (search_for_symbol(name, &headerptr, &count)) {
273         *result = make_lispobj(headerptr, OTHER_POINTER_LOWTAG);
274         return 1;
275     }
276
277     return 0;
278 }
279
280 static int
281 parse_regnum(char *s)
282 {
283     if ((s[1] == 'R') || (s[1] == 'r')) {
284         int regnum;
285
286         if (s[2] == '\0')
287             return -1;
288
289         /* skip the $R part and call atoi on the number */
290         regnum = atoi(s + 2);
291         if ((regnum >= 0) && (regnum < NREGS))
292             return regnum;
293         else
294             return -1;
295     } else {
296         int i;
297
298         for (i = 0; i < NREGS ; i++)
299             if (strcasecmp(s + 1, lisp_register_names[i]) == 0)
300 #ifdef LISP_FEATURE_X86
301                 return i*2;
302 #else
303         return i;
304 #endif
305
306         return -1;
307     }
308 }
309
310 lispobj parse_lispobj(ptr)
311 char **ptr;
312 {
313     struct thread *thread=arch_os_get_current_thread();
314     char *token = parse_token(ptr);
315     long pointer;
316     lispobj result;
317     long value;
318
319     if (token == NULL) {
320         printf("expected an object\n");
321         throw_to_monitor();
322     } else if (token[0] == '$') {
323         if (isalpha(token[1])) {
324             int free_ici;
325             int regnum;
326             os_context_t *context;
327
328             free_ici = fixnum_value(SymbolValue(FREE_INTERRUPT_CONTEXT_INDEX,thread));
329
330             if (free_ici == 0) {
331                 printf("Variable ``%s'' is not valid -- there is no current interrupt context.\n", token);
332                 throw_to_monitor();
333             }
334
335             context = thread->interrupt_contexts[free_ici - 1];
336
337             regnum = parse_regnum(token);
338             if (regnum < 0) {
339                 printf("bogus register: ``%s''\n", token);
340                 throw_to_monitor();
341             }
342
343             result = *os_context_register_addr(context, regnum);
344         } else if (!lookup_variable(token+1, &result)) {
345             printf("unknown variable: ``%s''\n", token);
346             throw_to_monitor();
347         }
348     } else if (token[0] == '@') {
349         if (string_to_long(token+1, &pointer)) {
350             pointer &= ~3;
351             if (is_valid_lisp_addr((os_vm_address_t)pointer))
352                 result = *(lispobj *)pointer;
353             else {
354                 printf("invalid Lisp-level address: ``%s''\n", token+1);
355                 throw_to_monitor();
356             }
357         }
358         else {
359             printf("invalid address: ``%s''\n", token+1);
360             throw_to_monitor();
361         }
362     }
363     else if (string_to_long(token, &value))
364         result = value;
365     else if (lookup_symbol(token, &result))
366         ;
367     else {
368         printf("invalid Lisp object: ``%s''\n", token);
369         throw_to_monitor();
370     }
371
372     return result;
373 }
374
375 #endif /* defined(LISP_FEATURE_SB_LDB) */