How do I get entire Data Layout for a class, using libclang?

84 Views Asked by At

I am trying to generate the Data Layout for a class. Specifically, I want

  1. the size of an object of type X
  2. the alignment of an object of type X
  3. the offset within an object of type X of each data component (base or member).

I can easily enough get 1 and 2. I can also easily get 3 for each member of X.

In addition, given a class, I can obtain the cursor for each of its base classes, and can traverse that to the root and build an inheritance graph.

However, I can't figure out how to get the offset of each base of class X.

Ultimately, I want the offsets of all members of X, and all the members of all bases of X, with their offsets relative to X.

Basically, I want the information that is described in Chapter 2: Data Layout from the Itanium C++ ABI for any arbitrary class, X.

I could imagine that this information is not available in the AST, and is only resolved in a specific backend targeting itanium, but other ABI specific information is available (like offsets of any class since the standard does not define class layout).


EDIT - EDIT - EDIT

After reading the comment by @Scott McPeak, I took a peek (see what I did there) at the internals, enough to hack something that seems to work, but likely has major issues.

Here is my somewhat feeble attempt using some of the C++ classes that are used to implement libclang. I implemented it as an extension of the libclang API, just to make it easier for me to consume and test. It does what I want, and maybe that makes things a bit more clear for those trying to help.

I'm sure I'm doing something terribly wrong, so I would love a proper answer, especially if what I want can be done somehow with the current libclang API.

It is based on clang_Type_getOffsetOf.

Obviously, CXTypeLayoutError_InvalidFieldName should be something different, or maybe CXTypeLayoutError_InvalidBase of aliased to CXTypeLayoutError_InvalidFieldNameOrBase. In addition, it returns the offset in bits, for consistency with the member offsets, even though I'm 99.9999% sure that there is no way a base class can have an offset in bits.

long long clang_Type_getOffsetOfBase(CXType PT,
                                     const CXIdxBaseClassInfo *BaseInfo) {
  // check that PT is not incomplete/dependent
  CXCursor PC = clang_getTypeDeclaration(PT);
  long long Error = validateFieldParentType(PC,PT);
  if (Error < 0)
    return Error;

  // get the record decl for PT
  ASTContext &Ctx = cxtu::getASTUnit(GetTU(PT))->getASTContext();
  const CXXRecordDecl *RD =
        dyn_cast_or_null<CXXRecordDecl>(cxcursor::getCursorDecl(PC));
  if (!RD)
    return CXTypeLayoutError_Invalid;

  // get the record decl for the base
  if (BaseInfo) {
    if (auto Spec = cxcursor::getCursorCXXBaseSpecifier(BaseInfo->cursor)) {
      if (auto BaseDecl = Spec->getType()->getAsCXXRecordDecl()) {
        return Ctx.toBits(
            Ctx.getASTRecordLayout(RD).getBaseClassOffset(BaseDecl));
      }
    }
  }
  return CXTypeLayoutError_InvalidFieldName;
}
0

There are 0 best solutions below