|
Packit Service |
d4effb |
/*
|
|
Packit Service |
d4effb |
* Extension module to dump log buffer of Intel(R) Processor Trace
|
|
Packit Service |
d4effb |
*
|
|
Packit Service |
d4effb |
* Copyright (C) 2016 FUJITSU LIMITED
|
|
Packit Service |
d4effb |
*
|
|
Packit Service |
d4effb |
* This program is free software; you can redistribute it and/or modify
|
|
Packit Service |
d4effb |
* it under the terms of the GNU General Public License as published by
|
|
Packit Service |
d4effb |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit Service |
d4effb |
* (at your option) any later version.
|
|
Packit Service |
d4effb |
*
|
|
Packit Service |
d4effb |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
d4effb |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
d4effb |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
d4effb |
* GNU General Public License for more details.
|
|
Packit Service |
d4effb |
*/
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
#define _GNU_SOURCE
|
|
Packit Service |
d4effb |
#include <sys/file.h>
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
#include "defs.h"
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
#ifdef DEBUG
|
|
Packit Service |
d4effb |
#define dbgprintf(...) fprintf(__VA_ARGS__)
|
|
Packit Service |
d4effb |
#else
|
|
Packit Service |
d4effb |
#define dbgprintf(...) {}
|
|
Packit Service |
d4effb |
#endif
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
#define TOPA_SHIFT 12
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
extern int fastdecode(char *, char *);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
typedef uint8_t u8;
|
|
Packit Service |
d4effb |
typedef uint16_t u16;
|
|
Packit Service |
d4effb |
typedef uint32_t u32;
|
|
Packit Service |
d4effb |
typedef uint64_t u64;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
struct topa_entry {
|
|
Packit Service |
d4effb |
u64 end : 1;
|
|
Packit Service |
d4effb |
u64 rsvd0 : 1;
|
|
Packit Service |
d4effb |
u64 intr : 1;
|
|
Packit Service |
d4effb |
u64 rsvd1 : 1;
|
|
Packit Service |
d4effb |
u64 stop : 1;
|
|
Packit Service |
d4effb |
u64 rsvd2 : 1;
|
|
Packit Service |
d4effb |
u64 size : 4;
|
|
Packit Service |
d4effb |
u64 rsvd3 : 2;
|
|
Packit Service |
d4effb |
u64 base : 36;
|
|
Packit Service |
d4effb |
u64 rsvd4 : 16;
|
|
Packit Service |
d4effb |
};
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
struct pt_info {
|
|
Packit Service |
d4effb |
ulong aux_pages;
|
|
Packit Service |
d4effb |
int aux_nr_pages;
|
|
Packit Service |
d4effb |
ulong pt_buffer;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
ulong topa_base;
|
|
Packit Service |
d4effb |
uint topa_idx;
|
|
Packit Service |
d4effb |
ulong output_off;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
ulong *buffer_ptr;
|
|
Packit Service |
d4effb |
int curr_buf_idx;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
ulong *pt_caps;
|
|
Packit Service |
d4effb |
u32 *cap_regs;
|
|
Packit Service |
d4effb |
} *pt_info_list;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
static inline int
|
|
Packit Service |
d4effb |
get_member(ulong addr, char *name, char *member, void* buf)
|
|
Packit Service |
d4effb |
{
|
|
Packit Service |
d4effb |
ulong offset, size;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
offset = MEMBER_OFFSET(name, member);
|
|
Packit Service |
d4effb |
size = MEMBER_SIZE(name, member);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (!readmem(addr + offset, KVADDR, buf, size, name, RETURN_ON_ERROR))
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
return TRUE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
int init_pt_info(int cpu)
|
|
Packit Service |
d4effb |
{
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
ulong struct_pt, struct_handle, struct_ring_buffer;
|
|
Packit Service |
d4effb |
ulong aux_pages, aux_priv;
|
|
Packit Service |
d4effb |
int aux_nr_pages, buf_len;
|
|
Packit Service |
d4effb |
int i, current_buf_idx;
|
|
Packit Service |
d4effb |
struct topa_entry topa;
|
|
Packit Service |
d4effb |
ulong topa_base, output_off, output_base;
|
|
Packit Service |
d4effb |
uint topa_idx;
|
|
Packit Service |
d4effb |
struct pt_info *pt_info_ptr = pt_info_list + cpu;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
/* Get pointer to struct pt */
|
|
Packit Service |
d4effb |
if (!symbol_exists("pt_ctx")) {
|
|
Packit Service |
d4effb |
fprintf(fp, "[%d] symbol not found: pt_ctx\n", cpu);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
struct_pt = symbol_value("pt_ctx") + kt->__per_cpu_offset[cpu];
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
/* Get pointer to struct perf_output_handle, struct ring_buffer */
|
|
Packit Service |
d4effb |
struct_handle = struct_pt + MEMBER_OFFSET("pt", "handle");
|
|
Packit Service |
d4effb |
if(!get_member(struct_handle, "perf_output_handle", "rb",
|
|
Packit Service |
d4effb |
&struct_ring_buffer))
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
if (!struct_ring_buffer) {
|
|
Packit Service |
d4effb |
fprintf(fp, "[%d] ring buffer is zero\n", cpu);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] struct pt=0x%016lx\n", cpu, struct_pt);
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] struct perf_output_handle=0x%016lx\n", cpu,
|
|
Packit Service |
d4effb |
struct_handle);
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] struct ring_buffer=0x%016lx\n", cpu,
|
|
Packit Service |
d4effb |
struct_ring_buffer);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
/* symbol access check */
|
|
Packit Service |
d4effb |
if (STRUCT_EXISTS("ring_buffer") &&
|
|
Packit Service |
d4effb |
!MEMBER_EXISTS("ring_buffer", "aux_pages")) {
|
|
Packit Service |
d4effb |
fprintf(fp, "[%d] invalid ring_buffer\n", cpu);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
/* array of struct pages for pt buffer */
|
|
Packit Service |
d4effb |
if(!get_member(struct_ring_buffer, "ring_buffer", "aux_pages",
|
|
Packit Service |
d4effb |
&aux_pages))
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
/* number of pages */
|
|
Packit Service |
d4effb |
if(!get_member(struct_ring_buffer, "ring_buffer", "aux_nr_pages",
|
|
Packit Service |
d4effb |
&aux_nr_pages))
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
/* private data (struct pt_buffer) */
|
|
Packit Service |
d4effb |
if(!get_member(struct_ring_buffer, "ring_buffer", "aux_priv",
|
|
Packit Service |
d4effb |
&aux_priv))
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (!aux_nr_pages) {
|
|
Packit Service |
d4effb |
fprintf(fp, "No aux pages\n");
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
pt_info_ptr->aux_pages = aux_pages;
|
|
Packit Service |
d4effb |
pt_info_ptr->aux_nr_pages = aux_nr_pages;
|
|
Packit Service |
d4effb |
pt_info_ptr->pt_buffer = aux_priv;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] rb.aux_pages=0x%016lx\n", cpu, aux_pages);
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] rb.aux_nr_pages=0x%d\n", cpu, aux_nr_pages);
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] rb.aux_priv=0x%016lx\n", cpu, aux_priv);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
/* Get address of pt buffer */
|
|
Packit Service |
d4effb |
buf_len = sizeof(void*)*aux_nr_pages;
|
|
Packit Service |
d4effb |
pt_info_ptr->buffer_ptr = (ulong *)malloc(buf_len);
|
|
Packit Service |
d4effb |
if (pt_info_ptr->buffer_ptr == NULL) {
|
|
Packit Service |
d4effb |
fprintf(fp, "malloc failed\n");
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
memset(pt_info_ptr->buffer_ptr, 0, buf_len);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
for (i=0; i
|
|
Packit Service |
d4effb |
ulong pgaddr = aux_pages + i*sizeof(void*);
|
|
Packit Service |
d4effb |
ulong page;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (!readmem(pgaddr, KVADDR, &page, sizeof(ulong),
|
|
Packit Service |
d4effb |
"struct page", RETURN_ON_ERROR))
|
|
Packit Service |
d4effb |
continue;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
pt_info_ptr->buffer_ptr[i] = page;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (!i)
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] Dump aux pages\n", cpu);
|
|
Packit Service |
d4effb |
dbgprintf(fp, " %d: 0x%016lx\n", i, page);
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
/* Get pt registes saved on panic */
|
|
Packit Service |
d4effb |
if(!get_member(pt_info_ptr->pt_buffer, "pt_buffer", "cur",
|
|
Packit Service |
d4effb |
&topa_base))
|
|
Packit Service |
d4effb |
goto out_error;
|
|
Packit Service |
d4effb |
if(!get_member(pt_info_ptr->pt_buffer, "pt_buffer", "cur_idx",
|
|
Packit Service |
d4effb |
&topa_idx))
|
|
Packit Service |
d4effb |
goto out_error;
|
|
Packit Service |
d4effb |
if(!get_member(pt_info_ptr->pt_buffer, "pt_buffer", "output_off",
|
|
Packit Service |
d4effb |
&output_off))
|
|
Packit Service |
d4effb |
goto out_error;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] buf.cur=0x%016lx\n", cpu, topa_base);
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] buf.cur_idx=0x%08x\n", cpu, topa_idx);
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] buf.output_off=0x%016lx\n", cpu, output_off);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
pt_info_ptr->topa_base = topa_base;
|
|
Packit Service |
d4effb |
pt_info_ptr->topa_idx = topa_idx;
|
|
Packit Service |
d4effb |
pt_info_ptr->output_off = output_off;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
/* Read topa entry */
|
|
Packit Service |
d4effb |
if (!readmem((topa_base) + topa_idx*(sizeof(struct topa_entry)),
|
|
Packit Service |
d4effb |
KVADDR, &topa, sizeof(topa),
|
|
Packit Service |
d4effb |
"struct topa_entry", RETURN_ON_ERROR)) {
|
|
Packit Service |
d4effb |
fprintf(fp, "Cannot read topa table\n");
|
|
Packit Service |
d4effb |
goto out_error;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] topa.end=%d\n", cpu, topa.end);
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] topa.intr=%d\n", cpu, topa.intr);
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] topa.stop=%d\n", cpu, topa.stop);
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] topa.size=%d\n", cpu, topa.size);
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] topa.base=0x%016lx\n", cpu, (ulong)topa.base);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
/*
|
|
Packit Service |
d4effb |
* Find buffer page which is currently used.
|
|
Packit Service |
d4effb |
*/
|
|
Packit Service |
d4effb |
output_base = (u64)(topa.base)<
|
|
Packit Service |
d4effb |
current_buf_idx = -1;
|
|
Packit Service |
d4effb |
for (i=0; i
|
|
Packit Service |
d4effb |
if (VTOP(pt_info_ptr->buffer_ptr[i]) == output_base) {
|
|
Packit Service |
d4effb |
current_buf_idx = i;
|
|
Packit Service |
d4effb |
break;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (current_buf_idx == -1) {
|
|
Packit Service |
d4effb |
fprintf(fp, "current buffer not found\n");
|
|
Packit Service |
d4effb |
goto out_error;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
pt_info_ptr->curr_buf_idx = current_buf_idx;
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] current bufidx=%d\n", cpu, current_buf_idx);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
return TRUE;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
out_error:
|
|
Packit Service |
d4effb |
if (pt_info_ptr->buffer_ptr != NULL)
|
|
Packit Service |
d4effb |
free(pt_info_ptr->buffer_ptr);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
static inline int is_zero_page(ulong page, int offset)
|
|
Packit Service |
d4effb |
{
|
|
Packit Service |
d4effb |
ulong read_addr = page + offset;
|
|
Packit Service |
d4effb |
ulong read_size = PAGESIZE() - offset;
|
|
Packit Service |
d4effb |
char *buf = malloc(PAGESIZE());
|
|
Packit Service |
d4effb |
int i;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (buf == NULL) {
|
|
Packit Service |
d4effb |
fprintf(fp, "malloc failed\n");
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
memset(buf, 0, PAGESIZE());
|
|
Packit Service |
d4effb |
dbgprintf(fp, "zero page chk: 0x%016lx, %lu\n", read_addr, read_size);
|
|
Packit Service |
d4effb |
if (!readmem(read_addr, KVADDR, buf, read_size, "zero page check",
|
|
Packit Service |
d4effb |
RETURN_ON_ERROR)) {
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
for (i = 0; i < PAGESIZE() - offset; i++) {
|
|
Packit Service |
d4effb |
if (buf[i]) {
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return TRUE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
int check_wrap_around(int cpu)
|
|
Packit Service |
d4effb |
{
|
|
Packit Service |
d4effb |
struct pt_info *pt_info_ptr = pt_info_list + cpu;
|
|
Packit Service |
d4effb |
int wrapped = 0, i, page_idx;
|
|
Packit Service |
d4effb |
ulong offset, mask, page;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
mask = (((ulong)1)<
|
|
Packit Service |
d4effb |
offset = pt_info_ptr->output_off & mask;
|
|
Packit Service |
d4effb |
page_idx = pt_info_ptr->curr_buf_idx +
|
|
Packit Service |
d4effb |
(pt_info_ptr->output_off >> PAGESHIFT());
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] buf: mask=0x%lx\n", cpu, mask);
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] buf: offset=0x%lx\n", cpu, offset);
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] buf: page_idx=%d\n", cpu, page_idx);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
for (i=page_idx; i<pt_info_ptr->aux_nr_pages; i++) {
|
|
Packit Service |
d4effb |
page = pt_info_ptr->buffer_ptr[i];
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (!is_zero_page(page, offset)) {
|
|
Packit Service |
d4effb |
wrapped = 1;
|
|
Packit Service |
d4effb |
break;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
offset = 0;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
return wrapped;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
int write_buffer_wrapped(int cpu, FILE *out_fp)
|
|
Packit Service |
d4effb |
{
|
|
Packit Service |
d4effb |
struct pt_info *pt_info_ptr = pt_info_list + cpu;
|
|
Packit Service |
d4effb |
int start_idx, idx, len, ret;
|
|
Packit Service |
d4effb |
ulong mask, offset, page;
|
|
Packit Service |
d4effb |
char *buf = malloc(PAGESIZE());
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (buf == NULL) {
|
|
Packit Service |
d4effb |
fprintf(fp, "malloc failed\n");
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
mask = (((ulong)1)<
|
|
Packit Service |
d4effb |
offset = pt_info_ptr->output_off & mask;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
start_idx = pt_info_ptr->curr_buf_idx +
|
|
Packit Service |
d4effb |
(pt_info_ptr->output_off >> PAGESHIFT());
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
for (idx = start_idx; idx<pt_info_ptr->aux_nr_pages; idx++) {
|
|
Packit Service |
d4effb |
page = pt_info_ptr->buffer_ptr[idx];
|
|
Packit Service |
d4effb |
len = PAGESIZE() - offset;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (!readmem(page + offset, KVADDR, buf, len, "read page for write",
|
|
Packit Service |
d4effb |
RETURN_ON_ERROR)) {
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] R/W1 buff: p=0x%lx, i=%d, o=%lu, l=%d\n",
|
|
Packit Service |
d4effb |
cpu, page + offset, idx, offset, len);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
ret = fwrite(buf, len, 1, out_fp);
|
|
Packit Service |
d4effb |
if (!ret) {
|
|
Packit Service |
d4effb |
fprintf(fp, "[%d] Cannot write file\n", cpu);
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
offset = 0;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
for (idx = 0; idx < start_idx; idx++) {
|
|
Packit Service |
d4effb |
page = pt_info_ptr->buffer_ptr[idx];
|
|
Packit Service |
d4effb |
len = PAGESIZE() - offset;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (!readmem(page + offset, KVADDR, buf, len, "read page for write",
|
|
Packit Service |
d4effb |
RETURN_ON_ERROR)) {
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] R/W2 buff: p=0x%lx, i=%d, o=%lu, l=%d\n",
|
|
Packit Service |
d4effb |
cpu, page + offset, idx, offset, len);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
ret = fwrite(buf, len, 1, out_fp);
|
|
Packit Service |
d4effb |
if (!ret) {
|
|
Packit Service |
d4effb |
fprintf(fp, "[%d] Cannot write file\n", cpu);
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
idx = start_idx;
|
|
Packit Service |
d4effb |
page = pt_info_ptr->buffer_ptr[idx];
|
|
Packit Service |
d4effb |
offset = pt_info_ptr->output_off & mask;
|
|
Packit Service |
d4effb |
len = offset;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (!len)
|
|
Packit Service |
d4effb |
goto done;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (!readmem(page, KVADDR, buf, len, "read page for write",
|
|
Packit Service |
d4effb |
RETURN_ON_ERROR)) {
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] R/W3 buff: p=0x%lx, i=%d, o=%lu, l=%d\n", cpu,
|
|
Packit Service |
d4effb |
page, idx, offset, len);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
ret = fwrite(buf, len, 1, out_fp);
|
|
Packit Service |
d4effb |
if (!ret) {
|
|
Packit Service |
d4effb |
fprintf(fp, "[%d] Cannot write file\n", cpu);
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
done:
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return TRUE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
int write_buffer_nowrapped(int cpu, FILE *out_fp)
|
|
Packit Service |
d4effb |
{
|
|
Packit Service |
d4effb |
struct pt_info *pt_info_ptr = pt_info_list + cpu;
|
|
Packit Service |
d4effb |
int last_idx, idx, len, ret;
|
|
Packit Service |
d4effb |
ulong mask, page;
|
|
Packit Service |
d4effb |
char *buf = malloc(PAGESIZE());
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (buf == NULL) {
|
|
Packit Service |
d4effb |
fprintf(fp, "malloc failed\n");
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
mask = (((ulong)1)<
|
|
Packit Service |
d4effb |
last_idx = pt_info_ptr->curr_buf_idx +
|
|
Packit Service |
d4effb |
(pt_info_ptr->output_off >> PAGESHIFT());
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
for (idx = 0; idx < last_idx; idx++) {
|
|
Packit Service |
d4effb |
page = pt_info_ptr->buffer_ptr[idx];
|
|
Packit Service |
d4effb |
len = PAGESIZE();
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (!readmem(page, KVADDR, buf, len, "read page for write",
|
|
Packit Service |
d4effb |
RETURN_ON_ERROR)) {
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] R/W1 buff: p=0x%lx, i=%d, o=%lu, l=%d\n",
|
|
Packit Service |
d4effb |
cpu, page, idx, (ulong)0, len);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
ret = fwrite(buf, len, 1, out_fp);
|
|
Packit Service |
d4effb |
if (!ret) {
|
|
Packit Service |
d4effb |
fprintf(fp, "[%d] Cannot write file\n", cpu);
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
idx = last_idx;
|
|
Packit Service |
d4effb |
page = pt_info_ptr->buffer_ptr[idx];
|
|
Packit Service |
d4effb |
len = pt_info_ptr->output_off & mask;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (!len)
|
|
Packit Service |
d4effb |
goto done;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (!readmem(page, KVADDR, buf, len, "read page for write",
|
|
Packit Service |
d4effb |
RETURN_ON_ERROR)) {
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] R/W2 buff: p=0x%lx, i=%d, o=%lu, l=%d\n", cpu,
|
|
Packit Service |
d4effb |
page, idx, (ulong)0, len);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
ret = fwrite(buf, len, 1, out_fp);
|
|
Packit Service |
d4effb |
if (!ret) {
|
|
Packit Service |
d4effb |
fprintf(fp, "[%d] Cannot write file\n", cpu);
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
done:
|
|
Packit Service |
d4effb |
free(buf);
|
|
Packit Service |
d4effb |
return TRUE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
int write_pt_log_buffer_cpu(int cpu, char *fname)
|
|
Packit Service |
d4effb |
{
|
|
Packit Service |
d4effb |
int wrapped, ret;
|
|
Packit Service |
d4effb |
FILE *out_fp;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
wrapped = check_wrap_around(cpu);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if ((out_fp = fopen(fname, "w")) == NULL) {
|
|
Packit Service |
d4effb |
fprintf(fp, "[%d] Cannot open file: %s\n", cpu, fname);
|
|
Packit Service |
d4effb |
return FALSE;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] Open file: %s\n", cpu, fname);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
/*
|
|
Packit Service |
d4effb |
* Write buffer to file
|
|
Packit Service |
d4effb |
*
|
|
Packit Service |
d4effb |
* Case 1: Not wrapped around
|
|
Packit Service |
d4effb |
*
|
|
Packit Service |
d4effb |
* start end
|
|
Packit Service |
d4effb |
* | |
|
|
Packit Service |
d4effb |
* v v
|
|
Packit Service |
d4effb |
* +------+ +------+ +------+ +------+
|
|
Packit Service |
d4effb |
* |buffer| |buffer| ... |buffer| |buffer|
|
|
Packit Service |
d4effb |
* +------+ +------+ +------+ +------+
|
|
Packit Service |
d4effb |
*
|
|
Packit Service |
d4effb |
* In this case, just write data between 'start' and 'end'
|
|
Packit Service |
d4effb |
*
|
|
Packit Service |
d4effb |
* Case 2: Wrapped around
|
|
Packit Service |
d4effb |
*
|
|
Packit Service |
d4effb |
* end start
|
|
Packit Service |
d4effb |
* | |
|
|
Packit Service |
d4effb |
* v v
|
|
Packit Service |
d4effb |
* +------+ +------+ +------+ +------+
|
|
Packit Service |
d4effb |
* |buffer| |buffer| ... |buffer| |buffer|
|
|
Packit Service |
d4effb |
* +------+ +------+ +------+ +------+
|
|
Packit Service |
d4effb |
*
|
|
Packit Service |
d4effb |
* In this case, at first write data between 'start' and end of last
|
|
Packit Service |
d4effb |
* buffer, and then write data between beginning of first buffer and
|
|
Packit Service |
d4effb |
* 'end'.
|
|
Packit Service |
d4effb |
*/
|
|
Packit Service |
d4effb |
if (wrapped) {
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] wrap around: true\n", cpu);
|
|
Packit Service |
d4effb |
ret = write_buffer_wrapped(cpu, out_fp);
|
|
Packit Service |
d4effb |
} else {
|
|
Packit Service |
d4effb |
dbgprintf(fp, "[%d] wrap around: false\n", cpu);
|
|
Packit Service |
d4effb |
ret = write_buffer_nowrapped(cpu, out_fp);
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
fclose(out_fp);
|
|
Packit Service |
d4effb |
return ret;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
void
|
|
Packit Service |
d4effb |
cmd_ptdump(void)
|
|
Packit Service |
d4effb |
{
|
|
Packit Service |
d4effb |
int i, ret, list_len;
|
|
Packit Service |
d4effb |
int online_cpus;
|
|
Packit Service |
d4effb |
char* outdir;
|
|
Packit Service |
d4effb |
char dumpfile[16];
|
|
Packit Service |
d4effb |
char decodefile[16];
|
|
Packit Service |
d4effb |
mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR |
|
|
Packit Service |
d4effb |
S_IRGRP | S_IXGRP |
|
|
Packit Service |
d4effb |
S_IROTH | S_IXOTH; /* 0755 */
|
|
Packit Service |
d4effb |
struct pt_info *pt_info_ptr;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (argcnt != 2)
|
|
Packit Service |
d4effb |
cmd_usage(pc->curcmd, SYNOPSIS);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (ACTIVE())
|
|
Packit Service |
d4effb |
error(FATAL, "not supported on a live system\n");
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
outdir = args[1];
|
|
Packit Service |
d4effb |
if ((ret = mkdir(outdir, mode))) {
|
|
Packit Service |
d4effb |
fprintf(fp, "Cannot create directory %s: %d\n", outdir, ret);
|
|
Packit Service |
d4effb |
return;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if ((ret = chdir(outdir))) {
|
|
Packit Service |
d4effb |
fprintf(fp, "Cannot chdir %s: %d\n", outdir, ret);
|
|
Packit Service |
d4effb |
return;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
/*
|
|
Packit Service |
d4effb |
* Set the gdb scope to ensure that the appropriate ring_buffer
|
|
Packit Service |
d4effb |
* structure is selected.
|
|
Packit Service |
d4effb |
*/
|
|
Packit Service |
d4effb |
if (kernel_symbol_exists("perf_mmap_to_page"))
|
|
Packit Service |
d4effb |
gdb_set_crash_scope(symbol_value("perf_mmap_to_page"),
|
|
Packit Service |
d4effb |
"perf_mmap_to_page");
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
online_cpus = get_cpus_online();
|
|
Packit Service |
d4effb |
list_len = sizeof(struct pt_info)*kt->cpus;
|
|
Packit Service |
d4effb |
pt_info_list = malloc(list_len);
|
|
Packit Service |
d4effb |
if (pt_info_list == NULL) {
|
|
Packit Service |
d4effb |
fprintf(fp, "Cannot alloc pt_info_list\n");
|
|
Packit Service |
d4effb |
return;
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
memset(pt_info_list, 0, list_len);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
for (i = 0; online_cpus > 0; i++) {
|
|
Packit Service |
d4effb |
if (!in_cpu_map(ONLINE_MAP, i))
|
|
Packit Service |
d4effb |
continue;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
online_cpus--;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
if (!init_pt_info(i))
|
|
Packit Service |
d4effb |
continue;
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
sprintf(dumpfile, "dump.%d", i);
|
|
Packit Service |
d4effb |
if (write_pt_log_buffer_cpu(i, dumpfile))
|
|
Packit Service |
d4effb |
fprintf(fp, "[%d] buffer dump: %s\n", i, dumpfile);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
sprintf(decodefile, "decode.%d", i);
|
|
Packit Service |
d4effb |
if (fastdecode(dumpfile, decodefile))
|
|
Packit Service |
d4effb |
fprintf(fp, "[%d] packet decode: %s\n", i, decodefile);
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
pt_info_ptr = pt_info_list + i;
|
|
Packit Service |
d4effb |
if (pt_info_ptr->buffer_ptr != NULL)
|
|
Packit Service |
d4effb |
free(pt_info_ptr->buffer_ptr);
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
free(pt_info_list);
|
|
Packit Service |
d4effb |
chdir("..");
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
char *help_ptdump[] = {
|
|
Packit Service |
d4effb |
"ptdump",
|
|
Packit Service |
d4effb |
"Dump log buffer of Intel(R) Processor Trace",
|
|
Packit Service |
d4effb |
"<output-dir>",
|
|
Packit Service |
d4effb |
"This command extracts log buffer of PT to the directory",
|
|
Packit Service |
d4effb |
"specified by <output-dir>",
|
|
Packit Service |
d4effb |
NULL
|
|
Packit Service |
d4effb |
};
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
static struct command_table_entry command_table[] = {
|
|
Packit Service |
d4effb |
{ "ptdump", cmd_ptdump, help_ptdump, 0},
|
|
Packit Service |
d4effb |
{ NULL },
|
|
Packit Service |
d4effb |
};
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
void __attribute__((constructor))
|
|
Packit Service |
d4effb |
ptdump_init(void)
|
|
Packit Service |
d4effb |
{
|
|
Packit Service |
d4effb |
register_extension(command_table);
|
|
Packit Service |
d4effb |
}
|
|
Packit Service |
d4effb |
|
|
Packit Service |
d4effb |
void __attribute__((destructor))
|
|
Packit Service |
d4effb |
ptdump_fini(void) { }
|
|
Packit Service |
d4effb |
|