Re: [RFC 00/13] objtool: Function validation tracing

From: Alexandre Chartre
Date: Tue Jun 10 2025 - 03:08:22 EST




On 6/9/25 20:31, Josh Poimboeuf wrote:
On Fri, Jun 06, 2025 at 05:34:27PM +0200, Alexandre Chartre wrote:
Hi,

This RFC provides two changes to objtool.

- Disassemble code with libopcodes instead of running objdump

objtool executes the objdump command to disassemble code. In particular,
if objtool fails to validate a function then it will use objdump to
disassemble the entire file which is not very helpful when processing
a large file (like vmlinux.o).

Using libopcodes provides more control about the disassembly scope and
output, and it is possible to disassemble a single instruction or
a single function. Now when objtool fails to validate a function it
will disassemble that single function instead of disassembling the
entire file.

- Add the --trace <function> option to trace function validation

Figuring out why a function validation has failed can be difficult because
objtool checks all code flows (including alternatives) and maintains
instructions states (in particular call frame information).

The trace option allows to follow the function validation done by objtool
instruction per instruction, see what objtool is doing and get function
validation information. An output example is shown below.

What do I need for this to build? It wasn't compiling due to missing
bfd.h, so I installed binutils-devel (Fedora) and now I get:

That's because of the more recent binutils versions, while I have been using an old
one (2.30) and some functions have changed. But tools/dis-asm-compat.h handles that
when the appropriate #define is set.

Below is a quick fix (tested with binutils 2.41), and I will work on a proper fix
(by using the tools/ features to check the disassembler version).

diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
index 00350fc7c662..300ea727e454 100644
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -36,6 +36,8 @@ WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed -
OBJTOOL_CFLAGS := -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES) $(LIBELF_FLAGS)
OBJTOOL_LDFLAGS := $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS) -lopcodes
+OBJTOOL_CFLAGS += -DDISASM_INIT_STYLED
+
# Allow old libelf to be used:
elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(HOSTCC) $(OBJTOOL_CFLAGS) -x c -E - 2>/dev/null | grep elf_getshdr)
OBJTOOL_CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED)


alex.


In file included from disas.c:12:
/home/jpoimboe/git/linux/tools/include/tools/dis-asm-compat.h:10:6: error: redeclaration of ‘enum disassembler_style’
10 | enum disassembler_style {DISASSEMBLER_STYLE_NOT_EMPTY};
| ^~~~~~~~~~~~~~~~~~
In file included from /home/jpoimboe/git/linux/tools/objtool/include/objtool/arch.h:10,
from disas.c:6:
/usr/include/dis-asm.h:53:6: note: originally defined here
53 | enum disassembler_style
| ^~~~~~~~~~~~~~~~~~
/home/jpoimboe/git/linux/tools/include/tools/dis-asm-compat.h: In function ‘init_disassemble_info_compat’:
/home/jpoimboe/git/linux/tools/include/tools/dis-asm-compat.h:50:9: error: too few arguments to function ‘init_disassemble_info’
50 | init_disassemble_info(info, stream,
| ^~~~~~~~~~~~~~~~~~~~~
/usr/include/dis-asm.h:480:13: note: declared here
480 | extern void init_disassemble_info (struct disassemble_info *dinfo, void *stream,
| ^~~~~~~~~~~~~~~~~~~~~
make[4]: *** [/home/jpoimboe/git/linux/tools/build/Makefile.build:86: /home/jpoimboe/git/linux/tools/objtool/disas.o] Error 1
make[4]: *** Waiting for unfinished jobs....
make[3]: *** [Makefile:65: /home/jpoimboe/git/linux/tools/objtool/objtool-in.o] Error 2
make[2]: *** [Makefile:73: objtool] Error 2
make[1]: *** [/home/jpoimboe/git/linux/Makefile:1448: tools/objtool] Error 2
make: *** [Makefile:248: __sub-make] Error 2