diff options
| -rw-r--r-- | tools/perf/util/header.c | 122 |
1 files changed, 94 insertions, 28 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 6d580267d043..c851495b9b48 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -1803,35 +1803,101 @@ out_free: | |||
| 1803 | return err; | 1803 | return err; |
| 1804 | } | 1804 | } |
| 1805 | 1805 | ||
| 1806 | static int check_magic_endian(u64 *magic, struct perf_file_header *header, | 1806 | static const int attr_file_abi_sizes[] = { |
| 1807 | struct perf_header *ph) | 1807 | [0] = PERF_ATTR_SIZE_VER0, |
| 1808 | [1] = PERF_ATTR_SIZE_VER1, | ||
| 1809 | 0, | ||
| 1810 | }; | ||
| 1811 | |||
| 1812 | /* | ||
| 1813 | * In the legacy file format, the magic number is not used to encode endianness. | ||
| 1814 | * hdr_sz was used to encode endianness. But given that hdr_sz can vary based | ||
| 1815 | * on ABI revisions, we need to try all combinations for all endianness to | ||
| 1816 | * detect the endianness. | ||
| 1817 | */ | ||
| 1818 | static int try_all_file_abis(uint64_t hdr_sz, struct perf_header *ph) | ||
| 1808 | { | 1819 | { |
| 1809 | int ret; | 1820 | uint64_t ref_size, attr_size; |
| 1821 | int i; | ||
| 1810 | 1822 | ||
| 1811 | /* check for legacy format */ | 1823 | for (i = 0 ; attr_file_abi_sizes[i]; i++) { |
| 1812 | ret = memcmp(magic, __perf_magic1, sizeof(*magic)); | 1824 | ref_size = attr_file_abi_sizes[i] |
| 1813 | if (ret == 0) { | 1825 | + sizeof(struct perf_file_section); |
| 1814 | pr_debug("legacy perf.data format\n"); | 1826 | if (hdr_sz != ref_size) { |
| 1815 | if (!header) | 1827 | attr_size = bswap_64(hdr_sz); |
| 1816 | return -1; | 1828 | if (attr_size != ref_size) |
| 1829 | continue; | ||
| 1817 | 1830 | ||
| 1818 | if (header->attr_size != sizeof(struct perf_file_attr)) { | 1831 | ph->needs_swap = true; |
| 1819 | u64 attr_size = bswap_64(header->attr_size); | 1832 | } |
| 1833 | pr_debug("ABI%d perf.data file detected, need_swap=%d\n", | ||
| 1834 | i, | ||
| 1835 | ph->needs_swap); | ||
| 1836 | return 0; | ||
| 1837 | } | ||
| 1838 | /* could not determine endianness */ | ||
| 1839 | return -1; | ||
| 1840 | } | ||
| 1820 | 1841 | ||
| 1821 | if (attr_size != sizeof(struct perf_file_attr)) | 1842 | #define PERF_PIPE_HDR_VER0 16 |
| 1822 | return -1; | 1843 | |
| 1844 | static const size_t attr_pipe_abi_sizes[] = { | ||
| 1845 | [0] = PERF_PIPE_HDR_VER0, | ||
| 1846 | 0, | ||
| 1847 | }; | ||
| 1848 | |||
| 1849 | /* | ||
| 1850 | * In the legacy pipe format, there is an implicit assumption that endiannesss | ||
| 1851 | * between host recording the samples, and host parsing the samples is the | ||
| 1852 | * same. This is not always the case given that the pipe output may always be | ||
| 1853 | * redirected into a file and analyzed on a different machine with possibly a | ||
| 1854 | * different endianness and perf_event ABI revsions in the perf tool itself. | ||
| 1855 | */ | ||
| 1856 | static int try_all_pipe_abis(uint64_t hdr_sz, struct perf_header *ph) | ||
| 1857 | { | ||
| 1858 | u64 attr_size; | ||
| 1859 | int i; | ||
| 1860 | |||
| 1861 | for (i = 0 ; attr_pipe_abi_sizes[i]; i++) { | ||
| 1862 | if (hdr_sz != attr_pipe_abi_sizes[i]) { | ||
| 1863 | attr_size = bswap_64(hdr_sz); | ||
| 1864 | if (attr_size != hdr_sz) | ||
| 1865 | continue; | ||
| 1823 | 1866 | ||
| 1824 | ph->needs_swap = true; | 1867 | ph->needs_swap = true; |
| 1825 | } | 1868 | } |
| 1869 | pr_debug("Pipe ABI%d perf.data file detected\n", i); | ||
| 1826 | return 0; | 1870 | return 0; |
| 1827 | } | 1871 | } |
| 1872 | return -1; | ||
| 1873 | } | ||
| 1874 | |||
| 1875 | static int check_magic_endian(u64 magic, uint64_t hdr_sz, | ||
| 1876 | bool is_pipe, struct perf_header *ph) | ||
| 1877 | { | ||
| 1878 | int ret; | ||
| 1879 | |||
| 1880 | /* check for legacy format */ | ||
| 1881 | ret = memcmp(&magic, __perf_magic1, sizeof(magic)); | ||
| 1882 | if (ret == 0) { | ||
| 1883 | pr_debug("legacy perf.data format\n"); | ||
| 1884 | if (is_pipe) | ||
| 1885 | return try_all_pipe_abis(hdr_sz, ph); | ||
| 1886 | |||
| 1887 | return try_all_file_abis(hdr_sz, ph); | ||
| 1888 | } | ||
| 1889 | /* | ||
| 1890 | * the new magic number serves two purposes: | ||
| 1891 | * - unique number to identify actual perf.data files | ||
| 1892 | * - encode endianness of file | ||
| 1893 | */ | ||
| 1828 | 1894 | ||
| 1829 | /* check magic number with same endianness */ | 1895 | /* check magic number with one endianness */ |
| 1830 | if (*magic == __perf_magic2) | 1896 | if (magic == __perf_magic2) |
| 1831 | return 0; | 1897 | return 0; |
| 1832 | 1898 | ||
| 1833 | /* check magic number but opposite endianness */ | 1899 | /* check magic number with opposite endianness */ |
| 1834 | if (*magic != __perf_magic2_sw) | 1900 | if (magic != __perf_magic2_sw) |
| 1835 | return -1; | 1901 | return -1; |
| 1836 | 1902 | ||
| 1837 | ph->needs_swap = true; | 1903 | ph->needs_swap = true; |
| @@ -1850,8 +1916,11 @@ int perf_file_header__read(struct perf_file_header *header, | |||
| 1850 | if (ret <= 0) | 1916 | if (ret <= 0) |
| 1851 | return -1; | 1917 | return -1; |
| 1852 | 1918 | ||
| 1853 | if (check_magic_endian(&header->magic, header, ph) < 0) | 1919 | if (check_magic_endian(header->magic, |
| 1920 | header->attr_size, false, ph) < 0) { | ||
| 1921 | pr_debug("magic/endian check failed\n"); | ||
| 1854 | return -1; | 1922 | return -1; |
| 1923 | } | ||
| 1855 | 1924 | ||
| 1856 | if (ph->needs_swap) { | 1925 | if (ph->needs_swap) { |
| 1857 | mem_bswap_64(header, offsetof(struct perf_file_header, | 1926 | mem_bswap_64(header, offsetof(struct perf_file_header, |
| @@ -1938,21 +2007,17 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, | |||
| 1938 | if (ret <= 0) | 2007 | if (ret <= 0) |
| 1939 | return -1; | 2008 | return -1; |
| 1940 | 2009 | ||
| 1941 | if (check_magic_endian(&header->magic, NULL, ph) < 0) | 2010 | if (check_magic_endian(header->magic, header->size, true, ph) < 0) { |
| 2011 | pr_debug("endian/magic failed\n"); | ||
| 1942 | return -1; | 2012 | return -1; |
| 2013 | } | ||
| 2014 | |||
| 2015 | if (ph->needs_swap) | ||
| 2016 | header->size = bswap_64(header->size); | ||
| 1943 | 2017 | ||
| 1944 | if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0) | 2018 | if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0) |
| 1945 | return -1; | 2019 | return -1; |
| 1946 | 2020 | ||
| 1947 | if (header->size != sizeof(*header)) { | ||
| 1948 | u64 size = bswap_64(header->size); | ||
| 1949 | |||
| 1950 | if (size != sizeof(*header)) | ||
| 1951 | return -1; | ||
| 1952 | |||
| 1953 | ph->needs_swap = true; | ||
| 1954 | } | ||
| 1955 | |||
| 1956 | return 0; | 2021 | return 0; |
| 1957 | } | 2022 | } |
| 1958 | 2023 | ||
| @@ -1992,6 +2057,7 @@ static int read_attr(int fd, struct perf_header *ph, | |||
| 1992 | 2057 | ||
| 1993 | /* on file perf_event_attr size */ | 2058 | /* on file perf_event_attr size */ |
| 1994 | sz = attr->size; | 2059 | sz = attr->size; |
| 2060 | |||
| 1995 | if (ph->needs_swap) | 2061 | if (ph->needs_swap) |
| 1996 | sz = bswap_32(sz); | 2062 | sz = bswap_32(sz); |
| 1997 | 2063 | ||
