[RFC 00/13] objtool: Function validation tracing

Alexandre Chartre posted 13 patches 8 months ago
There is a newer version of this series
tools/objtool/Build                     |   1 +
tools/objtool/Makefile                  |   2 +-
tools/objtool/arch/loongarch/decode.c   |  17 +
tools/objtool/arch/powerpc/decode.c     |  18 +
tools/objtool/arch/x86/decode.c         |  15 +
tools/objtool/builtin-check.c           |   1 +
tools/objtool/check.c                   | 829 ++++++++++++++++--------
tools/objtool/disas.c                   | 452 +++++++++++++
tools/objtool/include/objtool/arch.h    |   7 +
tools/objtool/include/objtool/builtin.h |   1 +
tools/objtool/include/objtool/check.h   |  29 +
tools/objtool/include/objtool/warn.h    |  17 +-
12 files changed, 1122 insertions(+), 267 deletions(-)
create mode 100644 tools/objtool/disas.c
[RFC 00/13] objtool: Function validation tracing
Posted by Alexandre Chartre 8 months ago
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.

Note: some changes are architecture specific (x86, powerpc, loongarch). So far,
I have only tested on x86, and some code might be x86 specific. Any feedback
about the behavior on powerpc and loongarch is welcome.

Thanks,

alex.


-----

Example: Trace the validation of the os_save() function in vmlinux.o

$ ./tools/objtool/objtool --hacks=jump_label --hacks=noinstr --hacks=skylake --ibt --orc --retpoline --rethunk --sls --static-call --uaccess --prefix=16 --link --trace os_xsave -v vmlinux.o
os_xsave: validation begin
 65c20: os_xsave+0x0  push %r12				- state: cfa=rsp+16 r12=(cfa-16) stack_size=16 
 65c22: os_xsave+0x2  mov 0x0(%rip),%eax # alternatives_patched 
 65c28: os_xsave+0x8  push %rbp 			- state: cfa=rsp+24 rbp=(cfa-24) stack_size=24 
 65c29: os_xsave+0x9  mov %rdi,%rbp 
 65c2c: os_xsave+0xc  push %rbx 			- state: cfa=rsp+32 rbx=(cfa-32) stack_size=32 
 65c2d: os_xsave+0xd  mov 0x8(%rdi),%rbx 
 65c31: os_xsave+0x11 mov %rbx,%r12 
 65c34: os_xsave+0x14 shr $0x20,%r12 
 65c38: os_xsave+0x18 test %eax,%eax 
 65c3a: os_xsave+0x1a je 65c6a <os_xsave+0x4a> 		- jump taken
 65c6a: os_xsave+0x4a | ud2 
 65c6c: os_xsave+0x4c | jmp 65c3c <os_xsave+0x1c> 	- unconditional jump
 65c3c: os_xsave+0x1c | xor %edx,%edx 
 65c3e: os_xsave+0x1e | mov %rbx,%rsi 
 65c41: os_xsave+0x21 | mov %rbp,%rdi 
 65c44: os_xsave+0x24 | callq xfd_validate_state 	- call
 65c49: os_xsave+0x29 | mov %ebx,%eax 
 65c4b: os_xsave+0x2b | mov %r12d,%edx 
 65c4e: os_xsave+0x2e | <alternative.65c4e> alt 1/4 begin
 65c55: os_xsave+0x35 | | test %ebx,%ebx 
 65c57: os_xsave+0x37 | | jne 65c6e <os_xsave+0x4e> 	- jump taken
 65c6e: os_xsave+0x4e | | | ud2 
 65c70: os_xsave+0x50 | | | pop %rbx 			- state: cfa=rsp+24 rbx=<undef> stack_size=24 
 65c71: os_xsave+0x51 | | | pop %rbp 			- state: cfa=rsp+16 rbp=<undef> stack_size=16 
 65c72: os_xsave+0x52 | | | pop %r12 			- state: cfa=rsp+8 r12=<undef> stack_size=8 
 65c74: os_xsave+0x54 | | | xor %eax,%eax 
 65c76: os_xsave+0x56 | | | xor %edx,%edx 
 65c78: os_xsave+0x58 | | | xor %esi,%esi 
 65c7a: os_xsave+0x5a | | | xor %edi,%edi 
 65c7c: os_xsave+0x5c | | | jmpq __x86_return_thunk 	- return
 65c57: os_xsave+0x37 | | jne 65c6e <os_xsave+0x4e> 	- jump not taken
 65c59: os_xsave+0x39 | | pop %rbx 			- state: cfa=rsp+24 rbx=<undef> stack_size=24 
 65c5a: os_xsave+0x3a | | pop %rbp 			- state: cfa=rsp+16 rbp=<undef> stack_size=16 
 65c5b: os_xsave+0x3b | | pop %r12 			- state: cfa=rsp+8 r12=<undef> stack_size=8 
 65c5d: os_xsave+0x3d | | xor %eax,%eax 
 65c5f: os_xsave+0x3f | | xor %edx,%edx 
 65c61: os_xsave+0x41 | | xor %esi,%esi 
 65c63: os_xsave+0x43 | | xor %edi,%edi 
 65c65: os_xsave+0x45 | | jmpq __x86_return_thunk - return
                      | <alternative.65c4e> alt 1/4 end
 65c4e: os_xsave+0x2e | <alternative.65c4e> alt 2/4 begin
 1c3d: .altinstr_replacement+0x1c3d | | xsaves64 0x40(%rbp) 
 65c53: os_xsave+0x33 | | xor %ebx,%ebx 
 65c55: os_xsave+0x35 | | test %ebx,%ebx - already visited
                      | <alternative.65c4e> alt 2/4 end
 65c4e: os_xsave+0x2e | <alternative.65c4e> alt 3/4 begin
 1c38: .altinstr_replacement+0x1c38 | | xsavec64 0x40(%rbp) 
 65c53: os_xsave+0x33 | | xor %ebx,%ebx - already visited
                      | <alternative.65c4e> alt 3/4 end
 65c4e: os_xsave+0x2e | <alternative.65c4e> alt 4/4 begin
 1c33: .altinstr_replacement+0x1c33 | | xsaveopt64 0x40(%rbp) 
 65c53: os_xsave+0x33 | | xor %ebx,%ebx - already visited
                      | <alternative.65c4e> alt 4/4 end
 65c4e: os_xsave+0x2e | <alternative.65c4e> alt default
 65c4e: os_xsave+0x2e | xsave64 0x40(%rbp) 
 65c53: os_xsave+0x33 | xor %ebx,%ebx - already visited
 65c3a: os_xsave+0x1a je 65c6a <os_xsave+0x4a> - jump not taken
 65c3c: os_xsave+0x1c xor %edx,%edx - already visited
