Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/tools/testing/selftests/bpf/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 6 kB image not shown  

Quelle  jit_disasm_helpers.c   Sprache: C

 
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <test_progs.h>

#ifdef HAVE_LLVM_SUPPORT

#include <llvm-c/Core.h>
#include <llvm-c/Disassembler.h>
#include <llvm-c/Target.h>
#include <llvm-c/TargetMachine.h>

/* The intent is to use get_jited_program_text() for small test
 * programs written in BPF assembly, thus assume that 32 local labels
 * would be sufficient.
 */

#define MAX_LOCAL_LABELS 32

/* Local labels are encoded as 'L42', this requires 4 bytes of storage:
 * 3 characters + zero byte
 */

#define LOCAL_LABEL_LEN 4

static bool llvm_initialized;

struct local_labels {
 bool print_phase;
 __u32 prog_len;
 __u32 cnt;
 __u32 pcs[MAX_LOCAL_LABELS];
 char names[MAX_LOCAL_LABELS][LOCAL_LABEL_LEN];
};

static const char *lookup_symbol(void *data, uint64_t ref_value, uint64_t *ref_type,
     uint64_t ref_pc, const char **ref_name)
{
 struct local_labels *labels = data;
 uint64_t type = *ref_type;
 int i;

 *ref_type = LLVMDisassembler_ReferenceType_InOut_None;
 *ref_name = NULL;
 if (type != LLVMDisassembler_ReferenceType_In_Branch)
  return NULL;
 /* Depending on labels->print_phase either discover local labels or
 * return a name assigned with local jump target:
 * - if print_phase is true and ref_value is in labels->pcs,
 *   return corresponding labels->name.
 * - if print_phase is false, save program-local jump targets
 *   in labels->pcs;
 */

 if (labels->print_phase) {
  for (i = 0; i < labels->cnt; ++i)
   if (labels->pcs[i] == ref_value)
    return labels->names[i];
 } else {
  if (labels->cnt < MAX_LOCAL_LABELS && ref_value < labels->prog_len)
   labels->pcs[labels->cnt++] = ref_value;
 }
 return NULL;
}

static int disasm_insn(LLVMDisasmContextRef ctx, uint8_t *image, __u32 len, __u32 pc,
         char *buf, __u32 buf_sz)
{
 int i, cnt;

 cnt = LLVMDisasmInstruction(ctx, image + pc, len - pc, pc,
        buf, buf_sz);
 if (cnt > 0)
  return cnt;
 PRINT_FAIL("Can't disasm instruction at offset %d:", pc);
 for (i = 0; i < 16 && pc + i < len; ++i)
  printf(" %02x", image[pc + i]);
 printf("\n");
 return -EINVAL;
}

static int cmp_u32(const void *_a, const void *_b)
{
 __u32 a = *(__u32 *)_a;
 __u32 b = *(__u32 *)_b;

 if (a < b)
  return -1;
 if (a > b)
  return 1;
 return 0;
}

