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