mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-16 00:34:20 +08:00
e65935969d
The current architecture detection method in bpftool is designed for host case. For offload case, we can't use the architecture of "bpftool" itself. Instead, we could call the existing "ifindex_to_name_ns" to get DEVNAME, then read pci id from /sys/class/dev/DEVNAME/device/vendor, finally we map vendor id to bfd arch name which will finally be used to select bfd backend for the disassembler. Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: Jiong Wang <jiong.wang@netronome.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
184 lines
3.7 KiB
C
184 lines
3.7 KiB
C
/*
|
|
* 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)
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <bfd.h>
|
|
#include <dis-asm.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <limits.h>
|
|
|
|
#include "json_writer.h"
|
|
#include "main.h"
|
|
|
|
static void get_exec_path(char *tpath, size_t size)
|
|
{
|
|
ssize_t len;
|
|
char *path;
|
|
|
|
snprintf(tpath, size, "/proc/%d/exe", (int) getpid());
|
|
tpath[size - 1] = 0;
|
|
|
|
path = strdup(tpath);
|
|
assert(path);
|
|
|
|
len = readlink(path, tpath, size - 1);
|
|
assert(len > 0);
|
|
tpath[len] = 0;
|
|
|
|
free(path);
|
|
}
|
|
|
|
static int oper_count;
|
|
static int fprintf_json(void *out, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
char *s;
|
|
|
|
va_start(ap, fmt);
|
|
if (!oper_count) {
|
|
int i;
|
|
|
|
s = va_arg(ap, char *);
|
|
|
|
/* 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 {
|
|
s = va_arg(ap, char *);
|
|
jsonw_string(json_wtr, s);
|
|
oper_count++;
|
|
}
|
|
va_end(ap);
|
|
return 0;
|
|
}
|
|
|
|
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
|
|
const char *arch)
|
|
{
|
|
disassembler_ftype disassemble;
|
|
struct disassemble_info info;
|
|
int count, i, pc = 0;
|
|
char tpath[PATH_MAX];
|
|
bfd *bfdf;
|
|
|
|
if (!len)
|
|
return;
|
|
|
|
memset(tpath, 0, sizeof(tpath));
|
|
get_exec_path(tpath, sizeof(tpath));
|
|
|
|
bfdf = bfd_openr(tpath, NULL);
|
|
assert(bfdf);
|
|
assert(bfd_check_format(bfdf, bfd_object));
|
|
|
|
if (json_output)
|
|
init_disassemble_info(&info, stdout,
|
|
(fprintf_ftype) fprintf_json);
|
|
else
|
|
init_disassemble_info(&info, stdout,
|
|
(fprintf_ftype) fprintf);
|
|
|
|
/* Update architecture info for offload. */
|
|
if (arch) {
|
|
const bfd_arch_info_type *inf = bfd_scan_arch(arch);
|
|
|
|
if (inf) {
|
|
bfdf->arch_info = inf;
|
|
} else {
|
|
p_err("No libfd support for %s", arch);
|
|
return;
|
|
}
|
|
}
|
|
|
|
info.arch = bfd_get_arch(bfdf);
|
|
info.mach = bfd_get_mach(bfdf);
|
|
info.buffer = image;
|
|
info.buffer_length = len;
|
|
|
|
disassemble_init_for_target(&info);
|
|
|
|
#ifdef DISASM_FOUR_ARGS_SIGNATURE
|
|
disassemble = disassembler(info.arch,
|
|
bfd_big_endian(bfdf),
|
|
info.mach,
|
|
bfdf);
|
|
#else
|
|
disassemble = disassembler(bfdf);
|
|
#endif
|
|
assert(disassemble);
|
|
|
|
if (json_output)
|
|
jsonw_start_array(json_wtr);
|
|
do {
|
|
if (json_output) {
|
|
jsonw_start_object(json_wtr);
|
|
oper_count = 0;
|
|
jsonw_name(json_wtr, "pc");
|
|
jsonw_printf(json_wtr, "\"0x%x\"", pc);
|
|
} else {
|
|
printf("%4x:\t", pc);
|
|
}
|
|
|
|
count = disassemble(pc, &info);
|
|
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);
|
|
}
|
|
|
|
if (opcodes) {
|
|
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]);
|
|
}
|
|
}
|
|
if (json_output)
|
|
jsonw_end_object(json_wtr);
|
|
else
|
|
printf("\n");
|
|
|
|
pc += count;
|
|
} while (count > 0 && pc < len);
|
|
if (json_output)
|
|
jsonw_end_array(json_wtr);
|
|
|
|
bfd_close(bfdf);
|
|
}
|