Skip to content

Commit 403f953

Browse files
committed
[CodeView] Add full repro to LF_BUILDINFO record
This patch adds some missing information to the LF_BUILDINFO which allows for rebuilding an .OBJ without any external dependency but the .OBJ itself (other than the compiler executable). Some tools need this information to reproduce a build without any knowledge of the build system. The LF_BUILDINFO therefore stores a full path to the compiler, the PWD (which is the CWD at program startup), a relative or absolute path to the TU, and the full CC1 command line. The command line needs to be freestanding (not depend on any environment variable). In the same way, MSVC doesn't store the provided command-line, but an expanded version (somehow their equivalent of CC1) which is also freestanding. For more information see PR36198 and D43002. Differential Revision: https://reviews.llvm.org/D80833
1 parent 89ea0b0 commit 403f953

File tree

6 files changed

+364
-50
lines changed

6 files changed

+364
-50
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %clang_cl /c /Z7 /Fo%t.obj -- %s
2+
// RUN: llvm-pdbutil dump --types %t.obj | FileCheck %s
3+
// RUN: %clang_cl /c /Z7 %s /Fo%t.obj -fdebug-compilation-dir .
4+
// RUN: llvm-pdbutil dump --types %t.obj | FileCheck %s --check-prefix RELATIVE
5+
6+
int main() { return 42; }
7+
8+
// CHECK: Types (.debug$T)
9+
// CHECK: ============================================================
10+
// CHECK: 0x[[PWD:.+]] | LF_STRING_ID [size = {{.+}}] ID: <no type>, String: [[PWDVAL:.+]]
11+
// CHECK: 0x[[FILEPATH:.+]] | LF_STRING_ID [size = {{.+}}] ID: <no type>, String: [[FILEPATHVAL:.+[\\/]debug-info-codeview-buildinfo.c]]
12+
// CHECK: 0x[[TOOL:.+]] | LF_STRING_ID [size = {{.+}}] ID: <no type>, String: [[TOOLVAL:.+[\\/]clang.*]]
13+
// CHECK: 0x[[CMDLINE:.+]] | LF_STRING_ID [size = {{.+}}] ID: <no type>, String: "-cc1
14+
// CHECK: 0x{{.+}} | LF_BUILDINFO [size = {{.+}}]
15+
// CHECK: 0x[[PWD]]: `[[PWDVAL]]`
16+
// CHECK: 0x[[TOOL]]: `[[TOOLVAL]]`
17+
// CHECK: 0x[[FILEPATH]]: `[[FILEPATHVAL]]`
18+
// CHECK: <no type>: ``
19+
// CHECK: 0x[[CMDLINE]]: `"-cc1
20+
21+
// RELATIVE: Types (.debug$T)
22+
// RELATIVE: ============================================================
23+
// RELATIVE: 0x{{.+}} | LF_BUILDINFO [size = {{.+}}]
24+
// RELATIVE: 0x{{.+}}: `.`

lld/COFF/PDB.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,72 @@ static void addTypeInfo(pdb::TpiStreamBuilder &tpiBuilder,
250250
});
251251
}
252252

253+
// LF_BUILDINFO records might contain relative paths, and we want to make them
254+
// absolute. We do this remapping only after the type records were merged,
255+
// because the full types graph isn't known during merging. In addition, we plan
256+
// to multi-thread the type merging, and the change below needs to be done
257+
// atomically, single-threaded.
258+
259+
// A complication could arise when a LF_STRING_ID record already exists with the
260+
// same content as the new absolutized path. In that case, we simply redirect
261+
// LF_BUILDINFO's CurrentDirectory index to reference the existing LF_STRING_ID
262+
// record.
263+
264+
static void remapBuildInfo(TypeCollection &idTable) {
265+
SimpleTypeSerializer s;
266+
idTable.ForEachRecord([&](TypeIndex ti, const CVType &type) {
267+
if (type.kind() != LF_BUILDINFO)
268+
return;
269+
BuildInfoRecord bi;
270+
cantFail(TypeDeserializer::deserializeAs(const_cast<CVType &>(type), bi));
271+
272+
auto makeAbsoluteRecord =
273+
[&](BuildInfoRecord::BuildInfoArg recordType) -> Optional<TypeIndex> {
274+
TypeIndex recordTi = bi.getArgs()[recordType];
275+
if (recordTi.isNoneType())
276+
return None;
277+
CVType recordRef = idTable.getType(recordTi);
278+
279+
StringIdRecord record;
280+
cantFail(TypeDeserializer::deserializeAs(recordRef, record));
281+
282+
SmallString<128> abolutizedPath(record.getString());
283+
pdbMakeAbsolute(abolutizedPath);
284+
285+
if (abolutizedPath == record.getString())
286+
return None; // The path is already absolute.
287+
288+
record.String = abolutizedPath;
289+
ArrayRef<uint8_t> recordData = s.serialize(record);
290+
291+
// Replace the previous LF_STRING_ID record
292+
if (!idTable.replaceType(recordTi, CVType(recordData),
293+
/*Stabilize=*/true))
294+
return recordTi;
295+
return None;
296+
};
297+
298+
Optional<TypeIndex> curDirTI =
299+
makeAbsoluteRecord(BuildInfoRecord::CurrentDirectory);
300+
Optional<TypeIndex> buildToolTI =
301+
makeAbsoluteRecord(BuildInfoRecord::BuildTool);
302+
303+
if (curDirTI || buildToolTI) {
304+
// This new record is already there. We don't want duplicates, so
305+
// re-serialize the BuildInfoRecord instead.
306+
if (curDirTI)
307+
bi.ArgIndices[BuildInfoRecord::CurrentDirectory] = *curDirTI;
308+
if (buildToolTI)
309+
bi.ArgIndices[BuildInfoRecord::BuildTool] = *buildToolTI;
310+
311+
ArrayRef<uint8_t> biData = s.serialize(bi);
312+
bool r = idTable.replaceType(ti, CVType(biData), /*Stabilize=*/true);
313+
assert(r && "Didn't expect two build records pointing to the same OBJ!");
314+
(void)r;
315+
}
316+
});
317+
}
318+
253319
static bool remapTypeIndex(TypeIndex &ti, ArrayRef<TypeIndex> typeIndexMap) {
254320
if (ti.isSimple())
255321
return true;
@@ -988,6 +1054,9 @@ void PDBLinker::addObjectsToPDB() {
9881054
builder.getStringTableBuilder().setStrings(pdbStrTab);
9891055
t1.stop();
9901056

1057+
// Remap the contents of the LF_BUILDINFO record.
1058+
remapBuildInfo(tMerger.getIDTable());
1059+
9911060
// Construct TPI and IPI stream contents.
9921061
ScopedTimer t2(tpiStreamLayoutTimer);
9931062
addTypeInfo(builder.getTpiBuilder(), tMerger.getTypeTable());

0 commit comments

Comments
 (0)