This is an archive of the discontinued LLVM Phabricator instance.

BPF: Fix skipping of types in map-in-map inner map def
Needs ReviewPublic

Authored by davemarchevsky on Apr 13 2023, 8:55 AM.

Details

Reviewers
yonghong-song
Summary

Consider the following BPF program:

struct keyval {
  u64 key;
  char whatever[16];
};

struct {
  __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
  __uint(max_entries, 1000);
  __type(key, int);
  __type(value, int);
  __array(values, struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 1000);
    __type(key, struct keyval);
    __type(value, int);
  });
} array_of_hash_maps SEC(".maps");

This program defines an array of hash maps, with __array(values
defining the inner map. struct keyval is only used as the key of the
inner hash map.

Currently, when BTFDebug walks DWARF debuginfo and generates BTF, it
will not emit a full type for struct keyval, instead emitting a
forward declaration. Without full information emitted, the kernel will
fail to load such a map since the size of struct keyval isn't known.

Even if size were known, without BTF information about the type's fields
which the verifier might give special treatment - e.g. bpf_spin_lock -
programs wouldn't be able to correctly use the map.

This patch fixes the issue described above by modifying
BTFDebug::visitMapDefType so that full BTF info is emitted for `struct
keyval`. Specifically, when visitMapDefType sees a "values" array - the
only way inner maps are defined currently - it will treat the array
element type like it's a map definition, recursively calling
visitMapDefType on it.

Implementation notes:

  • A single-parameter BTFDebug::visitMapDefType variant is added, similar to the single-param BTFDebug::visitTypeEntry in that it uses a scratch uint32_t for the outparam.
  • A new "visit" function is added: BTFDebug::maybeVisitInnerMapDefType. The function's purpose is to hop BaseTypes and cast things around until the inner map type is reached, then call visitMapDefType. I don't expect it to be called outside of visitMapDefType, but separating this logic out keeps things comprehensible.
  • The added test uses the example program above to validate that the fixed logic results in full type BTF type info emitted for struct keyval.

Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>

Diff Detail

Unit TestsFailed

Event Timeline

davemarchevsky created this revision.Apr 13 2023, 8:55 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 13 2023, 8:55 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
davemarchevsky requested review of this revision.Apr 13 2023, 8:55 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 13 2023, 8:55 AM

Overall looks good. Just a few minor comments above.

llvm/lib/Target/BPF/BTFDebug.cpp
954

Let us also check ValuesTy is an array type?

958

Let us also check InnerMapDerivedTy to be a pointer type?

llvm/test/CodeGen/BPF/BTF/inner-map-def.ll
21

Since we added the source code here, we should make the code compilable with compilation flags below.