10b57cec5SDimitry Andric //===--- LayoutOverrideSource.cpp --Override Record Layouts ---------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric #include "clang/Frontend/LayoutOverrideSource.h"
90b57cec5SDimitry Andric #include "clang/AST/Decl.h"
1006c3fb27SDimitry Andric #include "clang/AST/DeclCXX.h"
110b57cec5SDimitry Andric #include "clang/Basic/CharInfo.h"
120b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
130b57cec5SDimitry Andric #include <fstream>
140b57cec5SDimitry Andric #include <string>
150b57cec5SDimitry Andric
160b57cec5SDimitry Andric using namespace clang;
170b57cec5SDimitry Andric
180b57cec5SDimitry Andric /// Parse a simple identifier.
parseName(StringRef S)190b57cec5SDimitry Andric static std::string parseName(StringRef S) {
20349cc55cSDimitry Andric if (S.empty() || !isAsciiIdentifierStart(S[0]))
210b57cec5SDimitry Andric return "";
220b57cec5SDimitry Andric
230b57cec5SDimitry Andric unsigned Offset = 1;
24349cc55cSDimitry Andric while (Offset < S.size() && isAsciiIdentifierContinue(S[Offset]))
250b57cec5SDimitry Andric ++Offset;
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric return S.substr(0, Offset).str();
280b57cec5SDimitry Andric }
290b57cec5SDimitry Andric
3006c3fb27SDimitry Andric /// Parse an unsigned integer and move S to the next non-digit character.
parseUnsigned(StringRef & S,unsigned long long & ULL)3106c3fb27SDimitry Andric static bool parseUnsigned(StringRef &S, unsigned long long &ULL) {
3206c3fb27SDimitry Andric if (S.empty() || !isDigit(S[0]))
3306c3fb27SDimitry Andric return false;
3406c3fb27SDimitry Andric unsigned Idx = 1;
3506c3fb27SDimitry Andric while (Idx < S.size() && isDigit(S[Idx]))
3606c3fb27SDimitry Andric ++Idx;
3706c3fb27SDimitry Andric (void)S.substr(0, Idx).getAsInteger(10, ULL);
3806c3fb27SDimitry Andric S = S.substr(Idx);
3906c3fb27SDimitry Andric return true;
4006c3fb27SDimitry Andric }
4106c3fb27SDimitry Andric
LayoutOverrideSource(StringRef Filename)420b57cec5SDimitry Andric LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) {
430b57cec5SDimitry Andric std::ifstream Input(Filename.str().c_str());
440b57cec5SDimitry Andric if (!Input.is_open())
450b57cec5SDimitry Andric return;
460b57cec5SDimitry Andric
470b57cec5SDimitry Andric // Parse the output of -fdump-record-layouts.
480b57cec5SDimitry Andric std::string CurrentType;
490b57cec5SDimitry Andric Layout CurrentLayout;
500b57cec5SDimitry Andric bool ExpectingType = false;
510b57cec5SDimitry Andric
520b57cec5SDimitry Andric while (Input.good()) {
530b57cec5SDimitry Andric std::string Line;
540b57cec5SDimitry Andric getline(Input, Line);
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric StringRef LineStr(Line);
570b57cec5SDimitry Andric
580b57cec5SDimitry Andric // Determine whether the following line will start a
59349cc55cSDimitry Andric if (LineStr.contains("*** Dumping AST Record Layout")) {
600b57cec5SDimitry Andric // Flush the last type/layout, if there is one.
610b57cec5SDimitry Andric if (!CurrentType.empty())
620b57cec5SDimitry Andric Layouts[CurrentType] = CurrentLayout;
630b57cec5SDimitry Andric CurrentLayout = Layout();
640b57cec5SDimitry Andric
650b57cec5SDimitry Andric ExpectingType = true;
660b57cec5SDimitry Andric continue;
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric
690b57cec5SDimitry Andric // If we're expecting a type, grab it.
700b57cec5SDimitry Andric if (ExpectingType) {
710b57cec5SDimitry Andric ExpectingType = false;
720b57cec5SDimitry Andric
730b57cec5SDimitry Andric StringRef::size_type Pos;
740b57cec5SDimitry Andric if ((Pos = LineStr.find("struct ")) != StringRef::npos)
750b57cec5SDimitry Andric LineStr = LineStr.substr(Pos + strlen("struct "));
760b57cec5SDimitry Andric else if ((Pos = LineStr.find("class ")) != StringRef::npos)
770b57cec5SDimitry Andric LineStr = LineStr.substr(Pos + strlen("class "));
780b57cec5SDimitry Andric else if ((Pos = LineStr.find("union ")) != StringRef::npos)
790b57cec5SDimitry Andric LineStr = LineStr.substr(Pos + strlen("union "));
800b57cec5SDimitry Andric else
810b57cec5SDimitry Andric continue;
820b57cec5SDimitry Andric
830b57cec5SDimitry Andric // Find the name of the type.
840b57cec5SDimitry Andric CurrentType = parseName(LineStr);
850b57cec5SDimitry Andric CurrentLayout = Layout();
860b57cec5SDimitry Andric continue;
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric
890b57cec5SDimitry Andric // Check for the size of the type.
900b57cec5SDimitry Andric StringRef::size_type Pos = LineStr.find(" Size:");
910b57cec5SDimitry Andric if (Pos != StringRef::npos) {
920b57cec5SDimitry Andric // Skip past the " Size:" prefix.
930b57cec5SDimitry Andric LineStr = LineStr.substr(Pos + strlen(" Size:"));
940b57cec5SDimitry Andric
950b57cec5SDimitry Andric unsigned long long Size = 0;
9606c3fb27SDimitry Andric if (parseUnsigned(LineStr, Size))
970b57cec5SDimitry Andric CurrentLayout.Size = Size;
980b57cec5SDimitry Andric continue;
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric
1010b57cec5SDimitry Andric // Check for the alignment of the type.
1020b57cec5SDimitry Andric Pos = LineStr.find("Alignment:");
1030b57cec5SDimitry Andric if (Pos != StringRef::npos) {
1040b57cec5SDimitry Andric // Skip past the "Alignment:" prefix.
1050b57cec5SDimitry Andric LineStr = LineStr.substr(Pos + strlen("Alignment:"));
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric unsigned long long Alignment = 0;
10806c3fb27SDimitry Andric if (parseUnsigned(LineStr, Alignment))
1090b57cec5SDimitry Andric CurrentLayout.Align = Alignment;
1100b57cec5SDimitry Andric continue;
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric
11306c3fb27SDimitry Andric // Check for the size/alignment of the type. The number follows "size=" or
11406c3fb27SDimitry Andric // "align=" indicates number of bytes.
1150b57cec5SDimitry Andric Pos = LineStr.find("sizeof=");
1160b57cec5SDimitry Andric if (Pos != StringRef::npos) {
1170b57cec5SDimitry Andric /* Skip past the sizeof= prefix. */
1180b57cec5SDimitry Andric LineStr = LineStr.substr(Pos + strlen("sizeof="));
1190b57cec5SDimitry Andric
1200b57cec5SDimitry Andric // Parse size.
1210b57cec5SDimitry Andric unsigned long long Size = 0;
12206c3fb27SDimitry Andric if (parseUnsigned(LineStr, Size))
12306c3fb27SDimitry Andric CurrentLayout.Size = Size * 8;
1240b57cec5SDimitry Andric
1250b57cec5SDimitry Andric Pos = LineStr.find("align=");
1260b57cec5SDimitry Andric if (Pos != StringRef::npos) {
1270b57cec5SDimitry Andric /* Skip past the align= prefix. */
1280b57cec5SDimitry Andric LineStr = LineStr.substr(Pos + strlen("align="));
1290b57cec5SDimitry Andric
1300b57cec5SDimitry Andric // Parse alignment.
1310b57cec5SDimitry Andric unsigned long long Alignment = 0;
13206c3fb27SDimitry Andric if (parseUnsigned(LineStr, Alignment))
13306c3fb27SDimitry Andric CurrentLayout.Align = Alignment * 8;
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric
1360b57cec5SDimitry Andric continue;
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric
1390b57cec5SDimitry Andric // Check for the field offsets of the type.
1400b57cec5SDimitry Andric Pos = LineStr.find("FieldOffsets: [");
14106c3fb27SDimitry Andric if (Pos != StringRef::npos) {
1420b57cec5SDimitry Andric LineStr = LineStr.substr(Pos + strlen("FieldOffsets: ["));
1430b57cec5SDimitry Andric while (!LineStr.empty() && isDigit(LineStr[0])) {
1440b57cec5SDimitry Andric unsigned long long Offset = 0;
14506c3fb27SDimitry Andric if (parseUnsigned(LineStr, Offset))
1460b57cec5SDimitry Andric CurrentLayout.FieldOffsets.push_back(Offset);
1470b57cec5SDimitry Andric
1480b57cec5SDimitry Andric // Skip over this offset, the following comma, and any spaces.
14906c3fb27SDimitry Andric LineStr = LineStr.substr(1);
150*647cbc5dSDimitry Andric LineStr = LineStr.drop_while(isWhitespace);
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric
15406c3fb27SDimitry Andric // Check for the virtual base offsets.
15506c3fb27SDimitry Andric Pos = LineStr.find("VBaseOffsets: [");
15606c3fb27SDimitry Andric if (Pos != StringRef::npos) {
15706c3fb27SDimitry Andric LineStr = LineStr.substr(Pos + strlen("VBaseOffsets: ["));
15806c3fb27SDimitry Andric while (!LineStr.empty() && isDigit(LineStr[0])) {
15906c3fb27SDimitry Andric unsigned long long Offset = 0;
16006c3fb27SDimitry Andric if (parseUnsigned(LineStr, Offset))
16106c3fb27SDimitry Andric CurrentLayout.VBaseOffsets.push_back(CharUnits::fromQuantity(Offset));
16206c3fb27SDimitry Andric
16306c3fb27SDimitry Andric // Skip over this offset, the following comma, and any spaces.
16406c3fb27SDimitry Andric LineStr = LineStr.substr(1);
165*647cbc5dSDimitry Andric LineStr = LineStr.drop_while(isWhitespace);
16606c3fb27SDimitry Andric }
16706c3fb27SDimitry Andric continue;
16806c3fb27SDimitry Andric }
16906c3fb27SDimitry Andric
17006c3fb27SDimitry Andric // Check for the base offsets.
17106c3fb27SDimitry Andric Pos = LineStr.find("BaseOffsets: [");
17206c3fb27SDimitry Andric if (Pos != StringRef::npos) {
17306c3fb27SDimitry Andric LineStr = LineStr.substr(Pos + strlen("BaseOffsets: ["));
17406c3fb27SDimitry Andric while (!LineStr.empty() && isDigit(LineStr[0])) {
17506c3fb27SDimitry Andric unsigned long long Offset = 0;
17606c3fb27SDimitry Andric if (parseUnsigned(LineStr, Offset))
17706c3fb27SDimitry Andric CurrentLayout.BaseOffsets.push_back(CharUnits::fromQuantity(Offset));
17806c3fb27SDimitry Andric
17906c3fb27SDimitry Andric // Skip over this offset, the following comma, and any spaces.
18006c3fb27SDimitry Andric LineStr = LineStr.substr(1);
181*647cbc5dSDimitry Andric LineStr = LineStr.drop_while(isWhitespace);
18206c3fb27SDimitry Andric }
18306c3fb27SDimitry Andric }
18406c3fb27SDimitry Andric }
18506c3fb27SDimitry Andric
1860b57cec5SDimitry Andric // Flush the last type/layout, if there is one.
1870b57cec5SDimitry Andric if (!CurrentType.empty())
1880b57cec5SDimitry Andric Layouts[CurrentType] = CurrentLayout;
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric
1910b57cec5SDimitry Andric bool
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)1920b57cec5SDimitry Andric LayoutOverrideSource::layoutRecordType(const RecordDecl *Record,
1930b57cec5SDimitry Andric uint64_t &Size, uint64_t &Alignment,
1940b57cec5SDimitry Andric llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
1950b57cec5SDimitry Andric llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
1960b57cec5SDimitry Andric llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets)
1970b57cec5SDimitry Andric {
1980b57cec5SDimitry Andric // We can't override unnamed declarations.
1990b57cec5SDimitry Andric if (!Record->getIdentifier())
2000b57cec5SDimitry Andric return false;
2010b57cec5SDimitry Andric
2020b57cec5SDimitry Andric // Check whether we have a layout for this record.
2030b57cec5SDimitry Andric llvm::StringMap<Layout>::iterator Known = Layouts.find(Record->getName());
2040b57cec5SDimitry Andric if (Known == Layouts.end())
2050b57cec5SDimitry Andric return false;
2060b57cec5SDimitry Andric
2070b57cec5SDimitry Andric // Provide field layouts.
2080b57cec5SDimitry Andric unsigned NumFields = 0;
2090b57cec5SDimitry Andric for (RecordDecl::field_iterator F = Record->field_begin(),
2100b57cec5SDimitry Andric FEnd = Record->field_end();
2110b57cec5SDimitry Andric F != FEnd; ++F, ++NumFields) {
2120b57cec5SDimitry Andric if (NumFields >= Known->second.FieldOffsets.size())
2130b57cec5SDimitry Andric continue;
2140b57cec5SDimitry Andric
2150b57cec5SDimitry Andric FieldOffsets[*F] = Known->second.FieldOffsets[NumFields];
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric
2180b57cec5SDimitry Andric // Wrong number of fields.
2190b57cec5SDimitry Andric if (NumFields != Known->second.FieldOffsets.size())
2200b57cec5SDimitry Andric return false;
2210b57cec5SDimitry Andric
22206c3fb27SDimitry Andric // Provide base offsets.
22306c3fb27SDimitry Andric if (const auto *RD = dyn_cast<CXXRecordDecl>(Record)) {
22406c3fb27SDimitry Andric unsigned NumNB = 0;
22506c3fb27SDimitry Andric unsigned NumVB = 0;
22606c3fb27SDimitry Andric for (const auto &I : RD->vbases()) {
22706c3fb27SDimitry Andric if (NumVB >= Known->second.VBaseOffsets.size())
22806c3fb27SDimitry Andric continue;
22906c3fb27SDimitry Andric const CXXRecordDecl *VBase = I.getType()->getAsCXXRecordDecl();
23006c3fb27SDimitry Andric VirtualBaseOffsets[VBase] = Known->second.VBaseOffsets[NumVB++];
23106c3fb27SDimitry Andric }
23206c3fb27SDimitry Andric for (const auto &I : RD->bases()) {
23306c3fb27SDimitry Andric if (I.isVirtual() || NumNB >= Known->second.BaseOffsets.size())
23406c3fb27SDimitry Andric continue;
23506c3fb27SDimitry Andric const CXXRecordDecl *Base = I.getType()->getAsCXXRecordDecl();
23606c3fb27SDimitry Andric BaseOffsets[Base] = Known->second.BaseOffsets[NumNB++];
23706c3fb27SDimitry Andric }
23806c3fb27SDimitry Andric }
23906c3fb27SDimitry Andric
2400b57cec5SDimitry Andric Size = Known->second.Size;
2410b57cec5SDimitry Andric Alignment = Known->second.Align;
2420b57cec5SDimitry Andric return true;
2430b57cec5SDimitry Andric }
2440b57cec5SDimitry Andric
dump()2450b57cec5SDimitry Andric LLVM_DUMP_METHOD void LayoutOverrideSource::dump() {
2460b57cec5SDimitry Andric raw_ostream &OS = llvm::errs();
2470b57cec5SDimitry Andric for (llvm::StringMap<Layout>::iterator L = Layouts.begin(),
2480b57cec5SDimitry Andric LEnd = Layouts.end();
2490b57cec5SDimitry Andric L != LEnd; ++L) {
2500b57cec5SDimitry Andric OS << "Type: blah " << L->first() << '\n';
2510b57cec5SDimitry Andric OS << " Size:" << L->second.Size << '\n';
2520b57cec5SDimitry Andric OS << " Alignment:" << L->second.Align << '\n';
2530b57cec5SDimitry Andric OS << " FieldOffsets: [";
2540b57cec5SDimitry Andric for (unsigned I = 0, N = L->second.FieldOffsets.size(); I != N; ++I) {
2550b57cec5SDimitry Andric if (I)
2560b57cec5SDimitry Andric OS << ", ";
2570b57cec5SDimitry Andric OS << L->second.FieldOffsets[I];
2580b57cec5SDimitry Andric }
2590b57cec5SDimitry Andric OS << "]\n";
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric }
2620b57cec5SDimitry Andric
263