GDB (API)
|
00001 /* Linux-dependent part of branch trace support for GDB, and GDBserver. 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 #ifdef GDBSERVER 00023 #include "server.h" 00024 #else 00025 #include "defs.h" 00026 #endif 00027 00028 #include "linux-btrace.h" 00029 #include "common-utils.h" 00030 #include "gdb_assert.h" 00031 #include "regcache.h" 00032 #include "gdbthread.h" 00033 #include "gdb_wait.h" 00034 #include "i386-cpuid.h" 00035 00036 #ifdef HAVE_SYS_SYSCALL_H 00037 #include <sys/syscall.h> 00038 #endif 00039 00040 #if HAVE_LINUX_PERF_EVENT_H && defined(SYS_perf_event_open) 00041 00042 #include <errno.h> 00043 #include <string.h> 00044 #include <stdint.h> 00045 #include <unistd.h> 00046 #include <sys/mman.h> 00047 #include <sys/user.h> 00048 #include <sys/ptrace.h> 00049 #include <sys/types.h> 00050 #include <signal.h> 00051 00052 /* A branch trace record in perf_event. */ 00053 struct perf_event_bts 00054 { 00055 /* The linear address of the branch source. */ 00056 uint64_t from; 00057 00058 /* The linear address of the branch destination. */ 00059 uint64_t to; 00060 }; 00061 00062 /* A perf_event branch trace sample. */ 00063 struct perf_event_sample 00064 { 00065 /* The perf_event sample header. */ 00066 struct perf_event_header header; 00067 00068 /* The perf_event branch tracing payload. */ 00069 struct perf_event_bts bts; 00070 }; 00071 00072 /* Get the perf_event header. */ 00073 00074 static inline volatile struct perf_event_mmap_page * 00075 perf_event_header (struct btrace_target_info* tinfo) 00076 { 00077 return tinfo->buffer; 00078 } 00079 00080 /* Get the size of the perf_event mmap buffer. */ 00081 00082 static inline size_t 00083 perf_event_mmap_size (const struct btrace_target_info *tinfo) 00084 { 00085 /* The branch trace buffer is preceded by a configuration page. */ 00086 return (tinfo->size + 1) * PAGE_SIZE; 00087 } 00088 00089 /* Get the size of the perf_event buffer. */ 00090 00091 static inline size_t 00092 perf_event_buffer_size (struct btrace_target_info* tinfo) 00093 { 00094 return tinfo->size * PAGE_SIZE; 00095 } 00096 00097 /* Get the start address of the perf_event buffer. */ 00098 00099 static inline const uint8_t * 00100 perf_event_buffer_begin (struct btrace_target_info* tinfo) 00101 { 00102 return ((const uint8_t *) tinfo->buffer) + PAGE_SIZE; 00103 } 00104 00105 /* Get the end address of the perf_event buffer. */ 00106 00107 static inline const uint8_t * 00108 perf_event_buffer_end (struct btrace_target_info* tinfo) 00109 { 00110 return perf_event_buffer_begin (tinfo) + perf_event_buffer_size (tinfo); 00111 } 00112 00113 /* Check whether an address is in the kernel. */ 00114 00115 static inline int 00116 perf_event_is_kernel_addr (const struct btrace_target_info *tinfo, 00117 uint64_t addr) 00118 { 00119 uint64_t mask; 00120 00121 /* If we don't know the size of a pointer, we can't check. Let's assume it's 00122 not a kernel address in this case. */ 00123 if (tinfo->ptr_bits == 0) 00124 return 0; 00125 00126 /* A bit mask for the most significant bit in an address. */ 00127 mask = (uint64_t) 1 << (tinfo->ptr_bits - 1); 00128 00129 /* Check whether the most significant bit in the address is set. */ 00130 return (addr & mask) != 0; 00131 } 00132 00133 /* Check whether a perf event record should be skipped. */ 00134 00135 static inline int 00136 perf_event_skip_record (const struct btrace_target_info *tinfo, 00137 const struct perf_event_bts *bts) 00138 { 00139 /* The hardware may report branches from kernel into user space. Branches 00140 from user into kernel space will be suppressed. We filter the former to 00141 provide a consistent branch trace excluding kernel. */ 00142 return perf_event_is_kernel_addr (tinfo, bts->from); 00143 } 00144 00145 /* Perform a few consistency checks on a perf event sample record. This is 00146 meant to catch cases when we get out of sync with the perf event stream. */ 00147 00148 static inline int 00149 perf_event_sample_ok (const struct perf_event_sample *sample) 00150 { 00151 if (sample->header.type != PERF_RECORD_SAMPLE) 00152 return 0; 00153 00154 if (sample->header.size != sizeof (*sample)) 00155 return 0; 00156 00157 return 1; 00158 } 00159 00160 /* Branch trace is collected in a circular buffer [begin; end) as pairs of from 00161 and to addresses (plus a header). 00162 00163 Start points into that buffer at the next sample position. 00164 We read the collected samples backwards from start. 00165 00166 While reading the samples, we convert the information into a list of blocks. 00167 For two adjacent samples s1 and s2, we form a block b such that b.begin = 00168 s1.to and b.end = s2.from. 00169 00170 In case the buffer overflows during sampling, one sample may have its lower 00171 part at the end and its upper part at the beginning of the buffer. */ 00172 00173 static VEC (btrace_block_s) * 00174 perf_event_read_bts (struct btrace_target_info* tinfo, const uint8_t *begin, 00175 const uint8_t *end, const uint8_t *start) 00176 { 00177 VEC (btrace_block_s) *btrace = NULL; 00178 struct perf_event_sample sample; 00179 size_t read = 0, size = (end - begin); 00180 struct btrace_block block = { 0, 0 }; 00181 struct regcache *regcache; 00182 00183 gdb_assert (begin <= start); 00184 gdb_assert (start <= end); 00185 00186 /* The first block ends at the current pc. */ 00187 #ifdef GDBSERVER 00188 regcache = get_thread_regcache (find_thread_ptid (tinfo->ptid), 1); 00189 #else 00190 regcache = get_thread_regcache (tinfo->ptid); 00191 #endif 00192 block.end = regcache_read_pc (regcache); 00193 00194 /* The buffer may contain a partial record as its last entry (i.e. when the 00195 buffer size is not a multiple of the sample size). */ 00196 read = sizeof (sample) - 1; 00197 00198 for (; read < size; read += sizeof (sample)) 00199 { 00200 const struct perf_event_sample *psample; 00201 00202 /* Find the next perf_event sample in a backwards traversal. */ 00203 start -= sizeof (sample); 00204 00205 /* If we're still inside the buffer, we're done. */ 00206 if (begin <= start) 00207 psample = (const struct perf_event_sample *) start; 00208 else 00209 { 00210 int missing; 00211 00212 /* We're to the left of the ring buffer, we will wrap around and 00213 reappear at the very right of the ring buffer. */ 00214 00215 missing = (begin - start); 00216 start = (end - missing); 00217 00218 /* If the entire sample is missing, we're done. */ 00219 if (missing == sizeof (sample)) 00220 psample = (const struct perf_event_sample *) start; 00221 else 00222 { 00223 uint8_t *stack; 00224 00225 /* The sample wrapped around. The lower part is at the end and 00226 the upper part is at the beginning of the buffer. */ 00227 stack = (uint8_t *) &sample; 00228 00229 /* Copy the two parts so we have a contiguous sample. */ 00230 memcpy (stack, start, missing); 00231 memcpy (stack + missing, begin, sizeof (sample) - missing); 00232 00233 psample = &sample; 00234 } 00235 } 00236 00237 if (!perf_event_sample_ok (psample)) 00238 { 00239 warning (_("Branch trace may be incomplete.")); 00240 break; 00241 } 00242 00243 if (perf_event_skip_record (tinfo, &psample->bts)) 00244 continue; 00245 00246 /* We found a valid sample, so we can complete the current block. */ 00247 block.begin = psample->bts.to; 00248 00249 VEC_safe_push (btrace_block_s, btrace, &block); 00250 00251 /* Start the next block. */ 00252 block.end = psample->bts.from; 00253 } 00254 00255 return btrace; 00256 } 00257 00258 /* Check whether the kernel supports branch tracing. */ 00259 00260 static int 00261 kernel_supports_btrace (void) 00262 { 00263 struct perf_event_attr attr; 00264 pid_t child, pid; 00265 int status, file; 00266 00267 errno = 0; 00268 child = fork (); 00269 switch (child) 00270 { 00271 case -1: 00272 warning (_("test branch tracing: cannot fork: %s."), strerror (errno)); 00273 return 0; 00274 00275 case 0: 00276 status = ptrace (PTRACE_TRACEME, 0, NULL, NULL); 00277 if (status != 0) 00278 { 00279 warning (_("test branch tracing: cannot PTRACE_TRACEME: %s."), 00280 strerror (errno)); 00281 _exit (1); 00282 } 00283 00284 status = raise (SIGTRAP); 00285 if (status != 0) 00286 { 00287 warning (_("test branch tracing: cannot raise SIGTRAP: %s."), 00288 strerror (errno)); 00289 _exit (1); 00290 } 00291 00292 _exit (1); 00293 00294 default: 00295 pid = waitpid (child, &status, 0); 00296 if (pid != child) 00297 { 00298 warning (_("test branch tracing: bad pid %ld, error: %s."), 00299 (long) pid, strerror (errno)); 00300 return 0; 00301 } 00302 00303 if (!WIFSTOPPED (status)) 00304 { 00305 warning (_("test branch tracing: expected stop. status: %d."), 00306 status); 00307 return 0; 00308 } 00309 00310 memset (&attr, 0, sizeof (attr)); 00311 00312 attr.type = PERF_TYPE_HARDWARE; 00313 attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; 00314 attr.sample_period = 1; 00315 attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ADDR; 00316 attr.exclude_kernel = 1; 00317 attr.exclude_hv = 1; 00318 attr.exclude_idle = 1; 00319 00320 file = syscall (SYS_perf_event_open, &attr, child, -1, -1, 0); 00321 if (file >= 0) 00322 close (file); 00323 00324 kill (child, SIGKILL); 00325 ptrace (PTRACE_KILL, child, NULL, NULL); 00326 00327 pid = waitpid (child, &status, 0); 00328 if (pid != child) 00329 { 00330 warning (_("test branch tracing: bad pid %ld, error: %s."), 00331 (long) pid, strerror (errno)); 00332 if (!WIFSIGNALED (status)) 00333 warning (_("test branch tracing: expected killed. status: %d."), 00334 status); 00335 } 00336 00337 return (file >= 0); 00338 } 00339 } 00340 00341 /* Check whether an Intel cpu supports branch tracing. */ 00342 00343 static int 00344 intel_supports_btrace (void) 00345 { 00346 unsigned int cpuid, model, family; 00347 00348 if (!i386_cpuid (1, &cpuid, NULL, NULL, NULL)) 00349 return 0; 00350 00351 family = (cpuid >> 8) & 0xf; 00352 model = (cpuid >> 4) & 0xf; 00353 00354 switch (family) 00355 { 00356 case 0x6: 00357 model += (cpuid >> 12) & 0xf0; 00358 00359 switch (model) 00360 { 00361 case 0x1a: /* Nehalem */ 00362 case 0x1f: 00363 case 0x1e: 00364 case 0x2e: 00365 case 0x25: /* Westmere */ 00366 case 0x2c: 00367 case 0x2f: 00368 case 0x2a: /* Sandy Bridge */ 00369 case 0x2d: 00370 case 0x3a: /* Ivy Bridge */ 00371 00372 /* AAJ122: LBR, BTM, or BTS records may have incorrect branch 00373 "from" information afer an EIST transition, T-states, C1E, or 00374 Adaptive Thermal Throttling. */ 00375 return 0; 00376 } 00377 } 00378 00379 return 1; 00380 } 00381 00382 /* Check whether the cpu supports branch tracing. */ 00383 00384 static int 00385 cpu_supports_btrace (void) 00386 { 00387 unsigned int ebx, ecx, edx; 00388 00389 if (!i386_cpuid (0, NULL, &ebx, &ecx, &edx)) 00390 return 0; 00391 00392 if (ebx == signature_INTEL_ebx && ecx == signature_INTEL_ecx 00393 && edx == signature_INTEL_edx) 00394 return intel_supports_btrace (); 00395 00396 /* Don't know about others. Let's assume they do. */ 00397 return 1; 00398 } 00399 00400 /* See linux-btrace.h. */ 00401 00402 int 00403 linux_supports_btrace (void) 00404 { 00405 static int cached; 00406 00407 if (cached == 0) 00408 { 00409 if (!kernel_supports_btrace ()) 00410 cached = -1; 00411 else if (!cpu_supports_btrace ()) 00412 cached = -1; 00413 else 00414 cached = 1; 00415 } 00416 00417 return cached > 0; 00418 } 00419 00420 /* See linux-btrace.h. */ 00421 00422 struct btrace_target_info * 00423 linux_enable_btrace (ptid_t ptid) 00424 { 00425 struct btrace_target_info *tinfo; 00426 int pid; 00427 00428 tinfo = xzalloc (sizeof (*tinfo)); 00429 tinfo->ptid = ptid; 00430 00431 tinfo->attr.size = sizeof (tinfo->attr); 00432 tinfo->attr.type = PERF_TYPE_HARDWARE; 00433 tinfo->attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; 00434 tinfo->attr.sample_period = 1; 00435 00436 /* We sample from and to address. */ 00437 tinfo->attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ADDR; 00438 00439 tinfo->attr.exclude_kernel = 1; 00440 tinfo->attr.exclude_hv = 1; 00441 tinfo->attr.exclude_idle = 1; 00442 00443 tinfo->ptr_bits = 0; 00444 00445 pid = ptid_get_lwp (ptid); 00446 if (pid == 0) 00447 pid = ptid_get_pid (ptid); 00448 00449 errno = 0; 00450 tinfo->file = syscall (SYS_perf_event_open, &tinfo->attr, pid, -1, -1, 0); 00451 if (tinfo->file < 0) 00452 goto err; 00453 00454 /* We hard-code the trace buffer size. 00455 At some later time, we should make this configurable. */ 00456 tinfo->size = 1; 00457 tinfo->buffer = mmap (NULL, perf_event_mmap_size (tinfo), 00458 PROT_READ, MAP_SHARED, tinfo->file, 0); 00459 if (tinfo->buffer == MAP_FAILED) 00460 goto err_file; 00461 00462 return tinfo; 00463 00464 err_file: 00465 close (tinfo->file); 00466 00467 err: 00468 xfree (tinfo); 00469 return NULL; 00470 } 00471 00472 /* See linux-btrace.h. */ 00473 00474 int 00475 linux_disable_btrace (struct btrace_target_info *tinfo) 00476 { 00477 int errcode; 00478 00479 errno = 0; 00480 errcode = munmap (tinfo->buffer, perf_event_mmap_size (tinfo)); 00481 if (errcode != 0) 00482 return errno; 00483 00484 close (tinfo->file); 00485 xfree (tinfo); 00486 00487 return 0; 00488 } 00489 00490 /* Check whether the branch trace has changed. */ 00491 00492 static int 00493 linux_btrace_has_changed (struct btrace_target_info *tinfo) 00494 { 00495 volatile struct perf_event_mmap_page *header = perf_event_header (tinfo); 00496 00497 return header->data_head != tinfo->data_head; 00498 } 00499 00500 /* See linux-btrace.h. */ 00501 00502 VEC (btrace_block_s) * 00503 linux_read_btrace (struct btrace_target_info *tinfo, 00504 enum btrace_read_type type) 00505 { 00506 VEC (btrace_block_s) *btrace = NULL; 00507 volatile struct perf_event_mmap_page *header; 00508 const uint8_t *begin, *end, *start; 00509 unsigned long data_head, retries = 5; 00510 size_t buffer_size; 00511 00512 if (type == btrace_read_new && !linux_btrace_has_changed (tinfo)) 00513 return NULL; 00514 00515 header = perf_event_header (tinfo); 00516 buffer_size = perf_event_buffer_size (tinfo); 00517 00518 /* We may need to retry reading the trace. See below. */ 00519 while (retries--) 00520 { 00521 data_head = header->data_head; 00522 00523 /* If there's new trace, let's read it. */ 00524 if (data_head != tinfo->data_head) 00525 { 00526 /* Data_head keeps growing; the buffer itself is circular. */ 00527 begin = perf_event_buffer_begin (tinfo); 00528 start = begin + data_head % buffer_size; 00529 00530 if (data_head <= buffer_size) 00531 end = start; 00532 else 00533 end = perf_event_buffer_end (tinfo); 00534 00535 btrace = perf_event_read_bts (tinfo, begin, end, start); 00536 } 00537 00538 /* The stopping thread notifies its ptracer before it is scheduled out. 00539 On multi-core systems, the debugger might therefore run while the 00540 kernel might be writing the last branch trace records. 00541 00542 Let's check whether the data head moved while we read the trace. */ 00543 if (data_head == header->data_head) 00544 break; 00545 } 00546 00547 tinfo->data_head = data_head; 00548 00549 return btrace; 00550 } 00551 00552 #else /* !HAVE_LINUX_PERF_EVENT_H */ 00553 00554 /* See linux-btrace.h. */ 00555 00556 int 00557 linux_supports_btrace (void) 00558 { 00559 return 0; 00560 } 00561 00562 /* See linux-btrace.h. */ 00563 00564 struct btrace_target_info * 00565 linux_enable_btrace (ptid_t ptid) 00566 { 00567 return NULL; 00568 } 00569 00570 /* See linux-btrace.h. */ 00571 00572 int 00573 linux_disable_btrace (struct btrace_target_info *tinfo) 00574 { 00575 return ENOSYS; 00576 } 00577 00578 /* See linux-btrace.h. */ 00579 00580 VEC (btrace_block_s) * 00581 linux_read_btrace (struct btrace_target_info *tinfo, 00582 enum btrace_read_type type) 00583 { 00584 return NULL; 00585 } 00586 00587 #endif /* !HAVE_LINUX_PERF_EVENT_H */