aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/util/symbol-elf.c252
-rw-r--r--tools/perf/util/symbol.h22
2 files changed, 274 insertions, 0 deletions
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index b222552c7159..6f15b92cbf70 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1789,6 +1789,258 @@ void kcore_extract__delete(struct kcore_extract *kce)
1789 unlink(kce->extract_filename); 1789 unlink(kce->extract_filename);
1790} 1790}
1791 1791
1792/**
1793 * populate_sdt_note : Parse raw data and identify SDT note
1794 * @elf: elf of the opened file
1795 * @data: raw data of a section with description offset applied
1796 * @len: note description size
1797 * @type: type of the note
1798 * @sdt_notes: List to add the SDT note
1799 *
1800 * Responsible for parsing the @data in section .note.stapsdt in @elf and
1801 * if its an SDT note, it appends to @sdt_notes list.
1802 */
1803static int populate_sdt_note(Elf **elf, const char *data, size_t len,
1804 struct list_head *sdt_notes)
1805{
1806 const char *provider, *name;
1807 struct sdt_note *tmp = NULL;
1808 GElf_Ehdr ehdr;
1809 GElf_Addr base_off = 0;
1810 GElf_Shdr shdr;
1811 int ret = -EINVAL;
1812
1813 union {
1814 Elf64_Addr a64[NR_ADDR];
1815 Elf32_Addr a32[NR_ADDR];
1816 } buf;
1817
1818 Elf_Data dst = {
1819 .d_buf = &buf, .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
1820 .d_size = gelf_fsize((*elf), ELF_T_ADDR, NR_ADDR, EV_CURRENT),
1821 .d_off = 0, .d_align = 0
1822 };
1823 Elf_Data src = {
1824 .d_buf = (void *) data, .d_type = ELF_T_ADDR,
1825 .d_version = EV_CURRENT, .d_size = dst.d_size, .d_off = 0,
1826 .d_align = 0
1827 };
1828
1829 tmp = (struct sdt_note *)calloc(1, sizeof(struct sdt_note));
1830 if (!tmp) {
1831 ret = -ENOMEM;
1832 goto out_err;
1833 }
1834
1835 INIT_LIST_HEAD(&tmp->note_list);
1836
1837 if (len < dst.d_size + 3)
1838 goto out_free_note;
1839
1840 /* Translation from file representation to memory representation */
1841 if (gelf_xlatetom(*elf, &dst, &src,
1842 elf_getident(*elf, NULL)[EI_DATA]) == NULL) {
1843 pr_err("gelf_xlatetom : %s\n", elf_errmsg(-1));
1844 goto out_free_note;
1845 }
1846
1847 /* Populate the fields of sdt_note */
1848 provider = data + dst.d_size;
1849
1850 name = (const char *)memchr(provider, '\0', data + len - provider);
1851 if (name++ == NULL)
1852 goto out_free_note;
1853
1854 tmp->provider = strdup(provider);
1855 if (!tmp->provider) {
1856 ret = -ENOMEM;
1857 goto out_free_note;
1858 }
1859 tmp->name = strdup(name);
1860 if (!tmp->name) {
1861 ret = -ENOMEM;
1862 goto out_free_prov;
1863 }
1864
1865 if (gelf_getclass(*elf) == ELFCLASS32) {
1866 memcpy(&tmp->addr, &buf, 3 * sizeof(Elf32_Addr));
1867 tmp->bit32 = true;
1868 } else {
1869 memcpy(&tmp->addr, &buf, 3 * sizeof(Elf64_Addr));
1870 tmp->bit32 = false;
1871 }
1872
1873 if (!gelf_getehdr(*elf, &ehdr)) {
1874 pr_debug("%s : cannot get elf header.\n", __func__);
1875 ret = -EBADF;
1876 goto out_free_name;
1877 }
1878
1879 /* Adjust the prelink effect :
1880 * Find out the .stapsdt.base section.
1881 * This scn will help us to handle prelinking (if present).
1882 * Compare the retrieved file offset of the base section with the
1883 * base address in the description of the SDT note. If its different,
1884 * then accordingly, adjust the note location.
1885 */
1886 if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) {
1887 base_off = shdr.sh_offset;
1888 if (base_off) {
1889 if (tmp->bit32)
1890 tmp->addr.a32[0] = tmp->addr.a32[0] + base_off -
1891 tmp->addr.a32[1];
1892 else
1893 tmp->addr.a64[0] = tmp->addr.a64[0] + base_off -
1894 tmp->addr.a64[1];
1895 }
1896 }
1897
1898 list_add_tail(&tmp->note_list, sdt_notes);
1899 return 0;
1900
1901out_free_name:
1902 free(tmp->name);
1903out_free_prov:
1904 free(tmp->provider);
1905out_free_note:
1906 free(tmp);
1907out_err:
1908 return ret;
1909}
1910
1911/**
1912 * construct_sdt_notes_list : constructs a list of SDT notes
1913 * @elf : elf to look into
1914 * @sdt_notes : empty list_head
1915 *
1916 * Scans the sections in 'elf' for the section
1917 * .note.stapsdt. It, then calls populate_sdt_note to find
1918 * out the SDT events and populates the 'sdt_notes'.
1919 */
1920static int construct_sdt_notes_list(Elf *elf, struct list_head *sdt_notes)
1921{
1922 GElf_Ehdr ehdr;
1923 Elf_Scn *scn = NULL;
1924 Elf_Data *data;
1925 GElf_Shdr shdr;
1926 size_t shstrndx, next;
1927 GElf_Nhdr nhdr;
1928 size_t name_off, desc_off, offset;
1929 int ret = 0;
1930
1931 if (gelf_getehdr(elf, &ehdr) == NULL) {
1932 ret = -EBADF;
1933 goto out_ret;
1934 }
1935 if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
1936 ret = -EBADF;
1937 goto out_ret;
1938 }
1939
1940 /* Look for the required section */
1941 scn = elf_section_by_name(elf, &ehdr, &shdr, SDT_NOTE_SCN, NULL);
1942 if (!scn) {
1943 ret = -ENOENT;
1944 goto out_ret;
1945 }
1946
1947 if ((shdr.sh_type != SHT_NOTE) || (shdr.sh_flags & SHF_ALLOC)) {
1948 ret = -ENOENT;
1949 goto out_ret;
1950 }
1951
1952 data = elf_getdata(scn, NULL);
1953
1954 /* Get the SDT notes */
1955 for (offset = 0; (next = gelf_getnote(data, offset, &nhdr, &name_off,
1956 &desc_off)) > 0; offset = next) {
1957 if (nhdr.n_namesz == sizeof(SDT_NOTE_NAME) &&
1958 !memcmp(data->d_buf + name_off, SDT_NOTE_NAME,
1959 sizeof(SDT_NOTE_NAME))) {
1960 /* Check the type of the note */
1961 if (nhdr.n_type != SDT_NOTE_TYPE)
1962 goto out_ret;
1963
1964 ret = populate_sdt_note(&elf, ((data->d_buf) + desc_off),
1965 nhdr.n_descsz, sdt_notes);
1966 if (ret < 0)
1967 goto out_ret;
1968 }
1969 }
1970 if (list_empty(sdt_notes))
1971 ret = -ENOENT;
1972
1973out_ret:
1974 return ret;
1975}
1976
1977/**
1978 * get_sdt_note_list : Wrapper to construct a list of sdt notes
1979 * @head : empty list_head
1980 * @target : file to find SDT notes from
1981 *
1982 * This opens the file, initializes
1983 * the ELF and then calls construct_sdt_notes_list.
1984 */
1985int get_sdt_note_list(struct list_head *head, const char *target)
1986{
1987 Elf *elf;
1988 int fd, ret;
1989
1990 fd = open(target, O_RDONLY);
1991 if (fd < 0)
1992 return -EBADF;
1993
1994 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1995 if (!elf) {
1996 ret = -EBADF;
1997 goto out_close;
1998 }
1999 ret = construct_sdt_notes_list(elf, head);
2000 elf_end(elf);
2001out_close:
2002 close(fd);
2003 return ret;
2004}
2005
2006/**
2007 * cleanup_sdt_note_list : free the sdt notes' list
2008 * @sdt_notes: sdt notes' list
2009 *
2010 * Free up the SDT notes in @sdt_notes.
2011 * Returns the number of SDT notes free'd.
2012 */
2013int cleanup_sdt_note_list(struct list_head *sdt_notes)
2014{
2015 struct sdt_note *tmp, *pos;
2016 int nr_free = 0;
2017
2018 list_for_each_entry_safe(pos, tmp, sdt_notes, note_list) {
2019 list_del(&pos->note_list);
2020 free(pos->name);
2021 free(pos->provider);
2022 free(pos);
2023 nr_free++;
2024 }
2025 return nr_free;
2026}
2027
2028/**
2029 * sdt_notes__get_count: Counts the number of sdt events
2030 * @start: list_head to sdt_notes list
2031 *
2032 * Returns the number of SDT notes in a list
2033 */
2034int sdt_notes__get_count(struct list_head *start)
2035{
2036 struct sdt_note *sdt_ptr;
2037 int count = 0;
2038
2039 list_for_each_entry(sdt_ptr, start, note_list)
2040 count++;
2041 return count;
2042}
2043
1792void symbol__elf_init(void) 2044void symbol__elf_init(void)
1793{ 2045{
1794 elf_version(EV_CURRENT); 2046 elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index b10d558a8803..699f7cbcfe72 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -342,4 +342,26 @@ void arch__sym_update(struct symbol *s, GElf_Sym *sym);
342 342
343int arch__choose_best_symbol(struct symbol *syma, struct symbol *symb); 343int arch__choose_best_symbol(struct symbol *syma, struct symbol *symb);
344 344
345/* structure containing an SDT note's info */
346struct sdt_note {
347 char *name; /* name of the note*/
348 char *provider; /* provider name */
349 bool bit32; /* whether the location is 32 bits? */
350 union { /* location, base and semaphore addrs */
351 Elf64_Addr a64[3];
352 Elf32_Addr a32[3];
353 } addr;
354 struct list_head note_list; /* SDT notes' list */
355};
356
357int get_sdt_note_list(struct list_head *head, const char *target);
358int cleanup_sdt_note_list(struct list_head *sdt_notes);
359int sdt_notes__get_count(struct list_head *start);
360
361#define SDT_BASE_SCN ".stapsdt.base"
362#define SDT_NOTE_SCN ".note.stapsdt"
363#define SDT_NOTE_TYPE 3
364#define SDT_NOTE_NAME "stapsdt"
365#define NR_ADDR 3
366
345#endif /* __PERF_SYMBOL */ 367#endif /* __PERF_SYMBOL */