| //===--- LayoutOverrideSource.cpp --Override Record Layouts ---------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| #include "clang/Frontend/LayoutOverrideSource.h" |
| #include "clang/AST/Decl.h" |
| #include "clang/Basic/CharInfo.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <fstream> |
| #include <string> |
| |
| using namespace clang; |
| |
| /// Parse a simple identifier. |
| static std::string parseName(StringRef S) { |
| if (S.empty() || !isAsciiIdentifierStart(S[0])) |
| return ""; |
| |
| unsigned Offset = 1; |
| while (Offset < S.size() && isAsciiIdentifierContinue(S[Offset])) |
| ++Offset; |
| |
| return S.substr(0, Offset).str(); |
| } |
| |
| LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) { |
| std::ifstream Input(Filename.str().c_str()); |
| if (!Input.is_open()) |
| return; |
| |
| // Parse the output of -fdump-record-layouts. |
| std::string CurrentType; |
| Layout CurrentLayout; |
| bool ExpectingType = false; |
| |
| while (Input.good()) { |
| std::string Line; |
| getline(Input, Line); |
| |
| StringRef LineStr(Line); |
| |
| // Determine whether the following line will start a |
| if (LineStr.contains("*** Dumping AST Record Layout")) { |
| // Flush the last type/layout, if there is one. |
| if (!CurrentType.empty()) |
| Layouts[CurrentType] = CurrentLayout; |
| CurrentLayout = Layout(); |
| |
| ExpectingType = true; |
| continue; |
| } |
| |
| // If we're expecting a type, grab it. |
| if (ExpectingType) { |
| ExpectingType = false; |
| |
| StringRef::size_type Pos; |
| if ((Pos = LineStr.find("struct ")) != StringRef::npos) |
| LineStr = LineStr.substr(Pos + strlen("struct ")); |
| else if ((Pos = LineStr.find("class ")) != StringRef::npos) |
| LineStr = LineStr.substr(Pos + strlen("class ")); |
| else if ((Pos = LineStr.find("union ")) != StringRef::npos) |
| LineStr = LineStr.substr(Pos + strlen("union ")); |
| else |
| continue; |
| |
| // Find the name of the type. |
| CurrentType = parseName(LineStr); |
| CurrentLayout = Layout(); |
| continue; |
| } |
| |
| // Check for the size of the type. |
| StringRef::size_type Pos = LineStr.find(" Size:"); |
| if (Pos != StringRef::npos) { |
| // Skip past the " Size:" prefix. |
| LineStr = LineStr.substr(Pos + strlen(" Size:")); |
| |
| unsigned long long Size = 0; |
| (void)LineStr.getAsInteger(10, Size); |
| CurrentLayout.Size = Size; |
| continue; |
| } |
| |
| // Check for the alignment of the type. |
| Pos = LineStr.find("Alignment:"); |
| if (Pos != StringRef::npos) { |
| // Skip past the "Alignment:" prefix. |
| LineStr = LineStr.substr(Pos + strlen("Alignment:")); |
| |
| unsigned long long Alignment = 0; |
| (void)LineStr.getAsInteger(10, Alignment); |
| CurrentLayout.Align = Alignment; |
| continue; |
| } |
| |
| // Check for the size/alignment of the type. |
| Pos = LineStr.find("sizeof="); |
| if (Pos != StringRef::npos) { |
| /* Skip past the sizeof= prefix. */ |
| LineStr = LineStr.substr(Pos + strlen("sizeof=")); |
| |
| // Parse size. |
| unsigned long long Size = 0; |
| (void)LineStr.getAsInteger(10, Size); |
| CurrentLayout.Size = Size; |
| |
| Pos = LineStr.find("align="); |
| if (Pos != StringRef::npos) { |
| /* Skip past the align= prefix. */ |
| LineStr = LineStr.substr(Pos + strlen("align=")); |
| |
| // Parse alignment. |
| unsigned long long Alignment = 0; |
| (void)LineStr.getAsInteger(10, Alignment); |
| CurrentLayout.Align = Alignment; |
| } |
| |
| continue; |
| } |
| |
| // Check for the field offsets of the type. |
| Pos = LineStr.find("FieldOffsets: ["); |
| if (Pos == StringRef::npos) |
| continue; |
| |
| LineStr = LineStr.substr(Pos + strlen("FieldOffsets: [")); |
| while (!LineStr.empty() && isDigit(LineStr[0])) { |
| // Parse this offset. |
| unsigned Idx = 1; |
| while (Idx < LineStr.size() && isDigit(LineStr[Idx])) |
| ++Idx; |
| |
| unsigned long long Offset = 0; |
| (void)LineStr.substr(0, Idx).getAsInteger(10, Offset); |
| |
| CurrentLayout.FieldOffsets.push_back(Offset); |
| |
| // Skip over this offset, the following comma, and any spaces. |
| LineStr = LineStr.substr(Idx + 1); |
| while (!LineStr.empty() && isWhitespace(LineStr[0])) |
| LineStr = LineStr.substr(1); |
| } |
| } |
| |
| // Flush the last type/layout, if there is one. |
| if (!CurrentType.empty()) |
| Layouts[CurrentType] = CurrentLayout; |
| } |
| |
| bool |
| LayoutOverrideSource::layoutRecordType(const RecordDecl *Record, |
| uint64_t &Size, uint64_t &Alignment, |
| llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets, |
| llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets, |
| llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets) |
| { |
| // We can't override unnamed declarations. |
| if (!Record->getIdentifier()) |
| return false; |
| |
| // Check whether we have a layout for this record. |
| llvm::StringMap<Layout>::iterator Known = Layouts.find(Record->getName()); |
| if (Known == Layouts.end()) |
| return false; |
| |
| // Provide field layouts. |
| unsigned NumFields = 0; |
| for (RecordDecl::field_iterator F = Record->field_begin(), |
| FEnd = Record->field_end(); |
| F != FEnd; ++F, ++NumFields) { |
| if (NumFields >= Known->second.FieldOffsets.size()) |
| continue; |
| |
| FieldOffsets[*F] = Known->second.FieldOffsets[NumFields]; |
| } |
| |
| // Wrong number of fields. |
| if (NumFields != Known->second.FieldOffsets.size()) |
| return false; |
| |
| Size = Known->second.Size; |
| Alignment = Known->second.Align; |
| return true; |
| } |
| |
| LLVM_DUMP_METHOD void LayoutOverrideSource::dump() { |
| raw_ostream &OS = llvm::errs(); |
| for (llvm::StringMap<Layout>::iterator L = Layouts.begin(), |
| LEnd = Layouts.end(); |
| L != LEnd; ++L) { |
| OS << "Type: blah " << L->first() << '\n'; |
| OS << " Size:" << L->second.Size << '\n'; |
| OS << " Alignment:" << L->second.Align << '\n'; |
| OS << " FieldOffsets: ["; |
| for (unsigned I = 0, N = L->second.FieldOffsets.size(); I != N; ++I) { |
| if (I) |
| OS << ", "; |
| OS << L->second.FieldOffsets[I]; |
| } |
| OS << "]\n"; |
| } |
| } |
| |