summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2021-03-15 05:44:24 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2021-03-15 05:44:24 +0000
commitb718c5930b8816b54f57e6333b3b90fda0051b2c (patch)
treef471d8d4d37db874eaec90688c1180eb6a7d959e
parentReleasing progress-linux version 1.19-1~progress5+u1. (diff)
downloaddwarves-dfsg-b718c5930b8816b54f57e6333b3b90fda0051b2c.tar.xz
dwarves-dfsg-b718c5930b8816b54f57e6333b3b90fda0051b2c.zip
Merging upstream version 1.20.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--.gitignore2
-rw-r--r--.gitmodules3
-rw-r--r--CMakeLists.txt6
-rw-r--r--MANIFEST1
-rw-r--r--NEWS30
-rw-r--r--README.cross7
-rw-r--r--btf_encoder.c278
-rw-r--r--changes-v1.2066
-rwxr-xr-xctfdwdiff57
-rw-r--r--dtagnames.c9
-rw-r--r--dutil.c18
-rw-r--r--dutil.h2
-rw-r--r--dwarf_loader.c118
-rw-r--r--dwarves.c10
-rw-r--r--dwarves.h2
-rw-r--r--elf_symtab.c41
-rw-r--r--elf_symtab.h29
-rw-r--r--libbtf.c26
-rw-r--r--libbtf.h1
-rw-r--r--pahole.c2
-rw-r--r--rpm/SPECS/dwarves.spec28
21 files changed, 537 insertions, 199 deletions
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 96e05c7..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/build
-/config.h
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 6be99dc..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "lib/bpf"]
- path = lib/bpf
- url = https://github.com/libbpf/libbpf
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 857487a..7f72c7a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
project(pahole C)
-cmake_minimum_required(VERSION 2.8.8)
+cmake_minimum_required(VERSION 2.8.12)
cmake_policy(SET CMP0005 NEW)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}
@@ -33,9 +33,9 @@ set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -ggdb -O0")
set(CMAKE_C_FLAGS_RELEASE "-Wall -O2")
# Just for grepping, DWARVES_VERSION isn't used anywhere anymore
-# add_definitions(-D_GNU_SOURCE -DDWARVES_VERSION="v1.19")
+# add_definitions(-D_GNU_SOURCE -DDWARVES_VERSION="v1.20")
add_definitions(-D_GNU_SOURCE -DDWARVES_MAJOR_VERSION=1)
-add_definitions(-D_GNU_SOURCE -DDWARVES_MINOR_VERSION=19)
+add_definitions(-D_GNU_SOURCE -DDWARVES_MINOR_VERSION=20)
find_package(DWARF REQUIRED)
find_package(ZLIB REQUIRED)
diff --git a/MANIFEST b/MANIFEST
index 57a721a..c964ec5 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -50,6 +50,7 @@ changes-v1.16
changes-v1.17
changes-v1.18
changes-v1.19
+changes-v1.20
COPYING
NEWS
README
diff --git a/NEWS b/NEWS
index 9de30d8..a6796ee 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,33 @@
+v1.20:
+
+Tue Feb 2 2021
+
+8d6f06f053a06829 (HEAD -> master, seventh/master, quaco/master, origin/master, origin/HEAD) dwarf_loader: Add conditional DW_FORM_implicit_const definition for older systems
+66d12e4790b7c5e5 dtagnames: Stop using the deprecated mallinfo() function
+1279e439b622aeb5 cmake: Bump minimum required version to 2.8.12 as per upstream support warning
+b1eaf0da6d1f72b2 dwarves: Make enum prefix search more robust
+d783117162c0212d dwarf_loader: Handle DWARF5 DW_TAG_call_site like DW_TAG_GNU_call_site
+3ff98a6396e91d0a dwarf_loader: Support DW_FORM_implicit_const in __attr_offset()
+b91b19840b0062b8 dwarf_loader: Support DW_AT_data_bit_offset
+c692e8ac5ccbab99 dwarf_loader: Optimize a bit the reading of DW_AT_data_member_location
+65917b24942ce620 dwarf_loader: Fix typo
+77205a119c85e396 dwarf_loader: Introduce __attr_offset() to reuse call to dwarf_attr()
+8ec231f6b0c8aaef dwarf_loader: Support DW_FORM_implicit_const in attr_numeric()
+7453895e01edb535 btf_encoder: Improve ELF error reporting
+1bb49897dd2b65b0 bpf_encoder: Translate SHN_XINDEX in symbol's st_shndx values
+3f8aad340bf1a188 elf_symtab: Handle SHN_XINDEX index in elf_section_by_name()
+e32b9800e650a6eb btf_encoder: Add extra checks for symbol names
+82749180b23d3c9c libbpf: allow to use packaged version
+452dbcf35f1a7bf9 btf_encoder: Improve error-handling around objcopy
+cf381f9a3822d68b btf_encoder: Fix handling of restrict qualifier
+b688e35970600c15 btf_encoder: fix skipping per-CPU variables at offset 0
+8c009d6ce762dfc9 btf_encoder: fix BTF variable generation for kernel modules
+b94e97e015a94e6b dwarves: Fix compilation on 32-bit architectures
+17df51c700248f02 btf_encoder: Detect kernel module ftrace addresses
+06ca639505fc56c6 btf_encoder: Use address size based on ELF's class
+aff60970d16b909e btf_encoder: Factor filter_functions function
+1e6a3fed6e52d365 rpm: Fix changelog date
+
v1.19:
Fri Nov 20 2020
diff --git a/README.cross b/README.cross
deleted file mode 100644
index 1faa0e9..0000000
--- a/README.cross
+++ /dev/null
@@ -1,7 +0,0 @@
-CC=s390x-linux-gnu-gcc \
- cmake -DDWARF_INCLUDE_DIR=/usr/s390x-linux-gnu/include/ \
- -DLIBDW_INCLUDE_DIR=/usr/s390x-linux-gnu/include/ \
- -DDWARF_LIBRARY=/usr/s390x-linux-gnu/lib/libdw.so.1 \
- -DELF_LIBRARY=/usr/s390x-linux-gnu/lib/libelf.so.1 \
- -DZLIB_LIBRARY=/usr/s390x-linux-gnu/lib/libz.so.1 \
- -DZLIB_INCLUDE_DIR=/usr/s390x-linux-gnu/include/ ..
diff --git a/btf_encoder.c b/btf_encoder.c
index c40f059..b124ec2 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -36,6 +36,7 @@ struct funcs_layout {
struct elf_function {
const char *name;
unsigned long addr;
+ unsigned long sh_addr;
bool generated;
};
@@ -62,13 +63,18 @@ static void delete_functions(void)
#define max(x, y) ((x) < (y) ? (y) : (x))
#endif
-static int collect_function(struct btf_elf *btfe, GElf_Sym *sym)
+static int collect_function(struct btf_elf *btfe, GElf_Sym *sym,
+ size_t sym_sec_idx)
{
struct elf_function *new;
+ static GElf_Shdr sh;
+ static size_t last_idx;
+ const char *name;
if (elf_sym__type(sym) != STT_FUNC)
return 0;
- if (!elf_sym__value(sym))
+ name = elf_sym__name(sym, btfe->symtab);
+ if (!name)
return 0;
if (functions_cnt == functions_alloc) {
@@ -84,8 +90,15 @@ static int collect_function(struct btf_elf *btfe, GElf_Sym *sym)
functions = new;
}
- functions[functions_cnt].name = elf_sym__name(sym, btfe->symtab);
+ if (sym_sec_idx != last_idx) {
+ if (!elf_section_by_idx(btfe->elf, &sh, sym_sec_idx))
+ return 0;
+ last_idx = sym_sec_idx;
+ }
+
+ functions[functions_cnt].name = name;
functions[functions_cnt].addr = elf_sym__value(sym);
+ functions[functions_cnt].sh_addr = sh.sh_addr;
functions[functions_cnt].generated = false;
functions_cnt++;
return 0;
@@ -93,22 +106,30 @@ static int collect_function(struct btf_elf *btfe, GElf_Sym *sym)
static int addrs_cmp(const void *_a, const void *_b)
{
- const unsigned long *a = _a;
- const unsigned long *b = _b;
+ const __u64 *a = _a;
+ const __u64 *b = _b;
if (*a == *b)
return 0;
return *a < *b ? -1 : 1;
}
-static int filter_functions(struct btf_elf *btfe, struct funcs_layout *fl)
+static int get_vmlinux_addrs(struct btf_elf *btfe, struct funcs_layout *fl,
+ __u64 **paddrs, __u64 *pcount)
{
- unsigned long *addrs, count, offset, i;
- int functions_valid = 0;
+ __u64 *addrs, count, offset;
+ unsigned int addr_size, i;
Elf_Data *data;
GElf_Shdr shdr;
Elf_Scn *sec;
+ /* Initialize for the sake of all error paths below. */
+ *paddrs = NULL;
+ *pcount = 0;
+
+ if (!fl->mcount_start || !fl->mcount_stop)
+ return 0;
+
/*
* Find mcount addressed marked by __start_mcount_loc
* and __stop_mcount_loc symbols and load them into
@@ -121,8 +142,11 @@ static int filter_functions(struct btf_elf *btfe, struct funcs_layout *fl)
return -1;
}
+ /* Get address size from processed file's ELF class. */
+ addr_size = gelf_getclass(btfe->elf) == ELFCLASS32 ? 4 : 8;
+
offset = fl->mcount_start - shdr.sh_addr;
- count = (fl->mcount_stop - fl->mcount_start) / 8;
+ count = (fl->mcount_stop - fl->mcount_start) / addr_size;
data = elf_getdata(sec, 0);
if (!data) {
@@ -137,8 +161,113 @@ static int filter_functions(struct btf_elf *btfe, struct funcs_layout *fl)
return -1;
}
- memcpy(addrs, data->d_buf + offset, count * sizeof(addrs[0]));
+ if (addr_size == sizeof(__u64)) {
+ memcpy(addrs, data->d_buf + offset, count * addr_size);
+ } else {
+ for (i = 0; i < count; i++)
+ addrs[i] = (__u64) *((__u32 *) (data->d_buf + offset + i * addr_size));
+ }
+
+ *paddrs = addrs;
+ *pcount = count;
+ return 0;
+}
+
+static int
+get_kmod_addrs(struct btf_elf *btfe, __u64 **paddrs, __u64 *pcount)
+{
+ __u64 *addrs, count;
+ unsigned int addr_size, i;
+ GElf_Shdr shdr_mcount;
+ Elf_Data *data;
+ Elf_Scn *sec;
+
+ /* Initialize for the sake of all error paths below. */
+ *paddrs = NULL;
+ *pcount = 0;
+
+ /* get __mcount_loc */
+ sec = elf_section_by_name(btfe->elf, &btfe->ehdr, &shdr_mcount,
+ "__mcount_loc", NULL);
+ if (!sec) {
+ if (btf_elf__verbose) {
+ printf("%s: '%s' doesn't have __mcount_loc section\n", __func__,
+ btfe->filename);
+ }
+ return 0;
+ }
+
+ data = elf_getdata(sec, NULL);
+ if (!data) {
+ fprintf(stderr, "Failed to data for __mcount_loc section.\n");
+ return -1;
+ }
+
+ /* Get address size from processed file's ELF class. */
+ addr_size = gelf_getclass(btfe->elf) == ELFCLASS32 ? 4 : 8;
+
+ count = data->d_size / addr_size;
+
+ addrs = malloc(count * sizeof(addrs[0]));
+ if (!addrs) {
+ fprintf(stderr, "Failed to allocate memory for ftrace addresses.\n");
+ return -1;
+ }
+
+ if (addr_size == sizeof(__u64)) {
+ memcpy(addrs, data->d_buf, count * addr_size);
+ } else {
+ for (i = 0; i < count; i++)
+ addrs[i] = (__u64) *((__u32 *) (data->d_buf + i * addr_size));
+ }
+
+ /*
+ * We get Elf object from dwfl_module_getelf function,
+ * which performs all possible relocations, including
+ * __mcount_loc section.
+ *
+ * So addrs array now contains relocated values, which
+ * we need take into account when we compare them to
+ * functions values, see comment in setup_functions
+ * function.
+ */
+ *paddrs = addrs;
+ *pcount = count;
+ return 0;
+}
+
+static int setup_functions(struct btf_elf *btfe, struct funcs_layout *fl)
+{
+ __u64 *addrs, count, i;
+ int functions_valid = 0;
+ bool kmod = false;
+
+ /*
+ * Check if we are processing vmlinux image and
+ * get mcount data if it's detected.
+ */
+ if (get_vmlinux_addrs(btfe, fl, &addrs, &count))
+ return -1;
+
+ /*
+ * Check if we are processing kernel module and
+ * get mcount data if it's detected.
+ */
+ if (!addrs) {
+ if (get_kmod_addrs(btfe, &addrs, &count))
+ return -1;
+ kmod = true;
+ }
+
+ if (!addrs) {
+ if (btf_elf__verbose)
+ printf("ftrace symbols not detected, falling back to DWARF data\n");
+ delete_functions();
+ return 0;
+ }
+
qsort(addrs, count, sizeof(addrs[0]), addrs_cmp);
+ qsort(functions, functions_cnt, sizeof(functions[0]), functions_cmp);
/*
* Let's got through all collected functions and filter
@@ -146,9 +275,18 @@ static int filter_functions(struct btf_elf *btfe, struct funcs_layout *fl)
*/
for (i = 0; i < functions_cnt; i++) {
struct elf_function *func = &functions[i];
+ /*
+ * For vmlinux image both addrs[x] and functions[x]::addr
+ * values are final address and are comparable.
+ *
+ * For kernel module addrs[x] is final address, but
+ * functions[x]::addr is relative address within section
+ * and needs to be relocated by adding sh_addr.
+ */
+ __u64 addr = kmod ? func->addr + func->sh_addr : func->addr;
/* Make sure function is within ftrace addresses. */
- if (bsearch(&func->addr, addrs, count, sizeof(addrs[0]), addrs_cmp)) {
+ if (bsearch(&addr, addrs, count, sizeof(addrs[0]), addrs_cmp)) {
/*
* We iterate over sorted array, so we can easily skip
* not valid item and move following valid field into
@@ -162,6 +300,9 @@ static int filter_functions(struct btf_elf *btfe, struct funcs_layout *fl)
functions_cnt = functions_valid;
free(addrs);
+
+ if (btf_elf__verbose)
+ printf("Found %d functions!\n", functions_cnt);
return 0;
}
@@ -399,34 +540,20 @@ static bool percpu_var_exists(uint64_t addr, uint32_t *sz, const char **name)
return true;
}
-static int collect_percpu_var(struct btf_elf *btfe, GElf_Sym *sym)
+static int collect_percpu_var(struct btf_elf *btfe, GElf_Sym *sym,
+ size_t sym_sec_idx)
{
const char *sym_name;
uint64_t addr;
uint32_t size;
/* compare a symbol's shndx to determine if it's a percpu variable */
- if (elf_sym__section(sym) != btfe->percpu_shndx)
+ if (sym_sec_idx != btfe->percpu_shndx)
return 0;
if (elf_sym__type(sym) != STT_OBJECT)
return 0;
addr = elf_sym__value(sym);
- /*
- * Store only those symbols that have allocated space in the percpu section.
- * This excludes the following three types of symbols:
- *
- * 1. __ADDRESSABLE(sym), which are forcely emitted as symbols.
- * 2. __UNIQUE_ID(prefix), which are introduced to generate unique ids.
- * 3. __exitcall(fn), functions which are labeled as exit calls.
- *
- * In addition, the variables defined using DEFINE_PERCPU_FIRST are
- * also not included, which currently includes:
- *
- * 1. fixed_percpu_data
- */
- if (!addr)
- return 0;
size = elf_sym__size(sym);
if (!size)
@@ -442,7 +569,7 @@ static int collect_percpu_var(struct btf_elf *btfe, GElf_Sym *sym)
}
if (btf_elf__verbose)
- printf("Found per-CPU symbol '%s' at address 0x%lx\n", sym_name, addr);
+ printf("Found per-CPU symbol '%s' at address 0x%" PRIx64 "\n", sym_name, addr);
if (percpu_var_cnt == MAX_PERCPU_VAR_CNT) {
fprintf(stderr, "Reached the limit of per-CPU variables: %d\n",
@@ -457,12 +584,13 @@ static int collect_percpu_var(struct btf_elf *btfe, GElf_Sym *sym)
return 0;
}
-static void collect_symbol(GElf_Sym *sym, struct funcs_layout *fl)
+static void collect_symbol(GElf_Sym *sym, struct funcs_layout *fl,
+ size_t sym_sec_idx)
{
if (!fl->mcount_start &&
!strcmp("__start_mcount_loc", elf_sym__name(sym, btfe->symtab))) {
fl->mcount_start = sym->st_value;
- fl->mcount_sec_idx = sym->st_shndx;
+ fl->mcount_sec_idx = sym_sec_idx;
}
if (!fl->mcount_stop &&
@@ -470,14 +598,10 @@ static void collect_symbol(GElf_Sym *sym, struct funcs_layout *fl)
fl->mcount_stop = sym->st_value;
}
-static int has_all_symbols(struct funcs_layout *fl)
-{
- return fl->mcount_start && fl->mcount_stop;
-}
-
static int collect_symbols(struct btf_elf *btfe, bool collect_percpu_vars)
{
struct funcs_layout fl = { };
+ Elf32_Word sym_sec_idx;
uint32_t core_id;
GElf_Sym sym;
@@ -485,12 +609,12 @@ static int collect_symbols(struct btf_elf *btfe, bool collect_percpu_vars)
percpu_var_cnt = 0;
/* search within symtab for percpu variables */
- elf_symtab__for_each_symbol(btfe->symtab, core_id, sym) {
- if (collect_percpu_vars && collect_percpu_var(btfe, &sym))
+ elf_symtab__for_each_symbol_index(btfe->symtab, core_id, sym, sym_sec_idx) {
+ if (collect_percpu_vars && collect_percpu_var(btfe, &sym, sym_sec_idx))
return -1;
- if (collect_function(btfe, &sym))
+ if (collect_function(btfe, &sym, sym_sec_idx))
return -1;
- collect_symbol(&sym, &fl);
+ collect_symbol(&sym, &fl, sym_sec_idx);
}
if (collect_percpu_vars) {
@@ -501,18 +625,9 @@ static int collect_symbols(struct btf_elf *btfe, bool collect_percpu_vars)
printf("Found %d per-CPU variables!\n", percpu_var_cnt);
}
- if (functions_cnt && has_all_symbols(&fl)) {
- qsort(functions, functions_cnt, sizeof(functions[0]), functions_cmp);
- if (filter_functions(btfe, &fl)) {
- fprintf(stderr, "Failed to filter dwarf functions\n");
- return -1;
- }
- if (btf_elf__verbose)
- printf("Found %d functions!\n", functions_cnt);
- } else {
- if (btf_elf__verbose)
- printf("ftrace symbols not detected, falling back to DWARF data\n");
- delete_functions();
+ if (functions_cnt && setup_functions(btfe, &fl)) {
+ fprintf(stderr, "Failed to filter DWARF functions\n");
+ return -1;
}
return 0;
@@ -621,8 +736,13 @@ int cu__encode_btf(struct cu *cu, int verbose, bool force,
continue;
if (functions_cnt) {
struct elf_function *func;
+ const char *name;
- func = find_function(btfe, function__name(fn, cu));
+ name = function__name(fn, cu);
+ if (!name)
+ continue;
+
+ func = find_function(btfe, name);
if (!func || func->generated)
continue;
func->generated = true;
@@ -651,8 +771,8 @@ int cu__encode_btf(struct cu *cu, int verbose, bool force,
printf("search cu '%s' for percpu global variables.\n", cu->name);
cu__for_each_variable(cu, core_id, pos) {
- uint32_t size, type, linkage, offset;
- const char *name;
+ uint32_t size, type, linkage;
+ const char *name, *dwarf_name;
uint64_t addr;
int id;
@@ -665,12 +785,47 @@ int cu__encode_btf(struct cu *cu, int verbose, bool force,
/* addr has to be recorded before we follow spec */
addr = var->ip.addr;
- if (var->spec)
- var = var->spec;
+
+ /* DWARF takes into account .data..percpu section offset
+ * within its segment, which for vmlinux is 0, but for kernel
+ * modules is >0. ELF symbols, on the other hand, don't take
+ * into account these offsets (as they are relative to the
+ * section start), so to match DWARF and ELF symbols we need
+ * to negate the section base address here.
+ */
+ if (addr < btfe->percpu_base_addr || addr >= btfe->percpu_base_addr + btfe->percpu_sec_sz)
+ continue;
+ addr -= btfe->percpu_base_addr;
if (!percpu_var_exists(addr, &size, &name))
continue; /* not a per-CPU variable */
+ /* A lot of "special" DWARF variables (e.g, __UNIQUE_ID___xxx)
+ * have addr == 0, which is the same as, say, valid
+ * fixed_percpu_data per-CPU variable. To distinguish between
+ * them, additionally compare DWARF and ELF symbol names. If
+ * DWARF doesn't provide proper name, pessimistically assume
+ * bad variable.
+ *
+ * Examples of such special variables are:
+ *
+ * 1. __ADDRESSABLE(sym), which are forcely emitted as symbols.
+ * 2. __UNIQUE_ID(prefix), which are introduced to generate unique ids.
+ * 3. __exitcall(fn), functions which are labeled as exit calls.
+ *
+ * This is relevant only for vmlinux image, as for kernel
+ * modules per-CPU data section has non-zero offset so all
+ * per-CPU symbols have non-zero values.
+ */
+ if (var->ip.addr == 0) {
+ dwarf_name = variable__name(var, cu);
+ if (!dwarf_name || strcmp(dwarf_name, name))
+ continue;
+ }
+
+ if (var->spec)
+ var = var->spec;
+
if (var->ip.tag.type == 0) {
fprintf(stderr, "error: found variable '%s' in CU '%s' that has void type\n",
name, cu->name);
@@ -684,7 +839,7 @@ int cu__encode_btf(struct cu *cu, int verbose, bool force,
linkage = var->external ? BTF_VAR_GLOBAL_ALLOCATED : BTF_VAR_STATIC;
if (btf_elf__verbose) {
- printf("Variable '%s' from CU '%s' at address 0x%lx encoded\n",
+ printf("Variable '%s' from CU '%s' at address 0x%" PRIx64 " encoded\n",
name, cu->name, addr);
}
@@ -692,7 +847,7 @@ int cu__encode_btf(struct cu *cu, int verbose, bool force,
id = btf_elf__add_var_type(btfe, type, name, linkage);
if (id < 0) {
err = -1;
- fprintf(stderr, "error: failed to encode variable '%s' at addr 0x%lx\n",
+ fprintf(stderr, "error: failed to encode variable '%s' at addr 0x%" PRIx64 "\n",
name, addr);
break;
}
@@ -701,11 +856,10 @@ int cu__encode_btf(struct cu *cu, int verbose, bool force,
* add a BTF_VAR_SECINFO in btfe->percpu_secinfo, which will be added into
* btfe->types later when we add BTF_VAR_DATASEC.
*/
- offset = addr - btfe->percpu_base_addr;
- id = btf_elf__add_var_secinfo(&btfe->percpu_secinfo, id, offset, size);
+ id = btf_elf__add_var_secinfo(&btfe->percpu_secinfo, id, addr, size);
if (id < 0) {
err = -1;
- fprintf(stderr, "error: failed to encode section info for variable '%s' at addr 0x%lx\n",
+ fprintf(stderr, "error: failed to encode section info for variable '%s' at addr 0x%" PRIx64 "\n",
name, addr);
break;
}
diff --git a/changes-v1.20 b/changes-v1.20
new file mode 100644
index 0000000..0dddfda
--- /dev/null
+++ b/changes-v1.20
@@ -0,0 +1,66 @@
+BTF encoder:
+
+ - Improve ELF error reporting using elf_errmsg(elf_errno()).
+
+ - Improve objcopy error handling.
+
+ - Fix handling of 'restrict' qualifier, that was being treated as a 'const'.
+
+ - Support SHN_XINDEX in st_shndx symbol indexes, to handle ELF objects with
+ more than 65534 sections, for instance, which happens with kernels built
+ with 'KCFLAGS="-ffunction-sections -fdata-sections", Other cases may
+ include when using FG-ASLR, LTO.
+
+ - Cope with functions without a name, as seen sometimes when building kernel
+ images with some versions of clang, when a SEGFAULT was taking place.
+
+ - Fix BTF variable generation for kernel modules, not skipping variables at
+ offset zero.
+
+ - Fix address size to match what is in the ELF file being processed, to fix using
+ a 64-bit pahole binary to generate BTF for a 32-bit vmlinux image.
+
+ - Use kernel module ftrace addresses when finding which functions to encode,
+ which increases the number of functions encoded.
+
+libbpf:
+
+ - Allow use of packaged version, for distros wanting to dynamically link with
+ the system's libbpf package instead of using the libbpf git submodule shipped
+ in pahole's source code.
+
+DWARF loader:
+
+ - Support DW_AT_data_bit_offset
+
+ This appeared in DWARF4 but is supported only in gcc's -gdwarf-5,
+ support it in a way that makes the output be the same for both cases.
+
+ $ gcc -gdwarf-5 -c examples/dwarf5/bf.c
+ $ pahole bf.o
+ struct pea {
+ long int a:1; /* 0: 0 8 */
+ long int b:1; /* 0: 1 8 */
+ long int c:1; /* 0: 2 8 */
+
+ /* XXX 29 bits hole, try to pack */
+ /* Bitfield combined with next fields */
+
+ int after_bitfield; /* 4 4 */
+
+ /* size: 8, cachelines: 1, members: 4 */
+ /* sum members: 4 */
+ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */
+ /* last cacheline: 8 bytes */
+ };
+
+ - DW_FORM_implicit_const in attr_numeric() and attr_offset()
+
+ - Support DW_TAG_GNU_call_site, its the standardized rename of the previously supported
+ DW_TAG_GNU_call_site.
+
+build:
+
+ - Fix compilation on 32-bit architectures.
+
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
diff --git a/ctfdwdiff b/ctfdwdiff
deleted file mode 100755
index 4ed989f..0000000
--- a/ctfdwdiff
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/bin/bash
-
-results_dir=/tmp/ctfdwdiff
-
-diff_tool() {
- local tool=$1
- local dwarf_options=$2
- local ctf_options=$3
- local obj=$4
-
- diff=$results_dir/$obj.$tool.diff
- ctf=$results_dir/$obj.$tool.ctf.c
- dwarf=$results_dir/$obj.$tool.dwarf.c
- $tool -F ctf $ctf_options $obj > $ctf
- $tool -F dwarf $dwarf_options $obj > $dwarf
- diff -up $dwarf $ctf > $diff
- if [ -s $diff ] ; then
- [ $# -gt 4 ] && vim $diff
- exit 0
- else
- rm -f $diff $ctf $dwarf
- fi
-}
-
-diff_one() {
- local obj=$1
- diff_tool "pahole" "--flat_arrays --show_private_classes --fixup_silly_bitfields" " " $obj $2
- diff_tool "pfunct" "-V --no_parm_names" "-V" $obj $2
-}
-
-
-diff_dir() {
- find . -type d | \
- while read dir ; do
- cd $dir
- ls *.o 2> /dev/null |
- while read obj ; do
- ncus=$(readelf -wi $obj | grep DW_TAG_compile_unit | wc -l)
- if [ $ncus -ne 1 ] ; then
- continue
- fi
- echo $obj
- pahole -Z $obj
- diff_one $obj $1
- done
- cd - > /dev/null
- done
-}
-
-rm -rf $results_dir
-mkdir $results_dir
-
-if [ $# -lt 2 ] ; then
- diff_dir
-else
- diff_one $*
-fi
diff --git a/dtagnames.c b/dtagnames.c
index 0ffcbf7..6a24c37 100644
--- a/dtagnames.c
+++ b/dtagnames.c
@@ -7,18 +7,10 @@
#include <stdio.h>
#include <stdlib.h>
-#include <malloc.h>
#include "dwarves.h"
#include "dutil.h"
-static void print_malloc_stats(void)
-{
- struct mallinfo m = mallinfo();
-
- fprintf(stderr, "size: %u\n", m.uordblks);
-}
-
static int class__tag_name(struct tag *tag, struct cu *cu __unused,
void *cookie __unused)
{
@@ -54,7 +46,6 @@ int main(int argc __unused, char *argv[])
}
cus__dump_class_tag_names(cus);
- print_malloc_stats();
rc = EXIT_SUCCESS;
out:
cus__delete(cus);
diff --git a/dutil.c b/dutil.c
index f7b853f..11fb720 100644
--- a/dutil.c
+++ b/dutil.c
@@ -179,12 +179,18 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
{
Elf_Scn *sec = NULL;
size_t cnt = 1;
+ size_t str_idx;
+
+ if (elf_getshdrstrndx(elf, &str_idx))
+ return NULL;
while ((sec = elf_nextscn(elf, sec)) != NULL) {
char *str;
gelf_getshdr(sec, shp);
- str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
+ str = elf_strptr(elf, str_idx, shp->sh_name);
+ if (!str)
+ return NULL;
if (!strcmp(name, str)) {
if (index)
*index = cnt;
@@ -196,6 +202,16 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
return sec;
}
+Elf_Scn *elf_section_by_idx(Elf *elf, GElf_Shdr *shp, int idx)
+{
+ Elf_Scn *sec;
+
+ sec = elf_getscn(elf, idx);
+ if (sec)
+ gelf_getshdr(sec, shp);
+ return sec;
+}
+
char *strlwr(char *s)
{
int len = strlen(s), i;
diff --git a/dutil.h b/dutil.h
index 676770d..0838dff 100644
--- a/dutil.h
+++ b/dutil.h
@@ -324,6 +324,8 @@ void *zalloc(const size_t size);
Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
GElf_Shdr *shp, const char *name, size_t *index);
+Elf_Scn *elf_section_by_idx(Elf *elf, GElf_Shdr *shp, int idx);
+
#ifndef SHT_GNU_ATTRIBUTES
/* Just a way to check if we're using an old elfutils version */
static inline int elf_getshdrstrndx(Elf *elf, size_t *dst)
diff --git a/dwarf_loader.c b/dwarf_loader.c
index 4638df7..b73d786 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -41,6 +41,15 @@ struct strings *strings;
#define DW_TAG_GNU_call_site_parameter 0x410a
#endif
+#ifndef DW_TAG_call_site
+#define DW_TAG_call_site 0x48
+#define DW_TAG_call_site_parameter 0x49
+#endif
+
+#ifndef DW_FORM_implicit_const
+#define DW_FORM_implicit_const 0x21
+#endif
+
#define hashtags__fn(key) hash_64(key, HASHTAGS__BITS)
bool no_bitfield_type_recode = true;
@@ -248,6 +257,7 @@ static uint64_t attr_numeric(Dwarf_Die *die, uint32_t name)
return addr;
}
break;
+ case DW_FORM_implicit_const:
case DW_FORM_data1:
case DW_FORM_data2:
case DW_FORM_data4:
@@ -290,15 +300,12 @@ static uint64_t dwarf_expr(const uint8_t *expr, uint32_t len __unused)
return UINT64_MAX;
}
-static Dwarf_Off attr_offset(Dwarf_Die *die, const uint32_t name)
+static Dwarf_Off __attr_offset(Dwarf_Attribute *attr)
{
- Dwarf_Attribute attr;
Dwarf_Block block;
- if (dwarf_attr(die, name, &attr) == NULL)
- return 0;
-
- switch (dwarf_whatform(&attr)) {
+ switch (dwarf_whatform(attr)) {
+ case DW_FORM_implicit_const:
case DW_FORM_data1:
case DW_FORM_data2:
case DW_FORM_data4:
@@ -306,18 +313,28 @@ static Dwarf_Off attr_offset(Dwarf_Die *die, const uint32_t name)
case DW_FORM_sdata:
case DW_FORM_udata: {
Dwarf_Word value;
- if (dwarf_formudata(&attr, &value) == 0)
+ if (dwarf_formudata(attr, &value) == 0)
return value;
break;
}
default:
- if (dwarf_formblock(&attr, &block) == 0)
+ if (dwarf_formblock(attr, &block) == 0)
return dwarf_expr(block.data, block.length);
}
return 0;
}
+static Dwarf_Off attr_offset(Dwarf_Die *die, const uint32_t name)
+{
+ Dwarf_Attribute attr;
+
+ if (dwarf_attr(die, name, &attr) == NULL)
+ return 0;
+
+ return __attr_offset(&attr);
+}
+
static const char *attr_string(Dwarf_Die *die, uint32_t name)
{
Dwarf_Attribute attr;
@@ -764,25 +781,41 @@ static struct class_member *class_member__new(Dwarf_Die *die, struct cu *cu,
if (member != NULL) {
tag__init(&member->tag, cu, die);
member->name = strings__add(strings, attr_string(die, DW_AT_name));
- member->is_static = !in_union && !dwarf_hasattr(die, DW_AT_data_member_location);
member->const_value = attr_numeric(die, DW_AT_const_value);
member->alignment = attr_numeric(die, DW_AT_alignment);
- member->byte_offset = attr_offset(die, DW_AT_data_member_location);
- /*
- * Bit offset calculated here is valid only for byte-aligned
- * fields. For bitfields on little-endian archs we need to
- * adjust them taking into account byte size of the field,
- * which might not be yet known. So we'll re-calculate bit
- * offset later, in class_member__cache_byte_size.
- */
- member->bit_offset = member->byte_offset * 8;
+
+ Dwarf_Attribute attr;
+
+ member->has_bit_offset = dwarf_attr(die, DW_AT_data_bit_offset, &attr) != NULL;
+
+ if (member->has_bit_offset) {
+ member->bit_offset = __attr_offset(&attr);
+ // byte_offset and bitfield_offset will be recalculated later, when
+ // we discover the size of this bitfield base type.
+ } else {
+ if (dwarf_attr(die, DW_AT_data_member_location, &attr) != NULL) {
+ member->byte_offset = __attr_offset(&attr);
+ } else {
+ member->is_static = !in_union;
+ }
+
+ /*
+ * Bit offset calculated here is valid only for byte-aligned
+ * fields. For bitfields on little-endian archs we need to
+ * adjust them taking into account byte size of the field,
+ * which might not be yet known. So we'll re-calculate bit
+ * offset later, in class_member__cache_byte_size.
+ */
+ member->bit_offset = member->byte_offset * 8;
+ member->bitfield_offset = attr_numeric(die, DW_AT_bit_offset);
+ }
+
/*
* If DW_AT_byte_size is not present, byte size will be
* determined later in class_member__cache_byte_size using
* base integer/enum type
*/
member->byte_size = attr_numeric(die, DW_AT_byte_size);
- member->bitfield_offset = attr_numeric(die, DW_AT_bit_offset);
member->bitfield_size = attr_numeric(die, DW_AT_bit_size);
member->bit_hole = 0;
member->bitfield_end = 0;
@@ -1471,6 +1504,8 @@ static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblo
uint32_t id;
switch (dwarf_tag(die)) {
+ case DW_TAG_call_site:
+ case DW_TAG_call_site_parameter:
case DW_TAG_GNU_call_site:
case DW_TAG_GNU_call_site_parameter:
/*
@@ -1572,6 +1607,8 @@ static int die__process_function(Dwarf_Die *die, struct ftype *ftype,
uint32_t id;
switch (dwarf_tag(die)) {
+ case DW_TAG_call_site:
+ case DW_TAG_call_site_parameter:
case DW_TAG_GNU_call_site:
case DW_TAG_GNU_call_site_parameter:
/*
@@ -2250,7 +2287,7 @@ static int class_member__cache_byte_size(struct tag *tag, struct cu *cu,
member->bit_size = member->byte_size * 8;
/*
- * XXX: after all the attemps to determine byte size, we might still
+ * XXX: after all the attempts to determine byte size, we might still
* be unsuccessful, because base_type__name_to_size doesn't know about
* the base_type name, so one has to add there when such base_type
* isn't found. pahole will put zero on the struct output so it should
@@ -2261,24 +2298,31 @@ static int class_member__cache_byte_size(struct tag *tag, struct cu *cu,
return 0;
}
- /*
- * For little-endian architectures, DWARF data emitted by gcc/clang
- * specifies bitfield offset as an offset from the highest-order bit
- * of an underlying integral type (e.g., int) to a highest-order bit
- * of a bitfield. E.g., for bitfield taking first 5 bits of int-backed
- * bitfield, bit offset will be 27 (sizeof(int) - 0 offset - 5 bit
- * size), which is very counter-intuitive and isn't a natural
- * extension of byte offset, which on little-endian points to
- * lowest-order byte. So here we re-adjust bitfield offset to be an
- * offset from lowest-order bit of underlying integral type to
- * a lowest-order bit of a bitfield. This makes bitfield offset
- * a natural extension of byte offset for bitfields and is uniform
- * with how big-endian bit offsets work.
- */
- if (cu->little_endian) {
- member->bitfield_offset = member->bit_size - member->bitfield_offset - member->bitfield_size;
+ if (!member->has_bit_offset) {
+ /*
+ * For little-endian architectures, DWARF data emitted by gcc/clang
+ * specifies bitfield offset as an offset from the highest-order bit
+ * of an underlying integral type (e.g., int) to a highest-order bit
+ * of a bitfield. E.g., for bitfield taking first 5 bits of int-backed
+ * bitfield, bit offset will be 27 (sizeof(int) - 0 offset - 5 bit
+ * size), which is very counter-intuitive and isn't a natural
+ * extension of byte offset, which on little-endian points to
+ * lowest-order byte. So here we re-adjust bitfield offset to be an
+ * offset from lowest-order bit of underlying integral type to
+ * a lowest-order bit of a bitfield. This makes bitfield offset
+ * a natural extension of byte offset for bitfields and is uniform
+ * with how big-endian bit offsets work.
+ */
+ if (cu->little_endian)
+ member->bitfield_offset = member->bit_size - member->bitfield_offset - member->bitfield_size;
+
+ member->bit_offset = member->byte_offset * 8 + member->bitfield_offset;
+ } else {
+ // DWARF5 has DW_AT_data_bit_offset, offset in bits from the
+ // start of the container type (struct, class, etc).
+ member->byte_offset = member->bit_offset / 8;
+ member->bitfield_offset = member->bit_offset - member->byte_offset * 8;
}
- member->bit_offset = member->byte_offset * 8 + member->bitfield_offset;
/* make sure bitfield offset is non-negative */
if (member->bitfield_offset < 0) {
diff --git a/dwarves.c b/dwarves.c
index a2d871a..4aa2cd7 100644
--- a/dwarves.c
+++ b/dwarves.c
@@ -1680,8 +1680,14 @@ void enumeration__calc_prefix(struct type *enumeration, const struct cu *cu)
previous_name = curr_name;
}
- enumeration->member_prefix = strndup(curr_name, common_part);
- enumeration->member_prefix_len = common_part == INT32_MAX ? 0 : common_part;
+ enumeration->member_prefix = NULL;
+ enumeration->member_prefix_len = 0;
+
+ if (common_part != INT32_MAX) {
+ enumeration->member_prefix = strndup(curr_name, common_part);
+ if (enumeration->member_prefix != NULL)
+ enumeration->member_prefix_len = common_part;
+ }
}
void enumerations__calc_prefix(struct list_head *enumerations)
diff --git a/dwarves.h b/dwarves.h
index 24405b7..98caf1a 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -899,6 +899,7 @@ static inline int function__inlined(const struct function *func)
* @accessibility - DW_ACCESS_{public,protected,private}
* @virtuality - DW_VIRTUALITY_{none,virtual,pure_virtual}
* @hole - If there is a hole before the next one (or the end of the struct)
+ * @has_bit_offset: Don't recalcule this, it came from the debug info (DWARF5's DW_AT_data_bit_offset)
*/
struct class_member {
struct tag tag;
@@ -915,6 +916,7 @@ struct class_member {
uint32_t alignment;
uint8_t visited:1;
uint8_t is_static:1;
+ uint8_t has_bit_offset:1;
uint8_t accessibility:2;
uint8_t virtuality:2;
uint16_t hole;
diff --git a/elf_symtab.c b/elf_symtab.c
index 741990e..77c5dc4 100644
--- a/elf_symtab.c
+++ b/elf_symtab.c
@@ -17,11 +17,13 @@
struct elf_symtab *elf_symtab__new(const char *name, Elf *elf, GElf_Ehdr *ehdr)
{
+ size_t symtab_index;
+
if (name == NULL)
name = ".symtab";
GElf_Shdr shdr;
- Elf_Scn *sec = elf_section_by_name(elf, ehdr, &shdr, name, NULL);
+ Elf_Scn *sec = elf_section_by_name(elf, ehdr, &shdr, name, &symtab_index);
if (sec == NULL)
return NULL;
@@ -29,7 +31,7 @@ struct elf_symtab *elf_symtab__new(const char *name, Elf *elf, GElf_Ehdr *ehdr)
if (gelf_getshdr(sec, &shdr) == NULL)
return NULL;
- struct elf_symtab *symtab = malloc(sizeof(*symtab));
+ struct elf_symtab *symtab = zalloc(sizeof(*symtab));
if (symtab == NULL)
return NULL;
@@ -41,6 +43,12 @@ struct elf_symtab *elf_symtab__new(const char *name, Elf *elf, GElf_Ehdr *ehdr)
if (symtab->syms == NULL)
goto out_free_name;
+ /*
+ * This returns extended section index table's
+ * section index, if it exists.
+ */
+ int symtab_xindex = elf_scnshndx(sec);
+
sec = elf_getscn(elf, shdr.sh_link);
if (sec == NULL)
goto out_free_name;
@@ -49,6 +57,35 @@ struct elf_symtab *elf_symtab__new(const char *name, Elf *elf, GElf_Ehdr *ehdr)
if (symtab->symstrs == NULL)
goto out_free_name;
+ /*
+ * The .symtab section has optional extended section index
+ * table, load its data so it can be used to resolve symbol's
+ * section index.
+ **/
+ if (symtab_xindex > 0) {
+ GElf_Shdr shdr_xindex;
+ Elf_Scn *sec_xindex;
+
+ sec_xindex = elf_getscn(elf, symtab_xindex);
+ if (sec_xindex == NULL)
+ goto out_free_name;
+
+ if (gelf_getshdr(sec_xindex, &shdr_xindex) == NULL)
+ goto out_free_name;
+
+ /* Extra check to verify it's correct type */
+ if (shdr_xindex.sh_type != SHT_SYMTAB_SHNDX)
+ goto out_free_name;
+
+ /* Extra check to verify it belongs to the .symtab */
+ if (symtab_index != shdr_xindex.sh_link)
+ goto out_free_name;
+
+ symtab->syms_sec_idx_table = elf_getdata(elf_getscn(elf, symtab_xindex), NULL);
+ if (symtab->syms_sec_idx_table == NULL)
+ goto out_free_name;
+ }
+
symtab->nr_syms = shdr.sh_size / shdr.sh_entsize;
return symtab;
diff --git a/elf_symtab.h b/elf_symtab.h
index 359add6..489e2b1 100644
--- a/elf_symtab.h
+++ b/elf_symtab.h
@@ -16,6 +16,8 @@ struct elf_symtab {
uint32_t nr_syms;
Elf_Data *syms;
Elf_Data *symstrs;
+ /* Data of SHT_SYMTAB_SHNDX section. */
+ Elf_Data *syms_sec_idx_table;
char *name;
};
@@ -77,6 +79,19 @@ static inline bool elf_sym__is_local_object(const GElf_Sym *sym)
sym->st_shndx != SHN_UNDEF;
}
+static inline bool
+elf_sym__get(Elf_Data *syms, Elf_Data *syms_sec_idx_table,
+ int id, GElf_Sym *sym, Elf32_Word *sym_sec_idx)
+{
+ if (!gelf_getsymshndx(syms, syms_sec_idx_table, id, sym, sym_sec_idx))
+ return false;
+
+ if (sym->st_shndx != SHN_XINDEX)
+ *sym_sec_idx = sym->st_shndx;
+
+ return true;
+}
+
/**
* elf_symtab__for_each_symbol - iterate thru all the symbols
*
@@ -89,4 +104,18 @@ static inline bool elf_sym__is_local_object(const GElf_Sym *sym)
index < symtab->nr_syms; \
index++, gelf_getsym(symtab->syms, index, &sym))
+/**
+ * elf_symtab__for_each_symbol_index - iterate through all the symbols,
+ * that takes extended symbols indexes into account
+ *
+ * @symtab: struct elf_symtab instance to iterate
+ * @index: uint32_t index
+ * @sym: GElf_Sym iterator
+ * @sym_sec_idx: symbol's index
+ */
+#define elf_symtab__for_each_symbol_index(symtab, id, sym, sym_sec_idx) \
+ for (id = 0; id < symtab->nr_syms; id++) \
+ if (elf_sym__get(symtab->syms, symtab->syms_sec_idx_table, \
+ id, &sym, &sym_sec_idx))
+
#endif /* _ELF_SYMTAB_H_ */
diff --git a/libbtf.c b/libbtf.c
index 246762c..9f76283 100644
--- a/libbtf.c
+++ b/libbtf.c
@@ -110,8 +110,8 @@ try_as_raw_btf:
btfe->elf = elf_begin(btfe->in_fd, ELF_C_READ_MMAP, NULL);
if (!btfe->elf) {
- fprintf(stderr, "%s: cannot read %s ELF file.\n",
- __func__, filename);
+ fprintf(stderr, "%s: cannot read %s ELF file: %s.\n",
+ __func__, filename, elf_errmsg(elf_errno()));
goto errout;
}
}
@@ -170,6 +170,7 @@ try_as_raw_btf:
}
btfe->percpu_shndx = elf_ndxscn(sec);
btfe->percpu_base_addr = shdr.sh_addr;
+ btfe->percpu_sec_sz = shdr.sh_size;
return btfe;
@@ -416,7 +417,7 @@ int32_t btf_elf__add_ref_type(struct btf_elf *btfe, uint16_t kind, uint32_t type
id = btf__add_const(btf, type);
break;
case BTF_KIND_RESTRICT:
- id = btf__add_const(btf, type);
+ id = btf__add_restrict(btf, type);
break;
case BTF_KIND_TYPEDEF:
id = btf__add_typedef(btf, name, type);
@@ -706,13 +707,15 @@ static int btf_elf__write(const char *filename, struct btf *btf)
}
if (elf_version(EV_CURRENT) == EV_NONE) {
- fprintf(stderr, "Cannot set libelf version.\n");
+ fprintf(stderr, "Cannot set libelf version: %s.\n",
+ elf_errmsg(elf_errno()));
goto out;
}
elf = elf_begin(fd, ELF_C_RDWR, NULL);
if (elf == NULL) {
- fprintf(stderr, "Cannot update ELF file.\n");
+ fprintf(stderr, "Cannot update ELF file: %s.\n",
+ elf_errmsg(elf_errno()));
goto out;
}
@@ -720,7 +723,8 @@ static int btf_elf__write(const char *filename, struct btf *btf)
ehdr = gelf_getehdr(elf, &ehdr_mem);
if (ehdr == NULL) {
- fprintf(stderr, "%s: elf_getehdr failed.\n", __func__);
+ fprintf(stderr, "%s: elf_getehdr failed: %s.\n", __func__,
+ elf_errmsg(elf_errno()));
goto out;
}
@@ -763,6 +767,9 @@ static int btf_elf__write(const char *filename, struct btf *btf)
if (elf_update(elf, ELF_C_NULL) >= 0 &&
elf_update(elf, ELF_C_WRITE) >= 0)
err = 0;
+ else
+ fprintf(stderr, "%s: elf_update failed: %s.\n",
+ __func__, elf_errmsg(elf_errno()));
} else {
const char *llvm_objcopy;
char tmp_fn[PATH_MAX];
@@ -785,18 +792,19 @@ static int btf_elf__write(const char *filename, struct btf *btf)
if (write(fd, raw_btf_data, raw_btf_size) != raw_btf_size) {
fprintf(stderr, "%s: write of %d bytes to '%s' failed: %d!\n",
__func__, raw_btf_size, tmp_fn, errno);
- goto out;
+ goto unlink;
}
snprintf(cmd, sizeof(cmd), "%s --add-section .BTF=%s %s",
llvm_objcopy, tmp_fn, filename);
if (system(cmd)) {
fprintf(stderr, "%s: failed to add .BTF section to '%s': %d!\n",
- __func__, tmp_fn, errno);
- goto out;
+ __func__, filename, errno);
+ goto unlink;
}
err = 0;
+ unlink:
unlink(tmp_fn);
}
diff --git a/libbtf.h b/libbtf.h
index 71f6cec..191f586 100644
--- a/libbtf.h
+++ b/libbtf.h
@@ -26,6 +26,7 @@ struct btf_elf {
bool raw_btf; // "/sys/kernel/btf/vmlinux"
uint32_t percpu_shndx;
uint64_t percpu_base_addr;
+ uint64_t percpu_sec_sz;
struct btf *btf;
struct btf *base_btf;
};
diff --git a/pahole.c b/pahole.c
index fe8d2cd..4a34ba5 100644
--- a/pahole.c
+++ b/pahole.c
@@ -1869,7 +1869,7 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty
// Since we're reading stdin, we need to account for what we already read
if (seek_bytes < total_read_bytes) {
- fprintf(stderr, "pahole: can't go back in stdin, already read %" PRIu64 " bytes, can't go to position %ld\n",
+ fprintf(stderr, "pahole: can't go back in stdin, already read %" PRIu64 " bytes, can't go to position %#" PRIx64 "\n",
total_read_bytes, seek_bytes);
return -ENOMEM;
}
diff --git a/rpm/SPECS/dwarves.spec b/rpm/SPECS/dwarves.spec
index 9232002..98433e3 100644
--- a/rpm/SPECS/dwarves.spec
+++ b/rpm/SPECS/dwarves.spec
@@ -2,7 +2,7 @@
%define libver 1
Name: dwarves
-Version: 1.19
+Version: 1.20
Release: 1%{?dist}
License: GPLv2
Summary: Debugging Information Manipulation Tools (pahole & friends)
@@ -10,7 +10,7 @@ URL: http://acmel.wordpress.com
Source: http://fedorapeople.org/~acme/dwarves/%{name}-%{version}.tar.xz
Requires: %{libname}%{libver} = %{version}-%{release}
BuildRequires: gcc
-BuildRequires: cmake
+BuildRequires: cmake >= 2.8.12
BuildRequires: zlib-devel
BuildRequires: elfutils-devel >= 0.130
@@ -79,7 +79,7 @@ rm -Rf %{buildroot}
%files
%doc README.ctracer
%doc README.btf
-%doc changes-v1.19
+%doc changes-v1.20
%doc NEWS
%{_bindir}/btfdiff
%{_bindir}/codiff
@@ -134,6 +134,26 @@ rm -Rf %{buildroot}
%{_libdir}/%{libname}_reorganize.so
%changelog
+* Tue Feb 2 2021 Arnaldo Carvalho de Melo <acme@redhat.com> - 1.20-1
+- New release: v1.20
+- btf_encoder:
+- Improve ELF error reporting using elf_errmsg(elf_errno())
+- Improve objcopy error handling.
+- Fix handling of 'restrict' qualifier, that was being treated as a 'const'.
+- Support SHN_XINDEX in st_shndx symbol indexes
+- Cope with functions without a name
+- Fix BTF variable generation for kernel modules
+- Fix address size to match what is in the ELF file being processed.
+- Use kernel module ftrace addresses when finding which functions to encode.
+- libbpf:
+- Allow use of packaged version.
+- dwarf_loader:
+- Support DW_AT_data_bit_offset
+- DW_FORM_implicit_const in attr_numeric() and attr_offset()
+- Support DW_TAG_GNU_call_site, standardized rename of DW_TAG_GNU_call_site.
+- build:
+- Fix compilation on 32-bit architectures.
+
* Fri Nov 20 2020 Arnaldo Carvalho de Melo <acme@redhat.com> - 1.19-1
- New release: 1.19
- Split BTF
@@ -275,7 +295,7 @@ rm -Rf %{buildroot}
* Sat Nov 20 2010 Arnaldo Carvalho de Melo <acme@redhat.com> - 1.9-1
- New release
-* Tue Feb 08 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.8-2
+* Tue Feb 08 2010 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.8-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
* Fri Dec 4 2009 Arnaldo Carvalho de Melo <acme@redhat.com> - 1.8-1