os_xsave: validation end

-----

Alexandre Chartre (13):
  objtool: Move disassembly functions to a separated file
  objtool: Create disassembly context
  objtool: Disassemble code with libopcodes instead of running objdump
  objtool: Print symbol during disassembly
  objtool: Store instruction disassembly result
  objtool: Disassemble instruction on warning or backtrace
  objtool: Extract code to validate instruction from the validate branch
    loop
  objtool: Record symbol name max length
  objtool: Add option to trace function validation
  objtool: Trace instruction state changes during function validation
  objtool: Improve register reporting during function validation
  objtool: Improve tracing of alternative instructions
  objtool: Do not validate IBT for .return_sites and .call_sites

 tools/objtool/Build                     |   1 +
 tools/objtool/Makefile                  |   2 +-
 tools/objtool/arch/loongarch/decode.c   |  17 +
 tools/objtool/arch/powerpc/decode.c     |  18 +
 tools/objtool/arch/x86/decode.c         |  15 +
 tools/objtool/builtin-check.c           |   1 +
 tools/objtool/check.c                   | 829 ++++++++++++++++--------
 tools/objtool/disas.c                   | 452 +++++++++++++
 tools/objtool/include/objtool/arch.h    |   7 +
 tools/objtool/include/objtool/builtin.h |   1 +
 tools/objtool/include/objtool/check.h   |  29 +
 tools/objtool/include/objtool/warn.h    |  17 +-
 12 files changed, 1122 insertions(+), 267 deletions(-)
 create mode 100644 tools/objtool/disas.c

-- 
2.43.5
Re: [RFC 00/13] objtool: Function validation tracing
Posted by Josh Poimboeuf 8 months ago
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:

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

-- 
Josh
Re: [RFC 00/13] objtool: Function validation tracing
Posted by Alexandre Chartre 8 months ago

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
> 

Re: [RFC 00/13] objtool: Function validation tracing
Posted by Alexandre Chartre 8 months ago
On 6/10/25 09:07, Alexandre Chartre wrote:
> 
> 
> 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).
> 

Here is the patch to handle both old and new binutils versions:

8<------------------------------------------------------------------->8
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
index 00350fc7c662..91a2858fea14 100644
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -7,6 +7,11 @@ srctree := $(patsubst %/,%,$(dir $(CURDIR)))
  srctree := $(patsubst %/,%,$(dir $(srctree)))
  endif
  
+FEATURE_USER = .objtool
+FEATURE_TESTS = disassembler-init-styled
+FEATURE_DISPLAY = disassembler-init-styled
+include $(srctree)/tools/build/Makefile.feature
+
  LIBSUBCMD_DIR = $(srctree)/tools/lib/subcmd/
  ifneq ($(OUTPUT),)
    LIBSUBCMD_OUTPUT = $(abspath $(OUTPUT))/libsubcmd
@@ -40,6 +45,10 @@ OBJTOOL_LDFLAGS := $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS) -lopcodes
  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)
  
+ifeq ($(feature-disassembler-init-styled), 1)
+OBJTOOL_CFLAGS += -DDISASM_INIT_STYLED
+endif
+
  # Always want host compilation.
  HOST_OVERRIDES := CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)"
  
8<------------------------------------------------------------------->8

alex.


