2013-03-12 Hui Zhu <hui@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / btrace.c
CommitLineData
02d27625
MM
1/* Branch trace support for GDB, the GNU debugger.
2
3 Copyright (C) 2013 Free Software Foundation, Inc.
4
5 Contributed by Intel Corp. <markus.t.metzger@intel.com>
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22#include "btrace.h"
23#include "gdbthread.h"
24#include "exceptions.h"
25#include "inferior.h"
26#include "target.h"
27#include "record.h"
28#include "symtab.h"
29#include "disasm.h"
30#include "source.h"
31#include "filenames.h"
c12a2917 32#include "xml-support.h"
02d27625
MM
33
34/* Print a record debug message. Use do ... while (0) to avoid ambiguities
35 when used in if statements. */
36
37#define DEBUG(msg, args...) \
38 do \
39 { \
40 if (record_debug != 0) \
41 fprintf_unfiltered (gdb_stdlog, \
42 "[btrace] " msg "\n", ##args); \
43 } \
44 while (0)
45
46#define DEBUG_FTRACE(msg, args...) DEBUG ("[ftrace] " msg, ##args)
47
48/* Initialize the instruction iterator. */
49
50static void
51btrace_init_insn_iterator (struct btrace_thread_info *btinfo)
52{
53 DEBUG ("init insn iterator");
54
55 btinfo->insn_iterator.begin = 1;
56 btinfo->insn_iterator.end = 0;
57}
58
59/* Initialize the function iterator. */
60
61static void
62btrace_init_func_iterator (struct btrace_thread_info *btinfo)
63{
64 DEBUG ("init func iterator");
65
66 btinfo->func_iterator.begin = 1;
67 btinfo->func_iterator.end = 0;
68}
69
70/* Compute the instruction trace from the block trace. */
71
72static VEC (btrace_inst_s) *
73compute_itrace (VEC (btrace_block_s) *btrace)
74{
75 VEC (btrace_inst_s) *itrace;
76 struct gdbarch *gdbarch;
77 unsigned int b;
78
79 DEBUG ("compute itrace");
80
81 itrace = NULL;
82 gdbarch = target_gdbarch ();
83 b = VEC_length (btrace_block_s, btrace);
84
85 while (b-- != 0)
86 {
87 btrace_block_s *block;
88 CORE_ADDR pc;
89
90 block = VEC_index (btrace_block_s, btrace, b);
91 pc = block->begin;
92
93 /* Add instructions for this block. */
94 for (;;)
95 {
96 btrace_inst_s *inst;
97 int size;
98
99 /* We should hit the end of the block. Warn if we went too far. */
100 if (block->end < pc)
101 {
102 warning (_("Recorded trace may be corrupted."));
103 break;
104 }
105
106 inst = VEC_safe_push (btrace_inst_s, itrace, NULL);
107 inst->pc = pc;
108
109 /* We're done once we pushed the instruction at the end. */
110 if (block->end == pc)
111 break;
112
113 size = gdb_insn_length (gdbarch, pc);
114
115 /* Make sure we terminate if we fail to compute the size. */
116 if (size <= 0)
117 {
118 warning (_("Recorded trace may be incomplete."));
119 break;
120 }
121
122 pc += size;
123 }
124 }
125
126 return itrace;
127}
128
129/* Return the function name of a recorded function segment for printing.
130 This function never returns NULL. */
131
132static const char *
133ftrace_print_function_name (struct btrace_func *bfun)
134{
135 struct minimal_symbol *msym;
136 struct symbol *sym;
137
138 msym = bfun->msym;
139 sym = bfun->sym;
140
141 if (sym != NULL)
142 return SYMBOL_PRINT_NAME (sym);
143
144 if (msym != NULL)
145 return SYMBOL_PRINT_NAME (msym);
146
147 return "<unknown>";
148}
149
150/* Return the file name of a recorded function segment for printing.
151 This function never returns NULL. */
152
153static const char *
154ftrace_print_filename (struct btrace_func *bfun)
155{
156 struct symbol *sym;
157 const char *filename;
158
159 sym = bfun->sym;
160
161 if (sym != NULL)
162 filename = symtab_to_filename_for_display (sym->symtab);
163 else
164 filename = "<unknown>";
165
166 return filename;
167}
168
169/* Print an ftrace debug status message. */
170
171static void
172ftrace_debug (struct btrace_func *bfun, const char *prefix)
173{
174 DEBUG_FTRACE ("%s: fun = %s, file = %s, lines = [%d; %d], insn = [%u; %u]",
175 prefix, ftrace_print_function_name (bfun),
176 ftrace_print_filename (bfun), bfun->lbegin, bfun->lend,
177 bfun->ibegin, bfun->iend);
178}
179
180/* Initialize a recorded function segment. */
181
182static void
183ftrace_init_func (struct btrace_func *bfun, struct minimal_symbol *mfun,
184 struct symbol *fun, unsigned int idx)
185{
186 bfun->msym = mfun;
187 bfun->sym = fun;
188 bfun->lbegin = INT_MAX;
189 bfun->lend = 0;
190 bfun->ibegin = idx;
191 bfun->iend = idx;
192}
193
194/* Check whether the function has changed. */
195
196static int
197ftrace_function_switched (struct btrace_func *bfun,
198 struct minimal_symbol *mfun, struct symbol *fun)
199{
200 struct minimal_symbol *msym;
201 struct symbol *sym;
202
203 /* The function changed if we did not have one before. */
204 if (bfun == NULL)
205 return 1;
206
207 msym = bfun->msym;
208 sym = bfun->sym;
209
210 /* If the minimal symbol changed, we certainly switched functions. */
211 if (mfun != NULL && msym != NULL
212 && strcmp (SYMBOL_LINKAGE_NAME (mfun), SYMBOL_LINKAGE_NAME (msym)) != 0)
213 return 1;
214
215 /* If the symbol changed, we certainly switched functions. */
216 if (fun != NULL && sym != NULL)
217 {
218 const char *bfname, *fname;
219
220 /* Check the function name. */
221 if (strcmp (SYMBOL_LINKAGE_NAME (fun), SYMBOL_LINKAGE_NAME (sym)) != 0)
222 return 1;
223
224 /* Check the location of those functions, as well. */
225 bfname = symtab_to_fullname (sym->symtab);
226 fname = symtab_to_fullname (fun->symtab);
227 if (filename_cmp (fname, bfname) != 0)
228 return 1;
229 }
230
231 return 0;
232}
233
234/* Check if we should skip this file when generating the function call
235 history. We would want to do that if, say, a macro that is defined
236 in another file is expanded in this function. */
237
238static int
239ftrace_skip_file (struct btrace_func *bfun, const char *filename)
240{
241 struct symbol *sym;
242 const char *bfile;
243
244 sym = bfun->sym;
245
246 if (sym != NULL)
247 bfile = symtab_to_fullname (sym->symtab);
248 else
249 bfile = "";
250
251 if (filename == NULL)
252 filename = "";
253
254 return (filename_cmp (bfile, filename) != 0);
255}
256
257/* Compute the function trace from the instruction trace. */
258
259static VEC (btrace_func_s) *
260compute_ftrace (VEC (btrace_inst_s) *itrace)
261{
262 VEC (btrace_func_s) *ftrace;
263 struct btrace_inst *binst;
264 struct btrace_func *bfun;
265 unsigned int idx;
266
267 DEBUG ("compute ftrace");
268
269 ftrace = NULL;
270 bfun = NULL;
271
272 for (idx = 0; VEC_iterate (btrace_inst_s, itrace, idx, binst); ++idx)
273 {
274 struct symtab_and_line sal;
275 struct minimal_symbol *mfun;
276 struct symbol *fun;
277 const char *filename;
278 CORE_ADDR pc;
279
280 pc = binst->pc;
281
282 /* Try to determine the function we're in. We use both types of symbols
283 to avoid surprises when we sometimes get a full symbol and sometimes
284 only a minimal symbol. */
285 fun = find_pc_function (pc);
286 mfun = lookup_minimal_symbol_by_pc (pc);
287
288 if (fun == NULL && mfun == NULL)
289 {
290 DEBUG_FTRACE ("no symbol at %u, pc=%s", idx,
291 core_addr_to_string_nz (pc));
292 continue;
293 }
294
295 /* If we're switching functions, we start over. */
296 if (ftrace_function_switched (bfun, mfun, fun))
297 {
298 bfun = VEC_safe_push (btrace_func_s, ftrace, NULL);
299
300 ftrace_init_func (bfun, mfun, fun, idx);
301 ftrace_debug (bfun, "init");
302 }
303
304 /* Update the instruction range. */
305 bfun->iend = idx;
306 ftrace_debug (bfun, "update insns");
307
308 /* Let's see if we have source correlation, as well. */
309 sal = find_pc_line (pc, 0);
310 if (sal.symtab == NULL || sal.line == 0)
311 {
312 DEBUG_FTRACE ("no lines at %u, pc=%s", idx,
313 core_addr_to_string_nz (pc));
314 continue;
315 }
316
317 /* Check if we switched files. This could happen if, say, a macro that
318 is defined in another file is expanded here. */
319 filename = symtab_to_fullname (sal.symtab);
320 if (ftrace_skip_file (bfun, filename))
321 {
322 DEBUG_FTRACE ("ignoring file at %u, pc=%s, file=%s", idx,
323 core_addr_to_string_nz (pc), filename);
324 continue;
325 }
326
327 /* Update the line range. */
328 bfun->lbegin = min (bfun->lbegin, sal.line);
329 bfun->lend = max (bfun->lend, sal.line);
330 ftrace_debug (bfun, "update lines");
331 }
332
333 return ftrace;
334}
335
336/* See btrace.h. */
337
338void
339btrace_enable (struct thread_info *tp)
340{
341 if (tp->btrace.target != NULL)
342 return;
343
344 if (!target_supports_btrace ())
345 error (_("Target does not support branch tracing."));
346
347 DEBUG ("enable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
348
349 tp->btrace.target = target_enable_btrace (tp->ptid);
350}
351
352/* See btrace.h. */
353
354void
355btrace_disable (struct thread_info *tp)
356{
357 struct btrace_thread_info *btp = &tp->btrace;
358 int errcode = 0;
359
360 if (btp->target == NULL)
361 return;
362
363 DEBUG ("disable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
364
365 target_disable_btrace (btp->target);
366 btp->target = NULL;
367
368 btrace_clear (tp);
369}
370
371/* See btrace.h. */
372
373void
374btrace_teardown (struct thread_info *tp)
375{
376 struct btrace_thread_info *btp = &tp->btrace;
377 int errcode = 0;
378
379 if (btp->target == NULL)
380 return;
381
382 DEBUG ("teardown thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
383
384 target_teardown_btrace (btp->target);
385 btp->target = NULL;
386
387 btrace_clear (tp);
388}
389
390/* See btrace.h. */
391
392void
393btrace_fetch (struct thread_info *tp)
394{
395 struct btrace_thread_info *btinfo;
396 VEC (btrace_block_s) *btrace;
397
398 DEBUG ("fetch thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
399
400 btinfo = &tp->btrace;
401 if (btinfo->target == NULL)
402 return;
403
404 btrace = target_read_btrace (btinfo->target, btrace_read_new);
405 if (VEC_empty (btrace_block_s, btrace))
406 return;
407
408 btrace_clear (tp);
409
410 btinfo->btrace = btrace;
411 btinfo->itrace = compute_itrace (btinfo->btrace);
412 btinfo->ftrace = compute_ftrace (btinfo->itrace);
413
414 /* Initialize branch trace iterators. */
415 btrace_init_insn_iterator (btinfo);
416 btrace_init_func_iterator (btinfo);
417}
418
419/* See btrace.h. */
420
421void
422btrace_clear (struct thread_info *tp)
423{
424 struct btrace_thread_info *btinfo;
425
426 DEBUG ("clear thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
427
428 btinfo = &tp->btrace;
429
430 VEC_free (btrace_block_s, btinfo->btrace);
431 VEC_free (btrace_inst_s, btinfo->itrace);
432 VEC_free (btrace_func_s, btinfo->ftrace);
433
434 btinfo->btrace = NULL;
435 btinfo->itrace = NULL;
436 btinfo->ftrace = NULL;
437}
438
439/* See btrace.h. */
440
441void
442btrace_free_objfile (struct objfile *objfile)
443{
444 struct thread_info *tp;
445
446 DEBUG ("free objfile");
447
448 ALL_THREADS (tp)
449 btrace_clear (tp);
450}
c12a2917
MM
451
452#if defined (HAVE_LIBEXPAT)
453
454/* Check the btrace document version. */
455
456static void
457check_xml_btrace_version (struct gdb_xml_parser *parser,
458 const struct gdb_xml_element *element,
459 void *user_data, VEC (gdb_xml_value_s) *attributes)
460{
461 const char *version = xml_find_attribute (attributes, "version")->value;
462
463 if (strcmp (version, "1.0") != 0)
464 gdb_xml_error (parser, _("Unsupported btrace version: \"%s\""), version);
465}
466
467/* Parse a btrace "block" xml record. */
468
469static void
470parse_xml_btrace_block (struct gdb_xml_parser *parser,
471 const struct gdb_xml_element *element,
472 void *user_data, VEC (gdb_xml_value_s) *attributes)
473{
474 VEC (btrace_block_s) **btrace;
475 struct btrace_block *block;
476 ULONGEST *begin, *end;
477
478 btrace = user_data;
479 block = VEC_safe_push (btrace_block_s, *btrace, NULL);
480
481 begin = xml_find_attribute (attributes, "begin")->value;
482 end = xml_find_attribute (attributes, "end")->value;
483
484 block->begin = *begin;
485 block->end = *end;
486}
487
488static const struct gdb_xml_attribute block_attributes[] = {
489 { "begin", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
490 { "end", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
491 { NULL, GDB_XML_AF_NONE, NULL, NULL }
492};
493
494static const struct gdb_xml_attribute btrace_attributes[] = {
495 { "version", GDB_XML_AF_NONE, NULL, NULL },
496 { NULL, GDB_XML_AF_NONE, NULL, NULL }
497};
498
499static const struct gdb_xml_element btrace_children[] = {
500 { "block", block_attributes, NULL,
501 GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL, parse_xml_btrace_block, NULL },
502 { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
503};
504
505static const struct gdb_xml_element btrace_elements[] = {
506 { "btrace", btrace_attributes, btrace_children, GDB_XML_EF_NONE,
507 check_xml_btrace_version, NULL },
508 { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
509};
510
511#endif /* defined (HAVE_LIBEXPAT) */
512
513/* See btrace.h. */
514
515VEC (btrace_block_s) *
516parse_xml_btrace (const char *buffer)
517{
518 VEC (btrace_block_s) *btrace = NULL;
519 struct cleanup *cleanup;
520 int errcode;
521
522#if defined (HAVE_LIBEXPAT)
523
524 cleanup = make_cleanup (VEC_cleanup (btrace_block_s), &btrace);
525 errcode = gdb_xml_parse_quick (_("btrace"), "btrace.dtd", btrace_elements,
526 buffer, &btrace);
527 if (errcode != 0)
528 {
529 do_cleanups (cleanup);
530 return NULL;
531 }
532
533 /* Keep parse results. */
534 discard_cleanups (cleanup);
535
536#else /* !defined (HAVE_LIBEXPAT) */
537
538 error (_("Cannot process branch trace. XML parsing is not supported."));
539
540#endif /* !defined (HAVE_LIBEXPAT) */
541
542 return btrace;
543}
This page took 0.041787 seconds and 4 git commands to generate.