This is an archive of the discontinued LLVM Phabricator instance.

[BPF] Improve pruning to avoid generate more types in BTF
ClosedPublic

Authored by yonghong-song on Mar 10 2023, 11:11 AM.

Details

Summary

Commit 3671bdbcd214("[BPF] Fix a BTF type pruning bug") fixed a
pruning bug to allow generate more types. But the commit has a bug
which permits to generate more types than necessary. The following
is an example to illustrate the problem.

struct t1 {
  int a;
};  
struct t2 {
  struct t1 *p1;
  struct t1 *p2;
  int b;
};  
int foo(struct t2 *arg) {
  return arg->b;
}

The following is the part of BTF generation sequence:

(1). 'struct t2 *arg' -> 'struct t1 *p1'
     In this step, the type 'struct t1' will be generated as
     a forward decl and the ptr type (to 'struct t1') will
     be stored in the internal type table.
(2). now the second field 'struct t1 *p2' will be processed.
     Since the ptr type (to 'struct t1') already in the type
     table, the existing logic strips out ptr modifier and
     is able to generate BTF type for 'struct t1'.

In the above step (2), if CheckPointer is true (the type traversal
chain including a struct member), 'ptr' modifier should be checked
and the subsequent type generation should be skipped since
the same case has been processed in visitDerivedType().

The issue is exposed when I am trying to use llvm15 to compile
some internal bpf programs. The bpf skeleton put the whole
ELF section (after striping some sections like dwarf) as a string.
The large BTF section triggered the following error:

bpf_object_with_struct_ops_test_prog_bpf/BpfObjectWithStructOpsTestProg.skel.h:222:23:
error: string literal of length 140144 exceeds maximum length 65536 that C++ compilers
are required to support [-Werror,-Woverlength-strings]
      return (const void *)"\  
                           ^~
1 error generated.

Although adding -Wno-overlength-strings could workaround the issue,
improving llvm BTF generation sounds better esp. for users using vmlinux.h.

Diff Detail

Event Timeline

yonghong-song created this revision.Mar 10 2023, 11:11 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 10 2023, 11:11 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
yonghong-song requested review of this revision.Mar 10 2023, 11:11 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 10 2023, 11:11 AM
eddyz87 added inline comments.Mar 12 2023, 2:28 PM
llvm/lib/Target/BPF/BTFDebug.cpp
897

Looks reasonable.

To be honest, I find the logic with CheckPointer / SeenPointer a bit confusing. As far as I understand the main thing is the following code:

void BTFDebug::visitDerivedType(...) {
  if (CheckPointer && !SeenPointer) {
    SeenPointer = Tag == dwarf::DW_TAG_pointer_type;
  }

  if (CheckPointer && SeenPointer) {
    // generate forward declaration
    return;
  }
  ...
  if (Tag == dwarf::DW_TAG_member)
    visitTypeEntry(DTy->getBaseType(), TempTypeId, true /* !! */, false);
  else
    ...
}

And setting CheckPointer to true means that visitor should generate forward declarations when possible. Adding a comment describing behavior of these parameters somewhere would be really helpful.

add comments to explain CheckPointer and SeePointer.

update the comment.

Added some comments to explain the rationale behind CheckPointer and SeePointer. If it looks okay, could you accept the patch?

eddyz87 accepted this revision.Mar 13 2023, 5:44 AM

Added some comments to explain the rationale behind CheckPointer and SeePointer. If it looks okay, could you accept the patch?

Sure, thank you!

This revision is now accepted and ready to land.Mar 13 2023, 5:44 AM
ast accepted this revision.Mar 13 2023, 8:52 AM