1 /*
2 Copyright (C) 2005, 2007-2008, 2015, 2020 R. Bernstein <rocky@gnu.org>
3 This file is part of GNU Make (remake variant).
4 
5 GNU Make is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9 
10 GNU Make is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with GNU Make; see the file COPYING.  If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.  */
19 
20 /** debugger command stack routines. */
21 
22 #include <assert.h>
23 #include "break.h"
24 #include "msg.h"
25 #include "filedef.h"
26 #include "print.h"
27 
28 /*! Node for an item in the target call stack */
29 struct breakpoint_node
30 {
31   file_t            *p_target;
32   unsigned int      i_num;
33   brkpt_mask_t      brkpt_mask;
34   breakpoint_node_t *p_next;
35 };
36 
37 /** Pointers to top/bottom of current breakpoint target stack */
38 breakpoint_node_t *p_breakpoint_top    = NULL;
39 breakpoint_node_t *p_breakpoint_bottom = NULL;
40 
41 unsigned int i_breakpoints = 0;
42 
43 /*! Add "p_target" to the list of breakpoints. Return true if
44     there were no errors
45 */
46 bool
add_breakpoint(file_t * p_target,const brkpt_mask_t brkpt_mask)47 add_breakpoint (file_t *p_target, const brkpt_mask_t brkpt_mask)
48 {
49   breakpoint_node_t *p_new   = CALLOC (breakpoint_node_t, 1);
50 
51   if (!p_new) return false;
52 
53   /* Add breakpoint to list of breakpoints. */
54   if (!p_breakpoint_top) {
55     assert(!p_breakpoint_bottom);
56     p_breakpoint_top            = p_breakpoint_bottom = p_new;
57   } else {
58     p_breakpoint_bottom->p_next = p_new;
59   }
60   p_breakpoint_bottom           = p_new;
61   p_new->p_target               = p_target;
62   p_new->i_num                  = ++i_breakpoints;
63   p_new->brkpt_mask             = brkpt_mask;
64 
65 
66   /* Finally, note that we are tracing this target. */
67   if (p_target->tracing & (BRK_BEFORE_PREREQ & brkpt_mask)) {
68     dbg_msg(_("Note: prerequisite breakpoint already set at target %s."),
69             p_target->name);
70   }
71   if (p_target->tracing & (BRK_AFTER_PREREQ & brkpt_mask)) {
72     dbg_msg(_("Note: command breakpoint already set at target %s."),
73             p_target->name);
74   }
75   if (p_target->tracing & (BRK_AFTER_CMD & brkpt_mask)) {
76     dbg_msg(_("Note: target end breakpont set at target %s."),
77             p_target->name);
78   }
79   p_target->tracing = brkpt_mask;
80   printf(_("Breakpoint %u on target `%s', mask 0x%02x"), i_breakpoints,
81          p_target->name, brkpt_mask);
82   if (p_target->floc.filenm)
83     dbg_msg(": file %s, line %lu.", p_target->floc.filenm,
84             p_target->floc.lineno);
85   else
86     printf(".\n");
87   if (p_target->updated)
88       dbg_msg("Warning: target is already updated; so it might not get stopped at again.");
89   else if (p_target->updating && (brkpt_mask & (BRK_BEFORE_PREREQ | BRK_AFTER_PREREQ))) {
90       dbg_msg("Warning: target is in the process of being updated;");
91       dbg_msg("so it might not get stopped at again.");
92   }
93   return true;
94 
95 }
96 
97 /*! Remove breakpoint i from the list of breakpoints. Return true if
98     there were no errors
99 */
100 bool
remove_breakpoint(unsigned int i,bool silent)101 remove_breakpoint (unsigned int i, bool silent)
102 {
103   if (!i) {
104     dbg_errmsg(_("Invalid Breakpoint number 0."));
105     return false;
106   }
107   if (i > i_breakpoints) {
108     dbg_errmsg(_("Breakpoint number %u is too high. "
109                  "%u is the highest breakpoint number."), i, i_breakpoints);
110     return false;
111   } else {
112     /* Find breakpoint i */
113     breakpoint_node_t *p_prev = NULL;
114     breakpoint_node_t *p;
115     for (p = p_breakpoint_top; p && p->i_num != i; p = p->p_next) {
116       p_prev = p;
117     }
118 
119     if (p && p->i_num == i) {
120       /* Delete breakpoint */
121       if (!p->p_next) p_breakpoint_bottom = p_prev;
122       if (p == p_breakpoint_top) p_breakpoint_top = p->p_next;
123 
124       if (p_prev) p_prev->p_next = p->p_next;
125 
126       if (p->p_target->tracing) {
127 	p->p_target->tracing = BRK_NONE;
128 	dbg_msg(_("Breakpoint %u on target `%s' cleared."),
129 	       i, p->p_target->name);
130 	free(p);
131 	return true;
132       } else {
133 	dbg_msg(_("No breakpoint at target `%s'; nothing cleared."),
134 	       p->p_target->name);
135 	free(p);
136 	return false;
137       }
138     } else {
139       if (!silent)
140         dbg_errmsg(_("No Breakpoint number %u set."), i);
141       return false;
142     }
143   }
144 }
145 
146 /*! List breakpoints.*/
147 void
list_breakpoints(void)148 list_breakpoints (void)
149 {
150   breakpoint_node_t *p;
151 
152   if (!p_breakpoint_top) {
153     dbg_msg(_("No breakpoints."));
154     return;
155   }
156 
157   dbg_msg(  "Num Type           Disp Enb Mask Target  Location");
158   for (p = p_breakpoint_top; p; p = p->p_next) {
159     printf("%3u breakpoint     keep   y 0x%02x %s",
160 	   p->i_num,
161 	   p->brkpt_mask,
162            p->p_target->name);
163     if (p->p_target->floc.filenm) {
164 	printf(" at ");
165 	print_floc_prefix(&(p->p_target->floc));
166     }
167     printf("\n");
168   }
169 }
170 /*
171  * Local variables:
172  * eval: (c-set-style "gnu")
173  * indent-tabs-mode: nil
174  * End:
175  */
176