GDB (API)
|
00001 /* Branch trace support for GDB, the GNU debugger. 00002 00003 Copyright (C) 2013 Free Software Foundation, Inc. 00004 00005 Contributed by Intel Corp. <markus.t.metzger@intel.com> 00006 00007 This file is part of GDB. 00008 00009 This program is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 3 of the License, or 00012 (at your option) any later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00021 00022 #include "btrace.h" 00023 #include "gdbthread.h" 00024 #include "exceptions.h" 00025 #include "inferior.h" 00026 #include "target.h" 00027 #include "record.h" 00028 #include "symtab.h" 00029 #include "disasm.h" 00030 #include "source.h" 00031 #include "filenames.h" 00032 #include "xml-support.h" 00033 00034 /* Print a record debug message. Use do ... while (0) to avoid ambiguities 00035 when used in if statements. */ 00036 00037 #define DEBUG(msg, args...) \ 00038 do \ 00039 { \ 00040 if (record_debug != 0) \ 00041 fprintf_unfiltered (gdb_stdlog, \ 00042 "[btrace] " msg "\n", ##args); \ 00043 } \ 00044 while (0) 00045 00046 #define DEBUG_FTRACE(msg, args...) DEBUG ("[ftrace] " msg, ##args) 00047 00048 /* Initialize the instruction iterator. */ 00049 00050 static void 00051 btrace_init_insn_iterator (struct btrace_thread_info *btinfo) 00052 { 00053 DEBUG ("init insn iterator"); 00054 00055 btinfo->insn_iterator.begin = 1; 00056 btinfo->insn_iterator.end = 0; 00057 } 00058 00059 /* Initialize the function iterator. */ 00060 00061 static void 00062 btrace_init_func_iterator (struct btrace_thread_info *btinfo) 00063 { 00064 DEBUG ("init func iterator"); 00065 00066 btinfo->func_iterator.begin = 1; 00067 btinfo->func_iterator.end = 0; 00068 } 00069 00070 /* Compute the instruction trace from the block trace. */ 00071 00072 static VEC (btrace_inst_s) * 00073 compute_itrace (VEC (btrace_block_s) *btrace) 00074 { 00075 VEC (btrace_inst_s) *itrace; 00076 struct gdbarch *gdbarch; 00077 unsigned int b; 00078 00079 DEBUG ("compute itrace"); 00080 00081 itrace = NULL; 00082 gdbarch = target_gdbarch (); 00083 b = VEC_length (btrace_block_s, btrace); 00084 00085 while (b-- != 0) 00086 { 00087 btrace_block_s *block; 00088 CORE_ADDR pc; 00089 00090 block = VEC_index (btrace_block_s, btrace, b); 00091 pc = block->begin; 00092 00093 /* Add instructions for this block. */ 00094 for (;;) 00095 { 00096 btrace_inst_s *inst; 00097 int size; 00098 00099 /* We should hit the end of the block. Warn if we went too far. */ 00100 if (block->end < pc) 00101 { 00102 warning (_("Recorded trace may be corrupted.")); 00103 break; 00104 } 00105 00106 inst = VEC_safe_push (btrace_inst_s, itrace, NULL); 00107 inst->pc = pc; 00108 00109 /* We're done once we pushed the instruction at the end. */ 00110 if (block->end == pc) 00111 break; 00112 00113 size = gdb_insn_length (gdbarch, pc); 00114 00115 /* Make sure we terminate if we fail to compute the size. */ 00116 if (size <= 0) 00117 { 00118 warning (_("Recorded trace may be incomplete.")); 00119 break; 00120 } 00121 00122 pc += size; 00123 } 00124 } 00125 00126 return itrace; 00127 } 00128 00129 /* Return the function name of a recorded function segment for printing. 00130 This function never returns NULL. */ 00131 00132 static const char * 00133 ftrace_print_function_name (struct btrace_func *bfun) 00134 { 00135 struct minimal_symbol *msym; 00136 struct symbol *sym; 00137 00138 msym = bfun->msym; 00139 sym = bfun->sym; 00140 00141 if (sym != NULL) 00142 return SYMBOL_PRINT_NAME (sym); 00143 00144 if (msym != NULL) 00145 return SYMBOL_PRINT_NAME (msym); 00146 00147 return "<unknown>"; 00148 } 00149 00150 /* Return the file name of a recorded function segment for printing. 00151 This function never returns NULL. */ 00152 00153 static const char * 00154 ftrace_print_filename (struct btrace_func *bfun) 00155 { 00156 struct symbol *sym; 00157 const char *filename; 00158 00159 sym = bfun->sym; 00160 00161 if (sym != NULL) 00162 filename = symtab_to_filename_for_display (sym->symtab); 00163 else 00164 filename = "<unknown>"; 00165 00166 return filename; 00167 } 00168 00169 /* Print an ftrace debug status message. */ 00170 00171 static void 00172 ftrace_debug (struct btrace_func *bfun, const char *prefix) 00173 { 00174 DEBUG_FTRACE ("%s: fun = %s, file = %s, lines = [%d; %d], insn = [%u; %u]", 00175 prefix, ftrace_print_function_name (bfun), 00176 ftrace_print_filename (bfun), bfun->lbegin, bfun->lend, 00177 bfun->ibegin, bfun->iend); 00178 } 00179 00180 /* Initialize a recorded function segment. */ 00181 00182 static void 00183 ftrace_init_func (struct btrace_func *bfun, struct minimal_symbol *mfun, 00184 struct symbol *fun, unsigned int idx) 00185 { 00186 bfun->msym = mfun; 00187 bfun->sym = fun; 00188 bfun->lbegin = INT_MAX; 00189 bfun->lend = 0; 00190 bfun->ibegin = idx; 00191 bfun->iend = idx; 00192 } 00193 00194 /* Check whether the function has changed. */ 00195 00196 static int 00197 ftrace_function_switched (struct btrace_func *bfun, 00198 struct minimal_symbol *mfun, struct symbol *fun) 00199 { 00200 struct minimal_symbol *msym; 00201 struct symbol *sym; 00202 00203 /* The function changed if we did not have one before. */ 00204 if (bfun == NULL) 00205 return 1; 00206 00207 msym = bfun->msym; 00208 sym = bfun->sym; 00209 00210 /* If the minimal symbol changed, we certainly switched functions. */ 00211 if (mfun != NULL && msym != NULL 00212 && strcmp (SYMBOL_LINKAGE_NAME (mfun), SYMBOL_LINKAGE_NAME (msym)) != 0) 00213 return 1; 00214 00215 /* If the symbol changed, we certainly switched functions. */ 00216 if (fun != NULL && sym != NULL) 00217 { 00218 const char *bfname, *fname; 00219 00220 /* Check the function name. */ 00221 if (strcmp (SYMBOL_LINKAGE_NAME (fun), SYMBOL_LINKAGE_NAME (sym)) != 0) 00222 return 1; 00223 00224 /* Check the location of those functions, as well. */ 00225 bfname = symtab_to_fullname (sym->symtab); 00226 fname = symtab_to_fullname (fun->symtab); 00227 if (filename_cmp (fname, bfname) != 0) 00228 return 1; 00229 } 00230 00231 return 0; 00232 } 00233 00234 /* Check if we should skip this file when generating the function call 00235 history. We would want to do that if, say, a macro that is defined 00236 in another file is expanded in this function. */ 00237 00238 static int 00239 ftrace_skip_file (struct btrace_func *bfun, const char *filename) 00240 { 00241 struct symbol *sym; 00242 const char *bfile; 00243 00244 sym = bfun->sym; 00245 00246 if (sym != NULL) 00247 bfile = symtab_to_fullname (sym->symtab); 00248 else 00249 bfile = ""; 00250 00251 if (filename == NULL) 00252 filename = ""; 00253 00254 return (filename_cmp (bfile, filename) != 0); 00255 } 00256 00257 /* Compute the function trace from the instruction trace. */ 00258 00259 static VEC (btrace_func_s) * 00260 compute_ftrace (VEC (btrace_inst_s) *itrace) 00261 { 00262 VEC (btrace_func_s) *ftrace; 00263 struct btrace_inst *binst; 00264 struct btrace_func *bfun; 00265 unsigned int idx; 00266 00267 DEBUG ("compute ftrace"); 00268 00269 ftrace = NULL; 00270 bfun = NULL; 00271 00272 for (idx = 0; VEC_iterate (btrace_inst_s, itrace, idx, binst); ++idx) 00273 { 00274 struct symtab_and_line sal; 00275 struct bound_minimal_symbol mfun; 00276 struct symbol *fun; 00277 const char *filename; 00278 CORE_ADDR pc; 00279 00280 pc = binst->pc; 00281 00282 /* Try to determine the function we're in. We use both types of symbols 00283 to avoid surprises when we sometimes get a full symbol and sometimes 00284 only a minimal symbol. */ 00285 fun = find_pc_function (pc); 00286 mfun = lookup_minimal_symbol_by_pc (pc); 00287 00288 if (fun == NULL && mfun.minsym == NULL) 00289 { 00290 DEBUG_FTRACE ("no symbol at %u, pc=%s", idx, 00291 core_addr_to_string_nz (pc)); 00292 continue; 00293 } 00294 00295 /* If we're switching functions, we start over. */ 00296 if (ftrace_function_switched (bfun, mfun.minsym, fun)) 00297 { 00298 bfun = VEC_safe_push (btrace_func_s, ftrace, NULL); 00299 00300 ftrace_init_func (bfun, mfun.minsym, fun, idx); 00301 ftrace_debug (bfun, "init"); 00302 } 00303 00304 /* Update the instruction range. */ 00305 bfun->iend = idx; 00306 ftrace_debug (bfun, "update insns"); 00307 00308 /* Let's see if we have source correlation, as well. */ 00309 sal = find_pc_line (pc, 0); 00310 if (sal.symtab == NULL || sal.line == 0) 00311 { 00312 DEBUG_FTRACE ("no lines at %u, pc=%s", idx, 00313 core_addr_to_string_nz (pc)); 00314 continue; 00315 } 00316 00317 /* Check if we switched files. This could happen if, say, a macro that 00318 is defined in another file is expanded here. */ 00319 filename = symtab_to_fullname (sal.symtab); 00320 if (ftrace_skip_file (bfun, filename)) 00321 { 00322 DEBUG_FTRACE ("ignoring file at %u, pc=%s, file=%s", idx, 00323 core_addr_to_string_nz (pc), filename); 00324 continue; 00325 } 00326 00327 /* Update the line range. */ 00328 bfun->lbegin = min (bfun->lbegin, sal.line); 00329 bfun->lend = max (bfun->lend, sal.line); 00330 ftrace_debug (bfun, "update lines"); 00331 } 00332 00333 return ftrace; 00334 } 00335 00336 /* See btrace.h. */ 00337 00338 void 00339 btrace_enable (struct thread_info *tp) 00340 { 00341 if (tp->btrace.target != NULL) 00342 return; 00343 00344 if (!target_supports_btrace ()) 00345 error (_("Target does not support branch tracing.")); 00346 00347 DEBUG ("enable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); 00348 00349 tp->btrace.target = target_enable_btrace (tp->ptid); 00350 } 00351 00352 /* See btrace.h. */ 00353 00354 void 00355 btrace_disable (struct thread_info *tp) 00356 { 00357 struct btrace_thread_info *btp = &tp->btrace; 00358 int errcode = 0; 00359 00360 if (btp->target == NULL) 00361 return; 00362 00363 DEBUG ("disable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); 00364 00365 target_disable_btrace (btp->target); 00366 btp->target = NULL; 00367 00368 btrace_clear (tp); 00369 } 00370 00371 /* See btrace.h. */ 00372 00373 void 00374 btrace_teardown (struct thread_info *tp) 00375 { 00376 struct btrace_thread_info *btp = &tp->btrace; 00377 int errcode = 0; 00378 00379 if (btp->target == NULL) 00380 return; 00381 00382 DEBUG ("teardown thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); 00383 00384 target_teardown_btrace (btp->target); 00385 btp->target = NULL; 00386 00387 btrace_clear (tp); 00388 } 00389 00390 /* See btrace.h. */ 00391 00392 void 00393 btrace_fetch (struct thread_info *tp) 00394 { 00395 struct btrace_thread_info *btinfo; 00396 VEC (btrace_block_s) *btrace; 00397 00398 DEBUG ("fetch thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); 00399 00400 btinfo = &tp->btrace; 00401 if (btinfo->target == NULL) 00402 return; 00403 00404 btrace = target_read_btrace (btinfo->target, btrace_read_new); 00405 if (VEC_empty (btrace_block_s, btrace)) 00406 return; 00407 00408 btrace_clear (tp); 00409 00410 btinfo->btrace = btrace; 00411 btinfo->itrace = compute_itrace (btinfo->btrace); 00412 btinfo->ftrace = compute_ftrace (btinfo->itrace); 00413 00414 /* Initialize branch trace iterators. */ 00415 btrace_init_insn_iterator (btinfo); 00416 btrace_init_func_iterator (btinfo); 00417 } 00418 00419 /* See btrace.h. */ 00420 00421 void 00422 btrace_clear (struct thread_info *tp) 00423 { 00424 struct btrace_thread_info *btinfo; 00425 00426 DEBUG ("clear thread %d (%s)", tp->num, target_pid_to_str (tp->ptid)); 00427 00428 btinfo = &tp->btrace; 00429 00430 VEC_free (btrace_block_s, btinfo->btrace); 00431 VEC_free (btrace_inst_s, btinfo->itrace); 00432 VEC_free (btrace_func_s, btinfo->ftrace); 00433 00434 btinfo->btrace = NULL; 00435 btinfo->itrace = NULL; 00436 btinfo->ftrace = NULL; 00437 } 00438 00439 /* See btrace.h. */ 00440 00441 void 00442 btrace_free_objfile (struct objfile *objfile) 00443 { 00444 struct thread_info *tp; 00445 00446 DEBUG ("free objfile"); 00447 00448 ALL_THREADS (tp) 00449 btrace_clear (tp); 00450 } 00451 00452 #if defined (HAVE_LIBEXPAT) 00453 00454 /* Check the btrace document version. */ 00455 00456 static void 00457 check_xml_btrace_version (struct gdb_xml_parser *parser, 00458 const struct gdb_xml_element *element, 00459 void *user_data, VEC (gdb_xml_value_s) *attributes) 00460 { 00461 const char *version = xml_find_attribute (attributes, "version")->value; 00462 00463 if (strcmp (version, "1.0") != 0) 00464 gdb_xml_error (parser, _("Unsupported btrace version: \"%s\""), version); 00465 } 00466 00467 /* Parse a btrace "block" xml record. */ 00468 00469 static void 00470 parse_xml_btrace_block (struct gdb_xml_parser *parser, 00471 const struct gdb_xml_element *element, 00472 void *user_data, VEC (gdb_xml_value_s) *attributes) 00473 { 00474 VEC (btrace_block_s) **btrace; 00475 struct btrace_block *block; 00476 ULONGEST *begin, *end; 00477 00478 btrace = user_data; 00479 block = VEC_safe_push (btrace_block_s, *btrace, NULL); 00480 00481 begin = xml_find_attribute (attributes, "begin")->value; 00482 end = xml_find_attribute (attributes, "end")->value; 00483 00484 block->begin = *begin; 00485 block->end = *end; 00486 } 00487 00488 static const struct gdb_xml_attribute block_attributes[] = { 00489 { "begin", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, 00490 { "end", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, 00491 { NULL, GDB_XML_AF_NONE, NULL, NULL } 00492 }; 00493 00494 static const struct gdb_xml_attribute btrace_attributes[] = { 00495 { "version", GDB_XML_AF_NONE, NULL, NULL }, 00496 { NULL, GDB_XML_AF_NONE, NULL, NULL } 00497 }; 00498 00499 static const struct gdb_xml_element btrace_children[] = { 00500 { "block", block_attributes, NULL, 00501 GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL, parse_xml_btrace_block, NULL }, 00502 { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } 00503 }; 00504 00505 static const struct gdb_xml_element btrace_elements[] = { 00506 { "btrace", btrace_attributes, btrace_children, GDB_XML_EF_NONE, 00507 check_xml_btrace_version, NULL }, 00508 { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } 00509 }; 00510 00511 #endif /* defined (HAVE_LIBEXPAT) */ 00512 00513 /* See btrace.h. */ 00514 00515 VEC (btrace_block_s) * 00516 parse_xml_btrace (const char *buffer) 00517 { 00518 VEC (btrace_block_s) *btrace = NULL; 00519 struct cleanup *cleanup; 00520 int errcode; 00521 00522 #if defined (HAVE_LIBEXPAT) 00523 00524 cleanup = make_cleanup (VEC_cleanup (btrace_block_s), &btrace); 00525 errcode = gdb_xml_parse_quick (_("btrace"), "btrace.dtd", btrace_elements, 00526 buffer, &btrace); 00527 if (errcode != 0) 00528 { 00529 do_cleanups (cleanup); 00530 return NULL; 00531 } 00532 00533 /* Keep parse results. */ 00534 discard_cleanups (cleanup); 00535 00536 #else /* !defined (HAVE_LIBEXPAT) */ 00537 00538 error (_("Cannot process branch trace. XML parsing is not supported.")); 00539 00540 #endif /* !defined (HAVE_LIBEXPAT) */ 00541 00542 return btrace; 00543 }