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