xref: /openbsd-src/gnu/llvm/clang/lib/Frontend/LayoutOverrideSource.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===--- LayoutOverrideSource.cpp --Override Record Layouts ---------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick #include "clang/Frontend/LayoutOverrideSource.h"
9e5dd7070Spatrick #include "clang/AST/Decl.h"
10e5dd7070Spatrick #include "clang/Basic/CharInfo.h"
11e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
12e5dd7070Spatrick #include <fstream>
13e5dd7070Spatrick #include <string>
14e5dd7070Spatrick 
15e5dd7070Spatrick using namespace clang;
16e5dd7070Spatrick 
17e5dd7070Spatrick /// Parse a simple identifier.
parseName(StringRef S)18e5dd7070Spatrick static std::string parseName(StringRef S) {
19*12c85518Srobert   if (S.empty() || !isAsciiIdentifierStart(S[0]))
20e5dd7070Spatrick     return "";
21e5dd7070Spatrick 
22e5dd7070Spatrick   unsigned Offset = 1;
23*12c85518Srobert   while (Offset < S.size() && isAsciiIdentifierContinue(S[Offset]))
24e5dd7070Spatrick     ++Offset;
25e5dd7070Spatrick 
26e5dd7070Spatrick   return S.substr(0, Offset).str();
27e5dd7070Spatrick }
28e5dd7070Spatrick 
LayoutOverrideSource(StringRef Filename)29e5dd7070Spatrick LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) {
30e5dd7070Spatrick   std::ifstream Input(Filename.str().c_str());
31e5dd7070Spatrick   if (!Input.is_open())
32e5dd7070Spatrick     return;
33e5dd7070Spatrick 
34e5dd7070Spatrick   // Parse the output of -fdump-record-layouts.
35e5dd7070Spatrick   std::string CurrentType;
36e5dd7070Spatrick   Layout CurrentLayout;
37e5dd7070Spatrick   bool ExpectingType = false;
38e5dd7070Spatrick 
39e5dd7070Spatrick   while (Input.good()) {
40e5dd7070Spatrick     std::string Line;
41e5dd7070Spatrick     getline(Input, Line);
42e5dd7070Spatrick 
43e5dd7070Spatrick     StringRef LineStr(Line);
44e5dd7070Spatrick 
45e5dd7070Spatrick     // Determine whether the following line will start a
46*12c85518Srobert     if (LineStr.contains("*** Dumping AST Record Layout")) {
47e5dd7070Spatrick       // Flush the last type/layout, if there is one.
48e5dd7070Spatrick       if (!CurrentType.empty())
49e5dd7070Spatrick         Layouts[CurrentType] = CurrentLayout;
50e5dd7070Spatrick       CurrentLayout = Layout();
51e5dd7070Spatrick 
52e5dd7070Spatrick       ExpectingType = true;
53e5dd7070Spatrick       continue;
54e5dd7070Spatrick     }
55e5dd7070Spatrick 
56e5dd7070Spatrick     // If we're expecting a type, grab it.
57e5dd7070Spatrick     if (ExpectingType) {
58e5dd7070Spatrick       ExpectingType = false;
59e5dd7070Spatrick 
60e5dd7070Spatrick       StringRef::size_type Pos;
61e5dd7070Spatrick       if ((Pos = LineStr.find("struct ")) != StringRef::npos)
62e5dd7070Spatrick         LineStr = LineStr.substr(Pos + strlen("struct "));
63e5dd7070Spatrick       else if ((Pos = LineStr.find("class ")) != StringRef::npos)
64e5dd7070Spatrick         LineStr = LineStr.substr(Pos + strlen("class "));
65e5dd7070Spatrick       else if ((Pos = LineStr.find("union ")) != StringRef::npos)
66e5dd7070Spatrick         LineStr = LineStr.substr(Pos + strlen("union "));
67e5dd7070Spatrick       else
68e5dd7070Spatrick         continue;
69e5dd7070Spatrick 
70e5dd7070Spatrick       // Find the name of the type.
71e5dd7070Spatrick       CurrentType = parseName(LineStr);
72e5dd7070Spatrick       CurrentLayout = Layout();
73e5dd7070Spatrick       continue;
74e5dd7070Spatrick     }
75e5dd7070Spatrick 
76e5dd7070Spatrick     // Check for the size of the type.
77e5dd7070Spatrick     StringRef::size_type Pos = LineStr.find(" Size:");
78e5dd7070Spatrick     if (Pos != StringRef::npos) {
79e5dd7070Spatrick       // Skip past the " Size:" prefix.
80e5dd7070Spatrick       LineStr = LineStr.substr(Pos + strlen(" Size:"));
81e5dd7070Spatrick 
82e5dd7070Spatrick       unsigned long long Size = 0;
83e5dd7070Spatrick       (void)LineStr.getAsInteger(10, Size);
84e5dd7070Spatrick       CurrentLayout.Size = Size;
85e5dd7070Spatrick       continue;
86e5dd7070Spatrick     }
87e5dd7070Spatrick 
88e5dd7070Spatrick     // Check for the alignment of the type.
89e5dd7070Spatrick     Pos = LineStr.find("Alignment:");
90e5dd7070Spatrick     if (Pos != StringRef::npos) {
91e5dd7070Spatrick       // Skip past the "Alignment:" prefix.
92e5dd7070Spatrick       LineStr = LineStr.substr(Pos + strlen("Alignment:"));
93e5dd7070Spatrick 
94e5dd7070Spatrick       unsigned long long Alignment = 0;
95e5dd7070Spatrick       (void)LineStr.getAsInteger(10, Alignment);
96e5dd7070Spatrick       CurrentLayout.Align = Alignment;
97e5dd7070Spatrick       continue;
98e5dd7070Spatrick     }
99e5dd7070Spatrick 
100e5dd7070Spatrick     // Check for the size/alignment of the type.
101e5dd7070Spatrick     Pos = LineStr.find("sizeof=");
102e5dd7070Spatrick     if (Pos != StringRef::npos) {
103e5dd7070Spatrick       /* Skip past the sizeof= prefix. */
104e5dd7070Spatrick       LineStr = LineStr.substr(Pos + strlen("sizeof="));
105e5dd7070Spatrick 
106e5dd7070Spatrick       // Parse size.
107e5dd7070Spatrick       unsigned long long Size = 0;
108e5dd7070Spatrick       (void)LineStr.getAsInteger(10, Size);
109e5dd7070Spatrick       CurrentLayout.Size = Size;
110e5dd7070Spatrick 
111e5dd7070Spatrick       Pos = LineStr.find("align=");
112e5dd7070Spatrick       if (Pos != StringRef::npos) {
113e5dd7070Spatrick         /* Skip past the align= prefix. */
114e5dd7070Spatrick         LineStr = LineStr.substr(Pos + strlen("align="));
115e5dd7070Spatrick 
116e5dd7070Spatrick         // Parse alignment.
117e5dd7070Spatrick         unsigned long long Alignment = 0;
118e5dd7070Spatrick         (void)LineStr.getAsInteger(10, Alignment);
119e5dd7070Spatrick         CurrentLayout.Align = Alignment;
120e5dd7070Spatrick       }
121e5dd7070Spatrick 
122e5dd7070Spatrick       continue;
123e5dd7070Spatrick     }
124e5dd7070Spatrick 
125e5dd7070Spatrick     // Check for the field offsets of the type.
126e5dd7070Spatrick     Pos = LineStr.find("FieldOffsets: [");
127e5dd7070Spatrick     if (Pos == StringRef::npos)
128e5dd7070Spatrick       continue;
129e5dd7070Spatrick 
130e5dd7070Spatrick     LineStr = LineStr.substr(Pos + strlen("FieldOffsets: ["));
131e5dd7070Spatrick     while (!LineStr.empty() && isDigit(LineStr[0])) {
132e5dd7070Spatrick       // Parse this offset.
133e5dd7070Spatrick       unsigned Idx = 1;
134e5dd7070Spatrick       while (Idx < LineStr.size() && isDigit(LineStr[Idx]))
135e5dd7070Spatrick         ++Idx;
136e5dd7070Spatrick 
137e5dd7070Spatrick       unsigned long long Offset = 0;
138e5dd7070Spatrick       (void)LineStr.substr(0, Idx).getAsInteger(10, Offset);
139e5dd7070Spatrick 
140e5dd7070Spatrick       CurrentLayout.FieldOffsets.push_back(Offset);
141e5dd7070Spatrick 
142e5dd7070Spatrick       // Skip over this offset, the following comma, and any spaces.
143e5dd7070Spatrick       LineStr = LineStr.substr(Idx + 1);
144e5dd7070Spatrick       while (!LineStr.empty() && isWhitespace(LineStr[0]))
145e5dd7070Spatrick         LineStr = LineStr.substr(1);
146e5dd7070Spatrick     }
147e5dd7070Spatrick   }
148e5dd7070Spatrick 
149e5dd7070Spatrick   // Flush the last type/layout, if there is one.
150e5dd7070Spatrick   if (!CurrentType.empty())
151e5dd7070Spatrick     Layouts[CurrentType] = CurrentLayout;
152e5dd7070Spatrick }
153e5dd7070Spatrick 
154e5dd7070Spatrick 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)155e5dd7070Spatrick LayoutOverrideSource::layoutRecordType(const RecordDecl *Record,
156e5dd7070Spatrick   uint64_t &Size, uint64_t &Alignment,
157e5dd7070Spatrick   llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
158e5dd7070Spatrick   llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
159e5dd7070Spatrick   llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets)
160e5dd7070Spatrick {
161e5dd7070Spatrick   // We can't override unnamed declarations.
162e5dd7070Spatrick   if (!Record->getIdentifier())
163e5dd7070Spatrick     return false;
164e5dd7070Spatrick 
165e5dd7070Spatrick   // Check whether we have a layout for this record.
166e5dd7070Spatrick   llvm::StringMap<Layout>::iterator Known = Layouts.find(Record->getName());
167e5dd7070Spatrick   if (Known == Layouts.end())
168e5dd7070Spatrick     return false;
169e5dd7070Spatrick 
170e5dd7070Spatrick   // Provide field layouts.
171e5dd7070Spatrick   unsigned NumFields = 0;
172e5dd7070Spatrick   for (RecordDecl::field_iterator F = Record->field_begin(),
173e5dd7070Spatrick                                FEnd = Record->field_end();
174e5dd7070Spatrick        F != FEnd; ++F, ++NumFields) {
175e5dd7070Spatrick     if (NumFields >= Known->second.FieldOffsets.size())
176e5dd7070Spatrick       continue;
177e5dd7070Spatrick 
178e5dd7070Spatrick     FieldOffsets[*F] = Known->second.FieldOffsets[NumFields];
179e5dd7070Spatrick   }
180e5dd7070Spatrick 
181e5dd7070Spatrick   // Wrong number of fields.
182e5dd7070Spatrick   if (NumFields != Known->second.FieldOffsets.size())
183e5dd7070Spatrick     return false;
184e5dd7070Spatrick 
185e5dd7070Spatrick   Size = Known->second.Size;
186e5dd7070Spatrick   Alignment = Known->second.Align;
187e5dd7070Spatrick   return true;
188e5dd7070Spatrick }
189e5dd7070Spatrick 
dump()190e5dd7070Spatrick LLVM_DUMP_METHOD void LayoutOverrideSource::dump() {
191e5dd7070Spatrick   raw_ostream &OS = llvm::errs();
192e5dd7070Spatrick   for (llvm::StringMap<Layout>::iterator L = Layouts.begin(),
193e5dd7070Spatrick                                       LEnd = Layouts.end();
194e5dd7070Spatrick        L != LEnd; ++L) {
195e5dd7070Spatrick     OS << "Type: blah " << L->first() << '\n';
196e5dd7070Spatrick     OS << "  Size:" << L->second.Size << '\n';
197e5dd7070Spatrick     OS << "  Alignment:" << L->second.Align << '\n';
198e5dd7070Spatrick     OS << "  FieldOffsets: [";
199e5dd7070Spatrick     for (unsigned I = 0, N = L->second.FieldOffsets.size(); I != N; ++I) {
200e5dd7070Spatrick       if (I)
201e5dd7070Spatrick         OS << ", ";
202e5dd7070Spatrick       OS << L->second.FieldOffsets[I];
203e5dd7070Spatrick     }
204e5dd7070Spatrick     OS << "]\n";
205e5dd7070Spatrick   }
206e5dd7070Spatrick }
207e5dd7070Spatrick 
208