Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 288731
b: refs/heads/master
c: 114382a
h: refs/heads/master
i:
  288729: 7a5f88f
  288727: ddd211b
v: v3
  • Loading branch information
Stephane Eranian authored and Ingo Molnar committed Mar 9, 2012
1 parent 015ae38 commit f5c68d4
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 29 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 62db90681c0db8c76e5db006b929a2edd5d12ae6
refs/heads/master: 114382a0aea97974803c942f106d462cbca5c64d
122 changes: 94 additions & 28 deletions trunk/tools/perf/util/header.c
Original file line number Diff line number Diff line change
Expand Up @@ -1803,35 +1803,101 @@ int perf_header__process_sections(struct perf_header *header, int fd,
return err;
}

static int check_magic_endian(u64 *magic, struct perf_file_header *header,
struct perf_header *ph)
static const int attr_file_abi_sizes[] = {
[0] = PERF_ATTR_SIZE_VER0,
[1] = PERF_ATTR_SIZE_VER1,
0,
};

/*
* In the legacy file format, the magic number is not used to encode endianness.
* hdr_sz was used to encode endianness. But given that hdr_sz can vary based
* on ABI revisions, we need to try all combinations for all endianness to
* detect the endianness.
*/
static int try_all_file_abis(uint64_t hdr_sz, struct perf_header *ph)
{
int ret;
uint64_t ref_size, attr_size;
int i;

/* check for legacy format */
ret = memcmp(magic, __perf_magic1, sizeof(*magic));
if (ret == 0) {
pr_debug("legacy perf.data format\n");
if (!header)
return -1;
for (i = 0 ; attr_file_abi_sizes[i]; i++) {
ref_size = attr_file_abi_sizes[i]
+ sizeof(struct perf_file_section);
if (hdr_sz != ref_size) {
attr_size = bswap_64(hdr_sz);
if (attr_size != ref_size)
continue;

if (header->attr_size != sizeof(struct perf_file_attr)) {
u64 attr_size = bswap_64(header->attr_size);
ph->needs_swap = true;
}
pr_debug("ABI%d perf.data file detected, need_swap=%d\n",
i,
ph->needs_swap);
return 0;
}
/* could not determine endianness */
return -1;
}

if (attr_size != sizeof(struct perf_file_attr))
return -1;
#define PERF_PIPE_HDR_VER0 16

static const size_t attr_pipe_abi_sizes[] = {
[0] = PERF_PIPE_HDR_VER0,
0,
};

/*
* In the legacy pipe format, there is an implicit assumption that endiannesss
* between host recording the samples, and host parsing the samples is the
* same. This is not always the case given that the pipe output may always be
* redirected into a file and analyzed on a different machine with possibly a
* different endianness and perf_event ABI revsions in the perf tool itself.
*/
static int try_all_pipe_abis(uint64_t hdr_sz, struct perf_header *ph)
{
u64 attr_size;
int i;

for (i = 0 ; attr_pipe_abi_sizes[i]; i++) {
if (hdr_sz != attr_pipe_abi_sizes[i]) {
attr_size = bswap_64(hdr_sz);
if (attr_size != hdr_sz)
continue;

ph->needs_swap = true;
}
pr_debug("Pipe ABI%d perf.data file detected\n", i);
return 0;
}
return -1;
}

static int check_magic_endian(u64 magic, uint64_t hdr_sz,
bool is_pipe, struct perf_header *ph)
{
int ret;

/* check for legacy format */
ret = memcmp(&magic, __perf_magic1, sizeof(magic));
if (ret == 0) {
pr_debug("legacy perf.data format\n");
if (is_pipe)
return try_all_pipe_abis(hdr_sz, ph);

return try_all_file_abis(hdr_sz, ph);
}
/*
* the new magic number serves two purposes:
* - unique number to identify actual perf.data files
* - encode endianness of file
*/

/* check magic number with same endianness */
if (*magic == __perf_magic2)
/* check magic number with one endianness */
if (magic == __perf_magic2)
return 0;

/* check magic number but opposite endianness */
if (*magic != __perf_magic2_sw)
/* check magic number with opposite endianness */
if (magic != __perf_magic2_sw)
return -1;

ph->needs_swap = true;
Expand All @@ -1850,8 +1916,11 @@ int perf_file_header__read(struct perf_file_header *header,
if (ret <= 0)
return -1;

if (check_magic_endian(&header->magic, header, ph) < 0)
if (check_magic_endian(header->magic,
header->attr_size, false, ph) < 0) {
pr_debug("magic/endian check failed\n");
return -1;
}

if (ph->needs_swap) {
mem_bswap_64(header, offsetof(struct perf_file_header,
Expand Down Expand Up @@ -1938,21 +2007,17 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
if (ret <= 0)
return -1;

if (check_magic_endian(&header->magic, NULL, ph) < 0)
if (check_magic_endian(header->magic, header->size, true, ph) < 0) {
pr_debug("endian/magic failed\n");
return -1;
}

if (ph->needs_swap)
header->size = bswap_64(header->size);

if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0)
return -1;

if (header->size != sizeof(*header)) {
u64 size = bswap_64(header->size);

if (size != sizeof(*header))
return -1;

ph->needs_swap = true;
}

return 0;
}

Expand Down Expand Up @@ -1992,6 +2057,7 @@ static int read_attr(int fd, struct perf_header *ph,

/* on file perf_event_attr size */
sz = attr->size;

if (ph->needs_swap)
sz = bswap_32(sz);

Expand Down

0 comments on commit f5c68d4

Please sign in to comment.