2018-12-12 19:59:26 -08:00
|
|
|
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
2017-10-04 20:10:04 -07:00
|
|
|
/*
|
|
|
|
* Based on:
|
|
|
|
*
|
|
|
|
* Minimal BPF JIT image disassembler
|
|
|
|
*
|
|
|
|
* Disassembles BPF JIT compiler emitted opcodes back to asm insn's for
|
|
|
|
* debugging or verification purposes.
|
|
|
|
*
|
|
|
|
* Copyright 2013 Daniel Borkmann <daniel@iogearbox.net>
|
|
|
|
* Licensed under the GNU General Public License, version 2.0 (GPLv2)
|
|
|
|
*/
|
|
|
|
|
2022-10-25 16:03:22 +01:00
|
|
|
#ifndef _GNU_SOURCE
|
tools: bpftool: Fix json dump crash on powerpc
Michael reported crash with by bpf program in json mode on powerpc:
# bpftool prog -p dump jited id 14
[{
"name": "0xd00000000a9aa760",
"insns": [{
"pc": "0x0",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x4",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x8",
"operation": "mflr",
Segmentation fault (core dumped)
The code is assuming char pointers in format, which is not always
true at least for powerpc. Fixing this by dumping the whole string
into buffer based on its format.
Please note that libopcodes code does not check return values from
fprintf callback, but as per Jakub suggestion returning -1 on allocation
failure so we do the best effort to propagate the error.
Fixes: 107f041212c1 ("tools: bpftool: add JSON output for `bpftool prog dump jited *` command")
Reported-by: Michael Petlan <mpetlan@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2019-07-05 14:10:31 +02:00
|
|
|
#define _GNU_SOURCE
|
2022-10-25 16:03:22 +01:00
|
|
|
#endif
|
tools: bpftool: Fix json dump crash on powerpc
Michael reported crash with by bpf program in json mode on powerpc:
# bpftool prog -p dump jited id 14
[{
"name": "0xd00000000a9aa760",
"insns": [{
"pc": "0x0",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x4",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x8",
"operation": "mflr",
Segmentation fault (core dumped)
The code is assuming char pointers in format, which is not always
true at least for powerpc. Fixing this by dumping the whole string
into buffer based on its format.
Please note that libopcodes code does not check return values from
fprintf callback, but as per Jakub suggestion returning -1 on allocation
failure so we do the best effort to propagate the error.
Fixes: 107f041212c1 ("tools: bpftool: add JSON output for `bpftool prog dump jited *` command")
Reported-by: Michael Petlan <mpetlan@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2019-07-05 14:10:31 +02:00
|
|
|
#include <stdio.h>
|
2017-10-23 09:24:09 -07:00
|
|
|
#include <stdarg.h>
|
2017-10-04 20:10:04 -07:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/stat.h>
|
2017-11-02 17:09:45 +09:00
|
|
|
#include <limits.h>
|
2020-01-20 14:06:46 +01:00
|
|
|
#include <bpf/libbpf.h>
|
bpftool: Add LLVM as default library for disassembling JIT-ed programs
To disassemble instructions for JIT-ed programs, bpftool has relied on
the libbfd library. This has been problematic in the past: libbfd's
interface is not meant to be stable and has changed several times. For
building bpftool, we have to detect how the libbfd version on the system
behaves, which is why we have to handle features disassembler-four-args
and disassembler-init-styled in the Makefile. When it comes to shipping
bpftool, this has also caused issues with several distribution
maintainers unwilling to support the feature (see for example Debian's
page for binutils-dev, which ships libbfd: "Note that building Debian
packages which depend on the shared libbfd is Not Allowed." [0]).
For these reasons, we add support for LLVM as an alternative to libbfd
for disassembling instructions of JIT-ed programs. Thanks to the
preparation work in the previous commits, it's easy to add the library
by passing the relevant compilation options in the Makefile, and by
adding the functions for setting up the LLVM disassembler in file
jit_disasm.c.
The LLVM disassembler requires the LLVM development package (usually
llvm-dev or llvm-devel).
The expectation is that the interface for this disassembler will be more
stable. There is a note in LLVM's Developer Policy [1] stating that the
stability for the C API is "best effort" and not guaranteed, but at
least there is some effort to keep compatibility when possible (which
hasn't really been the case for libbfd so far). Furthermore, the Debian
page for the related LLVM package does not caution against linking to
the lib, as binutils-dev page does.
Naturally, the display of disassembled instructions comes with a few
minor differences. Here is a sample output with libbfd (already
supported before this patch):
# bpftool prog dump jited id 56
bpf_prog_6deef7357e7b4530:
0: nopl 0x0(%rax,%rax,1)
5: xchg %ax,%ax
7: push %rbp
8: mov %rsp,%rbp
b: push %rbx
c: push %r13
e: push %r14
10: mov %rdi,%rbx
13: movzwq 0xb4(%rbx),%r13
1b: xor %r14d,%r14d
1e: or $0x2,%r14d
22: mov $0x1,%eax
27: cmp $0x2,%r14
2b: jne 0x000000000000002f
2d: xor %eax,%eax
2f: pop %r14
31: pop %r13
33: pop %rbx
34: leave
35: ret
LLVM supports several variants that we could set when initialising the
disassembler, for example with:
LLVMSetDisasmOptions(*ctx,
LLVMDisassembler_Option_AsmPrinterVariant);
but the default printer is used for now. Here is the output with LLVM:
# bpftool prog dump jited id 56
bpf_prog_6deef7357e7b4530:
0: nopl (%rax,%rax)
5: nop
7: pushq %rbp
8: movq %rsp, %rbp
b: pushq %rbx
c: pushq %r13
e: pushq %r14
10: movq %rdi, %rbx
13: movzwq 180(%rbx), %r13
1b: xorl %r14d, %r14d
1e: orl $2, %r14d
22: movl $1, %eax
27: cmpq $2, %r14
2b: jne 0x2f
2d: xorl %eax, %eax
2f: popq %r14
31: popq %r13
33: popq %rbx
34: leave
35: retq
The LLVM disassembler comes as the default choice, with libbfd as a
fall-back.
Of course, we could replace libbfd entirely and avoid supporting two
different libraries. One reason for keeping libbfd is that, right now,
it works well, we have all we need in terms of features detection in the
Makefile, so it provides a fallback for disassembling JIT-ed programs if
libbfd is installed but LLVM is not. The other motivation is that libbfd
supports nfp instruction for Netronome's SmartNICs and can be used to
disassemble offloaded programs, something that LLVM cannot do. If
libbfd's interface breaks again in the future, we might reconsider
keeping support for it.
[0] https://packages.debian.org/buster/binutils-dev
[1] https://llvm.org/docs/DeveloperPolicy.html#c-api-changes
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Tested-by: Niklas Söderlund <niklas.soderlund@corigine.com>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/r/20221025150329.97371-7-quentin@isovalent.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2022-10-25 16:03:27 +01:00
|
|
|
|
|
|
|
#ifdef HAVE_LLVM_SUPPORT
|
|
|
|
#include <llvm-c/Core.h>
|
|
|
|
#include <llvm-c/Disassembler.h>
|
|
|
|
#include <llvm-c/Target.h>
|
|
|
|
#include <llvm-c/TargetMachine.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBBFD_SUPPORT
|
|
|
|
#include <bfd.h>
|
|
|
|
#include <dis-asm.h>
|
2022-07-31 18:38:33 -07:00
|
|
|
#include <tools/dis-asm-compat.h>
|
bpftool: Add LLVM as default library for disassembling JIT-ed programs
To disassemble instructions for JIT-ed programs, bpftool has relied on
the libbfd library. This has been problematic in the past: libbfd's
interface is not meant to be stable and has changed several times. For
building bpftool, we have to detect how the libbfd version on the system
behaves, which is why we have to handle features disassembler-four-args
and disassembler-init-styled in the Makefile. When it comes to shipping
bpftool, this has also caused issues with several distribution
maintainers unwilling to support the feature (see for example Debian's
page for binutils-dev, which ships libbfd: "Note that building Debian
packages which depend on the shared libbfd is Not Allowed." [0]).
For these reasons, we add support for LLVM as an alternative to libbfd
for disassembling instructions of JIT-ed programs. Thanks to the
preparation work in the previous commits, it's easy to add the library
by passing the relevant compilation options in the Makefile, and by
adding the functions for setting up the LLVM disassembler in file
jit_disasm.c.
The LLVM disassembler requires the LLVM development package (usually
llvm-dev or llvm-devel).
The expectation is that the interface for this disassembler will be more
stable. There is a note in LLVM's Developer Policy [1] stating that the
stability for the C API is "best effort" and not guaranteed, but at
least there is some effort to keep compatibility when possible (which
hasn't really been the case for libbfd so far). Furthermore, the Debian
page for the related LLVM package does not caution against linking to
the lib, as binutils-dev page does.
Naturally, the display of disassembled instructions comes with a few
minor differences. Here is a sample output with libbfd (already
supported before this patch):
# bpftool prog dump jited id 56
bpf_prog_6deef7357e7b4530:
0: nopl 0x0(%rax,%rax,1)
5: xchg %ax,%ax
7: push %rbp
8: mov %rsp,%rbp
b: push %rbx
c: push %r13
e: push %r14
10: mov %rdi,%rbx
13: movzwq 0xb4(%rbx),%r13
1b: xor %r14d,%r14d
1e: or $0x2,%r14d
22: mov $0x1,%eax
27: cmp $0x2,%r14
2b: jne 0x000000000000002f
2d: xor %eax,%eax
2f: pop %r14
31: pop %r13
33: pop %rbx
34: leave
35: ret
LLVM supports several variants that we could set when initialising the
disassembler, for example with:
LLVMSetDisasmOptions(*ctx,
LLVMDisassembler_Option_AsmPrinterVariant);
but the default printer is used for now. Here is the output with LLVM:
# bpftool prog dump jited id 56
bpf_prog_6deef7357e7b4530:
0: nopl (%rax,%rax)
5: nop
7: pushq %rbp
8: movq %rsp, %rbp
b: pushq %rbx
c: pushq %r13
e: pushq %r14
10: movq %rdi, %rbx
13: movzwq 180(%rbx), %r13
1b: xorl %r14d, %r14d
1e: orl $2, %r14d
22: movl $1, %eax
27: cmpq $2, %r14
2b: jne 0x2f
2d: xorl %eax, %eax
2f: popq %r14
31: popq %r13
33: popq %rbx
34: leave
35: retq
The LLVM disassembler comes as the default choice, with libbfd as a
fall-back.
Of course, we could replace libbfd entirely and avoid supporting two
different libraries. One reason for keeping libbfd is that, right now,
it works well, we have all we need in terms of features detection in the
Makefile, so it provides a fallback for disassembling JIT-ed programs if
libbfd is installed but LLVM is not. The other motivation is that libbfd
supports nfp instruction for Netronome's SmartNICs and can be used to
disassemble offloaded programs, something that LLVM cannot do. If
libbfd's interface breaks again in the future, we might reconsider
keeping support for it.
[0] https://packages.debian.org/buster/binutils-dev
[1] https://llvm.org/docs/DeveloperPolicy.html#c-api-changes
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Tested-by: Niklas Söderlund <niklas.soderlund@corigine.com>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/r/20221025150329.97371-7-quentin@isovalent.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2022-10-25 16:03:27 +01:00
|
|
|
#endif
|
2017-10-04 20:10:04 -07:00
|
|
|
|
2017-10-23 09:24:09 -07:00
|
|
|
#include "json_writer.h"
|
|
|
|
#include "main.h"
|
|
|
|
|
2022-10-25 16:03:26 +01:00
|
|
|
static int oper_count;
|
|
|
|
|
bpftool: Add LLVM as default library for disassembling JIT-ed programs
To disassemble instructions for JIT-ed programs, bpftool has relied on
the libbfd library. This has been problematic in the past: libbfd's
interface is not meant to be stable and has changed several times. For
building bpftool, we have to detect how the libbfd version on the system
behaves, which is why we have to handle features disassembler-four-args
and disassembler-init-styled in the Makefile. When it comes to shipping
bpftool, this has also caused issues with several distribution
maintainers unwilling to support the feature (see for example Debian's
page for binutils-dev, which ships libbfd: "Note that building Debian
packages which depend on the shared libbfd is Not Allowed." [0]).
For these reasons, we add support for LLVM as an alternative to libbfd
for disassembling instructions of JIT-ed programs. Thanks to the
preparation work in the previous commits, it's easy to add the library
by passing the relevant compilation options in the Makefile, and by
adding the functions for setting up the LLVM disassembler in file
jit_disasm.c.
The LLVM disassembler requires the LLVM development package (usually
llvm-dev or llvm-devel).
The expectation is that the interface for this disassembler will be more
stable. There is a note in LLVM's Developer Policy [1] stating that the
stability for the C API is "best effort" and not guaranteed, but at
least there is some effort to keep compatibility when possible (which
hasn't really been the case for libbfd so far). Furthermore, the Debian
page for the related LLVM package does not caution against linking to
the lib, as binutils-dev page does.
Naturally, the display of disassembled instructions comes with a few
minor differences. Here is a sample output with libbfd (already
supported before this patch):
# bpftool prog dump jited id 56
bpf_prog_6deef7357e7b4530:
0: nopl 0x0(%rax,%rax,1)
5: xchg %ax,%ax
7: push %rbp
8: mov %rsp,%rbp
b: push %rbx
c: push %r13
e: push %r14
10: mov %rdi,%rbx
13: movzwq 0xb4(%rbx),%r13
1b: xor %r14d,%r14d
1e: or $0x2,%r14d
22: mov $0x1,%eax
27: cmp $0x2,%r14
2b: jne 0x000000000000002f
2d: xor %eax,%eax
2f: pop %r14
31: pop %r13
33: pop %rbx
34: leave
35: ret
LLVM supports several variants that we could set when initialising the
disassembler, for example with:
LLVMSetDisasmOptions(*ctx,
LLVMDisassembler_Option_AsmPrinterVariant);
but the default printer is used for now. Here is the output with LLVM:
# bpftool prog dump jited id 56
bpf_prog_6deef7357e7b4530:
0: nopl (%rax,%rax)
5: nop
7: pushq %rbp
8: movq %rsp, %rbp
b: pushq %rbx
c: pushq %r13
e: pushq %r14
10: movq %rdi, %rbx
13: movzwq 180(%rbx), %r13
1b: xorl %r14d, %r14d
1e: orl $2, %r14d
22: movl $1, %eax
27: cmpq $2, %r14
2b: jne 0x2f
2d: xorl %eax, %eax
2f: popq %r14
31: popq %r13
33: popq %rbx
34: leave
35: retq
The LLVM disassembler comes as the default choice, with libbfd as a
fall-back.
Of course, we could replace libbfd entirely and avoid supporting two
different libraries. One reason for keeping libbfd is that, right now,
it works well, we have all we need in terms of features detection in the
Makefile, so it provides a fallback for disassembling JIT-ed programs if
libbfd is installed but LLVM is not. The other motivation is that libbfd
supports nfp instruction for Netronome's SmartNICs and can be used to
disassemble offloaded programs, something that LLVM cannot do. If
libbfd's interface breaks again in the future, we might reconsider
keeping support for it.
[0] https://packages.debian.org/buster/binutils-dev
[1] https://llvm.org/docs/DeveloperPolicy.html#c-api-changes
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Tested-by: Niklas Söderlund <niklas.soderlund@corigine.com>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/r/20221025150329.97371-7-quentin@isovalent.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2022-10-25 16:03:27 +01:00
|
|
|
#ifdef HAVE_LLVM_SUPPORT
|
|
|
|
#define DISASM_SPACER
|
|
|
|
|
|
|
|
typedef LLVMDisasmContextRef disasm_ctx_t;
|
|
|
|
|
|
|
|
static int printf_json(char *s)
|
|
|
|
{
|
|
|
|
s = strtok(s, " \t");
|
|
|
|
jsonw_string_field(json_wtr, "operation", s);
|
|
|
|
|
|
|
|
jsonw_name(json_wtr, "operands");
|
|
|
|
jsonw_start_array(json_wtr);
|
|
|
|
oper_count = 1;
|
|
|
|
|
|
|
|
while ((s = strtok(NULL, " \t,()")) != 0) {
|
|
|
|
jsonw_string(json_wtr, s);
|
|
|
|
oper_count++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This callback to set the ref_type is necessary to have the LLVM disassembler
|
|
|
|
* print PC-relative addresses instead of byte offsets for branch instruction
|
|
|
|
* targets.
|
|
|
|
*/
|
|
|
|
static const char *
|
|
|
|
symbol_lookup_callback(__maybe_unused void *disasm_info,
|
|
|
|
__maybe_unused uint64_t ref_value,
|
|
|
|
uint64_t *ref_type, __maybe_unused uint64_t ref_PC,
|
|
|
|
__maybe_unused const char **ref_name)
|
|
|
|
{
|
|
|
|
*ref_type = LLVMDisassembler_ReferenceType_InOut_None;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
init_context(disasm_ctx_t *ctx, const char *arch,
|
|
|
|
__maybe_unused const char *disassembler_options,
|
|
|
|
__maybe_unused unsigned char *image, __maybe_unused ssize_t len)
|
|
|
|
{
|
|
|
|
char *triple;
|
|
|
|
|
2022-10-25 16:03:28 +01:00
|
|
|
if (arch)
|
|
|
|
triple = LLVMNormalizeTargetTriple(arch);
|
|
|
|
else
|
|
|
|
triple = LLVMGetDefaultTargetTriple();
|
bpftool: Add LLVM as default library for disassembling JIT-ed programs
To disassemble instructions for JIT-ed programs, bpftool has relied on
the libbfd library. This has been problematic in the past: libbfd's
interface is not meant to be stable and has changed several times. For
building bpftool, we have to detect how the libbfd version on the system
behaves, which is why we have to handle features disassembler-four-args
and disassembler-init-styled in the Makefile. When it comes to shipping
bpftool, this has also caused issues with several distribution
maintainers unwilling to support the feature (see for example Debian's
page for binutils-dev, which ships libbfd: "Note that building Debian
packages which depend on the shared libbfd is Not Allowed." [0]).
For these reasons, we add support for LLVM as an alternative to libbfd
for disassembling instructions of JIT-ed programs. Thanks to the
preparation work in the previous commits, it's easy to add the library
by passing the relevant compilation options in the Makefile, and by
adding the functions for setting up the LLVM disassembler in file
jit_disasm.c.
The LLVM disassembler requires the LLVM development package (usually
llvm-dev or llvm-devel).
The expectation is that the interface for this disassembler will be more
stable. There is a note in LLVM's Developer Policy [1] stating that the
stability for the C API is "best effort" and not guaranteed, but at
least there is some effort to keep compatibility when possible (which
hasn't really been the case for libbfd so far). Furthermore, the Debian
page for the related LLVM package does not caution against linking to
the lib, as binutils-dev page does.
Naturally, the display of disassembled instructions comes with a few
minor differences. Here is a sample output with libbfd (already
supported before this patch):
# bpftool prog dump jited id 56
bpf_prog_6deef7357e7b4530:
0: nopl 0x0(%rax,%rax,1)
5: xchg %ax,%ax
7: push %rbp
8: mov %rsp,%rbp
b: push %rbx
c: push %r13
e: push %r14
10: mov %rdi,%rbx
13: movzwq 0xb4(%rbx),%r13
1b: xor %r14d,%r14d
1e: or $0x2,%r14d
22: mov $0x1,%eax
27: cmp $0x2,%r14
2b: jne 0x000000000000002f
2d: xor %eax,%eax
2f: pop %r14
31: pop %r13
33: pop %rbx
34: leave
35: ret
LLVM supports several variants that we could set when initialising the
disassembler, for example with:
LLVMSetDisasmOptions(*ctx,
LLVMDisassembler_Option_AsmPrinterVariant);
but the default printer is used for now. Here is the output with LLVM:
# bpftool prog dump jited id 56
bpf_prog_6deef7357e7b4530:
0: nopl (%rax,%rax)
5: nop
7: pushq %rbp
8: movq %rsp, %rbp
b: pushq %rbx
c: pushq %r13
e: pushq %r14
10: movq %rdi, %rbx
13: movzwq 180(%rbx), %r13
1b: xorl %r14d, %r14d
1e: orl $2, %r14d
22: movl $1, %eax
27: cmpq $2, %r14
2b: jne 0x2f
2d: xorl %eax, %eax
2f: popq %r14
31: popq %r13
33: popq %rbx
34: leave
35: retq
The LLVM disassembler comes as the default choice, with libbfd as a
fall-back.
Of course, we could replace libbfd entirely and avoid supporting two
different libraries. One reason for keeping libbfd is that, right now,
it works well, we have all we need in terms of features detection in the
Makefile, so it provides a fallback for disassembling JIT-ed programs if
libbfd is installed but LLVM is not. The other motivation is that libbfd
supports nfp instruction for Netronome's SmartNICs and can be used to
disassemble offloaded programs, something that LLVM cannot do. If
libbfd's interface breaks again in the future, we might reconsider
keeping support for it.
[0] https://packages.debian.org/buster/binutils-dev
[1] https://llvm.org/docs/DeveloperPolicy.html#c-api-changes
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Tested-by: Niklas Söderlund <niklas.soderlund@corigine.com>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/r/20221025150329.97371-7-quentin@isovalent.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2022-10-25 16:03:27 +01:00
|
|
|
if (!triple) {
|
|
|
|
p_err("Failed to retrieve triple");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
*ctx = LLVMCreateDisasm(triple, NULL, 0, NULL, symbol_lookup_callback);
|
|
|
|
LLVMDisposeMessage(triple);
|
|
|
|
|
|
|
|
if (!*ctx) {
|
|
|
|
p_err("Failed to create disassembler");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void destroy_context(disasm_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
LLVMDisposeMessage(*ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
disassemble_insn(disasm_ctx_t *ctx, unsigned char *image, ssize_t len, int pc)
|
|
|
|
{
|
|
|
|
char buf[256];
|
|
|
|
int count;
|
|
|
|
|
|
|
|
count = LLVMDisasmInstruction(*ctx, image + pc, len - pc, pc,
|
|
|
|
buf, sizeof(buf));
|
|
|
|
if (json_output)
|
|
|
|
printf_json(buf);
|
|
|
|
else
|
|
|
|
printf("%s", buf);
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
int disasm_init(void)
|
|
|
|
{
|
2022-10-25 16:03:28 +01:00
|
|
|
LLVMInitializeAllTargetInfos();
|
|
|
|
LLVMInitializeAllTargetMCs();
|
|
|
|
LLVMInitializeAllDisassemblers();
|
bpftool: Add LLVM as default library for disassembling JIT-ed programs
To disassemble instructions for JIT-ed programs, bpftool has relied on
the libbfd library. This has been problematic in the past: libbfd's
interface is not meant to be stable and has changed several times. For
building bpftool, we have to detect how the libbfd version on the system
behaves, which is why we have to handle features disassembler-four-args
and disassembler-init-styled in the Makefile. When it comes to shipping
bpftool, this has also caused issues with several distribution
maintainers unwilling to support the feature (see for example Debian's
page for binutils-dev, which ships libbfd: "Note that building Debian
packages which depend on the shared libbfd is Not Allowed." [0]).
For these reasons, we add support for LLVM as an alternative to libbfd
for disassembling instructions of JIT-ed programs. Thanks to the
preparation work in the previous commits, it's easy to add the library
by passing the relevant compilation options in the Makefile, and by
adding the functions for setting up the LLVM disassembler in file
jit_disasm.c.
The LLVM disassembler requires the LLVM development package (usually
llvm-dev or llvm-devel).
The expectation is that the interface for this disassembler will be more
stable. There is a note in LLVM's Developer Policy [1] stating that the
stability for the C API is "best effort" and not guaranteed, but at
least there is some effort to keep compatibility when possible (which
hasn't really been the case for libbfd so far). Furthermore, the Debian
page for the related LLVM package does not caution against linking to
the lib, as binutils-dev page does.
Naturally, the display of disassembled instructions comes with a few
minor differences. Here is a sample output with libbfd (already
supported before this patch):
# bpftool prog dump jited id 56
bpf_prog_6deef7357e7b4530:
0: nopl 0x0(%rax,%rax,1)
5: xchg %ax,%ax
7: push %rbp
8: mov %rsp,%rbp
b: push %rbx
c: push %r13
e: push %r14
10: mov %rdi,%rbx
13: movzwq 0xb4(%rbx),%r13
1b: xor %r14d,%r14d
1e: or $0x2,%r14d
22: mov $0x1,%eax
27: cmp $0x2,%r14
2b: jne 0x000000000000002f
2d: xor %eax,%eax
2f: pop %r14
31: pop %r13
33: pop %rbx
34: leave
35: ret
LLVM supports several variants that we could set when initialising the
disassembler, for example with:
LLVMSetDisasmOptions(*ctx,
LLVMDisassembler_Option_AsmPrinterVariant);
but the default printer is used for now. Here is the output with LLVM:
# bpftool prog dump jited id 56
bpf_prog_6deef7357e7b4530:
0: nopl (%rax,%rax)
5: nop
7: pushq %rbp
8: movq %rsp, %rbp
b: pushq %rbx
c: pushq %r13
e: pushq %r14
10: movq %rdi, %rbx
13: movzwq 180(%rbx), %r13
1b: xorl %r14d, %r14d
1e: orl $2, %r14d
22: movl $1, %eax
27: cmpq $2, %r14
2b: jne 0x2f
2d: xorl %eax, %eax
2f: popq %r14
31: popq %r13
33: popq %rbx
34: leave
35: retq
The LLVM disassembler comes as the default choice, with libbfd as a
fall-back.
Of course, we could replace libbfd entirely and avoid supporting two
different libraries. One reason for keeping libbfd is that, right now,
it works well, we have all we need in terms of features detection in the
Makefile, so it provides a fallback for disassembling JIT-ed programs if
libbfd is installed but LLVM is not. The other motivation is that libbfd
supports nfp instruction for Netronome's SmartNICs and can be used to
disassemble offloaded programs, something that LLVM cannot do. If
libbfd's interface breaks again in the future, we might reconsider
keeping support for it.
[0] https://packages.debian.org/buster/binutils-dev
[1] https://llvm.org/docs/DeveloperPolicy.html#c-api-changes
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Tested-by: Niklas Söderlund <niklas.soderlund@corigine.com>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/r/20221025150329.97371-7-quentin@isovalent.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2022-10-25 16:03:27 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* HAVE_LLVM_SUPPORT */
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBBFD_SUPPORT
|
|
|
|
#define DISASM_SPACER "\t"
|
|
|
|
|
2022-10-25 16:03:26 +01:00
|
|
|
typedef struct {
|
|
|
|
struct disassemble_info *info;
|
|
|
|
disassembler_ftype disassemble;
|
|
|
|
bfd *bfdf;
|
|
|
|
} disasm_ctx_t;
|
|
|
|
|
2022-10-25 16:03:23 +01:00
|
|
|
static int get_exec_path(char *tpath, size_t size)
|
2017-10-04 20:10:04 -07:00
|
|
|
{
|
2018-11-30 16:25:44 +00:00
|
|
|
const char *path = "/proc/self/exe";
|
2017-10-04 20:10:04 -07:00
|
|
|
ssize_t len;
|
|
|
|
|
|
|
|
len = readlink(path, tpath, size - 1);
|
2022-10-25 16:03:23 +01:00
|
|
|
if (len <= 0)
|
|
|
|
return -1;
|
|
|
|
|
2017-10-04 20:10:04 -07:00
|
|
|
tpath[len] = 0;
|
2022-10-25 16:03:23 +01:00
|
|
|
|
|
|
|
return 0;
|
2017-10-04 20:10:04 -07:00
|
|
|
}
|
|
|
|
|
2022-07-31 18:38:33 -07:00
|
|
|
static int printf_json(void *out, const char *fmt, va_list ap)
|
2017-10-23 09:24:09 -07:00
|
|
|
{
|
|
|
|
char *s;
|
2021-07-05 18:35:43 -07:00
|
|
|
int err;
|
2017-10-23 09:24:09 -07:00
|
|
|
|
2021-07-05 18:35:43 -07:00
|
|
|
err = vasprintf(&s, fmt, ap);
|
|
|
|
if (err < 0)
|
|
|
|
return -1;
|
tools: bpftool: Fix json dump crash on powerpc
Michael reported crash with by bpf program in json mode on powerpc:
# bpftool prog -p dump jited id 14
[{
"name": "0xd00000000a9aa760",
"insns": [{
"pc": "0x0",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x4",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x8",
"operation": "mflr",
Segmentation fault (core dumped)
The code is assuming char pointers in format, which is not always
true at least for powerpc. Fixing this by dumping the whole string
into buffer based on its format.
Please note that libopcodes code does not check return values from
fprintf callback, but as per Jakub suggestion returning -1 on allocation
failure so we do the best effort to propagate the error.
Fixes: 107f041212c1 ("tools: bpftool: add JSON output for `bpftool prog dump jited *` command")
Reported-by: Michael Petlan <mpetlan@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2019-07-05 14:10:31 +02:00
|
|
|
|
2017-10-23 09:24:09 -07:00
|
|
|
if (!oper_count) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Strip trailing spaces */
|
|
|
|
i = strlen(s) - 1;
|
|
|
|
while (s[i] == ' ')
|
|
|
|
s[i--] = '\0';
|
|
|
|
|
|
|
|
jsonw_string_field(json_wtr, "operation", s);
|
|
|
|
jsonw_name(json_wtr, "operands");
|
|
|
|
jsonw_start_array(json_wtr);
|
|
|
|
oper_count++;
|
|
|
|
} else if (!strcmp(fmt, ",")) {
|
|
|
|
/* Skip */
|
|
|
|
} else {
|
|
|
|
jsonw_string(json_wtr, s);
|
|
|
|
oper_count++;
|
|
|
|
}
|
tools: bpftool: Fix json dump crash on powerpc
Michael reported crash with by bpf program in json mode on powerpc:
# bpftool prog -p dump jited id 14
[{
"name": "0xd00000000a9aa760",
"insns": [{
"pc": "0x0",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x4",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x8",
"operation": "mflr",
Segmentation fault (core dumped)
The code is assuming char pointers in format, which is not always
true at least for powerpc. Fixing this by dumping the whole string
into buffer based on its format.
Please note that libopcodes code does not check return values from
fprintf callback, but as per Jakub suggestion returning -1 on allocation
failure so we do the best effort to propagate the error.
Fixes: 107f041212c1 ("tools: bpftool: add JSON output for `bpftool prog dump jited *` command")
Reported-by: Michael Petlan <mpetlan@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
2019-07-05 14:10:31 +02:00
|
|
|
free(s);
|
2017-10-23 09:24:09 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-07-31 18:38:33 -07:00
|
|
|
static int fprintf_json(void *out, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
r = printf_json(out, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fprintf_json_styled(void *out,
|
|
|
|
enum disassembler_style style __maybe_unused,
|
|
|
|
const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
r = printf_json(out, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2022-10-25 16:03:26 +01:00
|
|
|
static int init_context(disasm_ctx_t *ctx, const char *arch,
|
|
|
|
const char *disassembler_options,
|
|
|
|
unsigned char *image, ssize_t len)
|
2017-10-04 20:10:04 -07:00
|
|
|
{
|
2022-10-25 16:03:26 +01:00
|
|
|
struct disassemble_info *info;
|
2017-11-02 17:09:45 +09:00
|
|
|
char tpath[PATH_MAX];
|
2017-10-04 20:10:04 -07:00
|
|
|
bfd *bfdf;
|
|
|
|
|
|
|
|
memset(tpath, 0, sizeof(tpath));
|
2022-10-25 16:03:23 +01:00
|
|
|
if (get_exec_path(tpath, sizeof(tpath))) {
|
2022-10-26 09:16:45 +01:00
|
|
|
p_err("failed to create disassembler (get_exec_path)");
|
2022-10-25 16:03:23 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2017-10-04 20:10:04 -07:00
|
|
|
|
2022-10-25 16:03:26 +01:00
|
|
|
ctx->bfdf = bfd_openr(tpath, NULL);
|
|
|
|
if (!ctx->bfdf) {
|
2022-10-25 16:03:23 +01:00
|
|
|
p_err("failed to create disassembler (bfd_openr)");
|
|
|
|
return -1;
|
|
|
|
}
|
2022-10-25 16:03:26 +01:00
|
|
|
if (!bfd_check_format(ctx->bfdf, bfd_object)) {
|
2022-10-25 16:03:23 +01:00
|
|
|
p_err("failed to create disassembler (bfd_check_format)");
|
2022-10-25 16:03:26 +01:00
|
|
|
goto err_close;
|
2022-10-25 16:03:23 +01:00
|
|
|
}
|
2022-10-25 16:03:26 +01:00
|
|
|
bfdf = ctx->bfdf;
|
|
|
|
|
|
|
|
ctx->info = malloc(sizeof(struct disassemble_info));
|
|
|
|
if (!ctx->info) {
|
|
|
|
p_err("mem alloc failed");
|
|
|
|
goto err_close;
|
|
|
|
}
|
|
|
|
info = ctx->info;
|
2017-10-04 20:10:04 -07:00
|
|
|
|
2017-10-23 09:24:09 -07:00
|
|
|
if (json_output)
|
2022-10-25 16:03:26 +01:00
|
|
|
init_disassemble_info_compat(info, stdout,
|
2022-07-31 18:38:33 -07:00
|
|
|
(fprintf_ftype) fprintf_json,
|
|
|
|
fprintf_json_styled);
|
2017-10-23 09:24:09 -07:00
|
|
|
else
|
2022-10-25 16:03:26 +01:00
|
|
|
init_disassemble_info_compat(info, stdout,
|
2022-07-31 18:38:33 -07:00
|
|
|
(fprintf_ftype) fprintf,
|
|
|
|
fprintf_styled);
|
2018-01-16 16:05:21 -08:00
|
|
|
|
|
|
|
/* Update architecture info for offload. */
|
|
|
|
if (arch) {
|
|
|
|
const bfd_arch_info_type *inf = bfd_scan_arch(arch);
|
|
|
|
|
|
|
|
if (inf) {
|
|
|
|
bfdf->arch_info = inf;
|
|
|
|
} else {
|
2018-11-12 13:44:10 -08:00
|
|
|
p_err("No libbfd support for %s", arch);
|
2022-10-25 16:03:26 +01:00
|
|
|
goto err_free;
|
2018-01-16 16:05:21 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-25 16:03:26 +01:00
|
|
|
info->arch = bfd_get_arch(bfdf);
|
|
|
|
info->mach = bfd_get_mach(bfdf);
|
2018-10-18 11:34:55 -07:00
|
|
|
if (disassembler_options)
|
2022-10-25 16:03:26 +01:00
|
|
|
info->disassembler_options = disassembler_options;
|
|
|
|
info->buffer = image;
|
|
|
|
info->buffer_length = len;
|
2017-10-04 20:10:04 -07:00
|
|
|
|
2022-10-25 16:03:26 +01:00
|
|
|
disassemble_init_for_target(info);
|
2017-10-04 20:10:04 -07:00
|
|
|
|
2017-12-27 19:16:29 +00:00
|
|
|
#ifdef DISASM_FOUR_ARGS_SIGNATURE
|
2022-10-25 16:03:26 +01:00
|
|
|
ctx->disassemble = disassembler(info->arch,
|
|
|
|
bfd_big_endian(bfdf),
|
|
|
|
info->mach,
|
|
|
|
bfdf);
|
2017-12-27 19:16:29 +00:00
|
|
|
#else
|
2022-10-25 16:03:26 +01:00
|
|
|
ctx->disassemble = disassembler(bfdf);
|
2017-12-27 19:16:29 +00:00
|
|
|
#endif
|
2022-10-25 16:03:26 +01:00
|
|
|
if (!ctx->disassemble) {
|
2022-10-25 16:03:23 +01:00
|
|
|
p_err("failed to create disassembler");
|
2022-10-25 16:03:26 +01:00
|
|
|
goto err_free;
|
2022-10-25 16:03:23 +01:00
|
|
|
}
|
2022-10-25 16:03:26 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_free:
|
|
|
|
free(info);
|
|
|
|
err_close:
|
|
|
|
bfd_close(ctx->bfdf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void destroy_context(disasm_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
free(ctx->info);
|
|
|
|
bfd_close(ctx->bfdf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
disassemble_insn(disasm_ctx_t *ctx, __maybe_unused unsigned char *image,
|
|
|
|
__maybe_unused ssize_t len, int pc)
|
|
|
|
{
|
|
|
|
return ctx->disassemble(pc, ctx->info);
|
|
|
|
}
|
|
|
|
|
|
|
|
int disasm_init(void)
|
|
|
|
{
|
|
|
|
bfd_init();
|
|
|
|
return 0;
|
|
|
|
}
|
bpftool: Add LLVM as default library for disassembling JIT-ed programs
To disassemble instructions for JIT-ed programs, bpftool has relied on
the libbfd library. This has been problematic in the past: libbfd's
interface is not meant to be stable and has changed several times. For
building bpftool, we have to detect how the libbfd version on the system
behaves, which is why we have to handle features disassembler-four-args
and disassembler-init-styled in the Makefile. When it comes to shipping
bpftool, this has also caused issues with several distribution
maintainers unwilling to support the feature (see for example Debian's
page for binutils-dev, which ships libbfd: "Note that building Debian
packages which depend on the shared libbfd is Not Allowed." [0]).
For these reasons, we add support for LLVM as an alternative to libbfd
for disassembling instructions of JIT-ed programs. Thanks to the
preparation work in the previous commits, it's easy to add the library
by passing the relevant compilation options in the Makefile, and by
adding the functions for setting up the LLVM disassembler in file
jit_disasm.c.
The LLVM disassembler requires the LLVM development package (usually
llvm-dev or llvm-devel).
The expectation is that the interface for this disassembler will be more
stable. There is a note in LLVM's Developer Policy [1] stating that the
stability for the C API is "best effort" and not guaranteed, but at
least there is some effort to keep compatibility when possible (which
hasn't really been the case for libbfd so far). Furthermore, the Debian
page for the related LLVM package does not caution against linking to
the lib, as binutils-dev page does.
Naturally, the display of disassembled instructions comes with a few
minor differences. Here is a sample output with libbfd (already
supported before this patch):
# bpftool prog dump jited id 56
bpf_prog_6deef7357e7b4530:
0: nopl 0x0(%rax,%rax,1)
5: xchg %ax,%ax
7: push %rbp
8: mov %rsp,%rbp
b: push %rbx
c: push %r13
e: push %r14
10: mov %rdi,%rbx
13: movzwq 0xb4(%rbx),%r13
1b: xor %r14d,%r14d
1e: or $0x2,%r14d
22: mov $0x1,%eax
27: cmp $0x2,%r14
2b: jne 0x000000000000002f
2d: xor %eax,%eax
2f: pop %r14
31: pop %r13
33: pop %rbx
34: leave
35: ret
LLVM supports several variants that we could set when initialising the
disassembler, for example with:
LLVMSetDisasmOptions(*ctx,
LLVMDisassembler_Option_AsmPrinterVariant);
but the default printer is used for now. Here is the output with LLVM:
# bpftool prog dump jited id 56
bpf_prog_6deef7357e7b4530:
0: nopl (%rax,%rax)
5: nop
7: pushq %rbp
8: movq %rsp, %rbp
b: pushq %rbx
c: pushq %r13
e: pushq %r14
10: movq %rdi, %rbx
13: movzwq 180(%rbx), %r13
1b: xorl %r14d, %r14d
1e: orl $2, %r14d
22: movl $1, %eax
27: cmpq $2, %r14
2b: jne 0x2f
2d: xorl %eax, %eax
2f: popq %r14
31: popq %r13
33: popq %rbx
34: leave
35: retq
The LLVM disassembler comes as the default choice, with libbfd as a
fall-back.
Of course, we could replace libbfd entirely and avoid supporting two
different libraries. One reason for keeping libbfd is that, right now,
it works well, we have all we need in terms of features detection in the
Makefile, so it provides a fallback for disassembling JIT-ed programs if
libbfd is installed but LLVM is not. The other motivation is that libbfd
supports nfp instruction for Netronome's SmartNICs and can be used to
disassemble offloaded programs, something that LLVM cannot do. If
libbfd's interface breaks again in the future, we might reconsider
keeping support for it.
[0] https://packages.debian.org/buster/binutils-dev
[1] https://llvm.org/docs/DeveloperPolicy.html#c-api-changes
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Tested-by: Niklas Söderlund <niklas.soderlund@corigine.com>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/r/20221025150329.97371-7-quentin@isovalent.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2022-10-25 16:03:27 +01:00
|
|
|
#endif /* HAVE_LIBBPFD_SUPPORT */
|
2022-10-25 16:03:26 +01:00
|
|
|
|
|
|
|
int disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
|
|
|
|
const char *arch, const char *disassembler_options,
|
|
|
|
const struct btf *btf,
|
|
|
|
const struct bpf_prog_linfo *prog_linfo,
|
|
|
|
__u64 func_ksym, unsigned int func_idx,
|
|
|
|
bool linum)
|
|
|
|
{
|
|
|
|
const struct bpf_line_info *linfo = NULL;
|
|
|
|
unsigned int nr_skip = 0;
|
|
|
|
int count, i, pc = 0;
|
|
|
|
disasm_ctx_t ctx;
|
|
|
|
|
|
|
|
if (!len)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (init_context(&ctx, arch, disassembler_options, image, len))
|
|
|
|
return -1;
|
2017-10-04 20:10:04 -07:00
|
|
|
|
2017-10-23 09:24:09 -07:00
|
|
|
if (json_output)
|
|
|
|
jsonw_start_array(json_wtr);
|
2017-10-04 20:10:04 -07:00
|
|
|
do {
|
bpf: libbpf: bpftool: Print bpf_line_info during prog dump
This patch adds print bpf_line_info function in 'prog dump jitted'
and 'prog dump xlated':
[root@arch-fb-vm1 bpf]# ~/devshare/fb-kernel/linux/tools/bpf/bpftool/bpftool prog dump jited pinned /sys/fs/bpf/test_btf_haskv
[...]
int test_long_fname_2(struct dummy_tracepoint_args * arg):
bpf_prog_44a040bf25481309_test_long_fname_2:
; static int test_long_fname_2(struct dummy_tracepoint_args *arg)
0: push %rbp
1: mov %rsp,%rbp
4: sub $0x30,%rsp
b: sub $0x28,%rbp
f: mov %rbx,0x0(%rbp)
13: mov %r13,0x8(%rbp)
17: mov %r14,0x10(%rbp)
1b: mov %r15,0x18(%rbp)
1f: xor %eax,%eax
21: mov %rax,0x20(%rbp)
25: xor %esi,%esi
; int key = 0;
27: mov %esi,-0x4(%rbp)
; if (!arg->sock)
2a: mov 0x8(%rdi),%rdi
; if (!arg->sock)
2e: cmp $0x0,%rdi
32: je 0x0000000000000070
34: mov %rbp,%rsi
; counts = bpf_map_lookup_elem(&btf_map, &key);
37: add $0xfffffffffffffffc,%rsi
3b: movabs $0xffff8881139d7480,%rdi
45: add $0x110,%rdi
4c: mov 0x0(%rsi),%eax
4f: cmp $0x4,%rax
53: jae 0x000000000000005e
55: shl $0x3,%rax
59: add %rdi,%rax
5c: jmp 0x0000000000000060
5e: xor %eax,%eax
; if (!counts)
60: cmp $0x0,%rax
64: je 0x0000000000000070
; counts->v6++;
66: mov 0x4(%rax),%edi
69: add $0x1,%rdi
6d: mov %edi,0x4(%rax)
70: mov 0x0(%rbp),%rbx
74: mov 0x8(%rbp),%r13
78: mov 0x10(%rbp),%r14
7c: mov 0x18(%rbp),%r15
80: add $0x28,%rbp
84: leaveq
85: retq
[...]
With linum:
[root@arch-fb-vm1 bpf]# ~/devshare/fb-kernel/linux/tools/bpf/bpftool/bpftool prog dump jited pinned /sys/fs/bpf/test_btf_haskv linum
int _dummy_tracepoint(struct dummy_tracepoint_args * arg):
bpf_prog_b07ccb89267cf242__dummy_tracepoint:
; return test_long_fname_1(arg); [file:/data/users/kafai/fb-kernel/linux/tools/testing/selftests/bpf/test_btf_haskv.c line_num:54 line_col:9]
0: push %rbp
1: mov %rsp,%rbp
4: sub $0x28,%rsp
b: sub $0x28,%rbp
f: mov %rbx,0x0(%rbp)
13: mov %r13,0x8(%rbp)
17: mov %r14,0x10(%rbp)
1b: mov %r15,0x18(%rbp)
1f: xor %eax,%eax
21: mov %rax,0x20(%rbp)
25: callq 0x000000000000851e
; return test_long_fname_1(arg); [file:/data/users/kafai/fb-kernel/linux/tools/testing/selftests/bpf/test_btf_haskv.c line_num:54 line_col:2]
2a: xor %eax,%eax
2c: mov 0x0(%rbp),%rbx
30: mov 0x8(%rbp),%r13
34: mov 0x10(%rbp),%r14
38: mov 0x18(%rbp),%r15
3c: add $0x28,%rbp
40: leaveq
41: retq
[...]
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Acked-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-12-07 16:42:32 -08:00
|
|
|
if (prog_linfo) {
|
|
|
|
linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
|
|
|
|
func_ksym + pc,
|
|
|
|
func_idx,
|
|
|
|
nr_skip);
|
|
|
|
if (linfo)
|
|
|
|
nr_skip++;
|
|
|
|
}
|
|
|
|
|
2017-10-23 09:24:09 -07:00
|
|
|
if (json_output) {
|
|
|
|
jsonw_start_object(json_wtr);
|
|
|
|
oper_count = 0;
|
bpf: libbpf: bpftool: Print bpf_line_info during prog dump
This patch adds print bpf_line_info function in 'prog dump jitted'
and 'prog dump xlated':
[root@arch-fb-vm1 bpf]# ~/devshare/fb-kernel/linux/tools/bpf/bpftool/bpftool prog dump jited pinned /sys/fs/bpf/test_btf_haskv
[...]
int test_long_fname_2(struct dummy_tracepoint_args * arg):
bpf_prog_44a040bf25481309_test_long_fname_2:
; static int test_long_fname_2(struct dummy_tracepoint_args *arg)
0: push %rbp
1: mov %rsp,%rbp
4: sub $0x30,%rsp
b: sub $0x28,%rbp
f: mov %rbx,0x0(%rbp)
13: mov %r13,0x8(%rbp)
17: mov %r14,0x10(%rbp)
1b: mov %r15,0x18(%rbp)
1f: xor %eax,%eax
21: mov %rax,0x20(%rbp)
25: xor %esi,%esi
; int key = 0;
27: mov %esi,-0x4(%rbp)
; if (!arg->sock)
2a: mov 0x8(%rdi),%rdi
; if (!arg->sock)
2e: cmp $0x0,%rdi
32: je 0x0000000000000070
34: mov %rbp,%rsi
; counts = bpf_map_lookup_elem(&btf_map, &key);
37: add $0xfffffffffffffffc,%rsi
3b: movabs $0xffff8881139d7480,%rdi
45: add $0x110,%rdi
4c: mov 0x0(%rsi),%eax
4f: cmp $0x4,%rax
53: jae 0x000000000000005e
55: shl $0x3,%rax
59: add %rdi,%rax
5c: jmp 0x0000000000000060
5e: xor %eax,%eax
; if (!counts)
60: cmp $0x0,%rax
64: je 0x0000000000000070
; counts->v6++;
66: mov 0x4(%rax),%edi
69: add $0x1,%rdi
6d: mov %edi,0x4(%rax)
70: mov 0x0(%rbp),%rbx
74: mov 0x8(%rbp),%r13
78: mov 0x10(%rbp),%r14
7c: mov 0x18(%rbp),%r15
80: add $0x28,%rbp
84: leaveq
85: retq
[...]
With linum:
[root@arch-fb-vm1 bpf]# ~/devshare/fb-kernel/linux/tools/bpf/bpftool/bpftool prog dump jited pinned /sys/fs/bpf/test_btf_haskv linum
int _dummy_tracepoint(struct dummy_tracepoint_args * arg):
bpf_prog_b07ccb89267cf242__dummy_tracepoint:
; return test_long_fname_1(arg); [file:/data/users/kafai/fb-kernel/linux/tools/testing/selftests/bpf/test_btf_haskv.c line_num:54 line_col:9]
0: push %rbp
1: mov %rsp,%rbp
4: sub $0x28,%rsp
b: sub $0x28,%rbp
f: mov %rbx,0x0(%rbp)
13: mov %r13,0x8(%rbp)
17: mov %r14,0x10(%rbp)
1b: mov %r15,0x18(%rbp)
1f: xor %eax,%eax
21: mov %rax,0x20(%rbp)
25: callq 0x000000000000851e
; return test_long_fname_1(arg); [file:/data/users/kafai/fb-kernel/linux/tools/testing/selftests/bpf/test_btf_haskv.c line_num:54 line_col:2]
2a: xor %eax,%eax
2c: mov 0x0(%rbp),%rbx
30: mov 0x8(%rbp),%r13
34: mov 0x10(%rbp),%r14
38: mov 0x18(%rbp),%r15
3c: add $0x28,%rbp
40: leaveq
41: retq
[...]
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Acked-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-12-07 16:42:32 -08:00
|
|
|
if (linfo)
|
|
|
|
btf_dump_linfo_json(btf, linfo, linum);
|
2017-10-23 09:24:09 -07:00
|
|
|
jsonw_name(json_wtr, "pc");
|
|
|
|
jsonw_printf(json_wtr, "\"0x%x\"", pc);
|
|
|
|
} else {
|
bpf: libbpf: bpftool: Print bpf_line_info during prog dump
This patch adds print bpf_line_info function in 'prog dump jitted'
and 'prog dump xlated':
[root@arch-fb-vm1 bpf]# ~/devshare/fb-kernel/linux/tools/bpf/bpftool/bpftool prog dump jited pinned /sys/fs/bpf/test_btf_haskv
[...]
int test_long_fname_2(struct dummy_tracepoint_args * arg):
bpf_prog_44a040bf25481309_test_long_fname_2:
; static int test_long_fname_2(struct dummy_tracepoint_args *arg)
0: push %rbp
1: mov %rsp,%rbp
4: sub $0x30,%rsp
b: sub $0x28,%rbp
f: mov %rbx,0x0(%rbp)
13: mov %r13,0x8(%rbp)
17: mov %r14,0x10(%rbp)
1b: mov %r15,0x18(%rbp)
1f: xor %eax,%eax
21: mov %rax,0x20(%rbp)
25: xor %esi,%esi
; int key = 0;
27: mov %esi,-0x4(%rbp)
; if (!arg->sock)
2a: mov 0x8(%rdi),%rdi
; if (!arg->sock)
2e: cmp $0x0,%rdi
32: je 0x0000000000000070
34: mov %rbp,%rsi
; counts = bpf_map_lookup_elem(&btf_map, &key);
37: add $0xfffffffffffffffc,%rsi
3b: movabs $0xffff8881139d7480,%rdi
45: add $0x110,%rdi
4c: mov 0x0(%rsi),%eax
4f: cmp $0x4,%rax
53: jae 0x000000000000005e
55: shl $0x3,%rax
59: add %rdi,%rax
5c: jmp 0x0000000000000060
5e: xor %eax,%eax
; if (!counts)
60: cmp $0x0,%rax
64: je 0x0000000000000070
; counts->v6++;
66: mov 0x4(%rax),%edi
69: add $0x1,%rdi
6d: mov %edi,0x4(%rax)
70: mov 0x0(%rbp),%rbx
74: mov 0x8(%rbp),%r13
78: mov 0x10(%rbp),%r14
7c: mov 0x18(%rbp),%r15
80: add $0x28,%rbp
84: leaveq
85: retq
[...]
With linum:
[root@arch-fb-vm1 bpf]# ~/devshare/fb-kernel/linux/tools/bpf/bpftool/bpftool prog dump jited pinned /sys/fs/bpf/test_btf_haskv linum
int _dummy_tracepoint(struct dummy_tracepoint_args * arg):
bpf_prog_b07ccb89267cf242__dummy_tracepoint:
; return test_long_fname_1(arg); [file:/data/users/kafai/fb-kernel/linux/tools/testing/selftests/bpf/test_btf_haskv.c line_num:54 line_col:9]
0: push %rbp
1: mov %rsp,%rbp
4: sub $0x28,%rsp
b: sub $0x28,%rbp
f: mov %rbx,0x0(%rbp)
13: mov %r13,0x8(%rbp)
17: mov %r14,0x10(%rbp)
1b: mov %r15,0x18(%rbp)
1f: xor %eax,%eax
21: mov %rax,0x20(%rbp)
25: callq 0x000000000000851e
; return test_long_fname_1(arg); [file:/data/users/kafai/fb-kernel/linux/tools/testing/selftests/bpf/test_btf_haskv.c line_num:54 line_col:2]
2a: xor %eax,%eax
2c: mov 0x0(%rbp),%rbx
30: mov 0x8(%rbp),%r13
34: mov 0x10(%rbp),%r14
38: mov 0x18(%rbp),%r15
3c: add $0x28,%rbp
40: leaveq
41: retq
[...]
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Acked-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-12-07 16:42:32 -08:00
|
|
|
if (linfo)
|
|
|
|
btf_dump_linfo_plain(btf, linfo, "; ",
|
|
|
|
linum);
|
bpftool: Add LLVM as default library for disassembling JIT-ed programs
To disassemble instructions for JIT-ed programs, bpftool has relied on
the libbfd library. This has been problematic in the past: libbfd's
interface is not meant to be stable and has changed several times. For
building bpftool, we have to detect how the libbfd version on the system
behaves, which is why we have to handle features disassembler-four-args
and disassembler-init-styled in the Makefile. When it comes to shipping
bpftool, this has also caused issues with several distribution
maintainers unwilling to support the feature (see for example Debian's
page for binutils-dev, which ships libbfd: "Note that building Debian
packages which depend on the shared libbfd is Not Allowed." [0]).
For these reasons, we add support for LLVM as an alternative to libbfd
for disassembling instructions of JIT-ed programs. Thanks to the
preparation work in the previous commits, it's easy to add the library
by passing the relevant compilation options in the Makefile, and by
adding the functions for setting up the LLVM disassembler in file
jit_disasm.c.
The LLVM disassembler requires the LLVM development package (usually
llvm-dev or llvm-devel).
The expectation is that the interface for this disassembler will be more
stable. There is a note in LLVM's Developer Policy [1] stating that the
stability for the C API is "best effort" and not guaranteed, but at
least there is some effort to keep compatibility when possible (which
hasn't really been the case for libbfd so far). Furthermore, the Debian
page for the related LLVM package does not caution against linking to
the lib, as binutils-dev page does.
Naturally, the display of disassembled instructions comes with a few
minor differences. Here is a sample output with libbfd (already
supported before this patch):
# bpftool prog dump jited id 56
bpf_prog_6deef7357e7b4530:
0: nopl 0x0(%rax,%rax,1)
5: xchg %ax,%ax
7: push %rbp
8: mov %rsp,%rbp
b: push %rbx
c: push %r13
e: push %r14
10: mov %rdi,%rbx
13: movzwq 0xb4(%rbx),%r13
1b: xor %r14d,%r14d
1e: or $0x2,%r14d
22: mov $0x1,%eax
27: cmp $0x2,%r14
2b: jne 0x000000000000002f
2d: xor %eax,%eax
2f: pop %r14
31: pop %r13
33: pop %rbx
34: leave
35: ret
LLVM supports several variants that we could set when initialising the
disassembler, for example with:
LLVMSetDisasmOptions(*ctx,
LLVMDisassembler_Option_AsmPrinterVariant);
but the default printer is used for now. Here is the output with LLVM:
# bpftool prog dump jited id 56
bpf_prog_6deef7357e7b4530:
0: nopl (%rax,%rax)
5: nop
7: pushq %rbp
8: movq %rsp, %rbp
b: pushq %rbx
c: pushq %r13
e: pushq %r14
10: movq %rdi, %rbx
13: movzwq 180(%rbx), %r13
1b: xorl %r14d, %r14d
1e: orl $2, %r14d
22: movl $1, %eax
27: cmpq $2, %r14
2b: jne 0x2f
2d: xorl %eax, %eax
2f: popq %r14
31: popq %r13
33: popq %rbx
34: leave
35: retq
The LLVM disassembler comes as the default choice, with libbfd as a
fall-back.
Of course, we could replace libbfd entirely and avoid supporting two
different libraries. One reason for keeping libbfd is that, right now,
it works well, we have all we need in terms of features detection in the
Makefile, so it provides a fallback for disassembling JIT-ed programs if
libbfd is installed but LLVM is not. The other motivation is that libbfd
supports nfp instruction for Netronome's SmartNICs and can be used to
disassemble offloaded programs, something that LLVM cannot do. If
libbfd's interface breaks again in the future, we might reconsider
keeping support for it.
[0] https://packages.debian.org/buster/binutils-dev
[1] https://llvm.org/docs/DeveloperPolicy.html#c-api-changes
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Tested-by: Niklas Söderlund <niklas.soderlund@corigine.com>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/r/20221025150329.97371-7-quentin@isovalent.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2022-10-25 16:03:27 +01:00
|
|
|
printf("%4x:" DISASM_SPACER, pc);
|
2017-10-23 09:24:09 -07:00
|
|
|
}
|
2017-10-04 20:10:04 -07:00
|
|
|
|
2022-10-25 16:03:26 +01:00
|
|
|
count = disassemble_insn(&ctx, image, len, pc);
|
|
|
|
|
2017-10-23 09:24:09 -07:00
|
|
|
if (json_output) {
|
|
|
|
/* Operand array, was started in fprintf_json. Before
|
|
|
|
* that, make sure we have a _null_ value if no operand
|
|
|
|
* other than operation code was present.
|
|
|
|
*/
|
|
|
|
if (oper_count == 1)
|
|
|
|
jsonw_null(json_wtr);
|
|
|
|
jsonw_end_array(json_wtr);
|
|
|
|
}
|
2017-10-04 20:10:04 -07:00
|
|
|
|
|
|
|
if (opcodes) {
|
2017-10-23 09:24:09 -07:00
|
|
|
if (json_output) {
|
|
|
|
jsonw_name(json_wtr, "opcodes");
|
|
|
|
jsonw_start_array(json_wtr);
|
|
|
|
for (i = 0; i < count; ++i)
|
|
|
|
jsonw_printf(json_wtr, "\"0x%02hhx\"",
|
|
|
|
(uint8_t)image[pc + i]);
|
|
|
|
jsonw_end_array(json_wtr);
|
|
|
|
} else {
|
|
|
|
printf("\n\t");
|
|
|
|
for (i = 0; i < count; ++i)
|
|
|
|
printf("%02x ",
|
|
|
|
(uint8_t)image[pc + i]);
|
|
|
|
}
|
2017-10-04 20:10:04 -07:00
|
|
|
}
|
2017-10-23 09:24:09 -07:00
|
|
|
if (json_output)
|
|
|
|
jsonw_end_object(json_wtr);
|
|
|
|
else
|
|
|
|
printf("\n");
|
2017-10-04 20:10:04 -07:00
|
|
|
|
|
|
|
pc += count;
|
|
|
|
} while (count > 0 && pc < len);
|
2017-10-23 09:24:09 -07:00
|
|
|
if (json_output)
|
|
|
|
jsonw_end_array(json_wtr);
|
2017-10-04 20:10:04 -07:00
|
|
|
|
2022-10-25 16:03:26 +01:00
|
|
|
destroy_context(&ctx);
|
2018-11-12 13:44:10 -08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|