static int disasm_one_func(FILE *text_out, uint8_t *image, __u32 len)
{
 char *label, *colon, *triple = NULL;
 LLVMDisasmContextRef ctx = NULL;
 struct local_labels labels = {};
 __u32 *label_pc, pc;
 int i, cnt, err = 0;
 char buf[64];

 triple = LLVMGetDefaultTargetTriple();
 ctx = LLVMCreateDisasm(triple, &labels, 0, NULL, lookup_symbol);
 if (!ASSERT_OK_PTR(ctx, "LLVMCreateDisasm")) {
  err = -EINVAL;
  goto out;
 }

 cnt = LLVMSetDisasmOptions(ctx, LLVMDisassembler_Option_PrintImmHex);
 if (!ASSERT_EQ(cnt, 1, "LLVMSetDisasmOptions")) {
  err = -EINVAL;
  goto out;
 }

 /* discover labels */
 labels.prog_len = len;
 pc = 0;
 while (pc < len) {
  cnt = disasm_insn(ctx, image, len, pc, buf, 1);
  if (cnt < 0) {
   err = cnt;
   goto out;
  }
  pc += cnt;
 }
 qsort(labels.pcs, labels.cnt, sizeof(*labels.pcs), cmp_u32);
 for (i = 0; i < labels.cnt; ++i)
  /* gcc is unable to infer upper bound for labels.cnt and assumes
 * it to be U32_MAX. U32_MAX takes 10 decimal digits.
 * snprintf below prints into labels.names[*],
 * which has space only for two digits and a letter.
 * To avoid truncation warning use (i % MAX_LOCAL_LABELS),
 * which informs gcc about printed value upper bound.
 */

  snprintf(labels.names[i], sizeof(labels.names[i]), "L%d", i % MAX_LOCAL_LABELS);

 /* now print with labels */
 labels.print_phase = true;
 pc = 0;
 while (pc < len) {
  cnt = disasm_insn(ctx, image, len, pc, buf, sizeof(buf));
  if (cnt < 0) {
   err = cnt;
   goto out;
  }
  label_pc = bsearch(&pc, labels.pcs, labels.cnt, sizeof(*labels.pcs), cmp_u32);
  label = "";
  colon = "";
  if (label_pc) {
   label = labels.names[label_pc - labels.pcs];
   colon = ":";
  }
  fprintf(text_out, "%x:\t", pc);
  for (i = 0; i < cnt; ++i)
   fprintf(text_out, "%02x ", image[pc + i]);
  for (i = cnt * 3; i < 12 * 3; ++i)
   fputc(' ', text_out);
  fprintf(text_out, "%s%s%s\n", label, colon, buf);
  pc += cnt;
 }

out:
 if (triple)
  LLVMDisposeMessage(triple);
 if (ctx)
  LLVMDisasmDispose(ctx);
 return err;
}

int get_jited_program_text(int fd, char *text, size_t text_sz)
{
 struct bpf_prog_info info = {};
 __u32 info_len = sizeof(info);
 __u32 jited_funcs, len, pc;
 __u32 *func_lens = NULL;
 FILE *text_out = NULL;
 uint8_t *image = NULL;
 int i, err = 0;

 if (!llvm_initialized) {
  LLVMInitializeAllTargetInfos();
  LLVMInitializeAllTargetMCs();
  LLVMInitializeAllDisassemblers();
  llvm_initialized = 1;
 }

 text_out = fmemopen(text, text_sz, "w");
 if (!ASSERT_OK_PTR(text_out, "open_memstream")) {
  err = -errno;
  goto out;
 }

 /* first call is to find out jited program len */
 err = bpf_prog_get_info_by_fd(fd, &info, &info_len);
 if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd #1"))
  goto out;

 len = info.jited_prog_len;
 image = malloc(len);
 if (!ASSERT_OK_PTR(image, "malloc(info.jited_prog_len)")) {
  err = -ENOMEM;
  goto out;
 }

 jited_funcs = info.nr_jited_func_lens;
 func_lens = malloc(jited_funcs * sizeof(__u32));
 if (!ASSERT_OK_PTR(func_lens, "malloc(info.nr_jited_func_lens)")) {
  err = -ENOMEM;
  goto out;
 }

 memset(&info, 0, sizeof(info));
 info.jited_prog_insns = (__u64)image;
 info.jited_prog_len = len;
 info.jited_func_lens = (__u64)func_lens;
 info.nr_jited_func_lens = jited_funcs;
 err = bpf_prog_get_info_by_fd(fd, &info, &info_len);
 if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd #2"))
  goto out;

 for (pc = 0, i = 0; i < jited_funcs; ++i) {
  fprintf(text_out, "func #%d:\n", i);
  disasm_one_func(text_out, image + pc, func_lens[i]);
  fprintf(text_out, "\n");
  pc += func_lens[i];
 }

out:
 if (text_out)
  fclose(text_out);
 if (image)
  free(image);
 if (func_lens)
  free(func_lens);
 return err;
}

#else /* HAVE_LLVM_SUPPORT */

int get_jited_program_text(int fd, char *text, size_t text_sz)
{
 if (env.verbosity >= VERBOSE_VERY)
  printf("compiled w/o llvm development libraries, can't dis-assembly binary code");
 return -EOPNOTSUPP;
}

#endif /* HAVE_LLVM_SUPPORT */

Messung V0.5
C=98 H=79 G=88

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.