Arduino-Debug
On-target sketch debugger for Arduino
Debug.cpp
Go to the documentation of this file.
1 
19 #include "Debug.h"
20 
21 #define ARCH "AVR"
22 #define VERSION "1.0a3"
23 
24 Debug debug __attribute__((weak));
25 
26 extern int __heap_start, *__brkval;
27 
28 bool
29 Debug::begin(Stream* dev,
30  const char* file,
31  int line,
32  const char* func)
33 {
34  if (m_dev != NULL) return (false);
35  m_dev = dev;
36  DATAEND =(int) &__heap_start;
37  DATASIZE = DATAEND - RAMSTART;
38  print(F("Arduino Debug (" ARCH ") " VERSION
39  ", Copyright (C) 2015-2016, Mikael Patel\n"
40  "For help, type \"help\".\n"
41  "Debug::begin:"));
42  run(file, line, func);
43  return (true);
44 }
45 
46 void
47 Debug::assert(const char* file,
48  int line,
49  const char* func,
50  str_P cond)
51 {
52  print(F("Debug::assert"));
53  run(file, line, func, cond);
54  end();
55  exit(0);
56 }
57 
58 void
59 Debug::break_at(const char* file,
60  int line,
61  const char* func,
62  str_P cond)
63 {
64  print(F("Debug::break_at"));
65  run(file, line, func, cond);
66 }
67 
68 bool
70 {
71  uint16_t marker = 0xA5A5;
72  int HEAPEND = (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
73  int STACKSTART = (int) ▮
74  return (STACKSTART > HEAPEND + room);
75 }
76 
77 void
78 Debug::observe_at(const char* file,
79  int line,
80  const char* func,
81  str_P expr)
82 {
83  UNUSED(file);
84  print(F("Debug::observe_at:"));
85  print(func);
86  print(':');
87  print(line);
88  print(':');
89  print(expr);
90  print('=');
91 }
92 
93 bool
95 {
96  if (m_dev == NULL) return (false);
97  println(F("Debug::end"));
98  delay(1000);
99  m_dev = NULL;
100  return (true);
101 }
102 
103 void
104 Debug::run(const char* file, int line, const char* func, str_P expr)
105 {
106  if (func != NULL) {
107  print(':');
108  print(func);
109  print(':');
110  print(line);
111  }
112  if (expr != NULL) {
113  print(':');
114  print(expr);
115  }
116  if (func != NULL) println();
117 
118  uint16_t marker = 0xA5A5;
119  str_P prompt = F("(debug) ");
120 
121  while (1) {
122  const size_t BUF_MAX = 32;
123  char buf[BUF_MAX];
124  char* bp = buf;
125  int c;
126  print(prompt);
127  while (1) {
128  c = read();
129  if (c == '\r' || c == '\n') break;
130  if (c > 0) {
131  *bp++ = c;
132  print((char) c);
133  }
134  else {
135  yield();
136  }
137  }
138  println();
139  *bp = 0;
140  size_t len = bp - buf;
141  if (len == 0) continue;
142 
143  if (!strncmp_P(buf, PSTR("go"), len)) return;
144 
145 #if !defined(DEBUG_NO_BACKTRACE)
146  if (!strncmp_P(buf, PSTR("backtrace"), len)) {
147  print(F("0x"));
148  print((int) &marker, HEX);
149  print(':');
150  println(func);
151  do_backtrace(func);
152  continue;
153  }
154 #endif
155 
156 #if !defined(DEBUG_NO_PRINT_DATA)
157  if (!strncmp_P(buf, PSTR("data"), len)) {
158  do_print_data();
159  continue;
160  }
161 #endif
162 
163 #if !defined(DEBUG_NO_PRINT_HEAP)
164  if (!strncmp_P(buf, PSTR("heap"), len)) {
165  do_print_heap();
166  continue;
167  }
168 #endif
169 
170 #if !defined(DEBUG_NO_MEMORY_USAGE)
171  if (!strncmp_P(buf, PSTR("memory"), len)) {
172  do_memory_usage((int) &marker);
173  continue;
174  }
175 #endif
176 
177 #if !defined(DEBUG_NO_PRINT_COMMANDS)
178  if (!strncmp_P(buf, PSTR("commands"), len)
179  || !strncmp_P(buf, PSTR("help"), len)) {
181  continue;
182  }
183 #endif
184 
185 #if !defined(DEBUG_NO_PRINT_STACK)
186  if (!strncmp_P(buf, PSTR("stack"), len)) {
187  do_print_stack((int) &marker);
188  continue;
189  }
190 #endif
191 
192 #if !defined(DEBUG_NO_PRINT_VARIABLES)
193  if (!strncmp_P(buf, PSTR("variables"), len)) {
195  continue;
196  }
197 #endif
198 
199 #if !defined(DEBUG_NO_QUIT)
200  if (!strncmp_P(buf, PSTR("quit"), len)) {
201  end();
202  exit(0);
203  }
204 #endif
205 
206 #if !defined(DEBUG_NO_WHERE)
207  if (!strncmp_P(buf, PSTR("where"), len)) {
208  print(file);
209  print(':');
210  print(line);
211  print(':');
212  println(func);
213  continue;
214  }
215 #endif
216 
217 #if !defined(DEBUG_NO_LOOKUP_VARIABLES)
218  if (*buf == '?' || *buf == '@' ) {
219  const char* name = buf + 1;
220  if (!do_lookup_variables(name, *buf == '@')) {
221  print(name);
222  println(F(": unknown variable"));
223  }
224  continue;
225  }
226 #endif
227  print(buf);
228  println(F(": unknown command"));
229  }
230 }
231 
232 #if !defined(DEBUG_NO_BACKTRACE)
233 void
234 Debug::do_backtrace(const char* func)
235 {
236  for (Variable* vp = m_var; vp != NULL; vp = vp->m_next) {
237  if (func != vp->m_func) {
238  func = vp->m_func;
239  print(F("0x"));
240  print((int) vp, HEX);
241  print(':');
242  println(vp->m_func);
243  }
244  }
245 }
246 #endif
247 
248 #if !defined(DEBUG_NO_LOOKUP_VARIABLES)
249 bool
250 Debug::do_lookup_variables(const char* name, bool is_pointer)
251 {
252  bool found = false;
253  for (Variable* vp = m_var; vp != NULL; vp = vp->m_next) {
254  if (strcmp_P(name, (const char*) vp->m_name) == 0) {
255  if (!is_pointer || (vp->m_size == sizeof(void*)))
256  vp->print(is_pointer);
257  found = true;
258  }
259  }
260  return (found);
261 }
262 #endif
263 
264 #if !defined(DEBUG_NO_MEMORY_USAGE)
265 void
267 {
268  int HEAPEND = (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
269  print(F("data="));
270  print(DATASIZE);
271  print(F(",heap="));
272  print(HEAPEND - (int) &__heap_start);
273  print(F(",stack="));
274  print(RAMEND - marker + 1);
275  print(F(",free="));
276  println(marker - HEAPEND);
277 }
278 #endif
279 
280 #if !defined(DEBUG_NO_PRINT_COMMANDS)
281 void
283 {
284  static const char help[] PROGMEM =
285 #if !defined(DEBUG_NO_LOOKUP_VARIABLES)
286  "?VARIABLE -- Print variable(s)\n"
287  "@VARIABLE -- Print pointer variable(s)\n"
288 #endif
289 #if !defined(DEBUG_NO_BACKTRACE)
290  "backtrace -- Print call stack\n"
291 #endif
292 #if !defined(DEBUG_NO_PRINT_DATA)
293  "data -- Print data\n"
294 #endif
295  "go -- Return to sketch\n"
296 #if !defined(DEBUG_NO_PRINT_HEAP)
297  "heap -- Print heap\n"
298 #endif
299 #if !defined(DEBUG_NO_MEMORY_USAGE)
300  "memory -- Print memory usage\n"
301 #endif
302 #if !defined(DEBUG_NO_QUIT)
303  "quit -- Exit sketch\n"
304 #endif
305 #if !defined(DEBUG_NO_PRINT_STACK)
306  "stack -- Print stack\n"
307 #endif
308 #if !defined(DEBUG_NO_PRINT_REGISTER)
309  "variables -- Print variables\n"
310 #endif
311 #if !defined(DEBUG_NO_WHERE)
312  "where -- Location in source code\n"
313 #endif
314  ;
315  print((str_P) help);
316 }
317 #endif
318 
319 #if !defined(DEBUG_NO_PRINT_DATA)
320 void
322 {
323  dump((uint16_t) RAMSTART, (void*) RAMSTART, DATASIZE);
324 }
325 #endif
326 
327 #if !defined(DEBUG_NO_PRINT_HEAP)
328 void
330 {
331  int HEAPSTART = (int) &__heap_start;
332  int HEAPEND = (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
333  int size = HEAPEND - HEAPSTART;
334  if (size == 0) return;
335  dump((uint16_t) HEAPSTART, (void*) HEAPSTART, size);
336 }
337 #endif
338 
339 #if !defined(DEBUG_NO_PRINT_STACK)
340 void
342 {
343  int size = RAMEND - marker + 1;
344  if (size == 0) return;
345  dump((uint16_t) marker, (void*) marker, size);
346 }
347 #endif
348 
349 #if !defined(DEBUG_NO_PRINT_VARIABLES)
350 void
352 {
353  for (Variable* vp = m_var; vp != NULL; vp = vp->m_next) vp->print();
354 }
355 #endif
356 
357 void
358 Debug::Variable::print(bool is_pointer)
359 {
360  debug.print(m_func);
361  debug.print(':');
362  debug.print(m_name);
363  debug.print('@');
364  debug.print(F("0x"));
365  debug.print((int) m_ref, HEX);
366  if (m_size == sizeof(void*) && is_pointer) {
367  int* ptr = *((int**) m_ref);
368  debug.print(F("=>"));
369  debug.dump((uint16_t) ptr, ptr, 16);
370  }
371  else {
372  if (m_size == 1) {
373  debug.print('=');
374  debug.print(*((uint8_t*) m_ref));
375  debug.print(F(" (0x"));
376  debug.print(*((uint8_t*) m_ref), HEX);
377  debug.println(')');
378  }
379  else if (m_size == 2) {
380  debug.print('=');
381  debug.print(*((int*) m_ref));
382  debug.print(F(" (0x"));
383  debug.print(*((uint16_t*) m_ref), HEX);
384  debug.println(')');
385  }
386  else {
387  debug.print('[');
388  debug.print(m_size);
389  debug.print(F("]:"));
390  if (m_size > 16) debug.println();
391  debug.dump((uint16_t) m_ref, m_ref, m_size);
392  }
393  }
394 }
395 
396 void
397 Debug::dump(uint16_t src, const void *ptr, size_t size)
398 {
399  uint8_t* p = (uint8_t*) ptr;
400  uint8_t n = 0;
401  print(F("0x"));
402  print(src, HEX);
403  print(F(": "));
404  while (size--) {
405  uint8_t d = *p++;
406  print(d >> 4, HEX);
407  print(d & 0x0F, HEX);
408  src += 1;
409  if (++n < 16) {
410  print(' ');
411  }
412  else {
413  println();
414  n = 0;
415  if (size > 0) {
416  print(F("0x"));
417  print(src, HEX);
418  print(F(": "));
419  }
420  }
421  }
422  if (n != 0) println();
423 }
void c()
Definition: DebugDemo.ino:68
const class __FlashStringHelper * str_P
Definition: Debug.h:32
void do_print_heap()
Definition: Debug.cpp:329
void run(const char *file=NULL, int line=0, const char *func=NULL, str_P expr=NULL)
Definition: Debug.cpp:104
#define ARCH
Definition: Debug.cpp:21
void do_print_stack(int marker)
Definition: Debug.cpp:341
bool check_stack(int room=128)
Definition: Debug.cpp:69
void observe_at(const char *file, int line, const char *func, str_P expr)
Definition: Debug.cpp:78
void do_print_variables()
Definition: Debug.cpp:351
char * buf
Definition: DebugDemo.ino:90
Debug debug
Definition: Debug.cpp:24
bool begin(Stream *dev, const char *file, int line, const char *func)
Definition: Debug.cpp:29
void do_backtrace(const char *func)
Definition: Debug.cpp:234
void assert(const char *file, int line, const char *func, str_P cond)
Definition: Debug.cpp:47
bool end()
Definition: Debug.cpp:94
Variable * m_var
Last registered variable.
Definition: Debug.h:287
void do_print_data()
Definition: Debug.cpp:321
virtual int read(void)
Definition: Debug.h:186
void do_print_commands()
Definition: Debug.cpp:282
void print(bool is_pointer=false)
Definition: Debug.cpp:358
void dump(uint16_t src, const void *ptr, size_t size)
Definition: Debug.cpp:397
Stream * m_dev
Debug stream.
Definition: Debug.h:286
void do_memory_usage(int marker)
Definition: Debug.cpp:266
int DATAEND
End of data segment.
Definition: Debug.h:288
int * __brkval
void break_at(const char *file, int line, const char *func, str_P cond)
Definition: Debug.cpp:59
int DATASIZE
Size of data segment.
Definition: Debug.h:289
const size_t BUF_MAX
Definition: DebugDemo.ino:89
bool do_lookup_variables(const char *name, bool is_pointer=false)
Definition: Debug.cpp:250
Definition: Debug.h:55
#define VERSION
Definition: Debug.cpp:22
int __heap_start
#define UNUSED(x)
Definition: Debug.h:25
class Variable * m_next
Next variable.
Definition: Debug.h:175