> 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
>>
> 

Re: [RFC 00/13] objtool: Function validation tracing
Posted by Josh Poimboeuf 8 months ago
On Tue, Jun 10, 2025 at 03:00:50PM +0200, Alexandre Chartre wrote:
> Here is the patch to handle both old and new binutils versions:
> 
> 8<------------------------------------------------------------------->8
> diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
> index 00350fc7c662..91a2858fea14 100644
> --- a/tools/objtool/Makefile
> +++ b/tools/objtool/Makefile
> @@ -7,6 +7,11 @@ srctree := $(patsubst %/,%,$(dir $(CURDIR)))
>  srctree := $(patsubst %/,%,$(dir $(srctree)))
>  endif
> +FEATURE_USER = .objtool
> +FEATURE_TESTS = disassembler-init-styled
> +FEATURE_DISPLAY = disassembler-init-styled
> +include $(srctree)/tools/build/Makefile.feature

Thanks, that worked.

That Makefile.feature thing is nice (except it prints an annoying
newline on every build after the first one).

Can we also use that to determine if binutils-devel (or binutils-dev or
whatever) is installed, and then make the build of disas.c optional?

Then if somebody tries to use '--trace', it could tell them to install
the binutils development package and rebuild objtool.  That way we don't
disrupt everybody's kernel build for a feature they probably won't use.

That would also mean disas_warned_funcs() would be disabled on missing
binutils-devel.  But I think that's probably fine.  In fact that will
now have less reason for existing now that we have this tracing.  Maybe
we won't need it at all.

-- 
Josh
Re: [RFC 00/13] objtool: Function validation tracing
Posted by Alexandre Chartre 8 months ago
On 6/10/25 23:05, Josh Poimboeuf wrote:
> On Tue, Jun 10, 2025 at 03:00:50PM +0200, Alexandre Chartre wrote:
>> Here is the patch to handle both old and new binutils versions:
>>
>> 8<------------------------------------------------------------------->8
>> diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
>> index 00350fc7c662..91a2858fea14 100644
>> --- a/tools/objtool/Makefile
>> +++ b/tools/objtool/Makefile
>> @@ -7,6 +7,11 @@ srctree := $(patsubst %/,%,$(dir $(CURDIR)))
>>   srctree := $(patsubst %/,%,$(dir $(srctree)))
>>   endif
>> +FEATURE_USER = .objtool
>> +FEATURE_TESTS = disassembler-init-styled
>> +FEATURE_DISPLAY = disassembler-init-styled
>> +include $(srctree)/tools/build/Makefile.feature
> 
> Thanks, that worked.
> 
> That Makefile.feature thing is nice (except it prints an annoying
> newline on every build after the first one).
> 
> Can we also use that to determine if binutils-devel (or binutils-dev or
> whatever) is installed, and then make the build of disas.c optional?

This would probably require a new feature test, I will look at it.

> Then if somebody tries to use '--trace', it could tell them to install
> the binutils development package and rebuild objtool.  That way we don't
> disrupt everybody's kernel build for a feature they probably won't use.
> 
> That would also mean disas_warned_funcs() would be disabled on missing
> binutils-devel.  But I think that's probably fine.  In fact that will
> now have less reason for existing now that we have this tracing.  Maybe
> we won't need it at all.
> 

We can also fall back to using objdump if binutils-devel is not there.

And thanks for all the other comments, I will address them and resubmit. I am
also adding the "disas" option.

alex.
Re: [RFC 00/13] objtool: Function validation tracing
Posted by Peter Zijlstra 8 months ago
On Wed, Jun 11, 2025 at 08:00:32AM +0200, Alexandre Chartre wrote:

> > That would also mean disas_warned_funcs() would be disabled on missing
> > binutils-devel.  But I think that's probably fine.  In fact that will
> > now have less reason for existing now that we have this tracing.  Maybe
> > we won't need it at all.
> > 
> 
> We can also fall back to using objdump if binutils-devel is not there.

I don't think that is needed; normal builds will never use this code.
Just print "Rebuild with libopcodes for disasm support" or somesuch when
not present. Then developers will know what to do when they need it.
Re: [RFC 00/13] objtool: Function validation tracing
Posted by Josh Poimboeuf 8 months ago
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.

Ah, nice to get rid of that awful objdump hack.

> - 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.

This is pretty freaking awesome!

I assume we could eventually build on this work to have an "objtool
disas" subcommand, which would basically be an improved "objdump -d"
which annotates alternatives and other runtime patching.

-- 
Josh
Re: [RFC 00/13] objtool: Function validation tracing
Posted by Alexandre Chartre 8 months ago

On 6/6/25 17:58, 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.
> 
> Ah, nice to get rid of that awful objdump hack.
> 
>> - 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.
> 
> This is pretty freaking awesome!
> 
> I assume we could eventually build on this work to have an "objtool
> disas" subcommand, which would basically be an improved "objdump -d"
> which annotates alternatives and other runtime patching.
> 

Yes, good idea. I will look at it.

alex.