1 /*
2 Copyright (C) 2004, 2005, 2007, 2008, 2010, 2011
3 R. Bernstein <rocky@gnu.org>
4 This file is part of GNU Make (remake variant).
5
6 GNU Make is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Make is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Make; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 /* Helper routines for debugger command interface. */
22
23 #include "../rule.h"
24 #include "../trace.h"
25 #include "../commands.h"
26 #include "../expand.h"
27 #include "fns.h"
28 #include "stack.h"
29 #include "debug.h"
30 #include "print.h"
31 #include "msg.h"
32
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #endif
36
37 #ifdef HAVE_SYS_WAIT_H
38 #include <sys/wait.h>
39 #endif
40
41 #ifdef HAVE_LIBREADLINE
42
43 # ifdef bcmp
44 # undef bcmp
45 # endif
46
47
48 # ifdef bzero
49 # undef bzero
50 # endif
51
52
53 # ifdef bcopy
54 # undef bcopy
55 # endif
56
57
58 #include <readline/readline.h>
59 #endif
60
61 gmk_floc *p_target_loc = NULL;
62 char *psz_target_name = NULL;
63
64 /*! We use the if when we fake a line number because
65 a real one hasn't been recorded on the stack. */
66 gmk_floc fake_floc;
67
68 /* From readline. ?? Should this be in configure? */
69 #ifndef whitespace
70 #define whitespace(c) (((c) == ' ') || ((c) == '\t'))
71 #endif
72
73 brkpt_mask_t
get_brkpt_option(const char * psz_break_type)74 get_brkpt_option(const char *psz_break_type)
75 {
76 if (is_abbrev_of (psz_break_type, "all", 1)) {
77 return BRK_ALL;
78 } else if (is_abbrev_of (psz_break_type, "prerequisite", 3)) {
79 return BRK_BEFORE_PREREQ;
80 } else if (is_abbrev_of (psz_break_type, "run", 1)) {
81 return BRK_AFTER_PREREQ;
82 } else if (is_abbrev_of (psz_break_type, "end", 1)) {
83 return BRK_AFTER_CMD;
84 } else if (is_abbrev_of (psz_break_type, "temp", 1)) {
85 return BRK_TEMP;
86 } else {
87 dbg_errmsg("Unknown breakpoint modifier %s", psz_break_type);
88 return BRK_NONE;
89 }
90 }
91
92 /*! Parse psz_arg for a signed integer. The value is returned in
93 *pi_result. If warn is true, then we'll give a warning if no
94 integer found. The return value is true if parsing succeeded in
95 any event..
96 */
97 bool
get_int(const char * psz_arg,int * pi_result,bool b_warn)98 get_int(const char *psz_arg, int *pi_result, bool b_warn)
99 {
100 int i;
101 char *endptr;
102
103 if (!psz_arg || 0==strlen(psz_arg)) return 0;
104
105 i = strtol(psz_arg, &endptr, 10);
106 if (*endptr != '\0') {
107 if (b_warn)
108 dbg_errmsg("expecting %s to be an integer", psz_arg);
109 return false;
110 }
111 *pi_result = i;
112 return true;
113 }
114
115 bool
get_uint(const char * psz_arg,unsigned int * result,bool b_warn)116 get_uint(const char *psz_arg, unsigned int *result, bool b_warn)
117 {
118 unsigned int i;
119 char *endptr;
120
121 if (!psz_arg || 0==strlen(psz_arg)) return 0;
122
123 i = strtol(psz_arg, &endptr, 10);
124 if (*endptr != '\0') {
125 if (b_warn)
126 dbg_errmsg("expecting %s to be an integer", psz_arg);
127 return false;
128 }
129 *result = i;
130 return true;
131 }
132
133 /* Find the next "word" - skip leading blanks and the "word" is the
134 largest non-blank characters after that. ppsz_str is modified to
135 point after the portion returned and also the region initially
136 pointed to by ppsz_str is modified so that word is zero-byte
137 termintated.
138 */
139 char *
get_word(char ** ppsz_str)140 get_word(char **ppsz_str)
141 {
142 char *psz_word;
143
144 /* Skip leading blanks. */
145 while (**ppsz_str && whitespace (**ppsz_str))
146 **ppsz_str += 1;
147
148 /* Word starts here at first non blank character. */
149 psz_word = *ppsz_str;
150
151 /* Find end of word - next whitespace. */
152 while (**ppsz_str && !whitespace (**ppsz_str))
153 (*ppsz_str)++;
154
155 if (**ppsz_str) *((*ppsz_str)++) = '\0';
156
157 return psz_word;
158 }
159
160 /*!
161 Return the current target from the stack or NULL
162 if none set.
163 */
164 const file_t *
get_current_target(void)165 get_current_target(void)
166 {
167 if (p_stack && p_stack->p_target)
168 return p_stack->p_target;
169 else
170 return NULL;
171 }
172
173
174 /*!
175 Return the current target from the stack or NULL
176 if none set.
177 */
178 const gmk_floc *
get_current_floc(void)179 get_current_floc(void)
180 {
181 file_t *p_target = (file_t *) get_current_target();
182 gmk_floc *p_floc;
183
184 p_floc = &p_target->floc;
185
186 if (p_floc->filenm && p_floc->lineno != 0)
187 return p_floc;
188 else
189 return NULL;
190 }
191
192
193 /*! Find the target in first word of psz_args or use $@ (the current
194 stack) if none. We also allow $@ or @ explicitly as a target name
195 to mean the current target on the stack. NULL is returned if a lookup
196 of the target name was not found. ppsz_target is to the name
197 looked up.
198 */
199 file_t *
get_target(char ** ppsz_args,const char ** ppsz_target)200 get_target(char **ppsz_args, /*out*/ const char **ppsz_target)
201 {
202 if (!*ppsz_args || !**ppsz_args) {
203 file_t *p_target = (file_t *) get_current_target();
204 /* Use current target */
205 if (p_target && p_target->name) {
206 *ppsz_args = (char *) p_target->name;
207 } else {
208 printf(_("Default target not found here. You must supply one\n"));
209 return NULL;
210 }
211 }
212
213 *ppsz_target = get_word(ppsz_args);
214
215 /* As a special case, we'll allow $@ or @ for the current target. */
216 if ( 0 == strcmp("$@", *ppsz_target) || 0 == strcmp("@", *ppsz_target) ) {
217 if (p_stack && p_stack->p_target && p_stack->p_target->name)
218 *ppsz_target = p_stack->p_target->name;
219 else {
220 printf(_("No current target found for $@ - supply a target name.\n"));
221 return NULL;
222 }
223 }
224
225 {
226 file_t *p_target = lookup_file (*ppsz_target);
227
228 if (!p_target)
229 printf(_("Target \"%s\" doesn't appear to be a target name.\n"),
230 *ppsz_target);
231 return p_target;
232 }
233 }
234
235 /*! Return true if psz_substr is an initial prefix (abbreviation) of
236 psz_word. The empty string is not a valid abbreviation. */
237 bool
is_abbrev_of(const char * psz_substr,const char * psz_word,unsigned int i_min)238 is_abbrev_of(const char* psz_substr, const char* psz_word,
239 unsigned int i_min)
240 {
241 if (strlen(psz_substr) < i_min)
242 return false;
243 else {
244 const char *psz = strstr(psz_word, psz_substr);
245 return (psz && psz == psz_word);
246 }
247 }
248
249 /*! toggle var on or on or off depending on psz_onoff */
250 void
on_off_toggle(const char * psz_onoff,int * var)251 on_off_toggle(const char *psz_onoff, int *var)
252 {
253 if (strcmp (psz_onoff, "on") == 0)
254 *var = 1;
255 else if (strcmp (psz_onoff, "off") == 0)
256 *var = 0;
257 else if (strcmp (psz_onoff, "toggle") == 0)
258 *var = !*var;
259 else
260 printf(_("expecting \"on\", \"off\", or \"toggle\"; got \"%s\" \n"),
261 psz_onoff);
262 }
263
264 /*! Print an interpretation of the debug level mask. */
265 void
print_db_level(debug_level_mask_t e_debug_level)266 print_db_level(debug_level_mask_t e_debug_level)
267 {
268 if (e_debug_level & DB_BASIC)
269 printf("Basic tracing (0x%x)\n", (unsigned int) DB_BASIC);
270 if (e_debug_level & DB_TRACE)
271 printf("Tracing (0x%x)\n", (unsigned int) DB_TRACE);
272 if (e_debug_level & DB_VERBOSE)
273 printf("Verbose Tracing (0x%x)\n", (unsigned int) DB_VERBOSE);
274 if (e_debug_level & DB_SHELL)
275 printf("Tracing shell commands 0x%x\n", (unsigned int) DB_SHELL);
276 if (e_debug_level & DB_MAKEFILES)
277 printf("Tracing Rebuilding Makefiles 0x%x\n", (unsigned int) DB_MAKEFILES);
278 if (e_debug_level & DB_UPDATE_GOAL)
279 printf("Tracing Goal target updates 0x%x\n", (unsigned int) DB_MAKEFILES);
280 if (e_debug_level & DB_UPDATE_GOAL)
281 printf("Tracing reading Makefiles 0x%x\n", (unsigned int) DB_READ_MAKEFILES);
282 if (e_debug_level & DB_CALL)
283 printf("Tracing function call and returns 0x%x\n", (unsigned int) DB_CALL);
284 }
285
286 static const char *reason2str[] = {
287 "->",
288 "..",
289 "<-",
290 "||",
291 "rd",
292 "!!",
293 "--",
294 "++",
295 ":o"
296 };
297
298
299
300 /** Print where we are in the Makefile. */
301 void
print_debugger_location(const file_t * p_target,debug_enter_reason_t reason,const floc_stack_node_t * p_stack_floc)302 print_debugger_location(const file_t *p_target, debug_enter_reason_t reason,
303 const floc_stack_node_t *p_stack_floc)
304 {
305 if (p_target_loc) {
306 if (reason != DEBUG_NOT_GIVEN && reason != DEBUG_STACK_CHANGING)
307 printf("%s ", reason2str[reason]);
308 printf("(");
309 if ( !p_target_loc->filenm && p_target_loc->lineno != 0
310 && p_target && p_target->name ) {
311 /* We don't have file location info in the target floc, but we
312 do have it as part of the name, so use that. This happens for
313 example with we've stopped before reading a Makefile.
314 */
315 if (p_target->cmds) {
316 gmk_floc floc;
317 memcpy(&floc, &(p_target->cmds->fileinfo.filenm), sizeof(gmk_floc));
318 /* HACK: is it okay to assume that the target is on the line
319 before the first command? Or should we list the line
320 that the command starts on - so we know we've faked the location?
321 */
322 floc.lineno--;
323 p_target_loc->filenm = floc.filenm;
324 p_target_loc->lineno = floc.lineno;
325 print_floc_prefix(&floc);
326 printf (")\n");
327 } else if (p_target->phony)
328 printf("%s: .PHONY target)\n", p_target->name);
329 else
330 printf("%s:0)\n", p_target->name);
331 } else {
332 print_floc_prefix(p_target_loc);
333 printf (")\n");
334 }
335 } else if (p_stack_floc && p_stack_floc->p_floc) {
336 printf("\n(");
337 print_floc_prefix(p_stack_floc->p_floc);
338 printf (")\n");
339 } else if (p_stack_floc_top && p_stack_floc_top->p_floc) {
340 printf("\n(");
341 print_floc_prefix(p_stack_floc_top->p_floc);
342 printf (")\n");
343 }
344
345 /* Could/should generalize the below into a prompt string. */
346 switch (reason)
347 {
348 case DEBUG_BRKPT_BEFORE_PREREQ:
349 case DEBUG_STEP_HIT:
350 dbg_cmd_show_exp((char *) "$@: $+", true);
351 break;
352 case DEBUG_STACK_CHANGING:
353 break;
354 default:
355 dbg_cmd_show_exp((char *) "$@", true);
356 break;
357 }
358 }
359
360 /** Strip whitespace from the start and end of STRING. Return a pointer
361 into STRING. */
362 char *
stripwhite(char * string)363 stripwhite (char *string)
364 {
365 char *s, *t;
366
367 for (s = string; whitespace (*s); s++)
368 ;
369
370 if (*s == 0)
371 return (s);
372
373 t = s + strlen (s) - 1;
374 while (t > s && whitespace (*t))
375 t--;
376 *++t = '\0';
377
378 return s;
379 }
380
381 /* Show if i_bool is "on" or "off" */
382 const char *
var_to_on_off(int i_bool)383 var_to_on_off(int i_bool)
384 {
385 return i_bool ? "on" : "off";
386 }
387
388 /*! See if psz_varname is $varname or $(varname) */
389 variable_t *
try_without_dollar(const char * psz_varname)390 try_without_dollar(const char *psz_varname)
391 {
392 printf("Can't find variable `%s'.\n", psz_varname);
393 if (psz_varname && psz_varname[0] == '$') {
394 const char *psz_nodollar = &(psz_varname[1]);
395 char *psz_try = calloc(1, strlen(psz_varname));
396 if (psz_nodollar && 1 == sscanf(psz_nodollar, "(%s)", psz_try)) {
397 /* Remove trailing ')' */
398 if ( ')' == psz_try[strlen(psz_try)-1] )
399 psz_try[strlen(psz_try)-1]='\0';
400 printf(_("Did you mean `%s'?\n"), psz_try);
401 } else
402 printf(_("Did you mean `%s'?\n"), psz_nodollar);
403 free(psz_try);
404 } else {
405 printf("Adding variable `%s'.\n", psz_varname);
406 return define_variable (psz_varname, strlen(psz_varname), "", o_debugger, 0);
407 }
408 return NULL;
409
410 }
411
412 /*! Show a expression. Set "expand" to 1 if you want variable
413 definitions inside the displayed value expanded.
414 */
415 bool
dbg_cmd_show_exp(char * psz_varname,bool expand)416 dbg_cmd_show_exp (char *psz_varname, bool expand)
417 {
418 if (!psz_varname || 0==strlen(psz_varname)) {
419 printf(_("You need to supply a variable name.\n"));
420 return false;
421 } else {
422 variable_t *p_v;
423 variable_set_t *p_set = NULL;
424 variable_set_list_t *p_file_vars = NULL;
425 if (p_stack && p_stack->p_target && p_stack->p_target->name) {
426 const char *psz_target = p_stack->p_target->name;
427 file_t *p_target = lookup_file (psz_target);
428 if (p_target) {
429 initialize_file_variables (p_target, 0);
430 set_file_variables (p_target);
431 p_file_vars = p_target->variables;
432 p_set = p_file_vars->set;
433 }
434 }
435 if (p_set) {
436 p_v = lookup_variable_in_set(psz_varname, strlen(psz_varname), p_set);
437 if (!p_v)
438 /* May be a global variable. */
439 p_v = lookup_variable (psz_varname, strlen (psz_varname));
440 } else {
441 p_v = lookup_variable (psz_varname, strlen (psz_varname));
442 }
443 if (p_v) {
444 if (expand) {
445 print_variable_expand(p_v);
446 } else
447 print_variable(p_v);
448 } else {
449 if (expand)
450 printf("%s\n", variable_expand_set(psz_varname, p_file_vars));
451 else {
452 try_without_dollar(psz_varname);
453 return false;
454 }
455 }
456 }
457 return true;
458 }
459
dbg_print_invocation(void)460 void dbg_print_invocation(void)
461 {
462 unsigned int i;
463 printf("%s ", global_argv[0]);
464 for (i = 1; global_argv[i]; i++) {
465 printf(" %s", global_argv[i]);
466 }
467 printf("\n");
468 }
469
find_rule(const char * psz_name)470 rule_t *find_rule (const char *psz_name)
471 {
472 rule_t *r;
473
474 for (r = pattern_rules; r != 0; r = r->next)
475 {
476 unsigned int i;
477 for (i = 0; r->targets[i] != 0; ++i)
478 if (0 == strcmp(r->targets[i], psz_name)) return r;
479 }
480 return NULL;
481 }
482
chomp(char * line)483 void chomp(char * line)
484 {
485 unsigned int len = strlen(line);
486 if (line[len-1] == '\n') line[len-1] = '\0';
487 }
488
489
shell_rc_status(int rc)490 void shell_rc_status(int rc)
491 {
492 if (rc == -1)
493 printf(_("Error: %s\n"), strerror(errno));
494 else if (WEXITSTATUS(rc) != 0)
495 printf(_("Warning: return code was %d\n"), WEXITSTATUS(rc));
496 }
497
498 /*
499 * Local variables:
500 * eval: (c-set-style "gnu")
501 * indent-tabs-mode: nil
502 * End:
503 */
504