31 #include <sys/syscall.h> 33 #if HAVE_LINUX_PERF_EVENT_H && defined(SYS_perf_event_open) 38 #include <sys/types.h> 52 struct perf_event_sample
55 struct perf_event_header header;
58 struct perf_event_bts bts;
63 btrace_this_cpu (void)
66 unsigned int eax, ebx, ecx, edx;
69 memset (&cpu, 0,
sizeof (cpu));
71 ok =
x86_cpuid (0, &eax, &ebx, &ecx, &edx);
77 unsigned int cpuid,
ignore;
84 cpu.family = (cpuid >> 8) & 0xf;
85 cpu.model = (cpuid >> 4) & 0xf;
87 if (cpu.family == 0x6)
88 cpu.model += (cpuid >> 12) & 0xf0;
99 perf_event_new_data (
const struct perf_event_buffer *pev)
101 return *pev->data_head != pev->last_head;
109 perf_event_read (
const struct perf_event_buffer *pev, __u64 data_head,
112 const gdb_byte *begin, *end, *start, *stop;
121 buffer_size = pev->size;
132 if (data_head <
size)
133 data_head += buffer_size;
136 data_tail = data_head -
size;
139 start = begin + data_tail % buffer_size;
140 stop = begin + data_head % buffer_size;
145 memcpy (
buffer, start, stop - start);
148 end = begin + buffer_size;
150 memcpy (
buffer, start, end - start);
151 memcpy (
buffer + (end - start), begin, stop - begin);
161 perf_event_read_all (
struct perf_event_buffer *pev,
gdb_byte **data,
167 data_head = *pev->data_head;
170 *data = perf_event_read (pev, data_head,
size);
173 pev->last_head = data_head;
180 perf_event_pt_event_type (
int *
type)
185 file = fopen (
"/sys/bus/event_source/devices/intel_pt/type",
"r");
189 found = fscanf (file,
"%d",
type);
201 linux_determine_kernel_start (
void)
203 static uint64_t kernel_start;
215 while (!feof (file.get ()))
225 match = sscanf (line,
"%" SCNx64
" %*[tT] %7s", &addr,
symbol);
229 if (strcmp (
symbol,
"_text") == 0)
242 perf_event_is_kernel_addr (uint64_t addr)
244 uint64_t kernel_start;
246 kernel_start = linux_determine_kernel_start ();
247 if (kernel_start != 0ull)
248 return (addr >= kernel_start);
252 return ((addr & (1ull << 63)) != 0);
258 perf_event_skip_bts_record (
const struct perf_event_bts *bts)
263 return perf_event_is_kernel_addr (bts->from);
270 perf_event_sample_ok (
const struct perf_event_sample *sample)
272 if (sample->header.type != PERF_RECORD_SAMPLE)
275 if (sample->header.size != sizeof (*sample))
296 const uint8_t *end,
const uint8_t *start,
size_t size)
299 struct perf_event_sample sample;
313 read =
sizeof (sample) - 1;
317 const struct perf_event_sample *psample;
320 start -=
sizeof (sample);
324 psample = (
const struct perf_event_sample *) start;
332 missing = (begin - start);
333 start = (end - missing);
336 if (missing ==
sizeof (sample))
337 psample = (
const struct perf_event_sample *) start;
344 stack = (uint8_t *) &sample;
347 memcpy (stack, start, missing);
348 memcpy (stack + missing, begin,
sizeof (sample) - missing);
354 if (!perf_event_sample_ok (psample))
356 warning (
_(
"Branch trace may be incomplete."));
360 if (perf_event_skip_bts_record (&psample->bts))
364 block.begin = psample->bts.to;
369 block.end = psample->bts.from;
385 kernel_supports_bts (
void)
387 struct perf_event_attr attr;
403 warning (
_(
"test bts: cannot PTRACE_TRACEME: %s."),
411 warning (
_(
"test bts: cannot raise SIGTRAP: %s."),
422 warning (
_(
"test bts: bad pid %ld, error: %s."),
429 warning (
_(
"test bts: expected stop. status: %d."),
434 memset (&attr, 0,
sizeof (attr));
436 attr.type = PERF_TYPE_HARDWARE;
437 attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
438 attr.sample_period = 1;
439 attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ADDR;
440 attr.exclude_kernel = 1;
442 attr.exclude_idle = 1;
444 file =
syscall (SYS_perf_event_open, &attr, child, -1, -1, 0);
448 kill (child, SIGKILL);
449 ptrace (PTRACE_KILL, child, NULL, NULL);
454 warning (
_(
"test bts: bad pid %ld, error: %s."),
457 warning (
_(
"test bts: expected killed. status: %d."),
468 kernel_supports_pt (
void)
470 struct perf_event_attr attr;
486 warning (
_(
"test pt: cannot PTRACE_TRACEME: %s."),
494 warning (
_(
"test pt: cannot raise SIGTRAP: %s."),
505 warning (
_(
"test pt: bad pid %ld, error: %s."),
512 warning (
_(
"test pt: expected stop. status: %d."),
522 memset (&attr, 0,
sizeof (attr));
524 attr.size =
sizeof (attr);
526 attr.exclude_kernel = 1;
528 attr.exclude_idle = 1;
530 file =
syscall (SYS_perf_event_open, &attr, child, -1, -1, 0);
535 kill (child, SIGKILL);
536 ptrace (PTRACE_KILL, child, NULL, NULL);
541 warning (
_(
"test pt: bad pid %ld, error: %s."),
544 warning (
_(
"test pt: expected killed. status: %d."),
555 intel_supports_bts (
const struct btrace_cpu *cpu)
586 cpu_supports_bts (
void)
590 cpu = btrace_this_cpu ();
598 return intel_supports_bts (&cpu);
605 linux_supports_bts (
void)
611 if (!kernel_supports_bts ())
613 else if (!cpu_supports_bts ())
625 linux_supports_pt (
void)
631 if (!kernel_supports_pt ())
651 return linux_supports_bts ();
654 return linux_supports_pt ();
665 struct perf_event_mmap_page *header;
667 struct btrace_tinfo_bts *bts;
676 bts = &tinfo->variant.bts;
678 bts->attr.size =
sizeof (bts->attr);
679 bts->attr.type = PERF_TYPE_HARDWARE;
680 bts->attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
681 bts->attr.sample_period = 1;
684 bts->attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ADDR;
686 bts->attr.exclude_kernel = 1;
687 bts->attr.exclude_hv = 1;
688 bts->attr.exclude_idle = 1;
695 bts->file =
syscall (SYS_perf_event_open, &bts->attr,
pid, -1, -1, 0);
700 pages = ((size_t) conf->
size / PAGE_SIZE
701 + ((conf->
size % PAGE_SIZE) == 0 ? 0 : 1));
708 for (pg = 0; pages != ((size_t) 1 << pg); ++pg)
709 if ((pages & ((
size_t) 1 << pg)) != 0)
710 pages += ((
size_t) 1 << pg);
714 for (; pages > 0; pages >>= 1)
719 data_size = (__u64) pages * PAGE_SIZE;
725 size = (size_t) data_size;
726 length =
size + PAGE_SIZE;
729 if ((__u64) length != data_size + PAGE_SIZE)
733 header = ((
struct perf_event_mmap_page *)
734 mmap (NULL, length, PROT_READ, MAP_SHARED, bts->file, 0));
742 data_offset = PAGE_SIZE;
744 #if defined (PERF_ATTR_SIZE_VER5) 745 if (offsetof (
struct perf_event_mmap_page, data_size) <= header->size)
749 data_offset = header->data_offset;
750 data_size = header->data_size;
752 size = (
unsigned int) data_size;
755 if ((__u64)
size != data_size)
757 munmap ((
void *) header,
size + PAGE_SIZE);
763 bts->header = header;
764 bts->bts.mem = ((
const uint8_t *) header) + data_offset;
765 bts->bts.size =
size;
766 bts->bts.data_head = &header->data_head;
767 bts->bts.last_head = 0ull;
781 #if defined (PERF_ATTR_SIZE_VER5) 788 struct perf_event_mmap_page *header;
790 struct btrace_tinfo_pt *pt;
797 errcode = perf_event_pt_event_type (&
type);
809 pt = &tinfo->variant.pt;
811 pt->attr.size =
sizeof (pt->attr);
812 pt->attr.type =
type;
814 pt->attr.exclude_kernel = 1;
815 pt->attr.exclude_hv = 1;
816 pt->attr.exclude_idle = 1;
819 pt->file =
syscall (SYS_perf_event_open, &pt->attr,
pid, -1, -1, 0);
824 header = ((
struct perf_event_mmap_page *)
825 mmap (NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
830 header->aux_offset = header->data_offset + header->data_size;
833 pages = ((size_t) conf->
size / PAGE_SIZE
834 + ((conf->
size % PAGE_SIZE) == 0 ? 0 : 1));
841 for (pg = 0; pages != ((size_t) 1 << pg); ++pg)
842 if ((pages & ((
size_t) 1 << pg)) != 0)
843 pages += ((
size_t) 1 << pg);
847 for (; pages > 0; pages >>= 1)
852 data_size = (__u64) pages * PAGE_SIZE;
858 size = (size_t) data_size;
861 if ((__u64)
size != data_size)
864 header->aux_size = data_size;
867 pt->pt.mem = ((
const uint8_t *)
868 mmap (NULL, length, PROT_READ, MAP_SHARED, pt->file,
869 header->aux_offset));
879 pt->pt.data_head = &header->aux_head;
885 munmap((
void *) header, PAGE_SIZE);
934 linux_disable_bts (
struct btrace_tinfo_bts *tinfo)
936 munmap((
void *) tinfo->header, tinfo->bts.size + PAGE_SIZE);
945 linux_disable_pt (
struct btrace_tinfo_pt *tinfo)
947 munmap((
void *) tinfo->pt.mem, tinfo->pt.size);
948 munmap((
void *) tinfo->header, PAGE_SIZE);
968 errcode = linux_disable_bts (&tinfo->variant.bts);
972 errcode = linux_disable_pt (&tinfo->variant.pt);
990 struct perf_event_buffer *pevent;
991 const uint8_t *begin, *end, *start;
992 size_t buffer_size,
size;
993 __u64 data_head, data_tail;
994 unsigned int retries = 5;
996 pevent = &tinfo->variant.bts.bts;
1003 buffer_size = pevent->size;
1004 data_tail = pevent->last_head;
1009 data_head = *pevent->data_head;
1024 if (data_head < data_tail)
1028 data_size = data_head - data_tail;
1029 if (buffer_size < data_size)
1033 size = (size_t) data_size;
1041 if (data_head <
size)
1042 size = (size_t) data_head;
1046 begin = pevent->mem;
1047 start = begin + data_head % buffer_size;
1049 if (data_head <= buffer_size)
1052 end = begin + pevent->size;
1054 btrace->blocks = perf_event_read_bts (tinfo, begin, end, start,
size);
1061 if (data_head == *pevent->data_head)
1065 pevent->last_head = data_head;
1082 conf->
cpu = btrace_this_cpu ();
1093 struct perf_event_buffer *pt;
1095 pt = &tinfo->variant.pt.pt;
1097 linux_fill_btrace_pt_config (&btrace->
config);
1107 if (!perf_event_new_data (pt))
1112 perf_event_read_all (pt, &btrace->
data, &btrace->
size);
1147 internal_error (__FILE__, __LINE__,
_(
"Unkown branch trace format."));
1155 return &tinfo->
conf;
mach_port_t mach_port_t name mach_port_t mach_port_t name kern_return_t err
struct regcache * get_thread_regcache_for_ptid(ptid_t ptid)
union btrace_data::@24 variant
ssize_t read(int fd, void *buf, size_t count)
struct btrace_config_bts bts
static __inline int x86_cpuid(unsigned int __level, unsigned int *__eax, unsigned int *__ebx, unsigned int *__ecx, unsigned int *__edx)
int ptid_get_pid(const ptid_t &ptid)
mach_port_t mach_port_t name mach_port_t mach_port_t name kern_return_t int int rusage_t pid_t pid
void warning(const char *fmt,...)
regcache(gdbarch *gdbarch)
struct btrace_data_bts bts
#define signature_INTEL_ecx
void * memset(T *s, int c, size_t n)=delete
void internal_error(const char *file, int line, const char *fmt,...)
#define VEC_safe_push(T, V, O)
enum btrace_error linux_read_btrace(struct btrace_data *btrace, struct btrace_target_info *tinfo, enum btrace_read_type type)
int linux_supports_btrace(struct target_ops *ops, enum btrace_format format)
std::unique_ptr< FILE, gdb_file_deleter > gdb_file_up
enum btrace_format format
const struct btrace_config * linux_btrace_conf(const struct btrace_target_info *tinfo)
gdb_file_up gdb_fopen_cloexec(const char *filename, const char *opentype)
mach_port_t mach_port_t name mach_port_t mach_port_t name kern_return_t int status
struct btrace_config conf
long ptid_get_lwp(const ptid_t &ptid)
struct btrace_config_pt pt
enum btrace_error linux_disable_btrace(struct btrace_target_info *tinfo)
CORE_ADDR regcache_read_pc(struct regcache *regcache)
struct btrace_data_pt_config config
char * safe_strerror(int)
#define signature_INTEL_edx
static int ignore(struct target_ops *ops, struct gdbarch *gdbarch, struct bp_target_info *bp_tgt)
struct btrace_target_info * linux_enable_btrace(ptid_t ptid, const struct btrace_config *conf)
enum btrace_format format
#define signature_INTEL_ebx