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. 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. 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 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 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 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