aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools')
-rw-r--r--contrib/llvm/tools/bugpoint/BugDriver.cpp7
-rw-r--r--contrib/llvm/tools/bugpoint/BugDriver.h7
-rw-r--r--contrib/llvm/tools/bugpoint/CrashDebugger.cpp7
-rw-r--r--contrib/llvm/tools/bugpoint/ExecutionDriver.cpp7
-rw-r--r--contrib/llvm/tools/bugpoint/ExtractFunction.cpp7
-rw-r--r--contrib/llvm/tools/bugpoint/FindBugs.cpp7
-rw-r--r--contrib/llvm/tools/bugpoint/ListReducer.h7
-rw-r--r--contrib/llvm/tools/bugpoint/Miscompilation.cpp27
-rw-r--r--contrib/llvm/tools/bugpoint/OptimizerDriver.cpp7
-rw-r--r--contrib/llvm/tools/bugpoint/ToolRunner.cpp7
-rw-r--r--contrib/llvm/tools/bugpoint/ToolRunner.h7
-rw-r--r--contrib/llvm/tools/bugpoint/bugpoint.cpp7
-rw-r--r--contrib/llvm/tools/llc/llc.cpp62
-rw-r--r--contrib/llvm/tools/lli/RemoteJITUtils.h9
-rw-r--r--contrib/llvm/tools/lli/lli.cpp97
-rw-r--r--contrib/llvm/tools/llvm-ar/llvm-ar.cpp168
-rw-r--r--contrib/llvm/tools/llvm-as/llvm-as.cpp29
-rw-r--r--contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp984
-rw-r--r--contrib/llvm/tools/llvm-cov/CodeCoverage.cpp20
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageExporter.h7
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageExporterJson.cpp69
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageExporterJson.h7
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageExporterLcov.cpp9
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageExporterLcov.h7
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageFilters.cpp7
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageFilters.h7
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageReport.cpp7
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageReport.h7
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp7
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.h7
-rw-r--r--contrib/llvm/tools/llvm-cov/CoverageViewOptions.h9
-rw-r--r--contrib/llvm/tools/llvm-cov/RenderingSupport.h7
-rw-r--r--contrib/llvm/tools/llvm-cov/SourceCoverageView.cpp11
-rw-r--r--contrib/llvm/tools/llvm-cov/SourceCoverageView.h7
-rw-r--r--contrib/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp7
-rw-r--r--contrib/llvm/tools/llvm-cov/SourceCoverageViewHTML.h7
-rw-r--r--contrib/llvm/tools/llvm-cov/SourceCoverageViewText.cpp7
-rw-r--r--contrib/llvm/tools/llvm-cov/SourceCoverageViewText.h7
-rw-r--r--contrib/llvm/tools/llvm-cov/TestingSupport.cpp20
-rw-r--r--contrib/llvm/tools/llvm-cov/gcov.cpp15
-rw-r--r--contrib/llvm/tools/llvm-cov/llvm-cov.cpp7
-rw-r--r--contrib/llvm/tools/llvm-cxxdump/Error.cpp7
-rw-r--r--contrib/llvm/tools/llvm-cxxdump/Error.h7
-rw-r--r--contrib/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp24
-rw-r--r--contrib/llvm/tools/llvm-cxxdump/llvm-cxxdump.h7
-rw-r--r--contrib/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp93
-rw-r--r--contrib/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp7
-rw-r--r--contrib/llvm/tools/llvm-diff/DiffConsumer.cpp9
-rw-r--r--contrib/llvm/tools/llvm-diff/DiffConsumer.h7
-rw-r--r--contrib/llvm/tools/llvm-diff/DiffLog.cpp7
-rw-r--r--contrib/llvm/tools/llvm-diff/DiffLog.h7
-rw-r--r--contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp9
-rw-r--r--contrib/llvm/tools/llvm-diff/DifferenceEngine.h7
-rw-r--r--contrib/llvm/tools/llvm-diff/llvm-diff.cpp7
-rw-r--r--contrib/llvm/tools/llvm-dis/llvm-dis.cpp7
-rw-r--r--contrib/llvm/tools/llvm-dwarfdump/Statistics.cpp178
-rw-r--r--contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp111
-rw-r--r--contrib/llvm/tools/llvm-extract/llvm-extract.cpp131
-rw-r--r--contrib/llvm/tools/llvm-link/llvm-link.cpp7
-rw-r--r--contrib/llvm/tools/llvm-lto/llvm-lto.cpp118
-rw-r--r--contrib/llvm/tools/llvm-lto2/llvm-lto2.cpp55
-rw-r--r--contrib/llvm/tools/llvm-mc/Disassembler.cpp7
-rw-r--r--contrib/llvm/tools/llvm-mc/Disassembler.h7
-rw-r--r--contrib/llvm/tools/llvm-mc/llvm-mc.cpp21
-rw-r--r--contrib/llvm/tools/llvm-mca/CodeRegion.cpp114
-rw-r--r--contrib/llvm/tools/llvm-mca/CodeRegion.h40
-rw-r--r--contrib/llvm/tools/llvm-mca/CodeRegionGenerator.cpp19
-rw-r--r--contrib/llvm/tools/llvm-mca/CodeRegionGenerator.h7
-rw-r--r--contrib/llvm/tools/llvm-mca/PipelinePrinter.cpp7
-rw-r--r--contrib/llvm/tools/llvm-mca/PipelinePrinter.h7
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp624
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h341
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp7
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/DispatchStatistics.h7
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp10
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/InstructionInfoView.h7
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/RegisterFileStatistics.cpp7
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h7
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp7
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/ResourcePressureView.h7
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp7
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h7
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/SchedulerStatistics.cpp37
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/SchedulerStatistics.h11
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/SummaryView.cpp25
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/SummaryView.h13
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/TimelineView.cpp7
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/TimelineView.h7
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/View.cpp7
-rw-r--r--contrib/llvm/tools/llvm-mca/Views/View.h7
-rw-r--r--contrib/llvm/tools/llvm-mca/llvm-mca.cpp56
-rw-r--r--contrib/llvm/tools/llvm-modextract/llvm-modextract.cpp7
-rw-r--r--contrib/llvm/tools/llvm-nm/llvm-nm.cpp517
-rw-r--r--contrib/llvm/tools/llvm-objcopy/Buffer.cpp50
-rw-r--r--contrib/llvm/tools/llvm-objcopy/Buffer.h16
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp158
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h12
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/Object.cpp91
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/Object.h79
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/Reader.cpp112
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/Reader.h9
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/Writer.cpp167
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/Writer.h10
-rw-r--r--contrib/llvm/tools/llvm-objcopy/CopyConfig.cpp661
-rw-r--r--contrib/llvm/tools/llvm-objcopy/CopyConfig.h130
-rw-r--r--contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp684
-rw-r--r--contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h18
-rw-r--r--contrib/llvm/tools/llvm-objcopy/ELF/Object.cpp1198
-rw-r--r--contrib/llvm/tools/llvm-objcopy/ELF/Object.h314
-rw-r--r--contrib/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp68
-rw-r--r--contrib/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h31
-rw-r--r--contrib/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp241
-rw-r--r--contrib/llvm/tools/llvm-objcopy/MachO/MachOReader.h48
-rw-r--r--contrib/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp590
-rw-r--r--contrib/llvm/tools/llvm-objcopy/MachO/MachOWriter.h64
-rw-r--r--contrib/llvm/tools/llvm-objcopy/MachO/Object.cpp15
-rw-r--r--contrib/llvm/tools/llvm-objcopy/MachO/Object.h232
-rw-r--r--contrib/llvm/tools/llvm-objcopy/ObjcopyOpts.td166
-rw-r--r--contrib/llvm/tools/llvm-objcopy/StripOpts.td61
-rw-r--r--contrib/llvm/tools/llvm-objcopy/llvm-objcopy.cpp237
-rw-r--r--contrib/llvm/tools/llvm-objcopy/llvm-objcopy.h8
-rw-r--r--contrib/llvm/tools/llvm-objdump/COFFDump.cpp82
-rw-r--r--contrib/llvm/tools/llvm-objdump/ELFDump.cpp252
-rw-r--r--contrib/llvm/tools/llvm-objdump/MachODump.cpp978
-rw-r--r--contrib/llvm/tools/llvm-objdump/WasmDump.cpp40
-rw-r--r--contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp2185
-rw-r--r--contrib/llvm/tools/llvm-objdump/llvm-objdump.h153
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp11
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp192
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h16
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/FormatUtil.cpp7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/FormatUtil.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/InputFile.cpp16
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/InputFile.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp10
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/LinePrinter.h10
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp159
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp29
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h14
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/OutputStyle.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PdbYaml.cpp10
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PdbYaml.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.cpp14
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.cpp7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/StreamUtil.cpp7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/StreamUtil.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp160
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/TypeReferenceTracker.h69
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp12
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.h7
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp43
-rw-r--r--contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h9
-rw-r--r--contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp153
-rw-r--r--contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h17
-rw-r--r--contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp21
-rw-r--r--contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.h9
-rw-r--r--contrib/llvm/tools/llvm-readobj/COFFDumper.cpp187
-rw-r--r--contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp9
-rw-r--r--contrib/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h7
-rw-r--r--contrib/llvm/tools/llvm-readobj/ELFDumper.cpp2259
-rw-r--r--contrib/llvm/tools/llvm-readobj/Error.cpp7
-rw-r--r--contrib/llvm/tools/llvm-readobj/Error.h7
-rw-r--r--contrib/llvm/tools/llvm-readobj/MachODumper.cpp43
-rw-r--r--contrib/llvm/tools/llvm-readobj/ObjDumper.cpp218
-rw-r--r--contrib/llvm/tools/llvm-readobj/ObjDumper.h56
-rw-r--r--contrib/llvm/tools/llvm-readobj/StackMapPrinter.h19
-rw-r--r--contrib/llvm/tools/llvm-readobj/WasmDumper.cpp62
-rw-r--r--contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp7
-rw-r--r--contrib/llvm/tools/llvm-readobj/Win64EHDumper.h7
-rw-r--r--contrib/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp7
-rw-r--r--contrib/llvm/tools/llvm-readobj/WindowsResourceDumper.h7
-rw-r--r--contrib/llvm/tools/llvm-readobj/XCOFFDumper.cpp190
-rw-r--r--contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp272
-rw-r--r--contrib/llvm/tools/llvm-readobj/llvm-readobj.h14
-rw-r--r--contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp361
-rw-r--r--contrib/llvm/tools/llvm-stress/llvm-stress.cpp9
-rw-r--r--contrib/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp161
-rw-r--r--contrib/llvm/tools/llvm-xray/func-id-helper.cpp21
-rw-r--r--contrib/llvm/tools/llvm-xray/func-id-helper.h7
-rw-r--r--contrib/llvm/tools/llvm-xray/llvm-xray.cpp7
-rw-r--r--contrib/llvm/tools/llvm-xray/trie-node.h7
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-account.cpp11
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-account.h19
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-color-helper.cpp7
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-color-helper.h7
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-converter.cpp11
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-converter.h7
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-extract.cpp11
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-fdr-dump.cpp18
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-graph-diff.cpp7
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-graph-diff.h7
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-graph.cpp11
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-graph.h10
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-registry.cpp7
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-registry.h7
-rw-r--r--contrib/llvm/tools/llvm-xray/xray-stacks.cpp17
-rw-r--r--contrib/llvm/tools/opt/AnalysisWrappers.cpp7
-rw-r--r--contrib/llvm/tools/opt/BreakpointPrinter.cpp11
-rw-r--r--contrib/llvm/tools/opt/BreakpointPrinter.h7
-rw-r--r--contrib/llvm/tools/opt/Debugify.cpp7
-rw-r--r--contrib/llvm/tools/opt/Debugify.h7
-rw-r--r--contrib/llvm/tools/opt/GraphPrinters.cpp7
-rw-r--r--contrib/llvm/tools/opt/NewPMDriver.cpp58
-rw-r--r--contrib/llvm/tools/opt/NewPMDriver.h14
-rw-r--r--contrib/llvm/tools/opt/PassPrinters.cpp7
-rw-r--r--contrib/llvm/tools/opt/PassPrinters.h7
-rw-r--r--contrib/llvm/tools/opt/PrintSCC.cpp7
-rw-r--r--contrib/llvm/tools/opt/opt.cpp151
230 files changed, 12548 insertions, 6685 deletions
diff --git a/contrib/llvm/tools/bugpoint/BugDriver.cpp b/contrib/llvm/tools/bugpoint/BugDriver.cpp
index 3832e075a693..942028cad80b 100644
--- a/contrib/llvm/tools/bugpoint/BugDriver.cpp
+++ b/contrib/llvm/tools/bugpoint/BugDriver.cpp
@@ -1,9 +1,8 @@
//===- BugDriver.cpp - Top-Level BugPoint class implementation ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/bugpoint/BugDriver.h b/contrib/llvm/tools/bugpoint/BugDriver.h
index bc60ae753548..75f166b21b2c 100644
--- a/contrib/llvm/tools/bugpoint/BugDriver.h
+++ b/contrib/llvm/tools/bugpoint/BugDriver.h
@@ -1,9 +1,8 @@
//===- BugDriver.h - Top-Level BugPoint class -------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/bugpoint/CrashDebugger.cpp b/contrib/llvm/tools/bugpoint/CrashDebugger.cpp
index ef6a214fde20..aab9debf9b59 100644
--- a/contrib/llvm/tools/bugpoint/CrashDebugger.cpp
+++ b/contrib/llvm/tools/bugpoint/CrashDebugger.cpp
@@ -1,9 +1,8 @@
//===- CrashDebugger.cpp - Debug compilation crashes ----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp b/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp
index 1b86b103d835..40f198b88d1a 100644
--- a/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp
+++ b/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp
@@ -1,9 +1,8 @@
//===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/bugpoint/ExtractFunction.cpp b/contrib/llvm/tools/bugpoint/ExtractFunction.cpp
index 48f1575c25eb..105702de3f1d 100644
--- a/contrib/llvm/tools/bugpoint/ExtractFunction.cpp
+++ b/contrib/llvm/tools/bugpoint/ExtractFunction.cpp
@@ -1,9 +1,8 @@
//===- ExtractFunction.cpp - Extract a function from Program --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/bugpoint/FindBugs.cpp b/contrib/llvm/tools/bugpoint/FindBugs.cpp
index a695e875b787..2b1146da9680 100644
--- a/contrib/llvm/tools/bugpoint/FindBugs.cpp
+++ b/contrib/llvm/tools/bugpoint/FindBugs.cpp
@@ -1,9 +1,8 @@
//===-- FindBugs.cpp - Run Many Different Optimizations -------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/bugpoint/ListReducer.h b/contrib/llvm/tools/bugpoint/ListReducer.h
index 0f9db022d555..04f2207a31ed 100644
--- a/contrib/llvm/tools/bugpoint/ListReducer.h
+++ b/contrib/llvm/tools/bugpoint/ListReducer.h
@@ -1,9 +1,8 @@
//===- ListReducer.h - Trim down list while retaining property --*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/bugpoint/Miscompilation.cpp b/contrib/llvm/tools/bugpoint/Miscompilation.cpp
index 375bee7a0d50..1621a51c91d6 100644
--- a/contrib/llvm/tools/bugpoint/Miscompilation.cpp
+++ b/contrib/llvm/tools/bugpoint/Miscompilation.cpp
@@ -1,9 +1,8 @@
//===- Miscompilation.cpp - Debug program miscompilations -----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -592,9 +591,6 @@ ExtractBlocks(BugDriver &BD,
if (Linker::linkModules(*ProgClone, std::move(Extracted)))
exit(1);
- // Set the new program and delete the old one.
- BD.setNewProgram(std::move(ProgClone));
-
// Update the list of miscompiled functions.
MiscompiledFunctions.clear();
@@ -604,6 +600,9 @@ ExtractBlocks(BugDriver &BD,
MiscompiledFunctions.push_back(NewF);
}
+ // Set the new program and delete the old one.
+ BD.setNewProgram(std::move(ProgClone));
+
return true;
}
@@ -706,8 +705,8 @@ static Expected<bool> TestOptimizer(BugDriver &BD, std::unique_ptr<Module> Test,
if (!Optimized) {
errs() << " Error running this sequence of passes"
<< " on the input program!\n";
- BD.setNewProgram(std::move(Test));
BD.EmitProgressBitcode(*Test, "pass-error", false);
+ BD.setNewProgram(std::move(Test));
if (Error E = BD.debugOptimizerCrash())
return std::move(E);
return false;
@@ -827,13 +826,14 @@ CleanupAndPrepareModules(BugDriver &BD, std::unique_ptr<Module> Test,
// Add the resolver to the Safe module.
// Prototype: void *getPointerToNamedFunction(const char* Name)
- Constant *resolverFunc = Safe->getOrInsertFunction(
+ FunctionCallee resolverFunc = Safe->getOrInsertFunction(
"getPointerToNamedFunction", Type::getInt8PtrTy(Safe->getContext()),
Type::getInt8PtrTy(Safe->getContext()));
// Use the function we just added to get addresses of functions we need.
for (Module::iterator F = Safe->begin(), E = Safe->end(); F != E; ++F) {
- if (F->isDeclaration() && !F->use_empty() && &*F != resolverFunc &&
+ if (F->isDeclaration() && !F->use_empty() &&
+ &*F != resolverFunc.getCallee() &&
!F->isIntrinsic() /* ignore intrinsics */) {
Function *TestFn = Test->getFunction(F->getName());
@@ -879,7 +879,8 @@ CleanupAndPrepareModules(BugDriver &BD, std::unique_ptr<Module> Test,
BasicBlock::Create(F->getContext(), "lookupfp", FuncWrapper);
// Check to see if we already looked up the value.
- Value *CachedVal = new LoadInst(Cache, "fpcache", EntryBB);
+ Value *CachedVal =
+ new LoadInst(F->getType(), Cache, "fpcache", EntryBB);
Value *IsNull = new ICmpInst(*EntryBB, ICmpInst::ICMP_EQ, CachedVal,
NullPtr, "isNull");
BranchInst::Create(LookupBB, DoCallBB, IsNull, EntryBB);
@@ -911,11 +912,11 @@ CleanupAndPrepareModules(BugDriver &BD, std::unique_ptr<Module> Test,
// Pass on the arguments to the real function, return its result
if (F->getReturnType()->isVoidTy()) {
- CallInst::Create(FuncPtr, Args, "", DoCallBB);
+ CallInst::Create(FuncTy, FuncPtr, Args, "", DoCallBB);
ReturnInst::Create(F->getContext(), DoCallBB);
} else {
CallInst *Call =
- CallInst::Create(FuncPtr, Args, "retval", DoCallBB);
+ CallInst::Create(FuncTy, FuncPtr, Args, "retval", DoCallBB);
ReturnInst::Create(F->getContext(), Call, DoCallBB);
}
diff --git a/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp b/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp
index 64fe675de20c..562de7952388 100644
--- a/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp
+++ b/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp
@@ -1,9 +1,8 @@
//===- OptimizerDriver.cpp - Allow BugPoint to run passes safely ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/bugpoint/ToolRunner.cpp b/contrib/llvm/tools/bugpoint/ToolRunner.cpp
index 7ba8ea1f16c5..da4244345e3b 100644
--- a/contrib/llvm/tools/bugpoint/ToolRunner.cpp
+++ b/contrib/llvm/tools/bugpoint/ToolRunner.cpp
@@ -1,9 +1,8 @@
//===-- ToolRunner.cpp ----------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/bugpoint/ToolRunner.h b/contrib/llvm/tools/bugpoint/ToolRunner.h
index ef8551cc669b..dde4ec539cfb 100644
--- a/contrib/llvm/tools/bugpoint/ToolRunner.h
+++ b/contrib/llvm/tools/bugpoint/ToolRunner.h
@@ -1,9 +1,8 @@
//===-- tools/bugpoint/ToolRunner.h -----------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/bugpoint/bugpoint.cpp b/contrib/llvm/tools/bugpoint/bugpoint.cpp
index f6b7d08455d4..2d5322a351ad 100644
--- a/contrib/llvm/tools/bugpoint/bugpoint.cpp
+++ b/contrib/llvm/tools/bugpoint/bugpoint.cpp
@@ -1,9 +1,8 @@
//===- bugpoint.cpp - The LLVM Bugpoint utility ---------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llc/llc.cpp b/contrib/llvm/tools/llc/llc.cpp
index 2329fb3e87c9..76da843f065e 100644
--- a/contrib/llvm/tools/llc/llc.cpp
+++ b/contrib/llvm/tools/llc/llc.cpp
@@ -1,9 +1,8 @@
//===-- llc.cpp - Implement the LLVM Native Code Generator ----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -32,6 +31,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/RemarkStreamer.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/MC/SubtargetFeature.h"
@@ -133,21 +133,33 @@ static cl::opt<bool> DiscardValueNames(
static cl::list<std::string> IncludeDirs("I", cl::desc("include search path"));
-static cl::opt<bool> PassRemarksWithHotness(
+static cl::opt<bool> RemarksWithHotness(
"pass-remarks-with-hotness",
cl::desc("With PGO, include profile count in optimization remarks"),
cl::Hidden);
-static cl::opt<unsigned> PassRemarksHotnessThreshold(
- "pass-remarks-hotness-threshold",
- cl::desc("Minimum profile count required for an optimization remark to be output"),
- cl::Hidden);
+static cl::opt<unsigned>
+ RemarksHotnessThreshold("pass-remarks-hotness-threshold",
+ cl::desc("Minimum profile count required for "
+ "an optimization remark to be output"),
+ cl::Hidden);
static cl::opt<std::string>
RemarksFilename("pass-remarks-output",
- cl::desc("YAML output filename for pass remarks"),
+ cl::desc("Output filename for pass remarks"),
cl::value_desc("filename"));
+static cl::opt<std::string>
+ RemarksPasses("pass-remarks-filter",
+ cl::desc("Only record optimization remarks from passes whose "
+ "names match the given regular expression"),
+ cl::value_desc("regex"));
+
+static cl::opt<std::string> RemarksFormat(
+ "pass-remarks-format",
+ cl::desc("The format used for serializing remarks (default: YAML)"),
+ cl::value_desc("format"), cl::init("yaml"));
+
namespace {
static ManagedStatic<std::vector<std::string>> RunPassNames;
@@ -302,6 +314,7 @@ int main(int argc, char **argv) {
initializeVectorization(*Registry);
initializeScalarizeMaskedMemIntrinPass(*Registry);
initializeExpandReductionsPass(*Registry);
+ initializeHardwareLoopsPass(*Registry);
// Initialize debugging passes.
initializeScavengerTestPass(*Registry);
@@ -319,24 +332,15 @@ int main(int argc, char **argv) {
llvm::make_unique<LLCDiagnosticHandler>(&HasError));
Context.setInlineAsmDiagnosticHandler(InlineAsmDiagHandler, &HasError);
- if (PassRemarksWithHotness)
- Context.setDiagnosticsHotnessRequested(true);
-
- if (PassRemarksHotnessThreshold)
- Context.setDiagnosticsHotnessThreshold(PassRemarksHotnessThreshold);
-
- std::unique_ptr<ToolOutputFile> YamlFile;
- if (RemarksFilename != "") {
- std::error_code EC;
- YamlFile =
- llvm::make_unique<ToolOutputFile>(RemarksFilename, EC, sys::fs::F_None);
- if (EC) {
- WithColor::error(errs(), argv[0]) << EC.message() << '\n';
- return 1;
- }
- Context.setDiagnosticsOutputFile(
- llvm::make_unique<yaml::Output>(YamlFile->os()));
+ Expected<std::unique_ptr<ToolOutputFile>> RemarksFileOrErr =
+ setupOptimizationRemarks(Context, RemarksFilename, RemarksPasses,
+ RemarksFormat, RemarksWithHotness,
+ RemarksHotnessThreshold);
+ if (Error E = RemarksFileOrErr.takeError()) {
+ WithColor::error(errs(), argv[0]) << toString(std::move(E)) << '\n';
+ return 1;
}
+ std::unique_ptr<ToolOutputFile> RemarksFile = std::move(*RemarksFileOrErr);
if (InputLanguage != "" && InputLanguage != "ir" &&
InputLanguage != "mir") {
@@ -351,8 +355,8 @@ int main(int argc, char **argv) {
if (int RetVal = compileModule(argv, Context))
return RetVal;
- if (YamlFile)
- YamlFile->keep();
+ if (RemarksFile)
+ RemarksFile->keep();
return 0;
}
diff --git a/contrib/llvm/tools/lli/RemoteJITUtils.h b/contrib/llvm/tools/lli/RemoteJITUtils.h
index 944881070c70..8e80e73c8082 100644
--- a/contrib/llvm/tools/lli/RemoteJITUtils.h
+++ b/contrib/llvm/tools/lli/RemoteJITUtils.h
@@ -1,9 +1,8 @@
//===-- RemoteJITUtils.h - Utilities for remote-JITing with LLI -*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -76,7 +75,7 @@ std::unique_ptr<FDRawChannel> launchRemote();
namespace llvm {
-// ForwardingMM - Adapter to connect MCJIT to Orc's Remote8
+// ForwardingMM - Adapter to connect MCJIT to Orc's Remote
// memory manager.
class ForwardingMemoryManager : public llvm::RTDyldMemoryManager {
public:
diff --git a/contrib/llvm/tools/lli/lli.cpp b/contrib/llvm/tools/lli/lli.cpp
index 7e93d31361aa..8c8cd88c9711 100644
--- a/contrib/llvm/tools/lli/lli.cpp
+++ b/contrib/llvm/tools/lli/lli.cpp
@@ -1,9 +1,8 @@
//===- lli.cpp - LLVM Interpreter / Dynamic compiler ----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -84,18 +83,15 @@ namespace {
cl::desc("Force interpretation: disable JIT"),
cl::init(false));
- cl::opt<JITKind> UseJITKind("jit-kind",
- cl::desc("Choose underlying JIT kind."),
- cl::init(JITKind::MCJIT),
- cl::values(
- clEnumValN(JITKind::MCJIT, "mcjit",
- "MCJIT"),
- clEnumValN(JITKind::OrcMCJITReplacement,
- "orc-mcjit",
- "Orc-based MCJIT replacement"),
- clEnumValN(JITKind::OrcLazy,
- "orc-lazy",
- "Orc-based lazy JIT.")));
+ cl::opt<JITKind> UseJITKind(
+ "jit-kind", cl::desc("Choose underlying JIT kind."),
+ cl::init(JITKind::MCJIT),
+ cl::values(clEnumValN(JITKind::MCJIT, "mcjit", "MCJIT"),
+ clEnumValN(JITKind::OrcMCJITReplacement, "orc-mcjit",
+ "Orc-based MCJIT replacement "
+ "(deprecated)"),
+ clEnumValN(JITKind::OrcLazy, "orc-lazy",
+ "Orc-based lazy JIT.")));
cl::opt<unsigned>
LazyJITCompileThreads("compile-threads",
@@ -173,7 +169,7 @@ namespace {
cl::opt<bool>
EnableCacheManager("enable-cache-manager",
- cl::desc("Use cache manager to save/load mdoules"),
+ cl::desc("Use cache manager to save/load modules"),
cl::init(false));
cl::opt<std::string>
@@ -420,7 +416,8 @@ int main(int argc, char **argv, char * const *envp) {
builder.setEngineKind(ForceInterpreter
? EngineKind::Interpreter
: EngineKind::JIT);
- builder.setUseOrcMCJITReplacement(UseJITKind == JITKind::OrcMCJITReplacement);
+ builder.setUseOrcMCJITReplacement(AcknowledgeORCv1Deprecation,
+ UseJITKind == JITKind::OrcMCJITReplacement);
// If we are supposed to override the target triple, do so now.
if (!TargetTriple.empty())
@@ -596,8 +593,8 @@ int main(int argc, char **argv, char * const *envp) {
if (!RemoteMCJIT) {
// If the program doesn't explicitly call exit, we will need the Exit
// function later on to make an explicit call, so get the function now.
- Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context),
- Type::getInt32Ty(Context));
+ FunctionCallee Exit = Mod->getOrInsertFunction(
+ "exit", Type::getVoidTy(Context), Type::getInt32Ty(Context));
// Run static constructors.
if (!ForceInterpreter) {
@@ -621,19 +618,21 @@ int main(int argc, char **argv, char * const *envp) {
// If the program didn't call exit explicitly, we should call it now.
// This ensures that any atexit handlers get called correctly.
- if (Function *ExitF = dyn_cast<Function>(Exit)) {
- std::vector<GenericValue> Args;
- GenericValue ResultGV;
- ResultGV.IntVal = APInt(32, Result);
- Args.push_back(ResultGV);
- EE->runFunction(ExitF, Args);
- WithColor::error(errs(), argv[0]) << "exit(" << Result << ") returned!\n";
- abort();
- } else {
- WithColor::error(errs(), argv[0])
- << "exit defined with wrong prototype!\n";
- abort();
+ if (Function *ExitF =
+ dyn_cast<Function>(Exit.getCallee()->stripPointerCasts())) {
+ if (ExitF->getFunctionType() == Exit.getFunctionType()) {
+ std::vector<GenericValue> Args;
+ GenericValue ResultGV;
+ ResultGV.IntVal = APInt(32, Result);
+ Args.push_back(ResultGV);
+ EE->runFunction(ExitF, Args);
+ WithColor::error(errs(), argv[0])
+ << "exit(" << Result << ") returned!\n";
+ abort();
+ }
}
+ WithColor::error(errs(), argv[0]) << "exit defined with wrong prototype!\n";
+ abort();
} else {
// else == "if (RemoteMCJIT)"
@@ -664,6 +663,7 @@ int main(int argc, char **argv, char * const *envp) {
// Forward MCJIT's symbol resolution calls to the remote.
static_cast<ForwardingMemoryManager *>(RTDyldMM)->setResolver(
orc::createLambdaResolver(
+ AcknowledgeORCv1Deprecation,
[](const std::string &Name) { return nullptr; },
[&](const std::string &Name) {
if (auto Addr = ExitOnErr(R->getSymbolAddress(Name)))
@@ -762,14 +762,17 @@ int runOrcLazyJIT(const char *ProgName) {
reportError(Err, ProgName);
const auto &TT = MainModule.getModule()->getTargetTriple();
- orc::JITTargetMachineBuilder JTMB =
+ orc::LLLazyJITBuilder Builder;
+
+ Builder.setJITTargetMachineBuilder(
TT.empty() ? ExitOnErr(orc::JITTargetMachineBuilder::detectHost())
- : orc::JITTargetMachineBuilder(Triple(TT));
+ : orc::JITTargetMachineBuilder(Triple(TT)));
if (!MArch.empty())
- JTMB.getTargetTriple().setArchName(MArch);
+ Builder.getJITTargetMachineBuilder()->getTargetTriple().setArchName(MArch);
- JTMB.setCPU(getCPUStr())
+ Builder.getJITTargetMachineBuilder()
+ ->setCPU(getCPUStr())
.addFeatures(getFeatureList())
.setRelocationModel(RelocModel.getNumOccurrences()
? Optional<Reloc::Model>(RelocModel)
@@ -778,12 +781,11 @@ int runOrcLazyJIT(const char *ProgName) {
? Optional<CodeModel::Model>(CMModel)
: None);
- DataLayout DL = ExitOnErr(JTMB.getDefaultDataLayoutForTarget());
+ Builder.setLazyCompileFailureAddr(
+ pointerToJITTargetAddress(exitOnLazyCallThroughFailure));
+ Builder.setNumCompileThreads(LazyJITCompileThreads);
- auto J = ExitOnErr(orc::LLLazyJIT::Create(
- std::move(JTMB), DL,
- pointerToJITTargetAddress(exitOnLazyCallThroughFailure),
- LazyJITCompileThreads));
+ auto J = ExitOnErr(Builder.create());
if (PerModuleLazy)
J->setPartitionFunction(orc::CompileOnDemandLayer::compileWholeModule);
@@ -799,9 +801,10 @@ int runOrcLazyJIT(const char *ProgName) {
return Dump(std::move(TSM), R);
});
J->getMainJITDylib().setGenerator(
- ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(DL)));
+ ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
+ J->getDataLayout().getGlobalPrefix())));
- orc::MangleAndInterner Mangle(J->getExecutionSession(), DL);
+ orc::MangleAndInterner Mangle(J->getExecutionSession(), J->getDataLayout());
orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides;
ExitOnErr(CXXRuntimeOverrides.enable(J->getMainJITDylib(), Mangle));
@@ -817,8 +820,10 @@ int runOrcLazyJIT(const char *ProgName) {
IdxToDylib[0] = &J->getMainJITDylib();
for (auto JDItr = JITDylibs.begin(), JDEnd = JITDylibs.end();
JDItr != JDEnd; ++JDItr) {
- IdxToDylib[JITDylibs.getPosition(JDItr - JITDylibs.begin())] =
- &J->createJITDylib(*JDItr);
+ orc::JITDylib *JD = J->getJITDylibByName(*JDItr);
+ if (!JD)
+ JD = &J->createJITDylib(*JDItr);
+ IdxToDylib[JITDylibs.getPosition(JDItr - JITDylibs.begin())] = JD;
}
for (auto EMItr = ExtraModules.begin(), EMEnd = ExtraModules.end();
@@ -861,8 +866,6 @@ int runOrcLazyJIT(const char *ProgName) {
AltEntryThreads.push_back(std::thread([EntryPoint]() { EntryPoint(); }));
}
- J->getExecutionSession().dump(llvm::dbgs());
-
// Run main.
auto MainSym = ExitOnErr(J->lookup("main"));
typedef int (*MainFnPtr)(int, const char *[]);
diff --git a/contrib/llvm/tools/llvm-ar/llvm-ar.cpp b/contrib/llvm/tools/llvm-ar/llvm-ar.cpp
index 1c453ee0b569..91746d0fab37 100644
--- a/contrib/llvm/tools/llvm-ar/llvm-ar.cpp
+++ b/contrib/llvm/tools/llvm-ar/llvm-ar.cpp
@@ -1,9 +1,8 @@
//===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -67,7 +66,7 @@ OPTIONS:
const char ArHelp[] = R"(
OVERVIEW: LLVM Archiver
-USAGE: llvm-ar [options] [-]<operation>[modifiers] [relpos] <archive> [files]
+USAGE: llvm-ar [options] [-]<operation>[modifiers] [relpos] [count] <archive> [files]
llvm-ar -M [<mri-script]
OPTIONS:
@@ -79,6 +78,7 @@ OPTIONS:
--plugin=<string> - Ignored for compatibility
--help - Display available options
--version - Display the version of this program
+ @<file> - read options from <file>
OPERATIONS:
d - delete [files] from the archive
@@ -98,7 +98,9 @@ MODIFIERS:
[i] - put [files] before [relpos] (same as [b])
[l] - ignored for compatibility
[L] - add archive's contents
+ [N] - use instance [count] of name
[o] - preserve original dates
+ [P] - use full names when matching (implied for thin archives)
[s] - create an archive index (cf. ranlib)
[S] - do not build a symbol table
[T] - create a thin archive
@@ -169,16 +171,17 @@ enum ArchiveOperation {
};
// Modifiers to follow operation to vary behavior
-static bool AddAfter = false; ///< 'a' modifier
-static bool AddBefore = false; ///< 'b' modifier
-static bool Create = false; ///< 'c' modifier
-static bool OriginalDates = false; ///< 'o' modifier
-static bool OnlyUpdate = false; ///< 'u' modifier
-static bool Verbose = false; ///< 'v' modifier
-static bool Symtab = true; ///< 's' modifier
-static bool Deterministic = true; ///< 'D' and 'U' modifiers
-static bool Thin = false; ///< 'T' modifier
-static bool AddLibrary = false; ///< 'L' modifier
+static bool AddAfter = false; ///< 'a' modifier
+static bool AddBefore = false; ///< 'b' modifier
+static bool Create = false; ///< 'c' modifier
+static bool OriginalDates = false; ///< 'o' modifier
+static bool CompareFullPath = false; ///< 'P' modifier
+static bool OnlyUpdate = false; ///< 'u' modifier
+static bool Verbose = false; ///< 'v' modifier
+static bool Symtab = true; ///< 's' modifier
+static bool Deterministic = true; ///< 'D' and 'U' modifiers
+static bool Thin = false; ///< 'T' modifier
+static bool AddLibrary = false; ///< 'L' modifier
// Relative Positional Argument (for insert/move). This variable holds
// the name of the archive member to which the 'a', 'b' or 'i' modifier
@@ -186,6 +189,11 @@ static bool AddLibrary = false; ///< 'L' modifier
// one variable.
static std::string RelPos;
+// Count parameter for 'N' modifier. This variable specifies which file should
+// match for extract/delete operations when there are multiple matches. This is
+// 1-indexed. A value of 0 is invalid, and implies 'N' is not used.
+static int CountParam = 0;
+
// This variable holds the name of the archive file as given on the
// command line.
static std::string ArchiveName;
@@ -194,6 +202,9 @@ static std::string ArchiveName;
// on the command line.
static std::vector<StringRef> Members;
+// Static buffer to hold StringRefs.
+static BumpPtrAllocator Alloc;
+
// Extract the member filename from the command line for the [relpos] argument
// associated with a, b, and i modifiers
static void getRelPos() {
@@ -203,6 +214,19 @@ static void getRelPos() {
PositionalArgs.erase(PositionalArgs.begin());
}
+// Extract the parameter from the command line for the [count] argument
+// associated with the N modifier
+static void getCountParam() {
+ if (PositionalArgs.empty())
+ fail("Expected [count] for N modifier");
+ auto CountParamArg = StringRef(PositionalArgs[0]);
+ if (CountParamArg.getAsInteger(10, CountParam))
+ fail("Value for [count] must be numeric, got: " + CountParamArg);
+ if (CountParam < 1)
+ fail("Value for [count] must be positive, got: " + CountParamArg);
+ PositionalArgs.erase(PositionalArgs.begin());
+}
+
// Get the archive file name from the command line
static void getArchive() {
if (PositionalArgs.empty())
@@ -295,6 +319,9 @@ static ArchiveOperation parseCommandLine() {
case 'o':
OriginalDates = true;
break;
+ case 'P':
+ CompareFullPath = true;
+ break;
case 's':
Symtab = true;
MaybeJustCreateSymTab = true;
@@ -329,8 +356,13 @@ static ArchiveOperation parseCommandLine() {
case 'U':
Deterministic = false;
break;
+ case 'N':
+ getCountParam();
+ break;
case 'T':
Thin = true;
+ // Thin archives store path names, so P should be forced.
+ CompareFullPath = true;
break;
case 'L':
AddLibrary = true;
@@ -362,11 +394,14 @@ static ArchiveOperation parseCommandLine() {
fail("Only one operation may be specified");
if (NumPositional > 1)
fail("You may only specify one of a, b, and i modifiers");
- if (AddAfter || AddBefore) {
+ if (AddAfter || AddBefore)
if (Operation != Move && Operation != ReplaceOrInsert)
fail("The 'a', 'b' and 'i' modifiers can only be specified with "
"the 'm' or 'r' operations");
- }
+ if (CountParam)
+ if (Operation != Extract && Operation != Delete)
+ fail("The 'N' modifier can only be specified with the 'x' or 'd' "
+ "operations");
if (OriginalDates && Operation != Extract)
fail("The 'o' modifier is only applicable to the 'x' operation");
if (OnlyUpdate && Operation != ReplaceOrInsert)
@@ -430,12 +465,19 @@ static void doDisplayTable(StringRef Name, const object::Archive::Child &C) {
}
if (C.getParent()->isThin()) {
- outs() << sys::path::parent_path(ArchiveName);
- outs() << '/';
+ if (!sys::path::is_absolute(Name)) {
+ StringRef ParentDir = sys::path::parent_path(ArchiveName);
+ if (!ParentDir.empty())
+ outs() << sys::path::convert_to_slash(ParentDir) << '/';
+ }
}
outs() << Name << "\n";
}
+static StringRef normalizePath(StringRef Path) {
+ return CompareFullPath ? Path : sys::path::filename(Path);
+}
+
// Implement the 'x' operation. This function extracts files back to the file
// system.
static void doExtract(StringRef Name, const object::Archive::Child &C) {
@@ -499,6 +541,7 @@ static void performReadOperation(ArchiveOperation Operation,
fail("extracting from a thin archive is not supported");
bool Filter = !Members.empty();
+ StringMap<int> MemberCount;
{
Error Err = Error::success();
for (auto &C : OldArchive->children(Err)) {
@@ -507,9 +550,13 @@ static void performReadOperation(ArchiveOperation Operation,
StringRef Name = NameOrErr.get();
if (Filter) {
- auto I = find(Members, Name);
+ auto I = find_if(Members, [Name](StringRef Path) {
+ return Name == normalizePath(Path);
+ });
if (I == Members.end())
continue;
+ if (CountParam && ++MemberCount[Name] != CountParam)
+ continue;
Members.erase(I);
}
@@ -545,6 +592,23 @@ static void addChildMember(std::vector<NewArchiveMember> &Members,
Expected<NewArchiveMember> NMOrErr =
NewArchiveMember::getOldMember(M, Deterministic);
failIfError(NMOrErr.takeError());
+ // If the child member we're trying to add is thin, use the path relative to
+ // the archive it's in, so the file resolves correctly.
+ if (Thin && FlattenArchive) {
+ StringSaver Saver(Alloc);
+ Expected<std::string> FileNameOrErr = M.getName();
+ failIfError(FileNameOrErr.takeError());
+ if (sys::path::is_absolute(*FileNameOrErr)) {
+ NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(*FileNameOrErr));
+ } else {
+ FileNameOrErr = M.getFullName();
+ failIfError(FileNameOrErr.takeError());
+ Expected<std::string> PathOrErr =
+ computeArchiveRelativePath(ArchiveName, *FileNameOrErr);
+ NMOrErr->MemberName = Saver.save(
+ PathOrErr ? *PathOrErr : sys::path::convert_to_slash(*FileNameOrErr));
+ }
+ }
if (FlattenArchive &&
identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
Expected<std::string> FileNameOrErr = M.getFullName();
@@ -568,6 +632,23 @@ static void addMember(std::vector<NewArchiveMember> &Members,
Expected<NewArchiveMember> NMOrErr =
NewArchiveMember::getFile(FileName, Deterministic);
failIfError(NMOrErr.takeError(), FileName);
+ StringSaver Saver(Alloc);
+ // For regular archives, use the basename of the object path for the member
+ // name. For thin archives, use the full relative paths so the file resolves
+ // correctly.
+ if (!Thin) {
+ NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
+ } else {
+ if (sys::path::is_absolute(FileName))
+ NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(FileName));
+ else {
+ Expected<std::string> PathOrErr =
+ computeArchiveRelativePath(ArchiveName, FileName);
+ NMOrErr->MemberName = Saver.save(
+ PathOrErr ? *PathOrErr : sys::path::convert_to_slash(FileName));
+ }
+ }
+
if (FlattenArchive &&
identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
object::Archive &Lib = readLibrary(FileName);
@@ -581,8 +662,6 @@ static void addMember(std::vector<NewArchiveMember> &Members,
return;
}
}
- // Use the basename of the object path for the member name.
- NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName);
Members.push_back(std::move(*NMOrErr));
}
@@ -597,27 +676,29 @@ enum InsertAction {
static InsertAction computeInsertAction(ArchiveOperation Operation,
const object::Archive::Child &Member,
StringRef Name,
- std::vector<StringRef>::iterator &Pos) {
+ std::vector<StringRef>::iterator &Pos,
+ StringMap<int> &MemberCount) {
if (Operation == QuickAppend || Members.empty())
return IA_AddOldMember;
-
- auto MI = find_if(Members, [Name](StringRef Path) {
- return Name == sys::path::filename(Path);
- });
+ auto MI = find_if(
+ Members, [Name](StringRef Path) { return Name == normalizePath(Path); });
if (MI == Members.end())
return IA_AddOldMember;
Pos = MI;
- if (Operation == Delete)
+ if (Operation == Delete) {
+ if (CountParam && ++MemberCount[Name] != CountParam)
+ return IA_AddOldMember;
return IA_Delete;
+ }
if (Operation == Move)
return IA_MoveOldMember;
if (Operation == ReplaceOrInsert) {
- StringRef PosName = sys::path::filename(RelPos);
+ StringRef PosName = normalizePath(RelPos);
if (!OnlyUpdate) {
if (PosName.empty())
return IA_AddNewMember;
@@ -651,9 +732,10 @@ computeNewArchiveMembers(ArchiveOperation Operation,
std::vector<NewArchiveMember> Ret;
std::vector<NewArchiveMember> Moved;
int InsertPos = -1;
- StringRef PosName = sys::path::filename(RelPos);
+ StringRef PosName = normalizePath(RelPos);
if (OldArchive) {
Error Err = Error::success();
+ StringMap<int> MemberCount;
for (auto &Child : OldArchive->children(Err)) {
int Pos = Ret.size();
Expected<StringRef> NameOrErr = Child.getName();
@@ -669,10 +751,10 @@ computeNewArchiveMembers(ArchiveOperation Operation,
std::vector<StringRef>::iterator MemberI = Members.end();
InsertAction Action =
- computeInsertAction(Operation, Child, Name, MemberI);
+ computeInsertAction(Operation, Child, Name, MemberI, MemberCount);
switch (Action) {
case IA_AddOldMember:
- addChildMember(Ret, Child);
+ addChildMember(Ret, Child, /*FlattenArchive=*/Thin);
break;
case IA_AddNewMember:
addMember(Ret, *MemberI);
@@ -680,13 +762,18 @@ computeNewArchiveMembers(ArchiveOperation Operation,
case IA_Delete:
break;
case IA_MoveOldMember:
- addChildMember(Moved, Child);
+ addChildMember(Moved, Child, /*FlattenArchive=*/Thin);
break;
case IA_MoveNewMember:
addMember(Moved, *MemberI);
break;
}
- if (MemberI != Members.end())
+ // When processing elements with the count param, we need to preserve the
+ // full members list when iterating over all archive members. For
+ // instance, "llvm-ar dN 2 archive.a member.o" should delete the second
+ // file named member.o it sees; we are not done with member.o the first
+ // time we see it in the archive.
+ if (MemberI != Members.end() && !CountParam)
Members.erase(MemberI);
}
failIfError(std::move(Err));
@@ -843,6 +930,8 @@ static int performOperation(ArchiveOperation Operation,
EC = errorToErrorCode(std::move(Err));
failIfError(EC,
"error loading '" + ArchiveName + "': " + EC.message() + "!");
+ if (Archive.isThin())
+ CompareFullPath = true;
performOperation(Operation, &Archive, std::move(Buf.get()), NewMembers);
return 0;
}
@@ -864,7 +953,7 @@ static int performOperation(ArchiveOperation Operation,
}
static void runMRIScript() {
- enum class MRICommand { AddLib, AddMod, Create, Delete, Save, End, Invalid };
+ enum class MRICommand { AddLib, AddMod, Create, CreateThin, Delete, Save, End, Invalid };
ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getSTDIN();
failIfError(Buf.getError());
@@ -888,6 +977,7 @@ static void runMRIScript() {
.Case("addlib", MRICommand::AddLib)
.Case("addmod", MRICommand::AddMod)
.Case("create", MRICommand::Create)
+ .Case("createthin", MRICommand::CreateThin)
.Case("delete", MRICommand::Delete)
.Case("save", MRICommand::Save)
.Case("end", MRICommand::End)
@@ -899,7 +989,7 @@ static void runMRIScript() {
{
Error Err = Error::success();
for (auto &Member : Lib.children(Err))
- addChildMember(NewMembers, Member);
+ addChildMember(NewMembers, Member, /*FlattenArchive=*/Thin);
failIfError(std::move(Err));
}
break;
@@ -907,6 +997,9 @@ static void runMRIScript() {
case MRICommand::AddMod:
addMember(NewMembers, Rest);
break;
+ case MRICommand::CreateThin:
+ Thin = true;
+ LLVM_FALLTHROUGH;
case MRICommand::Create:
Create = true;
if (!ArchiveName.empty())
@@ -916,7 +1009,7 @@ static void runMRIScript() {
ArchiveName = Rest;
break;
case MRICommand::Delete: {
- StringRef Name = sys::path::filename(Rest);
+ StringRef Name = normalizePath(Rest);
llvm::erase_if(NewMembers,
[=](NewArchiveMember &M) { return M.MemberName == Name; });
break;
@@ -951,7 +1044,6 @@ static bool handleGenericOption(StringRef arg) {
static int ar_main(int argc, char **argv) {
SmallVector<const char *, 0> Argv(argv, argv + argc);
- BumpPtrAllocator Alloc;
StringSaver Saver(Alloc);
cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv);
for (size_t i = 1; i < Argv.size(); ++i) {
diff --git a/contrib/llvm/tools/llvm-as/llvm-as.cpp b/contrib/llvm/tools/llvm-as/llvm-as.cpp
index bb4233aa9ba0..234fef907a38 100644
--- a/contrib/llvm/tools/llvm-as/llvm-as.cpp
+++ b/contrib/llvm/tools/llvm-as/llvm-as.cpp
@@ -1,9 +1,8 @@
//===--- llvm-as.cpp - The low-level LLVM assembler -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -31,38 +30,43 @@
#include <memory>
using namespace llvm;
+cl::OptionCategory AsCat("llvm-as Options");
+
static cl::opt<std::string> InputFilename(cl::Positional,
cl::desc("<input .llvm file>"),
cl::init("-"));
static cl::opt<std::string> OutputFilename("o",
cl::desc("Override output filename"),
- cl::value_desc("filename"));
+ cl::value_desc("filename"),
+ cl::cat(AsCat));
-static cl::opt<bool> Force("f", cl::desc("Enable binary output on terminals"));
+static cl::opt<bool> Force("f", cl::desc("Enable binary output on terminals"),
+ cl::cat(AsCat));
static cl::opt<bool> DisableOutput("disable-output", cl::desc("Disable output"),
- cl::init(false));
+ cl::init(false), cl::cat(AsCat));
static cl::opt<bool> EmitModuleHash("module-hash", cl::desc("Emit module hash"),
- cl::init(false));
+ cl::init(false), cl::cat(AsCat));
static cl::opt<bool> DumpAsm("d", cl::desc("Print assembly as parsed"),
- cl::Hidden);
+ cl::Hidden, cl::cat(AsCat));
static cl::opt<bool>
DisableVerify("disable-verify", cl::Hidden,
- cl::desc("Do not run verifier on input LLVM (dangerous!)"));
+ cl::desc("Do not run verifier on input LLVM (dangerous!)"),
+ cl::cat(AsCat));
static cl::opt<bool> PreserveBitcodeUseListOrder(
"preserve-bc-uselistorder",
cl::desc("Preserve use-list order when writing LLVM bitcode."),
- cl::init(true), cl::Hidden);
+ cl::init(true), cl::Hidden, cl::cat(AsCat));
static cl::opt<std::string> ClDataLayout("data-layout",
cl::desc("data layout string to use"),
cl::value_desc("layout-string"),
- cl::init(""));
+ cl::init(""), cl::cat(AsCat));
static void WriteOutputFile(const Module *M, const ModuleSummaryIndex *Index) {
// Infer the output filename if needed.
@@ -110,6 +114,7 @@ static void WriteOutputFile(const Module *M, const ModuleSummaryIndex *Index) {
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
LLVMContext Context;
+ cl::HideUnrelatedOptions(AsCat);
cl::ParseCommandLineOptions(argc, argv, "llvm .ll -> .bc assembler\n");
// Parse the file now...
diff --git a/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
index 789a666cb41a..01cba1f6e3c9 100644
--- a/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
+++ b/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
@@ -1,9 +1,8 @@
//===-- llvm-bcanalyzer.cpp - Bitcode Analyzer --------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -27,22 +26,18 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Bitcode/BitcodeReader.h"
-#include "llvm/Bitcode/BitstreamReader.h"
-#include "llvm/Bitcode/LLVMBitCodes.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Bitcode/BitcodeAnalyzer.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Format.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/SHA1.h"
-#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
+#include <memory>
using namespace llvm;
static cl::opt<std::string>
- InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
+ InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
static cl::opt<bool> Dump("dump", cl::desc("Dump low level bitcode trace"));
@@ -53,951 +48,66 @@ static cl::opt<bool> Dump("dump", cl::desc("Dump low level bitcode trace"));
static cl::opt<bool> NoHistogram("disable-histogram",
cl::desc("Do not print per-code histogram"));
-static cl::opt<bool>
-NonSymbolic("non-symbolic",
- cl::desc("Emit numeric info in dump even if"
- " symbolic info is available"));
+static cl::opt<bool> NonSymbolic("non-symbolic",
+ cl::desc("Emit numeric info in dump even if"
+ " symbolic info is available"));
static cl::opt<std::string>
- BlockInfoFilename("block-info",
- cl::desc("Use the BLOCK_INFO from the given file"));
+ BlockInfoFilename("block-info",
+ cl::desc("Use the BLOCK_INFO from the given file"));
static cl::opt<bool>
- ShowBinaryBlobs("show-binary-blobs",
- cl::desc("Print binary blobs using hex escapes"));
+ ShowBinaryBlobs("show-binary-blobs",
+ cl::desc("Print binary blobs using hex escapes"));
static cl::opt<std::string> CheckHash(
"check-hash",
cl::desc("Check module hash using the argument as a string table"));
-namespace {
-
-/// CurStreamTypeType - A type for CurStreamType
-enum CurStreamTypeType {
- UnknownBitstream,
- LLVMIRBitstream,
- ClangSerializedASTBitstream,
- ClangSerializedDiagnosticsBitstream,
-};
-
-}
-
-/// GetBlockName - Return a symbolic block name if known, otherwise return
-/// null.
-static const char *GetBlockName(unsigned BlockID,
- const BitstreamBlockInfo &BlockInfo,
- CurStreamTypeType CurStreamType) {
- // Standard blocks for all bitcode files.
- if (BlockID < bitc::FIRST_APPLICATION_BLOCKID) {
- if (BlockID == bitc::BLOCKINFO_BLOCK_ID)
- return "BLOCKINFO_BLOCK";
- return nullptr;
- }
-
- // Check to see if we have a blockinfo record for this block, with a name.
- if (const BitstreamBlockInfo::BlockInfo *Info =
- BlockInfo.getBlockInfo(BlockID)) {
- if (!Info->Name.empty())
- return Info->Name.c_str();
- }
-
-
- if (CurStreamType != LLVMIRBitstream) return nullptr;
-
- switch (BlockID) {
- default: return nullptr;
- case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID: return "OPERAND_BUNDLE_TAGS_BLOCK";
- case bitc::MODULE_BLOCK_ID: return "MODULE_BLOCK";
- case bitc::PARAMATTR_BLOCK_ID: return "PARAMATTR_BLOCK";
- case bitc::PARAMATTR_GROUP_BLOCK_ID: return "PARAMATTR_GROUP_BLOCK_ID";
- case bitc::TYPE_BLOCK_ID_NEW: return "TYPE_BLOCK_ID";
- case bitc::CONSTANTS_BLOCK_ID: return "CONSTANTS_BLOCK";
- case bitc::FUNCTION_BLOCK_ID: return "FUNCTION_BLOCK";
- case bitc::IDENTIFICATION_BLOCK_ID:
- return "IDENTIFICATION_BLOCK_ID";
- case bitc::VALUE_SYMTAB_BLOCK_ID: return "VALUE_SYMTAB";
- case bitc::METADATA_BLOCK_ID: return "METADATA_BLOCK";
- case bitc::METADATA_KIND_BLOCK_ID: return "METADATA_KIND_BLOCK";
- case bitc::METADATA_ATTACHMENT_ID: return "METADATA_ATTACHMENT_BLOCK";
- case bitc::USELIST_BLOCK_ID: return "USELIST_BLOCK_ID";
- case bitc::GLOBALVAL_SUMMARY_BLOCK_ID:
- return "GLOBALVAL_SUMMARY_BLOCK";
- case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID:
- return "FULL_LTO_GLOBALVAL_SUMMARY_BLOCK";
- case bitc::MODULE_STRTAB_BLOCK_ID: return "MODULE_STRTAB_BLOCK";
- case bitc::STRTAB_BLOCK_ID: return "STRTAB_BLOCK";
- case bitc::SYMTAB_BLOCK_ID: return "SYMTAB_BLOCK";
- }
-}
-
-/// GetCodeName - Return a symbolic code name if known, otherwise return
-/// null.
-static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
- const BitstreamBlockInfo &BlockInfo,
- CurStreamTypeType CurStreamType) {
- // Standard blocks for all bitcode files.
- if (BlockID < bitc::FIRST_APPLICATION_BLOCKID) {
- if (BlockID == bitc::BLOCKINFO_BLOCK_ID) {
- switch (CodeID) {
- default: return nullptr;
- case bitc::BLOCKINFO_CODE_SETBID: return "SETBID";
- case bitc::BLOCKINFO_CODE_BLOCKNAME: return "BLOCKNAME";
- case bitc::BLOCKINFO_CODE_SETRECORDNAME: return "SETRECORDNAME";
- }
- }
- return nullptr;
- }
-
- // Check to see if we have a blockinfo record for this record, with a name.
- if (const BitstreamBlockInfo::BlockInfo *Info =
- BlockInfo.getBlockInfo(BlockID)) {
- for (unsigned i = 0, e = Info->RecordNames.size(); i != e; ++i)
- if (Info->RecordNames[i].first == CodeID)
- return Info->RecordNames[i].second.c_str();
- }
-
-
- if (CurStreamType != LLVMIRBitstream) return nullptr;
-
-#define STRINGIFY_CODE(PREFIX, CODE) \
- case bitc::PREFIX##_##CODE: \
- return #CODE;
- switch (BlockID) {
- default: return nullptr;
- case bitc::MODULE_BLOCK_ID:
- switch (CodeID) {
- default: return nullptr;
- STRINGIFY_CODE(MODULE_CODE, VERSION)
- STRINGIFY_CODE(MODULE_CODE, TRIPLE)
- STRINGIFY_CODE(MODULE_CODE, DATALAYOUT)
- STRINGIFY_CODE(MODULE_CODE, ASM)
- STRINGIFY_CODE(MODULE_CODE, SECTIONNAME)
- STRINGIFY_CODE(MODULE_CODE, DEPLIB) // FIXME: Remove in 4.0
- STRINGIFY_CODE(MODULE_CODE, GLOBALVAR)
- STRINGIFY_CODE(MODULE_CODE, FUNCTION)
- STRINGIFY_CODE(MODULE_CODE, ALIAS)
- STRINGIFY_CODE(MODULE_CODE, GCNAME)
- STRINGIFY_CODE(MODULE_CODE, VSTOFFSET)
- STRINGIFY_CODE(MODULE_CODE, METADATA_VALUES_UNUSED)
- STRINGIFY_CODE(MODULE_CODE, SOURCE_FILENAME)
- STRINGIFY_CODE(MODULE_CODE, HASH)
- }
- case bitc::IDENTIFICATION_BLOCK_ID:
- switch (CodeID) {
- default:
- return nullptr;
- STRINGIFY_CODE(IDENTIFICATION_CODE, STRING)
- STRINGIFY_CODE(IDENTIFICATION_CODE, EPOCH)
- }
- case bitc::PARAMATTR_BLOCK_ID:
- switch (CodeID) {
- default: return nullptr;
- // FIXME: Should these be different?
- case bitc::PARAMATTR_CODE_ENTRY_OLD: return "ENTRY";
- case bitc::PARAMATTR_CODE_ENTRY: return "ENTRY";
- }
- case bitc::PARAMATTR_GROUP_BLOCK_ID:
- switch (CodeID) {
- default: return nullptr;
- case bitc::PARAMATTR_GRP_CODE_ENTRY: return "ENTRY";
- }
- case bitc::TYPE_BLOCK_ID_NEW:
- switch (CodeID) {
- default: return nullptr;
- STRINGIFY_CODE(TYPE_CODE, NUMENTRY)
- STRINGIFY_CODE(TYPE_CODE, VOID)
- STRINGIFY_CODE(TYPE_CODE, FLOAT)
- STRINGIFY_CODE(TYPE_CODE, DOUBLE)
- STRINGIFY_CODE(TYPE_CODE, LABEL)
- STRINGIFY_CODE(TYPE_CODE, OPAQUE)
- STRINGIFY_CODE(TYPE_CODE, INTEGER)
- STRINGIFY_CODE(TYPE_CODE, POINTER)
- STRINGIFY_CODE(TYPE_CODE, ARRAY)
- STRINGIFY_CODE(TYPE_CODE, VECTOR)
- STRINGIFY_CODE(TYPE_CODE, X86_FP80)
- STRINGIFY_CODE(TYPE_CODE, FP128)
- STRINGIFY_CODE(TYPE_CODE, PPC_FP128)
- STRINGIFY_CODE(TYPE_CODE, METADATA)
- STRINGIFY_CODE(TYPE_CODE, STRUCT_ANON)
- STRINGIFY_CODE(TYPE_CODE, STRUCT_NAME)
- STRINGIFY_CODE(TYPE_CODE, STRUCT_NAMED)
- STRINGIFY_CODE(TYPE_CODE, FUNCTION)
- }
-
- case bitc::CONSTANTS_BLOCK_ID:
- switch (CodeID) {
- default: return nullptr;
- STRINGIFY_CODE(CST_CODE, SETTYPE)
- STRINGIFY_CODE(CST_CODE, NULL)
- STRINGIFY_CODE(CST_CODE, UNDEF)
- STRINGIFY_CODE(CST_CODE, INTEGER)
- STRINGIFY_CODE(CST_CODE, WIDE_INTEGER)
- STRINGIFY_CODE(CST_CODE, FLOAT)
- STRINGIFY_CODE(CST_CODE, AGGREGATE)
- STRINGIFY_CODE(CST_CODE, STRING)
- STRINGIFY_CODE(CST_CODE, CSTRING)
- STRINGIFY_CODE(CST_CODE, CE_BINOP)
- STRINGIFY_CODE(CST_CODE, CE_CAST)
- STRINGIFY_CODE(CST_CODE, CE_GEP)
- STRINGIFY_CODE(CST_CODE, CE_INBOUNDS_GEP)
- STRINGIFY_CODE(CST_CODE, CE_SELECT)
- STRINGIFY_CODE(CST_CODE, CE_EXTRACTELT)
- STRINGIFY_CODE(CST_CODE, CE_INSERTELT)
- STRINGIFY_CODE(CST_CODE, CE_SHUFFLEVEC)
- STRINGIFY_CODE(CST_CODE, CE_CMP)
- STRINGIFY_CODE(CST_CODE, INLINEASM)
- STRINGIFY_CODE(CST_CODE, CE_SHUFVEC_EX)
- STRINGIFY_CODE(CST_CODE, CE_UNOP)
- case bitc::CST_CODE_BLOCKADDRESS: return "CST_CODE_BLOCKADDRESS";
- STRINGIFY_CODE(CST_CODE, DATA)
- }
- case bitc::FUNCTION_BLOCK_ID:
- switch (CodeID) {
- default: return nullptr;
- STRINGIFY_CODE(FUNC_CODE, DECLAREBLOCKS)
- STRINGIFY_CODE(FUNC_CODE, INST_BINOP)
- STRINGIFY_CODE(FUNC_CODE, INST_CAST)
- STRINGIFY_CODE(FUNC_CODE, INST_GEP_OLD)
- STRINGIFY_CODE(FUNC_CODE, INST_INBOUNDS_GEP_OLD)
- STRINGIFY_CODE(FUNC_CODE, INST_SELECT)
- STRINGIFY_CODE(FUNC_CODE, INST_EXTRACTELT)
- STRINGIFY_CODE(FUNC_CODE, INST_INSERTELT)
- STRINGIFY_CODE(FUNC_CODE, INST_SHUFFLEVEC)
- STRINGIFY_CODE(FUNC_CODE, INST_CMP)
- STRINGIFY_CODE(FUNC_CODE, INST_RET)
- STRINGIFY_CODE(FUNC_CODE, INST_BR)
- STRINGIFY_CODE(FUNC_CODE, INST_SWITCH)
- STRINGIFY_CODE(FUNC_CODE, INST_INVOKE)
- STRINGIFY_CODE(FUNC_CODE, INST_UNOP)
- STRINGIFY_CODE(FUNC_CODE, INST_UNREACHABLE)
- STRINGIFY_CODE(FUNC_CODE, INST_CLEANUPRET)
- STRINGIFY_CODE(FUNC_CODE, INST_CATCHRET)
- STRINGIFY_CODE(FUNC_CODE, INST_CATCHPAD)
- STRINGIFY_CODE(FUNC_CODE, INST_PHI)
- STRINGIFY_CODE(FUNC_CODE, INST_ALLOCA)
- STRINGIFY_CODE(FUNC_CODE, INST_LOAD)
- STRINGIFY_CODE(FUNC_CODE, INST_VAARG)
- STRINGIFY_CODE(FUNC_CODE, INST_STORE)
- STRINGIFY_CODE(FUNC_CODE, INST_EXTRACTVAL)
- STRINGIFY_CODE(FUNC_CODE, INST_INSERTVAL)
- STRINGIFY_CODE(FUNC_CODE, INST_CMP2)
- STRINGIFY_CODE(FUNC_CODE, INST_VSELECT)
- STRINGIFY_CODE(FUNC_CODE, DEBUG_LOC_AGAIN)
- STRINGIFY_CODE(FUNC_CODE, INST_CALL)
- STRINGIFY_CODE(FUNC_CODE, DEBUG_LOC)
- STRINGIFY_CODE(FUNC_CODE, INST_GEP)
- STRINGIFY_CODE(FUNC_CODE, OPERAND_BUNDLE)
- STRINGIFY_CODE(FUNC_CODE, INST_FENCE)
- STRINGIFY_CODE(FUNC_CODE, INST_ATOMICRMW)
- STRINGIFY_CODE(FUNC_CODE, INST_LOADATOMIC)
- STRINGIFY_CODE(FUNC_CODE, INST_STOREATOMIC)
- STRINGIFY_CODE(FUNC_CODE, INST_CMPXCHG)
- }
- case bitc::VALUE_SYMTAB_BLOCK_ID:
- switch (CodeID) {
- default: return nullptr;
- STRINGIFY_CODE(VST_CODE, ENTRY)
- STRINGIFY_CODE(VST_CODE, BBENTRY)
- STRINGIFY_CODE(VST_CODE, FNENTRY)
- STRINGIFY_CODE(VST_CODE, COMBINED_ENTRY)
- }
- case bitc::MODULE_STRTAB_BLOCK_ID:
- switch (CodeID) {
- default:
- return nullptr;
- STRINGIFY_CODE(MST_CODE, ENTRY)
- STRINGIFY_CODE(MST_CODE, HASH)
- }
- case bitc::GLOBALVAL_SUMMARY_BLOCK_ID:
- case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID:
- switch (CodeID) {
- default:
- return nullptr;
- STRINGIFY_CODE(FS, PERMODULE)
- STRINGIFY_CODE(FS, PERMODULE_PROFILE)
- STRINGIFY_CODE(FS, PERMODULE_RELBF)
- STRINGIFY_CODE(FS, PERMODULE_GLOBALVAR_INIT_REFS)
- STRINGIFY_CODE(FS, COMBINED)
- STRINGIFY_CODE(FS, COMBINED_PROFILE)
- STRINGIFY_CODE(FS, COMBINED_GLOBALVAR_INIT_REFS)
- STRINGIFY_CODE(FS, ALIAS)
- STRINGIFY_CODE(FS, COMBINED_ALIAS)
- STRINGIFY_CODE(FS, COMBINED_ORIGINAL_NAME)
- STRINGIFY_CODE(FS, VERSION)
- STRINGIFY_CODE(FS, FLAGS)
- STRINGIFY_CODE(FS, TYPE_TESTS)
- STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_VCALLS)
- STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_VCALLS)
- STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_CONST_VCALL)
- STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_CONST_VCALL)
- STRINGIFY_CODE(FS, VALUE_GUID)
- STRINGIFY_CODE(FS, CFI_FUNCTION_DEFS)
- STRINGIFY_CODE(FS, CFI_FUNCTION_DECLS)
- STRINGIFY_CODE(FS, TYPE_ID)
- }
- case bitc::METADATA_ATTACHMENT_ID:
- switch(CodeID) {
- default:return nullptr;
- STRINGIFY_CODE(METADATA, ATTACHMENT)
- }
- case bitc::METADATA_BLOCK_ID:
- switch(CodeID) {
- default:return nullptr;
- STRINGIFY_CODE(METADATA, STRING_OLD)
- STRINGIFY_CODE(METADATA, VALUE)
- STRINGIFY_CODE(METADATA, NODE)
- STRINGIFY_CODE(METADATA, NAME)
- STRINGIFY_CODE(METADATA, DISTINCT_NODE)
- STRINGIFY_CODE(METADATA, KIND) // Older bitcode has it in a MODULE_BLOCK
- STRINGIFY_CODE(METADATA, LOCATION)
- STRINGIFY_CODE(METADATA, OLD_NODE)
- STRINGIFY_CODE(METADATA, OLD_FN_NODE)
- STRINGIFY_CODE(METADATA, NAMED_NODE)
- STRINGIFY_CODE(METADATA, GENERIC_DEBUG)
- STRINGIFY_CODE(METADATA, SUBRANGE)
- STRINGIFY_CODE(METADATA, ENUMERATOR)
- STRINGIFY_CODE(METADATA, BASIC_TYPE)
- STRINGIFY_CODE(METADATA, FILE)
- STRINGIFY_CODE(METADATA, DERIVED_TYPE)
- STRINGIFY_CODE(METADATA, COMPOSITE_TYPE)
- STRINGIFY_CODE(METADATA, SUBROUTINE_TYPE)
- STRINGIFY_CODE(METADATA, COMPILE_UNIT)
- STRINGIFY_CODE(METADATA, SUBPROGRAM)
- STRINGIFY_CODE(METADATA, LEXICAL_BLOCK)
- STRINGIFY_CODE(METADATA, LEXICAL_BLOCK_FILE)
- STRINGIFY_CODE(METADATA, NAMESPACE)
- STRINGIFY_CODE(METADATA, TEMPLATE_TYPE)
- STRINGIFY_CODE(METADATA, TEMPLATE_VALUE)
- STRINGIFY_CODE(METADATA, GLOBAL_VAR)
- STRINGIFY_CODE(METADATA, LOCAL_VAR)
- STRINGIFY_CODE(METADATA, EXPRESSION)
- STRINGIFY_CODE(METADATA, OBJC_PROPERTY)
- STRINGIFY_CODE(METADATA, IMPORTED_ENTITY)
- STRINGIFY_CODE(METADATA, MODULE)
- STRINGIFY_CODE(METADATA, MACRO)
- STRINGIFY_CODE(METADATA, MACRO_FILE)
- STRINGIFY_CODE(METADATA, STRINGS)
- STRINGIFY_CODE(METADATA, GLOBAL_DECL_ATTACHMENT)
- STRINGIFY_CODE(METADATA, GLOBAL_VAR_EXPR)
- STRINGIFY_CODE(METADATA, INDEX_OFFSET)
- STRINGIFY_CODE(METADATA, INDEX)
- }
- case bitc::METADATA_KIND_BLOCK_ID:
- switch (CodeID) {
- default:
- return nullptr;
- STRINGIFY_CODE(METADATA, KIND)
- }
- case bitc::USELIST_BLOCK_ID:
- switch(CodeID) {
- default:return nullptr;
- case bitc::USELIST_CODE_DEFAULT: return "USELIST_CODE_DEFAULT";
- case bitc::USELIST_CODE_BB: return "USELIST_CODE_BB";
- }
-
- case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID:
- switch(CodeID) {
- default: return nullptr;
- case bitc::OPERAND_BUNDLE_TAG: return "OPERAND_BUNDLE_TAG";
- }
- case bitc::STRTAB_BLOCK_ID:
- switch(CodeID) {
- default: return nullptr;
- case bitc::STRTAB_BLOB: return "BLOB";
- }
- case bitc::SYMTAB_BLOCK_ID:
- switch(CodeID) {
- default: return nullptr;
- case bitc::SYMTAB_BLOB: return "BLOB";
- }
- }
-#undef STRINGIFY_CODE
-}
-
-struct PerRecordStats {
- unsigned NumInstances;
- unsigned NumAbbrev;
- uint64_t TotalBits;
-
- PerRecordStats() : NumInstances(0), NumAbbrev(0), TotalBits(0) {}
-};
-
-struct PerBlockIDStats {
- /// NumInstances - This the number of times this block ID has been seen.
- unsigned NumInstances;
-
- /// NumBits - The total size in bits of all of these blocks.
- uint64_t NumBits;
-
- /// NumSubBlocks - The total number of blocks these blocks contain.
- unsigned NumSubBlocks;
-
- /// NumAbbrevs - The total number of abbreviations.
- unsigned NumAbbrevs;
-
- /// NumRecords - The total number of records these blocks contain, and the
- /// number that are abbreviated.
- unsigned NumRecords, NumAbbreviatedRecords;
-
- /// CodeFreq - Keep track of the number of times we see each code.
- std::vector<PerRecordStats> CodeFreq;
-
- PerBlockIDStats()
- : NumInstances(0), NumBits(0),
- NumSubBlocks(0), NumAbbrevs(0), NumRecords(0), NumAbbreviatedRecords(0) {}
-};
-
-static std::map<unsigned, PerBlockIDStats> BlockIDStats;
-
-
-
-/// ReportError - All bitcode analysis errors go through this function, making this a
-/// good place to breakpoint if debugging.
-static bool ReportError(const Twine &Err) {
- WithColor::error() << Err << "\n";
- return true;
-}
-
-static bool decodeMetadataStringsBlob(StringRef Indent,
- ArrayRef<uint64_t> Record,
- StringRef Blob) {
- if (Blob.empty())
- return true;
-
- if (Record.size() != 2)
- return true;
-
- unsigned NumStrings = Record[0];
- unsigned StringsOffset = Record[1];
- outs() << " num-strings = " << NumStrings << " {\n";
-
- StringRef Lengths = Blob.slice(0, StringsOffset);
- SimpleBitstreamCursor R(Lengths);
- StringRef Strings = Blob.drop_front(StringsOffset);
- do {
- if (R.AtEndOfStream())
- return ReportError("bad length");
-
- unsigned Size = R.ReadVBR(6);
- if (Strings.size() < Size)
- return ReportError("truncated chars");
-
- outs() << Indent << " '";
- outs().write_escaped(Strings.slice(0, Size), /*hex=*/true);
- outs() << "'\n";
- Strings = Strings.drop_front(Size);
- } while (--NumStrings);
-
- outs() << Indent << " }";
- return false;
-}
-
-static bool decodeBlob(unsigned Code, unsigned BlockID, StringRef Indent,
- ArrayRef<uint64_t> Record, StringRef Blob) {
- if (BlockID != bitc::METADATA_BLOCK_ID)
- return true;
- if (Code != bitc::METADATA_STRINGS)
- return true;
-
- return decodeMetadataStringsBlob(Indent, Record, Blob);
-}
-
-/// ParseBlock - Read a block, updating statistics, etc.
-static bool ParseBlock(BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo,
- unsigned BlockID, unsigned IndentLevel,
- CurStreamTypeType CurStreamType) {
- std::string Indent(IndentLevel*2, ' ');
- uint64_t BlockBitStart = Stream.GetCurrentBitNo();
-
- // Get the statistics for this BlockID.
- PerBlockIDStats &BlockStats = BlockIDStats[BlockID];
-
- BlockStats.NumInstances++;
-
- // BLOCKINFO is a special part of the stream.
- bool DumpRecords = Dump;
- if (BlockID == bitc::BLOCKINFO_BLOCK_ID) {
- if (Dump) outs() << Indent << "<BLOCKINFO_BLOCK/>\n";
- Optional<BitstreamBlockInfo> NewBlockInfo =
- Stream.ReadBlockInfoBlock(/*ReadBlockInfoNames=*/true);
- if (!NewBlockInfo)
- return ReportError("Malformed BlockInfoBlock");
- BlockInfo = std::move(*NewBlockInfo);
- Stream.JumpToBit(BlockBitStart);
- // It's not really interesting to dump the contents of the blockinfo block.
- DumpRecords = false;
- }
-
- unsigned NumWords = 0;
- if (Stream.EnterSubBlock(BlockID, &NumWords))
- return ReportError("Malformed block record");
-
- // Keep it for later, when we see a MODULE_HASH record
- uint64_t BlockEntryPos = Stream.getCurrentByteNo();
-
- const char *BlockName = nullptr;
- if (DumpRecords) {
- outs() << Indent << "<";
- if ((BlockName = GetBlockName(BlockID, BlockInfo, CurStreamType)))
- outs() << BlockName;
- else
- outs() << "UnknownBlock" << BlockID;
-
- if (NonSymbolic && BlockName)
- outs() << " BlockID=" << BlockID;
-
- outs() << " NumWords=" << NumWords
- << " BlockCodeSize=" << Stream.getAbbrevIDWidth() << ">\n";
- }
-
- SmallVector<uint64_t, 64> Record;
-
- // Keep the offset to the metadata index if seen.
- uint64_t MetadataIndexOffset = 0;
-
- // Read all the records for this block.
- while (1) {
- if (Stream.AtEndOfStream())
- return ReportError("Premature end of bitstream");
-
- uint64_t RecordStartBit = Stream.GetCurrentBitNo();
-
- BitstreamEntry Entry =
- Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs);
-
- switch (Entry.Kind) {
- case BitstreamEntry::Error:
- return ReportError("malformed bitcode file");
- case BitstreamEntry::EndBlock: {
- uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
- BlockStats.NumBits += BlockBitEnd-BlockBitStart;
- if (DumpRecords) {
- outs() << Indent << "</";
- if (BlockName)
- outs() << BlockName << ">\n";
- else
- outs() << "UnknownBlock" << BlockID << ">\n";
- }
- return false;
- }
-
- case BitstreamEntry::SubBlock: {
- uint64_t SubBlockBitStart = Stream.GetCurrentBitNo();
- if (ParseBlock(Stream, BlockInfo, Entry.ID, IndentLevel + 1,
- CurStreamType))
- return true;
- ++BlockStats.NumSubBlocks;
- uint64_t SubBlockBitEnd = Stream.GetCurrentBitNo();
-
- // Don't include subblock sizes in the size of this block.
- BlockBitStart += SubBlockBitEnd-SubBlockBitStart;
- continue;
- }
- case BitstreamEntry::Record:
- // The interesting case.
- break;
- }
-
- if (Entry.ID == bitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
- ++BlockStats.NumAbbrevs;
- continue;
- }
-
- Record.clear();
-
- ++BlockStats.NumRecords;
-
- StringRef Blob;
- uint64_t CurrentRecordPos = Stream.GetCurrentBitNo();
- unsigned Code = Stream.readRecord(Entry.ID, Record, &Blob);
-
- // Increment the # occurrences of this code.
- if (BlockStats.CodeFreq.size() <= Code)
- BlockStats.CodeFreq.resize(Code+1);
- BlockStats.CodeFreq[Code].NumInstances++;
- BlockStats.CodeFreq[Code].TotalBits +=
- Stream.GetCurrentBitNo()-RecordStartBit;
- if (Entry.ID != bitc::UNABBREV_RECORD) {
- BlockStats.CodeFreq[Code].NumAbbrev++;
- ++BlockStats.NumAbbreviatedRecords;
- }
-
- if (DumpRecords) {
- outs() << Indent << " <";
- if (const char *CodeName =
- GetCodeName(Code, BlockID, BlockInfo, CurStreamType))
- outs() << CodeName;
- else
- outs() << "UnknownCode" << Code;
- if (NonSymbolic && GetCodeName(Code, BlockID, BlockInfo, CurStreamType))
- outs() << " codeid=" << Code;
- const BitCodeAbbrev *Abbv = nullptr;
- if (Entry.ID != bitc::UNABBREV_RECORD) {
- Abbv = Stream.getAbbrev(Entry.ID);
- outs() << " abbrevid=" << Entry.ID;
- }
-
- for (unsigned i = 0, e = Record.size(); i != e; ++i)
- outs() << " op" << i << "=" << (int64_t)Record[i];
-
- // If we found a metadata index, let's verify that we had an offset before
- // and validate its forward reference offset was correct!
- if (BlockID == bitc::METADATA_BLOCK_ID) {
- if (Code == bitc::METADATA_INDEX_OFFSET) {
- if (Record.size() != 2)
- outs() << "(Invalid record)";
- else {
- auto Offset = Record[0] + (Record[1] << 32);
- MetadataIndexOffset = Stream.GetCurrentBitNo() + Offset;
- }
- }
- if (Code == bitc::METADATA_INDEX) {
- outs() << " (offset ";
- if (MetadataIndexOffset == RecordStartBit)
- outs() << "match)";
- else
- outs() << "mismatch: " << MetadataIndexOffset << " vs "
- << RecordStartBit << ")";
- }
- }
-
- // If we found a module hash, let's verify that it matches!
- if (BlockID == bitc::MODULE_BLOCK_ID && Code == bitc::MODULE_CODE_HASH &&
- !CheckHash.empty()) {
- if (Record.size() != 5)
- outs() << " (invalid)";
- else {
- // Recompute the hash and compare it to the one in the bitcode
- SHA1 Hasher;
- StringRef Hash;
- Hasher.update(CheckHash);
- {
- int BlockSize = (CurrentRecordPos / 8) - BlockEntryPos;
- auto Ptr = Stream.getPointerToByte(BlockEntryPos, BlockSize);
- Hasher.update(ArrayRef<uint8_t>(Ptr, BlockSize));
- Hash = Hasher.result();
- }
- SmallString<20> RecordedHash;
- RecordedHash.resize(20);
- int Pos = 0;
- for (auto &Val : Record) {
- assert(!(Val >> 32) && "Unexpected high bits set");
- RecordedHash[Pos++] = (Val >> 24) & 0xFF;
- RecordedHash[Pos++] = (Val >> 16) & 0xFF;
- RecordedHash[Pos++] = (Val >> 8) & 0xFF;
- RecordedHash[Pos++] = (Val >> 0) & 0xFF;
- }
- if (Hash == RecordedHash)
- outs() << " (match)";
- else
- outs() << " (!mismatch!)";
- }
- }
-
- outs() << "/>";
-
- if (Abbv) {
- for (unsigned i = 1, e = Abbv->getNumOperandInfos(); i != e; ++i) {
- const BitCodeAbbrevOp &Op = Abbv->getOperandInfo(i);
- if (!Op.isEncoding() || Op.getEncoding() != BitCodeAbbrevOp::Array)
- continue;
- assert(i + 2 == e && "Array op not second to last");
- std::string Str;
- bool ArrayIsPrintable = true;
- for (unsigned j = i - 1, je = Record.size(); j != je; ++j) {
- if (!isPrint(static_cast<unsigned char>(Record[j]))) {
- ArrayIsPrintable = false;
- break;
- }
- Str += (char)Record[j];
- }
- if (ArrayIsPrintable)
- outs() << " record string = '" << Str << "'";
- break;
- }
- }
-
- if (Blob.data() && decodeBlob(Code, BlockID, Indent, Record, Blob)) {
- outs() << " blob data = ";
- if (ShowBinaryBlobs) {
- outs() << "'";
- outs().write_escaped(Blob, /*hex=*/true) << "'";
- } else {
- bool BlobIsPrintable = true;
- for (unsigned i = 0, e = Blob.size(); i != e; ++i)
- if (!isPrint(static_cast<unsigned char>(Blob[i]))) {
- BlobIsPrintable = false;
- break;
- }
-
- if (BlobIsPrintable)
- outs() << "'" << Blob << "'";
- else
- outs() << "unprintable, " << Blob.size() << " bytes.";
- }
- }
-
- outs() << "\n";
- }
-
- // Make sure that we can skip the current record.
- Stream.JumpToBit(CurrentRecordPos);
- Stream.skipRecord(Entry.ID);
- }
-}
-
-static void PrintSize(double Bits) {
- outs() << format("%.2f/%.2fB/%luW", Bits, Bits/8,(unsigned long)(Bits/32));
-}
-static void PrintSize(uint64_t Bits) {
- outs() << format("%lub/%.2fB/%luW", (unsigned long)Bits,
- (double)Bits/8, (unsigned long)(Bits/32));
+static Error reportError(StringRef Message) {
+ return createStringError(std::errc::illegal_byte_sequence, Message.data());
}
-static CurStreamTypeType ReadSignature(BitstreamCursor &Stream) {
- char Signature[6];
- Signature[0] = Stream.Read(8);
- Signature[1] = Stream.Read(8);
-
- // Autodetect the file contents, if it is one we know.
- if (Signature[0] == 'C' && Signature[1] == 'P') {
- Signature[2] = Stream.Read(8);
- Signature[3] = Stream.Read(8);
- if (Signature[2] == 'C' && Signature[3] == 'H')
- return ClangSerializedASTBitstream;
- } else if (Signature[0] == 'D' && Signature[1] == 'I') {
- Signature[2] = Stream.Read(8);
- Signature[3] = Stream.Read(8);
- if (Signature[2] == 'A' && Signature[3] == 'G')
- return ClangSerializedDiagnosticsBitstream;
- } else {
- Signature[2] = Stream.Read(4);
- Signature[3] = Stream.Read(4);
- Signature[4] = Stream.Read(4);
- Signature[5] = Stream.Read(4);
- if (Signature[0] == 'B' && Signature[1] == 'C' &&
- Signature[2] == 0x0 && Signature[3] == 0xC &&
- Signature[4] == 0xE && Signature[5] == 0xD)
- return LLVMIRBitstream;
- }
- return UnknownBitstream;
-}
-
-static bool openBitcodeFile(StringRef Path,
- std::unique_ptr<MemoryBuffer> &MemBuf,
- BitstreamCursor &Stream,
- CurStreamTypeType &CurStreamType) {
+static Expected<std::unique_ptr<MemoryBuffer>> openBitcodeFile(StringRef Path) {
// Read the input file.
- ErrorOr<std::unique_ptr<MemoryBuffer>> MemBufOrErr =
- MemoryBuffer::getFileOrSTDIN(Path);
- if (std::error_code EC = MemBufOrErr.getError())
- return ReportError(Twine("ReportError reading '") + Path + "': " + EC.message());
- MemBuf = std::move(MemBufOrErr.get());
-
- if (MemBuf->getBufferSize() & 3)
- return ReportError("Bitcode stream should be a multiple of 4 bytes in length");
-
- const unsigned char *BufPtr = (const unsigned char *)MemBuf->getBufferStart();
- const unsigned char *EndBufPtr = BufPtr + MemBuf->getBufferSize();
+ Expected<std::unique_ptr<MemoryBuffer>> MemBufOrErr =
+ errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Path));
+ if (Error E = MemBufOrErr.takeError())
+ return std::move(E);
- // If we have a wrapper header, parse it and ignore the non-bc file contents.
- // The magic number is 0x0B17C0DE stored in little endian.
- if (isBitcodeWrapper(BufPtr, EndBufPtr)) {
- if (MemBuf->getBufferSize() < BWH_HeaderSize)
- return ReportError("Invalid bitcode wrapper header");
+ std::unique_ptr<MemoryBuffer> MemBuf = std::move(*MemBufOrErr);
- if (Dump) {
- unsigned Magic = support::endian::read32le(&BufPtr[BWH_MagicField]);
- unsigned Version = support::endian::read32le(&BufPtr[BWH_VersionField]);
- unsigned Offset = support::endian::read32le(&BufPtr[BWH_OffsetField]);
- unsigned Size = support::endian::read32le(&BufPtr[BWH_SizeField]);
- unsigned CPUType = support::endian::read32le(&BufPtr[BWH_CPUTypeField]);
-
- outs() << "<BITCODE_WRAPPER_HEADER"
- << " Magic=" << format_hex(Magic, 10)
- << " Version=" << format_hex(Version, 10)
- << " Offset=" << format_hex(Offset, 10)
- << " Size=" << format_hex(Size, 10)
- << " CPUType=" << format_hex(CPUType, 10) << "/>\n";
- }
-
- if (SkipBitcodeWrapperHeader(BufPtr, EndBufPtr, true))
- return ReportError("Invalid bitcode wrapper header");
- }
-
- Stream = BitstreamCursor(ArrayRef<uint8_t>(BufPtr, EndBufPtr));
- CurStreamType = ReadSignature(Stream);
-
- return false;
+ if (MemBuf->getBufferSize() & 3)
+ return reportError(
+ "Bitcode stream should be a multiple of 4 bytes in length");
+ return std::move(MemBuf);
}
-/// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename.
-static int AnalyzeBitcode() {
- std::unique_ptr<MemoryBuffer> StreamBuffer;
- BitstreamCursor Stream;
- BitstreamBlockInfo BlockInfo;
- CurStreamTypeType CurStreamType;
- if (openBitcodeFile(InputFilename, StreamBuffer, Stream, CurStreamType))
- return true;
- Stream.setBlockInfo(&BlockInfo);
-
- // Read block info from BlockInfoFilename, if specified.
- // The block info must be a top-level block.
- if (!BlockInfoFilename.empty()) {
- std::unique_ptr<MemoryBuffer> BlockInfoBuffer;
- BitstreamCursor BlockInfoCursor;
- CurStreamTypeType BlockInfoStreamType;
- if (openBitcodeFile(BlockInfoFilename, BlockInfoBuffer, BlockInfoCursor,
- BlockInfoStreamType))
- return true;
-
- while (!BlockInfoCursor.AtEndOfStream()) {
- unsigned Code = BlockInfoCursor.ReadCode();
- if (Code != bitc::ENTER_SUBBLOCK)
- return ReportError("Invalid record at top-level in block info file");
-
- unsigned BlockID = BlockInfoCursor.ReadSubBlockID();
- if (BlockID == bitc::BLOCKINFO_BLOCK_ID) {
- Optional<BitstreamBlockInfo> NewBlockInfo =
- BlockInfoCursor.ReadBlockInfoBlock(/*ReadBlockInfoNames=*/true);
- if (!NewBlockInfo)
- return ReportError("Malformed BlockInfoBlock in block info file");
- BlockInfo = std::move(*NewBlockInfo);
- break;
- }
-
- BlockInfoCursor.SkipBlock();
- }
- }
-
- unsigned NumTopBlocks = 0;
-
- // Parse the top-level structure. We only allow blocks at the top-level.
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
- if (Code != bitc::ENTER_SUBBLOCK)
- return ReportError("Invalid record at top-level");
-
- unsigned BlockID = Stream.ReadSubBlockID();
-
- if (ParseBlock(Stream, BlockInfo, BlockID, 0, CurStreamType))
- return true;
- ++NumTopBlocks;
- }
-
- if (Dump) outs() << "\n\n";
-
- uint64_t BufferSizeBits = Stream.getBitcodeBytes().size() * CHAR_BIT;
- // Print a summary of the read file.
- outs() << "Summary of " << InputFilename << ":\n";
- outs() << " Total size: ";
- PrintSize(BufferSizeBits);
- outs() << "\n";
- outs() << " Stream type: ";
- switch (CurStreamType) {
- case UnknownBitstream:
- outs() << "unknown\n";
- break;
- case LLVMIRBitstream:
- outs() << "LLVM IR\n";
- break;
- case ClangSerializedASTBitstream:
- outs() << "Clang Serialized AST\n";
- break;
- case ClangSerializedDiagnosticsBitstream:
- outs() << "Clang Serialized Diagnostics\n";
- break;
- }
- outs() << " # Toplevel Blocks: " << NumTopBlocks << "\n";
- outs() << "\n";
-
- // Emit per-block stats.
- outs() << "Per-block Summary:\n";
- for (std::map<unsigned, PerBlockIDStats>::iterator I = BlockIDStats.begin(),
- E = BlockIDStats.end(); I != E; ++I) {
- outs() << " Block ID #" << I->first;
- if (const char *BlockName =
- GetBlockName(I->first, BlockInfo, CurStreamType))
- outs() << " (" << BlockName << ")";
- outs() << ":\n";
-
- const PerBlockIDStats &Stats = I->second;
- outs() << " Num Instances: " << Stats.NumInstances << "\n";
- outs() << " Total Size: ";
- PrintSize(Stats.NumBits);
- outs() << "\n";
- double pct = (Stats.NumBits * 100.0) / BufferSizeBits;
- outs() << " Percent of file: " << format("%2.4f%%", pct) << "\n";
- if (Stats.NumInstances > 1) {
- outs() << " Average Size: ";
- PrintSize(Stats.NumBits/(double)Stats.NumInstances);
- outs() << "\n";
- outs() << " Tot/Avg SubBlocks: " << Stats.NumSubBlocks << "/"
- << Stats.NumSubBlocks/(double)Stats.NumInstances << "\n";
- outs() << " Tot/Avg Abbrevs: " << Stats.NumAbbrevs << "/"
- << Stats.NumAbbrevs/(double)Stats.NumInstances << "\n";
- outs() << " Tot/Avg Records: " << Stats.NumRecords << "/"
- << Stats.NumRecords/(double)Stats.NumInstances << "\n";
- } else {
- outs() << " Num SubBlocks: " << Stats.NumSubBlocks << "\n";
- outs() << " Num Abbrevs: " << Stats.NumAbbrevs << "\n";
- outs() << " Num Records: " << Stats.NumRecords << "\n";
- }
- if (Stats.NumRecords) {
- double pct = (Stats.NumAbbreviatedRecords * 100.0) / Stats.NumRecords;
- outs() << " Percent Abbrevs: " << format("%2.4f%%", pct) << "\n";
- }
- outs() << "\n";
-
- // Print a histogram of the codes we see.
- if (!NoHistogram && !Stats.CodeFreq.empty()) {
- std::vector<std::pair<unsigned, unsigned> > FreqPairs; // <freq,code>
- for (unsigned i = 0, e = Stats.CodeFreq.size(); i != e; ++i)
- if (unsigned Freq = Stats.CodeFreq[i].NumInstances)
- FreqPairs.push_back(std::make_pair(Freq, i));
- std::stable_sort(FreqPairs.begin(), FreqPairs.end());
- std::reverse(FreqPairs.begin(), FreqPairs.end());
+int main(int argc, char **argv) {
+ InitLLVM X(argc, argv);
+ cl::ParseCommandLineOptions(argc, argv, "llvm-bcanalyzer file analyzer\n");
+ ExitOnError ExitOnErr("llvm-bcanalyzer: ");
- outs() << "\tRecord Histogram:\n";
- outs() << "\t\t Count # Bits b/Rec % Abv Record Kind\n";
- for (unsigned i = 0, e = FreqPairs.size(); i != e; ++i) {
- const PerRecordStats &RecStats = Stats.CodeFreq[FreqPairs[i].second];
+ std::unique_ptr<MemoryBuffer> MB = ExitOnErr(openBitcodeFile(InputFilename));
+ std::unique_ptr<MemoryBuffer> BlockInfoMB = nullptr;
+ if (!BlockInfoFilename.empty())
+ BlockInfoMB = ExitOnErr(openBitcodeFile(BlockInfoFilename));
- outs() << format("\t\t%7d %9lu",
- RecStats.NumInstances,
- (unsigned long)RecStats.TotalBits);
+ BitcodeAnalyzer BA(MB->getBuffer(),
+ BlockInfoMB ? Optional<StringRef>(BlockInfoMB->getBuffer())
+ : None);
- if (RecStats.NumInstances > 1)
- outs() << format(" %9.1f",
- (double)RecStats.TotalBits/RecStats.NumInstances);
- else
- outs() << " ";
+ BCDumpOptions O(outs());
+ O.Histogram = !NoHistogram;
+ O.Symbolic = !NonSymbolic;
+ O.ShowBinaryBlobs = ShowBinaryBlobs;
- if (RecStats.NumAbbrev)
- outs() <<
- format(" %7.2f",
- (double)RecStats.NumAbbrev/RecStats.NumInstances*100);
- else
- outs() << " ";
+ ExitOnErr(
+ BA.analyze(O, CheckHash.empty() ? None : Optional<StringRef>(CheckHash)));
- outs() << " ";
- if (const char *CodeName = GetCodeName(FreqPairs[i].second, I->first,
- BlockInfo, CurStreamType))
- outs() << CodeName << "\n";
- else
- outs() << "UnknownCode" << FreqPairs[i].second << "\n";
- }
- outs() << "\n";
+ if (Dump)
+ outs() << "\n\n";
- }
- }
+ BA.printStats(O, StringRef(InputFilename.getValue()));
return 0;
}
-
-
-int main(int argc, char **argv) {
- InitLLVM X(argc, argv);
- cl::ParseCommandLineOptions(argc, argv, "llvm-bcanalyzer file analyzer\n");
- return AnalyzeBitcode();
-}
diff --git a/contrib/llvm/tools/llvm-cov/CodeCoverage.cpp b/contrib/llvm/tools/llvm-cov/CodeCoverage.cpp
index 728e00e7c3c2..f707e3c7ab53 100644
--- a/contrib/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/contrib/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -1,9 +1,8 @@
//===- CodeCoverage.cpp - Coverage tool based on profiling instrumentation-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -1007,10 +1006,23 @@ int CodeCoverageTool::doReport(int argc, const char **argv,
int CodeCoverageTool::doExport(int argc, const char **argv,
CommandLineParserType commandLineParser) {
+ cl::OptionCategory ExportCategory("Exporting options");
+
+ cl::opt<bool> SkipExpansions("skip-expansions", cl::Optional,
+ cl::desc("Don't export expanded source regions"),
+ cl::cat(ExportCategory));
+
+ cl::opt<bool> SkipFunctions("skip-functions", cl::Optional,
+ cl::desc("Don't export per-function data"),
+ cl::cat(ExportCategory));
+
auto Err = commandLineParser(argc, argv);
if (Err)
return Err;
+ ViewOpts.SkipExpansions = SkipExpansions;
+ ViewOpts.SkipFunctions = SkipFunctions;
+
if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text &&
ViewOpts.Format != CoverageViewOptions::OutputFormat::Lcov) {
error("Coverage data can only be exported as textual JSON or an "
diff --git a/contrib/llvm/tools/llvm-cov/CoverageExporter.h b/contrib/llvm/tools/llvm-cov/CoverageExporter.h
index b226d68813d9..751e55dc0916 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageExporter.h
+++ b/contrib/llvm/tools/llvm-cov/CoverageExporter.h
@@ -1,9 +1,8 @@
//===- CoverageExporter.h - Code coverage exporter ------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-cov/CoverageExporterJson.cpp b/contrib/llvm/tools/llvm-cov/CoverageExporterJson.cpp
index 22243f8e2c3e..181d428ed9d8 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageExporterJson.cpp
+++ b/contrib/llvm/tools/llvm-cov/CoverageExporterJson.cpp
@@ -1,9 +1,8 @@
//===- CoverageExporterJson.cpp - Code coverage export --------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -43,7 +42,14 @@
#include "CoverageExporterJson.h"
#include "CoverageReport.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/JSON.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/Threading.h"
+#include <algorithm>
+#include <mutex>
+#include <utility>
/// The semantic version combined as a string.
#define LLVM_COVERAGE_EXPORT_JSON_STR "2.0.0"
@@ -128,13 +134,15 @@ json::Array renderFileSegments(const coverage::CoverageData &FileCoverage,
json::Object renderFile(const coverage::CoverageMapping &Coverage,
const std::string &Filename,
const FileCoverageSummary &FileReport,
- bool ExportSummaryOnly) {
+ const CoverageViewOptions &Options) {
json::Object File({{"filename", Filename}});
- if (!ExportSummaryOnly) {
+ if (!Options.ExportSummaryOnly) {
// Calculate and render detailed coverage information for given file.
auto FileCoverage = Coverage.getCoverageForFile(Filename);
File["segments"] = renderFileSegments(FileCoverage, FileReport);
- File["expansions"] = renderFileExpansions(FileCoverage, FileReport);
+ if (!Options.SkipExpansions) {
+ File["expansions"] = renderFileExpansions(FileCoverage, FileReport);
+ }
}
File["summary"] = renderSummary(FileReport);
return File;
@@ -143,11 +151,28 @@ json::Object renderFile(const coverage::CoverageMapping &Coverage,
json::Array renderFiles(const coverage::CoverageMapping &Coverage,
ArrayRef<std::string> SourceFiles,
ArrayRef<FileCoverageSummary> FileReports,
- bool ExportSummaryOnly) {
+ const CoverageViewOptions &Options) {
+ auto NumThreads = Options.NumThreads;
+ if (NumThreads == 0) {
+ NumThreads = std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(),
+ unsigned(SourceFiles.size())));
+ }
+ ThreadPool Pool(NumThreads);
json::Array FileArray;
- for (unsigned I = 0, E = SourceFiles.size(); I < E; ++I)
- FileArray.push_back(renderFile(Coverage, SourceFiles[I], FileReports[I],
- ExportSummaryOnly));
+ std::mutex FileArrayMutex;
+
+ for (unsigned I = 0, E = SourceFiles.size(); I < E; ++I) {
+ auto &SourceFile = SourceFiles[I];
+ auto &FileReport = FileReports[I];
+ Pool.async([&] {
+ auto File = renderFile(Coverage, SourceFile, FileReport, Options);
+ {
+ std::lock_guard<std::mutex> Lock(FileArrayMutex);
+ FileArray.push_back(std::move(File));
+ }
+ });
+ }
+ Pool.wait();
return FileArray;
}
@@ -178,12 +203,22 @@ void CoverageExporterJson::renderRoot(ArrayRef<std::string> SourceFiles) {
FileCoverageSummary Totals = FileCoverageSummary("Totals");
auto FileReports = CoverageReport::prepareFileReports(Coverage, Totals,
SourceFiles, Options);
- auto Export =
- json::Object({{"files", renderFiles(Coverage, SourceFiles, FileReports,
- Options.ExportSummaryOnly)},
- {"totals", renderSummary(Totals)}});
- // Skip functions-level information for summary-only export mode.
- if (!Options.ExportSummaryOnly)
+ auto Files = renderFiles(Coverage, SourceFiles, FileReports, Options);
+ // Sort files in order of their names.
+ std::sort(Files.begin(), Files.end(),
+ [](const json::Value &A, const json::Value &B) {
+ const json::Object *ObjA = A.getAsObject();
+ const json::Object *ObjB = B.getAsObject();
+ assert(ObjA != nullptr && "Value A was not an Object");
+ assert(ObjB != nullptr && "Value B was not an Object");
+ const StringRef FilenameA = ObjA->getString("filename").getValue();
+ const StringRef FilenameB = ObjB->getString("filename").getValue();
+ return FilenameA.compare(FilenameB) < 0;
+ });
+ auto Export = json::Object(
+ {{"files", std::move(Files)}, {"totals", renderSummary(Totals)}});
+ // Skip functions-level information if necessary.
+ if (!Options.ExportSummaryOnly && !Options.SkipFunctions)
Export["functions"] = renderFunctions(Coverage.getCoveredFunctions());
auto ExportArray = json::Array({std::move(Export)});
diff --git a/contrib/llvm/tools/llvm-cov/CoverageExporterJson.h b/contrib/llvm/tools/llvm-cov/CoverageExporterJson.h
index c37c86b42be9..c19475005552 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageExporterJson.h
+++ b/contrib/llvm/tools/llvm-cov/CoverageExporterJson.h
@@ -1,9 +1,8 @@
//===- CoverageExporterJson.h - Code coverage JSON exporter ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-cov/CoverageExporterLcov.cpp b/contrib/llvm/tools/llvm-cov/CoverageExporterLcov.cpp
index d149ba1a4c87..d9b0c3b0d7a8 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageExporterLcov.cpp
+++ b/contrib/llvm/tools/llvm-cov/CoverageExporterLcov.cpp
@@ -1,9 +1,8 @@
//===- CoverageExporterLcov.cpp - Code coverage export --------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -83,7 +82,7 @@ void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
OS << "SF:" << Filename << '\n';
if (!ExportSummaryOnly) {
- renderFunctions(OS, Coverage.getCoveredFunctions());
+ renderFunctions(OS, Coverage.getCoveredFunctions(Filename));
}
renderFunctionSummary(OS, FileReport);
diff --git a/contrib/llvm/tools/llvm-cov/CoverageExporterLcov.h b/contrib/llvm/tools/llvm-cov/CoverageExporterLcov.h
index 539b2dacd384..e8a260bf4937 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageExporterLcov.h
+++ b/contrib/llvm/tools/llvm-cov/CoverageExporterLcov.h
@@ -1,9 +1,8 @@
//===- CoverageExporterLcov.h - Code coverage lcov exporter ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-cov/CoverageFilters.cpp b/contrib/llvm/tools/llvm-cov/CoverageFilters.cpp
index 4dd0f552c7e0..ca241e386e87 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageFilters.cpp
+++ b/contrib/llvm/tools/llvm-cov/CoverageFilters.cpp
@@ -1,9 +1,8 @@
//===- CoverageFilters.cpp - Function coverage mapping filters ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-cov/CoverageFilters.h b/contrib/llvm/tools/llvm-cov/CoverageFilters.h
index 6424ca5a8081..ce56e1607111 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageFilters.h
+++ b/contrib/llvm/tools/llvm-cov/CoverageFilters.h
@@ -1,9 +1,8 @@
//===- CoverageFilters.h - Function coverage mapping filters --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-cov/CoverageReport.cpp b/contrib/llvm/tools/llvm-cov/CoverageReport.cpp
index 607a3ceb30cb..82259542c597 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageReport.cpp
+++ b/contrib/llvm/tools/llvm-cov/CoverageReport.cpp
@@ -1,9 +1,8 @@
//===- CoverageReport.cpp - Code coverage report -------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-cov/CoverageReport.h b/contrib/llvm/tools/llvm-cov/CoverageReport.h
index 4a6527e9fe5d..f9a092f510b5 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageReport.h
+++ b/contrib/llvm/tools/llvm-cov/CoverageReport.h
@@ -1,9 +1,8 @@
//===- CoverageReport.h - Code coverage report ----------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp b/contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
index 7847a2abf48c..1029f7784040 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
+++ b/contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
@@ -1,9 +1,8 @@
//===- CoverageSummaryInfo.cpp - Coverage summary for function/file -------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.h b/contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.h
index 0845e2ce2e77..97beacb26d07 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/contrib/llvm/tools/llvm-cov/CoverageSummaryInfo.h
@@ -1,9 +1,8 @@
//===- CoverageSummaryInfo.h - Coverage summary for function/file ---------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-cov/CoverageViewOptions.h b/contrib/llvm/tools/llvm-cov/CoverageViewOptions.h
index c8a472860027..dde0c692ab05 100644
--- a/contrib/llvm/tools/llvm-cov/CoverageViewOptions.h
+++ b/contrib/llvm/tools/llvm-cov/CoverageViewOptions.h
@@ -1,9 +1,8 @@
//===- CoverageViewOptions.h - Code coverage display options -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -35,6 +34,8 @@ struct CoverageViewOptions {
bool ShowRegionSummary;
bool ShowInstantiationSummary;
bool ExportSummaryOnly;
+ bool SkipExpansions;
+ bool SkipFunctions;
OutputFormat Format;
std::string ShowOutputDirectory;
std::vector<std::string> DemanglerOpts;
diff --git a/contrib/llvm/tools/llvm-cov/RenderingSupport.h b/contrib/llvm/tools/llvm-cov/RenderingSupport.h
index 2cfe24919142..0674fbac9a3c 100644
--- a/contrib/llvm/tools/llvm-cov/RenderingSupport.h
+++ b/contrib/llvm/tools/llvm-cov/RenderingSupport.h
@@ -1,9 +1,8 @@
//===- RenderingSupport.h - output stream rendering support functions ----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-cov/SourceCoverageView.cpp b/contrib/llvm/tools/llvm-cov/SourceCoverageView.cpp
index cebaf63adb12..616f667e2c84 100644
--- a/contrib/llvm/tools/llvm-cov/SourceCoverageView.cpp
+++ b/contrib/llvm/tools/llvm-cov/SourceCoverageView.cpp
@@ -1,9 +1,8 @@
//===- SourceCoverageView.cpp - Code coverage view for source code --------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -190,8 +189,8 @@ void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
// We need the expansions and instantiations sorted so we can go through them
// while we iterate lines.
- std::stable_sort(ExpansionSubViews.begin(), ExpansionSubViews.end());
- std::stable_sort(InstantiationSubViews.begin(), InstantiationSubViews.end());
+ llvm::stable_sort(ExpansionSubViews);
+ llvm::stable_sort(InstantiationSubViews);
auto NextESV = ExpansionSubViews.begin();
auto EndESV = ExpansionSubViews.end();
auto NextISV = InstantiationSubViews.begin();
diff --git a/contrib/llvm/tools/llvm-cov/SourceCoverageView.h b/contrib/llvm/tools/llvm-cov/SourceCoverageView.h
index e3a2f9e5c0b4..9ae928443651 100644
--- a/contrib/llvm/tools/llvm-cov/SourceCoverageView.h
+++ b/contrib/llvm/tools/llvm-cov/SourceCoverageView.h
@@ -1,9 +1,8 @@
//===- SourceCoverageView.h - Code coverage view for source code ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
diff --git a/contrib/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/contrib/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
index 3f730bb7bc82..e3332245f9c8 100644
--- a/contrib/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/contrib/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -1,9 +1,8 @@
//===- SourceCoverageViewHTML.cpp - A html code coverage view -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
diff --git a/contrib/llvm/tools/llvm-cov/SourceCoverageViewHTML.h b/contrib/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
index cb41fcaf37b9..9834040008a6 100644
--- a/contrib/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
+++ b/contrib/llvm/tools/llvm-cov/SourceCoverageViewHTML.h
@@ -1,9 +1,8 @@
//===- SourceCoverageViewHTML.h - A html code coverage view ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
diff --git a/contrib/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/contrib/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
index aac70baed613..fcabee2ee69d 100644
--- a/contrib/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/contrib/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -1,9 +1,8 @@
//===- SourceCoverageViewText.cpp - A text-based code coverage view -------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
diff --git a/contrib/llvm/tools/llvm-cov/SourceCoverageViewText.h b/contrib/llvm/tools/llvm-cov/SourceCoverageViewText.h
index a46f35cc6495..c8c4632c3b9d 100644
--- a/contrib/llvm/tools/llvm-cov/SourceCoverageViewText.h
+++ b/contrib/llvm/tools/llvm-cov/SourceCoverageViewText.h
@@ -1,9 +1,8 @@
//===- SourceCoverageViewText.h - A text-based code coverage view ---------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
diff --git a/contrib/llvm/tools/llvm-cov/TestingSupport.cpp b/contrib/llvm/tools/llvm-cov/TestingSupport.cpp
index 16a1c2665299..3ee318c9c640 100644
--- a/contrib/llvm/tools/llvm-cov/TestingSupport.cpp
+++ b/contrib/llvm/tools/llvm-cov/TestingSupport.cpp
@@ -1,9 +1,8 @@
//===- TestingSupport.cpp - Convert objects files into test files --------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -70,9 +69,18 @@ int convertForTestingMain(int argc, const char *argv[]) {
uint64_t ProfileNamesAddress = ProfileNames.getAddress();
StringRef CoverageMappingData;
StringRef ProfileNamesData;
- if (CoverageMapping.getContents(CoverageMappingData) ||
- ProfileNames.getContents(ProfileNamesData))
+ if (Expected<StringRef> E = CoverageMapping.getContents())
+ CoverageMappingData = *E;
+ else {
+ consumeError(E.takeError());
+ return 1;
+ }
+ if (Expected<StringRef> E = ProfileNames.getContents())
+ ProfileNamesData = *E;
+ else {
+ consumeError(E.takeError());
return 1;
+ }
int FD;
if (auto Err = sys::fs::openFileForWrite(OutputFilename, FD)) {
diff --git a/contrib/llvm/tools/llvm-cov/gcov.cpp b/contrib/llvm/tools/llvm-cov/gcov.cpp
index 7776f2aa9a68..8a00ff64711f 100644
--- a/contrib/llvm/tools/llvm-cov/gcov.cpp
+++ b/contrib/llvm/tools/llvm-cov/gcov.cpp
@@ -1,9 +1,8 @@
//===- gcov.cpp - GCOV compatible LLVM coverage tool ----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -125,6 +124,11 @@ int gcovMain(int argc, const char *argv[]) {
"(requires -b)"));
cl::alias UncondBranchA("unconditional-branches", cl::aliasopt(UncondBranch));
+ cl::opt<bool> HashFilenames("x", cl::Grouping, cl::init(false),
+ cl::desc("Hash long pathnames"));
+ cl::alias HashFilenamesA("hash-filenames", cl::aliasopt(HashFilenames));
+
+
cl::OptionCategory DebugCat("Internal and debugging options");
cl::opt<bool> DumpGCOV("dump", cl::init(false), cl::cat(DebugCat),
cl::desc("Dump the gcov file to stderr"));
@@ -136,7 +140,8 @@ int gcovMain(int argc, const char *argv[]) {
cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
GCOV::Options Options(AllBlocks, BranchProb, BranchCount, FuncSummary,
- PreservePaths, UncondBranch, LongNames, NoOutput);
+ PreservePaths, UncondBranch, LongNames, NoOutput,
+ HashFilenames);
for (const auto &SourceFile : SourceFiles)
reportCoverage(SourceFile, ObjectDir, InputGCNO, InputGCDA, DumpGCOV,
diff --git a/contrib/llvm/tools/llvm-cov/llvm-cov.cpp b/contrib/llvm/tools/llvm-cov/llvm-cov.cpp
index 4c3b574451c3..172ec9f3cedf 100644
--- a/contrib/llvm/tools/llvm-cov/llvm-cov.cpp
+++ b/contrib/llvm/tools/llvm-cov/llvm-cov.cpp
@@ -1,9 +1,8 @@
//===- llvm-cov.cpp - LLVM coverage tool ----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-cxxdump/Error.cpp b/contrib/llvm/tools/llvm-cxxdump/Error.cpp
index 54207fad32af..25317820409c 100644
--- a/contrib/llvm/tools/llvm-cxxdump/Error.cpp
+++ b/contrib/llvm/tools/llvm-cxxdump/Error.cpp
@@ -1,9 +1,8 @@
//===- Error.cpp - system_error extensions for llvm-cxxdump -----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-cxxdump/Error.h b/contrib/llvm/tools/llvm-cxxdump/Error.h
index 7caf6d6447c9..439902fa3803 100644
--- a/contrib/llvm/tools/llvm-cxxdump/Error.h
+++ b/contrib/llvm/tools/llvm-cxxdump/Error.h
@@ -1,9 +1,8 @@
//===- Error.h - system_error extensions for llvm-cxxdump -------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp b/contrib/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp
index 7594066a395d..833312655788 100644
--- a/contrib/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp
+++ b/contrib/llvm/tools/llvm-cxxdump/llvm-cxxdump.cpp
@@ -1,9 +1,8 @@
//===- llvm-cxxdump.cpp - Dump C++ data in an Object File -------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -49,15 +48,20 @@ static void error(std::error_code EC) {
exit(1);
}
-static void error(Error Err) {
- if (!Err)
- return;
+LLVM_ATTRIBUTE_NORETURN static void error(Error Err) {
logAllUnhandledErrors(std::move(Err), WithColor::error(outs()),
"reading file: ");
outs().flush();
exit(1);
}
+template <typename T>
+T unwrapOrError(Expected<T> EO) {
+ if (!EO)
+ error(EO.takeError());
+ return std::move(*EO);
+}
+
} // namespace llvm
static void reportError(StringRef Input, StringRef Message) {
@@ -196,8 +200,7 @@ static void dumpCXXData(const ObjectFile *Obj) {
// Skip virtual or BSS sections.
if (Sec.isBSS() || Sec.isVirtual())
continue;
- StringRef SecContents;
- error(Sec.getContents(SecContents));
+ StringRef SecContents = unwrapOrError(Sec.getContents());
Expected<uint64_t> SymAddressOrErr = Sym.getAddress();
error(errorToErrorCode(SymAddressOrErr.takeError()));
uint64_t SymAddress = *SymAddressOrErr;
@@ -511,7 +514,8 @@ static void dumpArchive(const Archive *Arc) {
else
reportError(Arc->getFileName(), cxxdump_error::unrecognized_file_format);
}
- error(std::move(Err));
+ if (Err)
+ error(std::move(Err));
}
static void dumpInput(StringRef File) {
diff --git a/contrib/llvm/tools/llvm-cxxdump/llvm-cxxdump.h b/contrib/llvm/tools/llvm-cxxdump/llvm-cxxdump.h
index daa05cb2ca0a..739cfe481a4b 100644
--- a/contrib/llvm/tools/llvm-cxxdump/llvm-cxxdump.h
+++ b/contrib/llvm/tools/llvm-cxxdump/llvm-cxxdump.h
@@ -1,9 +1,8 @@
//===-- llvm-cxxdump.h ------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp b/contrib/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
index afc1e4a8d128..9ac8bcf0ff01 100644
--- a/contrib/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
+++ b/contrib/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
@@ -1,12 +1,12 @@
//===-- llvm-c++filt.cpp --------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h"
@@ -25,7 +25,7 @@ enum Style {
EDG, ///< EDG compiler
GNUv3, ///< GNU C++ v3 ABI
Java, ///< Java (gcj)
- GNAT ///< ADA copiler (gnat)
+ GNAT ///< ADA compiler (gnat)
};
static cl::opt<Style>
Format("format", cl::desc("decoration style"),
@@ -52,31 +52,84 @@ static cl::alias TypesShort("t", cl::desc("alias for --types"),
static cl::list<std::string>
Decorated(cl::Positional, cl::desc("<mangled>"), cl::ZeroOrMore);
-static void demangle(llvm::raw_ostream &OS, const std::string &Mangled) {
+static cl::extrahelp
+ HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
+
+static std::string demangle(llvm::raw_ostream &OS, const std::string &Mangled) {
int Status;
- const char *Decorated = Mangled.c_str();
+ const char *DecoratedStr = Mangled.c_str();
if (StripUnderscore)
- if (Decorated[0] == '_')
- ++Decorated;
- size_t DecoratedLength = strlen(Decorated);
+ if (DecoratedStr[0] == '_')
+ ++DecoratedStr;
+ size_t DecoratedLength = strlen(DecoratedStr);
char *Undecorated = nullptr;
- if (Types || ((DecoratedLength >= 2 && strncmp(Decorated, "_Z", 2) == 0) ||
- (DecoratedLength >= 4 && strncmp(Decorated, "___Z", 4) == 0)))
- Undecorated = itaniumDemangle(Decorated, nullptr, nullptr, &Status);
+ if (Types ||
+ ((DecoratedLength >= 2 && strncmp(DecoratedStr, "_Z", 2) == 0) ||
+ (DecoratedLength >= 4 && strncmp(DecoratedStr, "___Z", 4) == 0)))
+ Undecorated = itaniumDemangle(DecoratedStr, nullptr, nullptr, &Status);
if (!Undecorated &&
- (DecoratedLength > 6 && strncmp(Decorated, "__imp_", 6) == 0)) {
+ (DecoratedLength > 6 && strncmp(DecoratedStr, "__imp_", 6) == 0)) {
OS << "import thunk for ";
- Undecorated = itaniumDemangle(Decorated + 6, nullptr, nullptr, &Status);
+ Undecorated = itaniumDemangle(DecoratedStr + 6, nullptr, nullptr, &Status);
}
- OS << (Undecorated ? Undecorated : Mangled) << '\n';
- OS.flush();
-
+ std::string Result(Undecorated ? Undecorated : Mangled);
free(Undecorated);
+ return Result;
+}
+
+// Split 'Source' on any character that fails to pass 'IsLegalChar'. The
+// returned vector consists of pairs where 'first' is the delimited word, and
+// 'second' are the delimiters following that word.
+static void SplitStringDelims(
+ StringRef Source,
+ SmallVectorImpl<std::pair<StringRef, StringRef>> &OutFragments,
+ function_ref<bool(char)> IsLegalChar) {
+ // The beginning of the input string.
+ const auto Head = Source.begin();
+
+ // Obtain any leading delimiters.
+ auto Start = std::find_if(Head, Source.end(), IsLegalChar);
+ if (Start != Head)
+ OutFragments.push_back({"", Source.slice(0, Start - Head)});
+
+ // Capture each word and the delimiters following that word.
+ while (Start != Source.end()) {
+ Start = std::find_if(Start, Source.end(), IsLegalChar);
+ auto End = std::find_if_not(Start, Source.end(), IsLegalChar);
+ auto DEnd = std::find_if(End, Source.end(), IsLegalChar);
+ OutFragments.push_back({Source.slice(Start - Head, End - Head),
+ Source.slice(End - Head, DEnd - Head)});
+ Start = DEnd;
+ }
+}
+
+// This returns true if 'C' is a character that can show up in an
+// Itanium-mangled string.
+static bool IsLegalItaniumChar(char C) {
+ // Itanium CXX ABI [External Names]p5.1.1:
+ // '$' and '.' in mangled names are reserved for private implementations.
+ return isalnum(C) || C == '.' || C == '$' || C == '_';
+}
+
+// If 'Split' is true, then 'Mangled' is broken into individual words and each
+// word is demangled. Otherwise, the entire string is treated as a single
+// mangled item. The result is output to 'OS'.
+static void demangleLine(llvm::raw_ostream &OS, StringRef Mangled, bool Split) {
+ std::string Result;
+ if (Split) {
+ SmallVector<std::pair<StringRef, StringRef>, 16> Words;
+ SplitStringDelims(Mangled, Words, IsLegalItaniumChar);
+ for (const auto &Word : Words)
+ Result += demangle(OS, Word.first) + Word.second.str();
+ } else
+ Result = demangle(OS, Mangled);
+ OS << Result << '\n';
+ OS.flush();
}
int main(int argc, char **argv) {
@@ -86,10 +139,10 @@ int main(int argc, char **argv) {
if (Decorated.empty())
for (std::string Mangled; std::getline(std::cin, Mangled);)
- demangle(llvm::outs(), Mangled);
+ demangleLine(llvm::outs(), Mangled, true);
else
for (const auto &Symbol : Decorated)
- demangle(llvm::outs(), Symbol);
+ demangleLine(llvm::outs(), Symbol, false);
return EXIT_SUCCESS;
}
diff --git a/contrib/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp b/contrib/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp
index 39028cc86723..87d4d06bbc96 100644
--- a/contrib/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp
+++ b/contrib/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp
@@ -1,9 +1,8 @@
//===- llvm-cxxmap.cpp ----------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-diff/DiffConsumer.cpp b/contrib/llvm/tools/llvm-diff/DiffConsumer.cpp
index ec189df27521..b797143bde1b 100644
--- a/contrib/llvm/tools/llvm-diff/DiffConsumer.cpp
+++ b/contrib/llvm/tools/llvm-diff/DiffConsumer.cpp
@@ -1,9 +1,8 @@
//===-- DiffConsumer.cpp - Difference Consumer ------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -13,8 +12,8 @@
#include "DiffConsumer.h"
#include "llvm/IR/Instructions.h"
-#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace llvm;
diff --git a/contrib/llvm/tools/llvm-diff/DiffConsumer.h b/contrib/llvm/tools/llvm-diff/DiffConsumer.h
index 82f5ce598b44..6cb8f2eb7eeb 100644
--- a/contrib/llvm/tools/llvm-diff/DiffConsumer.h
+++ b/contrib/llvm/tools/llvm-diff/DiffConsumer.h
@@ -1,9 +1,8 @@
//===-- DiffConsumer.h - Difference Consumer --------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-diff/DiffLog.cpp b/contrib/llvm/tools/llvm-diff/DiffLog.cpp
index 50c0c4cff2fc..6484197521f2 100644
--- a/contrib/llvm/tools/llvm-diff/DiffLog.cpp
+++ b/contrib/llvm/tools/llvm-diff/DiffLog.cpp
@@ -1,9 +1,8 @@
//===-- DiffLog.h - Difference Log Builder and accessories ------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-diff/DiffLog.h b/contrib/llvm/tools/llvm-diff/DiffLog.h
index 8f28461afdde..0c8952496155 100644
--- a/contrib/llvm/tools/llvm-diff/DiffLog.h
+++ b/contrib/llvm/tools/llvm-diff/DiffLog.h
@@ -1,9 +1,8 @@
//===-- DiffLog.h - Difference Log Builder and accessories ------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp b/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp
index acff8bb3e89b..bc93ece86490 100644
--- a/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp
+++ b/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp
@@ -1,9 +1,8 @@
//===-- DifferenceEngine.cpp - Structural function/module comparison ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -68,7 +67,7 @@ public:
unsigned NewSize = Storage.size() - 1;
if (NewSize) {
// Move the slot at the end to the beginning.
- if (isPodLike<T>::value)
+ if (is_trivially_copyable<T>::value)
Storage[0] = Storage[NewSize];
else
std::swap(Storage[0], Storage[NewSize]);
diff --git a/contrib/llvm/tools/llvm-diff/DifferenceEngine.h b/contrib/llvm/tools/llvm-diff/DifferenceEngine.h
index 7f084a377f0c..da1b6526a6e2 100644
--- a/contrib/llvm/tools/llvm-diff/DifferenceEngine.h
+++ b/contrib/llvm/tools/llvm-diff/DifferenceEngine.h
@@ -1,9 +1,8 @@
//===-- DifferenceEngine.h - Module comparator ------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-diff/llvm-diff.cpp b/contrib/llvm/tools/llvm-diff/llvm-diff.cpp
index e449d6994784..aaf7989e2e3d 100644
--- a/contrib/llvm/tools/llvm-diff/llvm-diff.cpp
+++ b/contrib/llvm/tools/llvm-diff/llvm-diff.cpp
@@ -1,9 +1,8 @@
//===-- llvm-diff.cpp - Module comparator command-line driver ---*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-dis/llvm-dis.cpp b/contrib/llvm/tools/llvm-dis/llvm-dis.cpp
index 8143a2a5a934..3f337b874b16 100644
--- a/contrib/llvm/tools/llvm-dis/llvm-dis.cpp
+++ b/contrib/llvm/tools/llvm-dis/llvm-dis.cpp
@@ -1,9 +1,8 @@
//===-- llvm-dis.cpp - The low-level LLVM disassembler --------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-dwarfdump/Statistics.cpp b/contrib/llvm/tools/llvm-dwarfdump/Statistics.cpp
index 5fe7e8b4615b..f26369b935cb 100644
--- a/contrib/llvm/tools/llvm-dwarfdump/Statistics.cpp
+++ b/contrib/llvm/tools/llvm-dwarfdump/Statistics.cpp
@@ -15,14 +15,38 @@ using namespace object;
struct PerFunctionStats {
/// Number of inlined instances of this function.
unsigned NumFnInlined = 0;
- /// Number of variables with location across all inlined instances.
+ /// Number of inlined instances that have abstract origins.
+ unsigned NumAbstractOrigins = 0;
+ /// Number of variables and parameters with location across all inlined
+ /// instances.
unsigned TotalVarWithLoc = 0;
/// Number of constants with location across all inlined instances.
unsigned ConstantMembers = 0;
- /// List of all Variables in this function.
+ /// List of all Variables and parameters in this function.
StringSet<> VarsInFunction;
/// Compile units also cover a PC range, but have this flag set to false.
bool IsFunction = false;
+ /// Verify function definition has PC addresses (for detecting when
+ /// a function has been inlined everywhere).
+ bool HasPCAddresses = false;
+ /// Function has source location information.
+ bool HasSourceLocation = false;
+ /// Number of function parameters.
+ unsigned NumParams = 0;
+ /// Number of function parameters with source location.
+ unsigned NumParamSourceLocations = 0;
+ /// Number of function parameters with type.
+ unsigned NumParamTypes = 0;
+ /// Number of function parameters with a DW_AT_location.
+ unsigned NumParamLocations = 0;
+ /// Number of variables.
+ unsigned NumVars = 0;
+ /// Number of variables with source location.
+ unsigned NumVarSourceLocations = 0;
+ /// Number of variables wtih type.
+ unsigned NumVarTypes = 0;
+ /// Number of variables wtih DW_AT_location.
+ unsigned NumVarLocations = 0;
};
/// Holds accumulated global statistics about DIEs.
@@ -32,7 +56,8 @@ struct GlobalStats {
/// Total number of PC range bytes in each variable's enclosing scope,
/// starting from the first definition of the variable.
unsigned ScopeBytesFromFirstDefinition = 0;
- /// Total number of call site entries (DW_TAG_call_site).
+ /// Total number of call site entries (DW_TAG_call_site) or
+ /// (DW_AT_call_file & DW_AT_call_line).
unsigned CallSiteEntries = 0;
/// Total byte size of concrete functions. This byte size includes
/// inline functions contained in the concrete functions.
@@ -59,11 +84,13 @@ static uint64_t getLowPC(DWARFDie Die) {
/// Collect debug info quality metrics for one DIE.
static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
std::string VarPrefix, uint64_t ScopeLowPC,
- uint64_t BytesInScope,
- uint32_t InlineDepth,
+ uint64_t BytesInScope, uint32_t InlineDepth,
StringMap<PerFunctionStats> &FnStatMap,
GlobalStats &GlobalStats) {
bool HasLoc = false;
+ bool HasSrcLoc = false;
+ bool HasType = false;
+ bool IsArtificial = false;
uint64_t BytesCovered = 0;
uint64_t OffsetToFirstDefinition = 0;
@@ -79,6 +106,16 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
return;
}
+ if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
+ Die.findRecursively(dwarf::DW_AT_decl_line))
+ HasSrcLoc = true;
+
+ if (Die.findRecursively(dwarf::DW_AT_type))
+ HasType = true;
+
+ if (Die.find(dwarf::DW_AT_artificial))
+ IsArtificial = true;
+
if (Die.find(dwarf::DW_AT_const_value)) {
// This catches constant members *and* variables.
HasLoc = true;
@@ -125,7 +162,7 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
// By using the variable name + the path through the lexical block tree, the
// keys are consistent across duplicate abstract origins in different CUs.
std::string VarName = StringRef(Die.getName(DINameKind::ShortName));
- FnStats.VarsInFunction.insert(VarPrefix+VarName);
+ FnStats.VarsInFunction.insert(VarPrefix + VarName);
if (BytesInScope) {
FnStats.TotalVarWithLoc += (unsigned)HasLoc;
// Adjust for the fact the variables often start their lifetime in the
@@ -136,16 +173,36 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
GlobalStats.ScopeBytesFromFirstDefinition += BytesInScope;
assert(GlobalStats.ScopeBytesCovered <=
GlobalStats.ScopeBytesFromFirstDefinition);
- } else {
+ } else if (Die.getTag() == dwarf::DW_TAG_member) {
FnStats.ConstantMembers++;
+ } else {
+ FnStats.TotalVarWithLoc += (unsigned)HasLoc;
+ }
+ if (!IsArtificial) {
+ if (Die.getTag() == dwarf::DW_TAG_formal_parameter) {
+ FnStats.NumParams++;
+ if (HasType)
+ FnStats.NumParamTypes++;
+ if (HasSrcLoc)
+ FnStats.NumParamSourceLocations++;
+ if (HasLoc)
+ FnStats.NumParamLocations++;
+ } else if (Die.getTag() == dwarf::DW_TAG_variable) {
+ FnStats.NumVars++;
+ if (HasType)
+ FnStats.NumVarTypes++;
+ if (HasSrcLoc)
+ FnStats.NumVarSourceLocations++;
+ if (HasLoc)
+ FnStats.NumVarLocations++;
+ }
}
}
/// Recursively collect debug info quality metrics.
static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,
std::string VarPrefix, uint64_t ScopeLowPC,
- uint64_t BytesInScope,
- uint32_t InlineDepth,
+ uint64_t BytesInScope, uint32_t InlineDepth,
StringMap<PerFunctionStats> &FnStatMap,
GlobalStats &GlobalStats) {
// Handle any kind of lexical scope.
@@ -164,20 +221,9 @@ static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,
if (Die.find(dwarf::DW_AT_declaration))
return;
- // Count the function.
- if (!IsBlock) {
- StringRef Name = Die.getName(DINameKind::LinkageName);
- if (Name.empty())
- Name = Die.getName(DINameKind::ShortName);
- FnPrefix = Name;
- // Skip over abstract origins.
- if (Die.find(dwarf::DW_AT_inline))
- return;
- // We've seen an (inlined) instance of this function.
- auto &FnStats = FnStatMap[Name];
- FnStats.NumFnInlined++;
- FnStats.IsFunction = true;
- }
+ // Check for call sites.
+ if (Die.find(dwarf::DW_AT_call_file) && Die.find(dwarf::DW_AT_call_line))
+ GlobalStats.CallSiteEntries++;
// PC Ranges.
auto RangesOrError = Die.getAddressRanges();
@@ -192,6 +238,31 @@ static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,
BytesInThisScope += Range.HighPC - Range.LowPC;
ScopeLowPC = getLowPC(Die);
+ // Count the function.
+ if (!IsBlock) {
+ StringRef Name = Die.getName(DINameKind::LinkageName);
+ if (Name.empty())
+ Name = Die.getName(DINameKind::ShortName);
+ FnPrefix = Name;
+ // Skip over abstract origins.
+ if (Die.find(dwarf::DW_AT_inline))
+ return;
+ // We've seen an (inlined) instance of this function.
+ auto &FnStats = FnStatMap[Name];
+ if (IsInlinedFunction) {
+ FnStats.NumFnInlined++;
+ if (Die.findRecursively(dwarf::DW_AT_abstract_origin))
+ FnStats.NumAbstractOrigins++;
+ }
+ FnStats.IsFunction = true;
+ if (BytesInThisScope && !IsInlinedFunction)
+ FnStats.HasPCAddresses = true;
+ std::string FnName = StringRef(Die.getName(DINameKind::ShortName));
+ if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
+ Die.findRecursively(dwarf::DW_AT_decl_line))
+ FnStats.HasSourceLocation = true;
+ }
+
if (BytesInThisScope) {
BytesInScope = BytesInThisScope;
if (IsFunction)
@@ -252,29 +323,53 @@ bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
GlobalStats GlobalStats;
StringMap<PerFunctionStats> Statistics;
for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units())
- if (DWARFDie CUDie = CU->getUnitDIE(false))
+ if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false))
collectStatsRecursive(CUDie, "/", "g", 0, 0, 0, Statistics, GlobalStats);
/// The version number should be increased every time the algorithm is changed
/// (including bug fixes). New metrics may be added without increasing the
/// version.
- unsigned Version = 1;
- unsigned VarTotal = 0;
- unsigned VarUnique = 0;
- unsigned VarWithLoc = 0;
+ unsigned Version = 3;
+ unsigned VarParamTotal = 0;
+ unsigned VarParamUnique = 0;
+ unsigned VarParamWithLoc = 0;
unsigned NumFunctions = 0;
unsigned NumInlinedFunctions = 0;
+ unsigned NumFuncsWithSrcLoc = 0;
+ unsigned NumAbstractOrigins = 0;
+ unsigned ParamTotal = 0;
+ unsigned ParamWithType = 0;
+ unsigned ParamWithLoc = 0;
+ unsigned ParamWithSrcLoc = 0;
+ unsigned VarTotal = 0;
+ unsigned VarWithType = 0;
+ unsigned VarWithSrcLoc = 0;
+ unsigned VarWithLoc = 0;
for (auto &Entry : Statistics) {
PerFunctionStats &Stats = Entry.getValue();
unsigned TotalVars = Stats.VarsInFunction.size() * Stats.NumFnInlined;
+ // Count variables in concrete out-of-line functions and in global scope.
+ if (Stats.HasPCAddresses || !Stats.IsFunction)
+ TotalVars += Stats.VarsInFunction.size();
unsigned Constants = Stats.ConstantMembers;
- VarWithLoc += Stats.TotalVarWithLoc + Constants;
- VarTotal += TotalVars + Constants;
- VarUnique += Stats.VarsInFunction.size();
- LLVM_DEBUG(for (auto &V : Stats.VarsInFunction) llvm::dbgs()
+ VarParamWithLoc += Stats.TotalVarWithLoc + Constants;
+ VarParamTotal += TotalVars;
+ VarParamUnique += Stats.VarsInFunction.size();
+ LLVM_DEBUG(for (auto &V
+ : Stats.VarsInFunction) llvm::dbgs()
<< Entry.getKey() << ": " << V.getKey() << "\n");
NumFunctions += Stats.IsFunction;
+ NumFuncsWithSrcLoc += Stats.HasSourceLocation;
NumInlinedFunctions += Stats.IsFunction * Stats.NumFnInlined;
+ NumAbstractOrigins += Stats.IsFunction * Stats.NumAbstractOrigins;
+ ParamTotal += Stats.NumParams;
+ ParamWithType += Stats.NumParamTypes;
+ ParamWithLoc += Stats.NumParamLocations;
+ ParamWithSrcLoc += Stats.NumParamSourceLocations;
+ VarTotal += Stats.NumVars;
+ VarWithType += Stats.NumVarTypes;
+ VarWithLoc += Stats.NumVarLocations;
+ VarWithSrcLoc += Stats.NumVarSourceLocations;
}
// Print summary.
@@ -285,20 +380,31 @@ bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
printDatum(OS, "file", Filename.str());
printDatum(OS, "format", FormatName);
printDatum(OS, "source functions", NumFunctions);
+ printDatum(OS, "source functions with location", NumFuncsWithSrcLoc);
printDatum(OS, "inlined functions", NumInlinedFunctions);
- printDatum(OS, "unique source variables", VarUnique);
- printDatum(OS, "source variables", VarTotal);
- printDatum(OS, "variables with location", VarWithLoc);
+ printDatum(OS, "inlined funcs with abstract origins", NumAbstractOrigins);
+ printDatum(OS, "unique source variables", VarParamUnique);
+ printDatum(OS, "source variables", VarParamTotal);
+ printDatum(OS, "variables with location", VarParamWithLoc);
printDatum(OS, "call site entries", GlobalStats.CallSiteEntries);
printDatum(OS, "scope bytes total",
GlobalStats.ScopeBytesFromFirstDefinition);
printDatum(OS, "scope bytes covered", GlobalStats.ScopeBytesCovered);
printDatum(OS, "total function size", GlobalStats.FunctionSize);
printDatum(OS, "total inlined function size", GlobalStats.InlineFunctionSize);
+ printDatum(OS, "total formal params", ParamTotal);
+ printDatum(OS, "formal params with source location", ParamWithSrcLoc);
+ printDatum(OS, "formal params with type", ParamWithType);
+ printDatum(OS, "formal params with binary location", ParamWithLoc);
+ printDatum(OS, "total vars", VarTotal);
+ printDatum(OS, "vars with source location", VarWithSrcLoc);
+ printDatum(OS, "vars with type", VarWithType);
+ printDatum(OS, "vars with binary location", VarWithLoc);
OS << "}\n";
LLVM_DEBUG(
llvm::dbgs() << "Total Availability: "
- << (int)std::round((VarWithLoc * 100.0) / VarTotal) << "%\n";
+ << (int)std::round((VarParamWithLoc * 100.0) / VarParamTotal)
+ << "%\n";
llvm::dbgs() << "PC Ranges covered: "
<< (int)std::round((GlobalStats.ScopeBytesCovered * 100.0) /
GlobalStats.ScopeBytesFromFirstDefinition)
diff --git a/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index d9e8e36efe5c..05a7aef67ece 100644
--- a/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/contrib/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -1,9 +1,8 @@
//===-- llvm-dwarfdump.cpp - Debug info dumping utility for llvm ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -93,8 +92,6 @@ namespace {
using namespace cl;
OptionCategory DwarfDumpCategory("Specific Options");
-static opt<bool> Help("h", desc("Alias for -help"), Hidden,
- cat(DwarfDumpCategory));
static list<std::string>
InputFilenames(Positional, desc("<input object files or .dSYM bundles>"),
ZeroOrMore, cat(DwarfDumpCategory));
@@ -142,10 +139,9 @@ static list<std::string>
"-name option can be used instead."),
value_desc("name"), cat(DwarfDumpCategory));
static alias FindAlias("f", desc("Alias for -find."), aliasopt(Find));
-static opt<bool>
- IgnoreCase("ignore-case",
- desc("Ignore case distinctions in when searching by name."),
- value_desc("i"), cat(DwarfDumpCategory));
+static opt<bool> IgnoreCase("ignore-case",
+ desc("Ignore case distinctions when searching."),
+ value_desc("i"), cat(DwarfDumpCategory));
static alias IgnoreCaseAlias("i", desc("Alias for -ignore-case."),
aliasopt(IgnoreCase));
static list<std::string> Name(
@@ -155,17 +151,17 @@ static list<std::string> Name(
"the -regex option <pattern> is interpreted as a regular expression."),
value_desc("pattern"), cat(DwarfDumpCategory));
static alias NameAlias("n", desc("Alias for -name"), aliasopt(Name));
-static opt<unsigned long long> Lookup("lookup",
+static opt<uint64_t>
+ Lookup("lookup",
desc("Lookup <address> in the debug information and print out any "
"available file, function, block and line table details."),
value_desc("address"), cat(DwarfDumpCategory));
static opt<std::string>
- OutputFilename("out-file", cl::init(""),
+ OutputFilename("o", cl::init("-"),
cl::desc("Redirect output to the specified file."),
- cl::value_desc("filename"));
-static alias OutputFilenameAlias("o", desc("Alias for -out-file."),
- aliasopt(OutputFilename),
- cat(DwarfDumpCategory));
+ cl::value_desc("filename"), cat(DwarfDumpCategory));
+static alias OutputFilenameAlias("out-file", desc("Alias for -o."),
+ aliasopt(OutputFilename));
static opt<bool>
UseRegex("regex",
desc("Treat any <pattern> strings as regular expressions when "
@@ -175,14 +171,14 @@ static alias RegexAlias("x", desc("Alias for -regex"), aliasopt(UseRegex));
static opt<bool>
ShowChildren("show-children",
desc("Show a debug info entry's children when selectively "
- "printing with the =<offset> option."),
+ "printing entries."),
cat(DwarfDumpCategory));
static alias ShowChildrenAlias("c", desc("Alias for -show-children."),
aliasopt(ShowChildren));
static opt<bool>
ShowParents("show-parents",
desc("Show a debug info entry's parents when selectively "
- "printing with the =<offset> option."),
+ "printing entries."),
cat(DwarfDumpCategory));
static alias ShowParentsAlias("p", desc("Alias for -show-parents."),
aliasopt(ShowParents));
@@ -192,13 +188,18 @@ static opt<bool>
cat(DwarfDumpCategory));
static alias ShowFormAlias("F", desc("Alias for -show-form."),
aliasopt(ShowForm), cat(DwarfDumpCategory));
-static opt<unsigned> RecurseDepth(
- "recurse-depth",
- desc("Only recurse to a depth of N when displaying debug info entries."),
- cat(DwarfDumpCategory), init(-1U), value_desc("N"));
-static alias RecurseDepthAlias("r", desc("Alias for -recurse-depth."),
- aliasopt(RecurseDepth));
-
+static opt<unsigned>
+ ChildRecurseDepth("recurse-depth",
+ desc("Only recurse to a depth of N when displaying "
+ "children of debug info entries."),
+ cat(DwarfDumpCategory), init(-1U), value_desc("N"));
+static alias ChildRecurseDepthAlias("r", desc("Alias for -recurse-depth."),
+ aliasopt(ChildRecurseDepth));
+static opt<unsigned>
+ ParentRecurseDepth("parent-recurse-depth",
+ desc("Only recurse to a depth of N when displaying "
+ "parents of debug info entries."),
+ cat(DwarfDumpCategory), init(-1U), value_desc("N"));
static opt<bool>
SummarizeTypes("summarize-types",
desc("Abbreviate the description of type unit entries."),
@@ -219,6 +220,8 @@ static opt<bool> Verbose("verbose",
cat(DwarfDumpCategory));
static alias VerboseAlias("v", desc("Alias for -verbose."), aliasopt(Verbose),
cat(DwarfDumpCategory));
+static cl::extrahelp
+ HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
} // namespace
/// @}
//===----------------------------------------------------------------------===//
@@ -233,7 +236,8 @@ static void error(StringRef Prefix, std::error_code EC) {
static DIDumpOptions getDumpOpts() {
DIDumpOptions DumpOpts;
DumpOpts.DumpType = DumpType;
- DumpOpts.RecurseDepth = RecurseDepth;
+ DumpOpts.ChildRecurseDepth = ChildRecurseDepth;
+ DumpOpts.ParentRecurseDepth = ParentRecurseDepth;
DumpOpts.ShowAddresses = !Diff;
DumpOpts.ShowChildren = ShowChildren;
DumpOpts.ShowParents = ShowParents;
@@ -259,19 +263,16 @@ static bool filterArch(ObjectFile &Obj) {
return true;
if (auto *MachO = dyn_cast<MachOObjectFile>(&Obj)) {
- std::string ObjArch =
- Triple::getArchTypeName(MachO->getArchTriple().getArch());
-
for (auto Arch : ArchFilters) {
- // Match name.
- if (Arch == ObjArch)
- return true;
-
// Match architecture number.
unsigned Value;
if (!StringRef(Arch).getAsInteger(0, Value))
if (Value == getCPUType(*MachO))
return true;
+
+ // Match as name.
+ if (MachO->getArchTriple().getArch() == Triple(Arch).getArch())
+ return true;
}
}
return false;
@@ -380,14 +381,19 @@ static void filterByAccelName(ArrayRef<std::string> Names, DWARFContext &DICtx,
/// Handle the --lookup option and dump the DIEs and line info for the given
/// address.
-static bool lookup(DWARFContext &DICtx, uint64_t Address, raw_ostream &OS) {
+/// TODO: specified Address for --lookup option could relate for several
+/// different sections(in case not-linked object file). llvm-dwarfdump
+/// need to do something with this: extend lookup option with section
+/// information or probably display all matched entries, or something else...
+static bool lookup(ObjectFile &Obj, DWARFContext &DICtx, uint64_t Address,
+ raw_ostream &OS) {
auto DIEsForAddr = DICtx.getDIEsForAddress(Lookup);
if (!DIEsForAddr)
return false;
DIDumpOptions DumpOpts = getDumpOpts();
- DumpOpts.RecurseDepth = 0;
+ DumpOpts.ChildRecurseDepth = 0;
DIEsForAddr.CompileUnit->dump(OS, DumpOpts);
if (DIEsForAddr.FunctionDIE) {
DIEsForAddr.FunctionDIE.dump(OS, 2, DumpOpts);
@@ -395,7 +401,10 @@ static bool lookup(DWARFContext &DICtx, uint64_t Address, raw_ostream &OS) {
DIEsForAddr.BlockDIE.dump(OS, 4, DumpOpts);
}
- if (DILineInfo LineInfo = DICtx.getLineInfoForAddress(Lookup))
+ // TODO: it is neccessary to set proper SectionIndex here.
+ // object::SectionedAddress::UndefSection works for only absolute addresses.
+ if (DILineInfo LineInfo = DICtx.getLineInfoForAddress(
+ {Lookup, object::SectionedAddress::UndefSection}))
LineInfo.dump(OS);
return true;
@@ -414,7 +423,7 @@ static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename,
// Handle the --lookup option.
if (Lookup)
- return lookup(DICtx, Lookup, OS);
+ return lookup(Obj, DICtx, Lookup, OS);
// Handle the --name option.
if (!Name.empty()) {
@@ -566,11 +575,6 @@ int main(int argc, char **argv) {
"pretty-print DWARF debug information in object files"
" and debug info archives.\n");
- if (Help) {
- PrintHelpMessage(/*Hidden =*/false, /*Categorized =*/true);
- return 0;
- }
-
// FIXME: Audit interactions between these two options and make them
// compatible.
if (Diff && Verbose) {
@@ -579,17 +583,12 @@ int main(int argc, char **argv) {
return 0;
}
- std::unique_ptr<ToolOutputFile> OutputFile;
- if (!OutputFilename.empty()) {
- std::error_code EC;
- OutputFile = llvm::make_unique<ToolOutputFile>(OutputFilename, EC,
- sys::fs::F_None);
- error("Unable to open output file" + OutputFilename, EC);
- // Don't remove output file if we exit with an error.
- OutputFile->keep();
- }
+ std::error_code EC;
+ ToolOutputFile OutputFile(OutputFilename, EC, sys::fs::OF_None);
+ error("Unable to open output file" + OutputFilename, EC);
+ // Don't remove output file if we exit with an error.
+ OutputFile.keep();
- raw_ostream &OS = OutputFile ? OutputFile->os() : outs();
bool OffsetRequested = false;
// Defaults to dumping all sections, unless brief mode is specified in which
@@ -633,15 +632,15 @@ int main(int argc, char **argv) {
if (Verify) {
// If we encountered errors during verify, exit with a non-zero exit status.
if (!all_of(Objects, [&](std::string Object) {
- return handleFile(Object, verifyObjectFile, OS);
+ return handleFile(Object, verifyObjectFile, OutputFile.os());
}))
- exit(1);
+ return 1;
} else if (Statistics)
for (auto Object : Objects)
- handleFile(Object, collectStatsForObjectFile, OS);
+ handleFile(Object, collectStatsForObjectFile, OutputFile.os());
else
for (auto Object : Objects)
- handleFile(Object, dumpObjectFile, OS);
+ handleFile(Object, dumpObjectFile, OutputFile.os());
return EXIT_SUCCESS;
}
diff --git a/contrib/llvm/tools/llvm-extract/llvm-extract.cpp b/contrib/llvm/tools/llvm-extract/llvm-extract.cpp
index 94aaa2f52eb5..300bc0b4bd52 100644
--- a/contrib/llvm/tools/llvm-extract/llvm-extract.cpp
+++ b/contrib/llvm/tools/llvm-extract/llvm-extract.cpp
@@ -1,9 +1,8 @@
//===- llvm-extract.cpp - LLVM function extraction utility ----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -34,86 +33,99 @@
#include <memory>
using namespace llvm;
+cl::OptionCategory ExtractCat("llvm-extract Options");
+
// InputFilename - The filename to read from.
-static cl::opt<std::string>
-InputFilename(cl::Positional, cl::desc("<input bitcode file>"),
- cl::init("-"), cl::value_desc("filename"));
+static cl::opt<std::string> InputFilename(cl::Positional,
+ cl::desc("<input bitcode file>"),
+ cl::init("-"),
+ cl::value_desc("filename"));
-static cl::opt<std::string>
-OutputFilename("o", cl::desc("Specify output filename"),
- cl::value_desc("filename"), cl::init("-"));
+static cl::opt<std::string> OutputFilename("o",
+ cl::desc("Specify output filename"),
+ cl::value_desc("filename"),
+ cl::init("-"), cl::cat(ExtractCat));
-static cl::opt<bool>
-Force("f", cl::desc("Enable binary output on terminals"));
+static cl::opt<bool> Force("f", cl::desc("Enable binary output on terminals"),
+ cl::cat(ExtractCat));
-static cl::opt<bool>
-DeleteFn("delete", cl::desc("Delete specified Globals from Module"));
+static cl::opt<bool> DeleteFn("delete",
+ cl::desc("Delete specified Globals from Module"),
+ cl::cat(ExtractCat));
static cl::opt<bool>
- Recursive("recursive",
- cl::desc("Recursively extract all called functions"));
+ Recursive("recursive", cl::desc("Recursively extract all called functions"),
+ cl::cat(ExtractCat));
// ExtractFuncs - The functions to extract from the module.
static cl::list<std::string>
-ExtractFuncs("func", cl::desc("Specify function to extract"),
- cl::ZeroOrMore, cl::value_desc("function"));
+ ExtractFuncs("func", cl::desc("Specify function to extract"),
+ cl::ZeroOrMore, cl::value_desc("function"),
+ cl::cat(ExtractCat));
// ExtractRegExpFuncs - The functions, matched via regular expression, to
// extract from the module.
static cl::list<std::string>
-ExtractRegExpFuncs("rfunc", cl::desc("Specify function(s) to extract using a "
- "regular expression"),
- cl::ZeroOrMore, cl::value_desc("rfunction"));
+ ExtractRegExpFuncs("rfunc",
+ cl::desc("Specify function(s) to extract using a "
+ "regular expression"),
+ cl::ZeroOrMore, cl::value_desc("rfunction"),
+ cl::cat(ExtractCat));
// ExtractBlocks - The blocks to extract from the module.
-static cl::list<std::string>
- ExtractBlocks("bb",
- cl::desc("Specify <function, basic block> pairs to extract"),
- cl::ZeroOrMore, cl::value_desc("function:bb"));
+static cl::list<std::string> ExtractBlocks(
+ "bb", cl::desc("Specify <function, basic block> pairs to extract"),
+ cl::ZeroOrMore, cl::value_desc("function:bb"), cl::cat(ExtractCat));
// ExtractAlias - The alias to extract from the module.
static cl::list<std::string>
-ExtractAliases("alias", cl::desc("Specify alias to extract"),
- cl::ZeroOrMore, cl::value_desc("alias"));
-
+ ExtractAliases("alias", cl::desc("Specify alias to extract"),
+ cl::ZeroOrMore, cl::value_desc("alias"),
+ cl::cat(ExtractCat));
// ExtractRegExpAliases - The aliases, matched via regular expression, to
// extract from the module.
static cl::list<std::string>
-ExtractRegExpAliases("ralias", cl::desc("Specify alias(es) to extract using a "
- "regular expression"),
- cl::ZeroOrMore, cl::value_desc("ralias"));
+ ExtractRegExpAliases("ralias",
+ cl::desc("Specify alias(es) to extract using a "
+ "regular expression"),
+ cl::ZeroOrMore, cl::value_desc("ralias"),
+ cl::cat(ExtractCat));
// ExtractGlobals - The globals to extract from the module.
static cl::list<std::string>
-ExtractGlobals("glob", cl::desc("Specify global to extract"),
- cl::ZeroOrMore, cl::value_desc("global"));
+ ExtractGlobals("glob", cl::desc("Specify global to extract"),
+ cl::ZeroOrMore, cl::value_desc("global"),
+ cl::cat(ExtractCat));
// ExtractRegExpGlobals - The globals, matched via regular expression, to
// extract from the module...
static cl::list<std::string>
-ExtractRegExpGlobals("rglob", cl::desc("Specify global(s) to extract using a "
- "regular expression"),
- cl::ZeroOrMore, cl::value_desc("rglobal"));
+ ExtractRegExpGlobals("rglob",
+ cl::desc("Specify global(s) to extract using a "
+ "regular expression"),
+ cl::ZeroOrMore, cl::value_desc("rglobal"),
+ cl::cat(ExtractCat));
-static cl::opt<bool>
-OutputAssembly("S",
- cl::desc("Write output as LLVM assembly"), cl::Hidden);
+static cl::opt<bool> OutputAssembly("S",
+ cl::desc("Write output as LLVM assembly"),
+ cl::Hidden, cl::cat(ExtractCat));
static cl::opt<bool> PreserveBitcodeUseListOrder(
"preserve-bc-uselistorder",
cl::desc("Preserve use-list order when writing LLVM bitcode."),
- cl::init(true), cl::Hidden);
+ cl::init(true), cl::Hidden, cl::cat(ExtractCat));
static cl::opt<bool> PreserveAssemblyUseListOrder(
"preserve-ll-uselistorder",
cl::desc("Preserve use-list order when writing LLVM assembly."),
- cl::init(false), cl::Hidden);
+ cl::init(false), cl::Hidden, cl::cat(ExtractCat));
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
LLVMContext Context;
+ cl::HideUnrelatedOptions(ExtractCat);
cl::ParseCommandLineOptions(argc, argv, "llvm extractor\n");
// Use lazy loading, since we only care about selected global values.
@@ -230,7 +242,7 @@ int main(int argc, char **argv) {
}
// Figure out which BasicBlocks we should extract.
- SmallVector<BasicBlock *, 4> BBs;
+ SmallVector<SmallVector<BasicBlock *, 16>, 4> GroupOfBBs;
for (StringRef StrPair : ExtractBlocks) {
auto BBInfo = StrPair.split(':');
// Get the function.
@@ -242,17 +254,24 @@ int main(int argc, char **argv) {
}
// Do not materialize this function.
GVs.insert(F);
- // Get the basic block.
- auto Res = llvm::find_if(*F, [&](const BasicBlock &BB) {
- return BB.getName().equals(BBInfo.second);
- });
- if (Res == F->end()) {
- errs() << argv[0] << ": function " << F->getName()
- << " doesn't contain a basic block named '" << BBInfo.second
- << "'!\n";
- return 1;
+ // Get the basic blocks.
+ SmallVector<BasicBlock *, 16> BBs;
+ SmallVector<StringRef, 16> BBNames;
+ BBInfo.second.split(BBNames, ';', /*MaxSplit=*/-1,
+ /*KeepEmpty=*/false);
+ for (StringRef BBName : BBNames) {
+ auto Res = llvm::find_if(*F, [&](const BasicBlock &BB) {
+ return BB.getName().equals(BBName);
+ });
+ if (Res == F->end()) {
+ errs() << argv[0] << ": function " << F->getName()
+ << " doesn't contain a basic block named '" << BBInfo.second
+ << "'!\n";
+ return 1;
+ }
+ BBs.push_back(&*Res);
}
- BBs.push_back(&*Res);
+ GroupOfBBs.push_back(BBs);
}
// Use *argv instead of argv[0] to work around a wrong GCC warning.
@@ -271,10 +290,10 @@ int main(int argc, char **argv) {
ExitOnErr(F->materialize());
for (auto &BB : *F) {
for (auto &I : BB) {
- auto *CI = dyn_cast<CallInst>(&I);
- if (!CI)
+ CallBase *CB = dyn_cast<CallBase>(&I);
+ if (!CB)
continue;
- Function *CF = CI->getCalledFunction();
+ Function *CF = CB->getCalledFunction();
if (!CF)
continue;
if (CF->isDeclaration() || GVs.count(CF))
@@ -317,7 +336,7 @@ int main(int argc, char **argv) {
// functions.
if (!ExtractBlocks.empty()) {
legacy::PassManager PM;
- PM.add(createBlockExtractorPass(BBs, true));
+ PM.add(createBlockExtractorPass(GroupOfBBs, true));
PM.run(*M);
}
diff --git a/contrib/llvm/tools/llvm-link/llvm-link.cpp b/contrib/llvm/tools/llvm-link/llvm-link.cpp
index b7a888375b3d..50ba57178d02 100644
--- a/contrib/llvm/tools/llvm-link/llvm-link.cpp
+++ b/contrib/llvm/tools/llvm-link/llvm-link.cpp
@@ -1,9 +1,8 @@
//===- llvm-link.cpp - Low-level LLVM linker ------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-lto/llvm-lto.cpp b/contrib/llvm/tools/llvm-lto/llvm-lto.cpp
index b6facc919b51..585207b25185 100644
--- a/contrib/llvm/tools/llvm-lto/llvm-lto.cpp
+++ b/contrib/llvm/tools/llvm-lto/llvm-lto.cpp
@@ -1,9 +1,8 @@
//===- llvm-lto: a simple command-line program to link modules with LTO ---===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -158,8 +157,8 @@ static cl::opt<int>
ThinLTOCachePruningInterval("thinlto-cache-pruning-interval",
cl::init(1200), cl::desc("Set ThinLTO cache pruning interval."));
-static cl::opt<unsigned long long>
- ThinLTOCacheMaxSizeBytes("thinlto-cache-max-size-bytes",
+static cl::opt<uint64_t> ThinLTOCacheMaxSizeBytes(
+ "thinlto-cache-max-size-bytes",
cl::desc("Set ThinLTO cache pruning directory maximum size in bytes."));
static cl::opt<int>
@@ -205,6 +204,10 @@ static cl::opt<bool> ListSymbolsOnly(
"list-symbols-only", cl::init(false),
cl::desc("Instead of running LTO, list the symbols in each IR file"));
+static cl::opt<bool> ListDependentLibrariesOnly(
+ "list-dependent-libraries-only", cl::init(false),
+ cl::desc("Instead of running LTO, list the dependent libraries in each IR file"));
+
static cl::opt<bool> SetMergedModule(
"set-merged-module", cl::init(false),
cl::desc("Use the first input module as the merged module"));
@@ -373,6 +376,34 @@ static void listSymbols(const TargetOptions &Options) {
}
}
+static std::unique_ptr<MemoryBuffer> loadFile(StringRef Filename) {
+ ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename.str() +
+ "': ");
+ return ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Filename)));
+}
+
+static void listDependentLibraries() {
+ for (auto &Filename : InputFilenames) {
+ auto Buffer = loadFile(Filename);
+ std::string E;
+ std::unique_ptr<lto::InputFile> Input(LTOModule::createInputFile(
+ Buffer->getBufferStart(), Buffer->getBufferSize(), Filename.c_str(),
+ E));
+ if (!Input)
+ error(E);
+
+ // List the dependent libraries.
+ outs() << Filename << ":\n";
+ for (size_t I = 0, C = LTOModule::getDependentLibraryCount(Input.get());
+ I != C; ++I) {
+ size_t L = 0;
+ const char *S = LTOModule::getDependentLibrary(Input.get(), I, &L);
+ assert(S);
+ outs() << StringRef(S, L) << "\n";
+ }
+ }
+}
+
/// Create a combined index file from the input IR files and write it.
///
/// This is meant to enable testing of ThinLTO combined index generation,
@@ -450,22 +481,31 @@ std::unique_ptr<ModuleSummaryIndex> loadCombinedIndex() {
return ExitOnErr(getModuleSummaryIndexForFile(ThinLTOIndex));
}
-static std::unique_ptr<Module> loadModule(StringRef Filename,
- LLVMContext &Ctx) {
- SMDiagnostic Err;
- std::unique_ptr<Module> M(parseIRFile(Filename, Err, Ctx));
- if (!M) {
- Err.print("llvm-lto", errs());
- report_fatal_error("Can't load module for file " + Filename);
- }
- maybeVerifyModule(*M);
+static std::unique_ptr<lto::InputFile> loadInputFile(MemoryBufferRef Buffer) {
+ ExitOnError ExitOnErr("llvm-lto: error loading input '" +
+ Buffer.getBufferIdentifier().str() + "': ");
+ return ExitOnErr(lto::InputFile::create(Buffer));
+}
+static std::unique_ptr<Module> loadModuleFromInput(lto::InputFile &File,
+ LLVMContext &CTX) {
+ auto &Mod = File.getSingleBitcodeModule();
+ auto ModuleOrErr = Mod.parseModule(CTX);
+ if (!ModuleOrErr) {
+ handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) {
+ SMDiagnostic Err = SMDiagnostic(Mod.getModuleIdentifier(),
+ SourceMgr::DK_Error, EIB.message());
+ Err.print("llvm-lto", errs());
+ });
+ report_fatal_error("Can't load module, abort.");
+ }
+ maybeVerifyModule(**ModuleOrErr);
if (ThinLTOModuleId.getNumOccurrences()) {
if (InputFilenames.size() != 1)
report_fatal_error("Can't override the module id for multiple files");
- M->setModuleIdentifier(ThinLTOModuleId);
+ (*ModuleOrErr)->setModuleIdentifier(ThinLTOModuleId);
}
- return M;
+ return std::move(*ModuleOrErr);
}
static void writeModuleToFile(Module &TheModule, StringRef Filename) {
@@ -563,13 +603,15 @@ private:
auto Index = loadCombinedIndex();
for (auto &Filename : InputFilenames) {
LLVMContext Ctx;
- auto TheModule = loadModule(Filename, Ctx);
+ auto Buffer = loadFile(Filename);
+ auto Input = loadInputFile(Buffer->getMemBufferRef());
+ auto TheModule = loadModuleFromInput(*Input, Ctx);
// Build a map of module to the GUIDs and summary objects that should
// be written to its index.
std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;
- ThinGenerator.gatherImportedSummariesForModule(*TheModule, *Index,
- ModuleToSummariesForIndex);
+ ThinGenerator.gatherImportedSummariesForModule(
+ *TheModule, *Index, ModuleToSummariesForIndex, *Input);
std::string OutputName = OutputFilename;
if (OutputName.empty()) {
@@ -598,13 +640,16 @@ private:
auto Index = loadCombinedIndex();
for (auto &Filename : InputFilenames) {
LLVMContext Ctx;
- auto TheModule = loadModule(Filename, Ctx);
+ auto Buffer = loadFile(Filename);
+ auto Input = loadInputFile(Buffer->getMemBufferRef());
+ auto TheModule = loadModuleFromInput(*Input, Ctx);
std::string OutputName = OutputFilename;
if (OutputName.empty()) {
OutputName = Filename + ".imports";
}
- OutputName = getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);
- ThinGenerator.emitImports(*TheModule, OutputName, *Index);
+ OutputName =
+ getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);
+ ThinGenerator.emitImports(*TheModule, OutputName, *Index, *Input);
}
}
@@ -622,9 +667,11 @@ private:
auto Index = loadCombinedIndex();
for (auto &Filename : InputFilenames) {
LLVMContext Ctx;
- auto TheModule = loadModule(Filename, Ctx);
+ auto Buffer = loadFile(Filename);
+ auto Input = loadInputFile(Buffer->getMemBufferRef());
+ auto TheModule = loadModuleFromInput(*Input, Ctx);
- ThinGenerator.promote(*TheModule, *Index);
+ ThinGenerator.promote(*TheModule, *Index, *Input);
std::string OutputName = OutputFilename;
if (OutputName.empty()) {
@@ -653,9 +700,11 @@ private:
for (auto &Filename : InputFilenames) {
LLVMContext Ctx;
- auto TheModule = loadModule(Filename, Ctx);
+ auto Buffer = loadFile(Filename);
+ auto Input = loadInputFile(Buffer->getMemBufferRef());
+ auto TheModule = loadModuleFromInput(*Input, Ctx);
- ThinGenerator.crossModuleImport(*TheModule, *Index);
+ ThinGenerator.crossModuleImport(*TheModule, *Index, *Input);
std::string OutputName = OutputFilename;
if (OutputName.empty()) {
@@ -684,9 +733,11 @@ private:
for (auto &Filename : InputFilenames) {
LLVMContext Ctx;
- auto TheModule = loadModule(Filename, Ctx);
+ auto Buffer = loadFile(Filename);
+ auto Input = loadInputFile(Buffer->getMemBufferRef());
+ auto TheModule = loadModuleFromInput(*Input, Ctx);
- ThinGenerator.internalize(*TheModule, *Index);
+ ThinGenerator.internalize(*TheModule, *Index, *Input);
std::string OutputName = OutputFilename;
if (OutputName.empty()) {
@@ -707,7 +758,9 @@ private:
for (auto &Filename : InputFilenames) {
LLVMContext Ctx;
- auto TheModule = loadModule(Filename, Ctx);
+ auto Buffer = loadFile(Filename);
+ auto Input = loadInputFile(Buffer->getMemBufferRef());
+ auto TheModule = loadModuleFromInput(*Input, Ctx);
ThinGenerator.optimize(*TheModule);
@@ -827,6 +880,11 @@ int main(int argc, char **argv) {
return 0;
}
+ if (ListDependentLibrariesOnly) {
+ listDependentLibraries();
+ return 0;
+ }
+
if (IndexStats) {
printIndexStats();
return 0;
diff --git a/contrib/llvm/tools/llvm-lto2/llvm-lto2.cpp b/contrib/llvm/tools/llvm-lto2/llvm-lto2.cpp
index 26426367e252..0bd9289dc938 100644
--- a/contrib/llvm/tools/llvm-lto2/llvm-lto2.cpp
+++ b/contrib/llvm/tools/llvm-lto2/llvm-lto2.cpp
@@ -1,9 +1,8 @@
//===-- llvm-lto2: test harness for the resolution-based LTO interface ----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -92,19 +91,40 @@ static cl::opt<std::string> DefaultTriple(
cl::desc(
"Replace unspecified target triples in input files with this triple"));
+static cl::opt<bool> RemarksWithHotness(
+ "pass-remarks-with-hotness",
+ cl::desc("With PGO, include profile count in optimization remarks"),
+ cl::Hidden);
+
static cl::opt<std::string>
- OptRemarksOutput("pass-remarks-output",
- cl::desc("YAML output file for optimization remarks"));
+ RemarksFilename("pass-remarks-output",
+ cl::desc("Output filename for pass remarks"),
+ cl::value_desc("filename"));
-static cl::opt<bool> OptRemarksWithHotness(
- "pass-remarks-with-hotness",
- cl::desc("Whether to include hotness informations in the remarks.\n"
- "Has effect only if -pass-remarks-output is specified."));
+static cl::opt<std::string>
+ RemarksPasses("pass-remarks-filter",
+ cl::desc("Only record optimization remarks from passes whose "
+ "names match the given regular expression"),
+ cl::value_desc("regex"));
+
+static cl::opt<std::string> RemarksFormat(
+ "pass-remarks-format",
+ cl::desc("The format used for serializing remarks (default: YAML)"),
+ cl::value_desc("format"), cl::init("yaml"));
static cl::opt<std::string>
SamplePGOFile("lto-sample-profile-file",
cl::desc("Specify a SamplePGO profile file"));
+static cl::opt<std::string>
+ CSPGOFile("lto-cspgo-profile-file",
+ cl::desc("Specify a context sensitive PGO profile file"));
+
+static cl::opt<bool>
+ RunCSIRInstr("lto-cspgo-gen",
+ cl::desc("Run PGO context sensitive IR instrumentation"),
+ cl::init(false), cl::Hidden);
+
static cl::opt<bool>
UseNewPM("use-new-pm",
cl::desc("Run LTO passes using the new pass manager"),
@@ -211,10 +231,14 @@ static int run(int argc, char **argv) {
"Config::addSaveTemps failed");
// Optimization remarks.
- Conf.RemarksFilename = OptRemarksOutput;
- Conf.RemarksWithHotness = OptRemarksWithHotness;
+ Conf.RemarksFilename = RemarksFilename;
+ Conf.RemarksPasses = RemarksPasses;
+ Conf.RemarksWithHotness = RemarksWithHotness;
+ Conf.RemarksFormat = RemarksFormat;
Conf.SampleProfile = SamplePGOFile;
+ Conf.CSIRProfile = CSPGOFile;
+ Conf.RunCSIRInstr = RunCSIRInstr;
// Run a custom pipeline, if asked for.
Conf.OptPipeline = OptPipeline;
@@ -343,6 +367,13 @@ static int dumpSymtab(int argc, char **argv) {
if (TT.isOSBinFormatCOFF())
outs() << "linker opts: " << Input->getCOFFLinkerOpts() << '\n';
+ if (TT.isOSBinFormatELF()) {
+ outs() << "dependent libraries:";
+ for (auto L : Input->getDependentLibraries())
+ outs() << " \"" << L << "\"";
+ outs() << '\n';
+ }
+
std::vector<StringRef> ComdatTable = Input->getComdatTable();
for (const InputFile::Symbol &Sym : Input->symbols()) {
switch (Sym.getVisibility()) {
diff --git a/contrib/llvm/tools/llvm-mc/Disassembler.cpp b/contrib/llvm/tools/llvm-mc/Disassembler.cpp
index acc5a5f4cab2..e2af2e7f2e32 100644
--- a/contrib/llvm/tools/llvm-mc/Disassembler.cpp
+++ b/contrib/llvm/tools/llvm-mc/Disassembler.cpp
@@ -1,9 +1,8 @@
//===- Disassembler.cpp - Disassembler for hex strings --------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-mc/Disassembler.h b/contrib/llvm/tools/llvm-mc/Disassembler.h
index 1f18ac075f85..11b685233abc 100644
--- a/contrib/llvm/tools/llvm-mc/Disassembler.h
+++ b/contrib/llvm/tools/llvm-mc/Disassembler.h
@@ -1,9 +1,8 @@
//===- Disassembler.h - Text File Disassembler ----------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-mc/llvm-mc.cpp b/contrib/llvm/tools/llvm-mc/llvm-mc.cpp
index c0976502f545..ec189c297860 100644
--- a/contrib/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/contrib/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -1,9 +1,8 @@
//===-- llvm-mc.cpp - Machine Code Hacking Driver ---------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -402,18 +401,8 @@ int main(int argc, char **argv) {
}
if (!MainFileName.empty())
Ctx.setMainFileName(MainFileName);
- if (GenDwarfForAssembly && DwarfVersion >= 5) {
- // DWARF v5 needs the root file as well as the compilation directory.
- // If we find a '.file 0' directive that will supersede these values.
- MD5 Hash;
- MD5::MD5Result *Cksum =
- (MD5::MD5Result *)Ctx.allocate(sizeof(MD5::MD5Result), 1);
- Hash.update(Buffer->getBuffer());
- Hash.final(*Cksum);
- Ctx.setMCLineTableRootFile(
- /*CUID=*/0, Ctx.getCompilationDir(),
- !MainFileName.empty() ? MainFileName : InputFilename, Cksum, None);
- }
+ if (GenDwarfForAssembly)
+ Ctx.setGenDwarfRootFile(InputFilename, Buffer->getBuffer());
// Package up features to be passed to target/subtarget
std::string FeaturesStr;
diff --git a/contrib/llvm/tools/llvm-mca/CodeRegion.cpp b/contrib/llvm/tools/llvm-mca/CodeRegion.cpp
index 29a27c50c171..bf592f67245e 100644
--- a/contrib/llvm/tools/llvm-mca/CodeRegion.cpp
+++ b/contrib/llvm/tools/llvm-mca/CodeRegion.cpp
@@ -1,9 +1,8 @@
//===-------------------------- CodeRegion.cpp -----------------*- C++ -* -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -17,7 +16,12 @@
namespace llvm {
namespace mca {
-bool CodeRegion::isLocInRange(llvm::SMLoc Loc) const {
+CodeRegions::CodeRegions(llvm::SourceMgr &S) : SM(S), FoundErrors(false) {
+ // Create a default region for the input code sequence.
+ Regions.emplace_back(make_unique<CodeRegion>("", SMLoc()));
+}
+
+bool CodeRegion::isLocInRange(SMLoc Loc) const {
if (RangeEnd.isValid() && Loc.getPointer() > RangeEnd.getPointer())
return false;
if (RangeStart.isValid() && Loc.getPointer() < RangeStart.getPointer())
@@ -25,42 +29,88 @@ bool CodeRegion::isLocInRange(llvm::SMLoc Loc) const {
return true;
}
-void CodeRegions::beginRegion(llvm::StringRef Description, llvm::SMLoc Loc) {
- assert(!Regions.empty() && "Missing Default region");
- const CodeRegion &CurrentRegion = *Regions.back();
- if (CurrentRegion.startLoc().isValid() && !CurrentRegion.endLoc().isValid()) {
- SM.PrintMessage(Loc, llvm::SourceMgr::DK_Warning,
- "Ignoring invalid region start");
- return;
+void CodeRegions::beginRegion(StringRef Description, SMLoc Loc) {
+ if (ActiveRegions.empty()) {
+ // Remove the default region if there is at least one user defined region.
+ // By construction, only the default region has an invalid start location.
+ if (Regions.size() == 1 && !Regions[0]->startLoc().isValid() &&
+ !Regions[0]->endLoc().isValid()) {
+ ActiveRegions[Description] = 0;
+ Regions[0] = make_unique<CodeRegion>(Description, Loc);
+ return;
+ }
+ } else {
+ auto It = ActiveRegions.find(Description);
+ if (It != ActiveRegions.end()) {
+ const CodeRegion &R = *Regions[It->second];
+ if (Description.empty()) {
+ SM.PrintMessage(Loc, SourceMgr::DK_Error,
+ "found multiple overlapping anonymous regions");
+ SM.PrintMessage(R.startLoc(), SourceMgr::DK_Note,
+ "Previous anonymous region was defined here");
+ FoundErrors = true;
+ return;
+ }
+
+ SM.PrintMessage(Loc, SourceMgr::DK_Error,
+ "overlapping regions cannot have the same name");
+ SM.PrintMessage(R.startLoc(), SourceMgr::DK_Note,
+ "region " + Description + " was previously defined here");
+ FoundErrors = true;
+ return;
+ }
}
- // Remove the default region if there are user defined regions.
- if (!CurrentRegion.startLoc().isValid())
- Regions.erase(Regions.begin());
- addRegion(Description, Loc);
+ ActiveRegions[Description] = Regions.size();
+ Regions.emplace_back(make_unique<CodeRegion>(Description, Loc));
+ return;
}
-void CodeRegions::endRegion(llvm::SMLoc Loc) {
- assert(!Regions.empty() && "Missing Default region");
- CodeRegion &CurrentRegion = *Regions.back();
- if (CurrentRegion.endLoc().isValid()) {
- SM.PrintMessage(Loc, llvm::SourceMgr::DK_Warning,
- "Ignoring invalid region end");
+void CodeRegions::endRegion(StringRef Description, SMLoc Loc) {
+ if (Description.empty()) {
+ // Special case where there is only one user defined region,
+ // and this LLVM-MCA-END directive doesn't provide a region name.
+ // In this case, we assume that the user simply wanted to just terminate
+ // the only active region.
+ if (ActiveRegions.size() == 1) {
+ auto It = ActiveRegions.begin();
+ Regions[It->second]->setEndLocation(Loc);
+ ActiveRegions.erase(It);
+ return;
+ }
+
+ // Special case where the region end marker applies to the default region.
+ if (ActiveRegions.empty() && Regions.size() == 1 &&
+ !Regions[0]->startLoc().isValid() && !Regions[0]->endLoc().isValid()) {
+ Regions[0]->setEndLocation(Loc);
+ return;
+ }
+ }
+
+ auto It = ActiveRegions.find(Description);
+ if (It != ActiveRegions.end()) {
+ Regions[It->second]->setEndLocation(Loc);
+ ActiveRegions.erase(It);
return;
}
- CurrentRegion.setEndLocation(Loc);
+ FoundErrors = true;
+ SM.PrintMessage(Loc, SourceMgr::DK_Error,
+ "found an invalid region end directive");
+ if (!Description.empty()) {
+ SM.PrintMessage(Loc, SourceMgr::DK_Note,
+ "unable to find an active region named " + Description);
+ } else {
+ SM.PrintMessage(Loc, SourceMgr::DK_Note,
+ "unable to find an active anonymous region");
+ }
}
-void CodeRegions::addInstruction(const llvm::MCInst &Instruction) {
- const llvm::SMLoc &Loc = Instruction.getLoc();
- const auto It =
- std::find_if(Regions.rbegin(), Regions.rend(),
- [Loc](const std::unique_ptr<CodeRegion> &Region) {
- return Region->isLocInRange(Loc);
- });
- if (It != Regions.rend())
- (*It)->addInstruction(Instruction);
+void CodeRegions::addInstruction(const MCInst &Instruction) {
+ SMLoc Loc = Instruction.getLoc();
+ for (UniqueCodeRegion &Region : Regions)
+ if (Region->isLocInRange(Loc))
+ Region->addInstruction(Instruction);
}
} // namespace mca
diff --git a/contrib/llvm/tools/llvm-mca/CodeRegion.h b/contrib/llvm/tools/llvm-mca/CodeRegion.h
index 867aa18bb4fe..cabb4a5d4484 100644
--- a/contrib/llvm/tools/llvm-mca/CodeRegion.h
+++ b/contrib/llvm/tools/llvm-mca/CodeRegion.h
@@ -1,9 +1,8 @@
//===-------------------------- CodeRegion.h -------------------*- C++ -* -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -35,6 +34,7 @@
#define LLVM_TOOLS_LLVM_MCA_CODEREGION_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCInst.h"
#include "llvm/Support/SMLoc.h"
@@ -51,7 +51,7 @@ class CodeRegion {
// An optional descriptor for this region.
llvm::StringRef Description;
// Instructions that form this region.
- std::vector<llvm::MCInst> Instructions;
+ llvm::SmallVector<llvm::MCInst, 8> Instructions;
// Source location range.
llvm::SMLoc RangeStart;
llvm::SMLoc RangeEnd;
@@ -79,24 +79,25 @@ public:
llvm::StringRef getDescription() const { return Description; }
};
+class CodeRegionParseError final : public Error {};
+
class CodeRegions {
// A source manager. Used by the tool to generate meaningful warnings.
llvm::SourceMgr &SM;
- std::vector<std::unique_ptr<CodeRegion>> Regions;
-
- // Construct a new region of code guarded by LLVM-MCA comments.
- void addRegion(llvm::StringRef Description, llvm::SMLoc Loc) {
- Regions.emplace_back(llvm::make_unique<CodeRegion>(Description, Loc));
- }
+ using UniqueCodeRegion = std::unique_ptr<CodeRegion>;
+ std::vector<UniqueCodeRegion> Regions;
+ llvm::StringMap<unsigned> ActiveRegions;
+ bool FoundErrors;
CodeRegions(const CodeRegions &) = delete;
CodeRegions &operator=(const CodeRegions &) = delete;
public:
- typedef std::vector<std::unique_ptr<CodeRegion>>::iterator iterator;
- typedef std::vector<std::unique_ptr<CodeRegion>>::const_iterator
- const_iterator;
+ CodeRegions(llvm::SourceMgr &S);
+
+ typedef std::vector<UniqueCodeRegion>::iterator iterator;
+ typedef std::vector<UniqueCodeRegion>::const_iterator const_iterator;
iterator begin() { return Regions.begin(); }
iterator end() { return Regions.end(); }
@@ -104,24 +105,21 @@ public:
const_iterator end() const { return Regions.cend(); }
void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc);
- void endRegion(llvm::SMLoc Loc);
+ void endRegion(llvm::StringRef Description, llvm::SMLoc Loc);
void addInstruction(const llvm::MCInst &Instruction);
llvm::SourceMgr &getSourceMgr() const { return SM; }
- CodeRegions(llvm::SourceMgr &S) : SM(S) {
- // Create a default region for the input code sequence.
- addRegion("Default", llvm::SMLoc());
- }
-
llvm::ArrayRef<llvm::MCInst> getInstructionSequence(unsigned Idx) const {
return Regions[Idx]->getInstructions();
}
bool empty() const {
- return llvm::all_of(Regions, [](const std::unique_ptr<CodeRegion> &Region) {
+ return llvm::all_of(Regions, [](const UniqueCodeRegion &Region) {
return Region->empty();
});
}
+
+ bool isValid() const { return !FoundErrors; }
};
} // namespace mca
diff --git a/contrib/llvm/tools/llvm-mca/CodeRegionGenerator.cpp b/contrib/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
index 5bd37adeeae9..c793169e64e0 100644
--- a/contrib/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
+++ b/contrib/llvm/tools/llvm-mca/CodeRegionGenerator.cpp
@@ -1,9 +1,8 @@
//===----------------------- CodeRegionGenerator.cpp ------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -49,8 +48,7 @@ public:
// We only want to intercept the emission of new instructions.
virtual void EmitInstruction(const MCInst &Inst,
- const MCSubtargetInfo & /* unused */,
- bool /* unused */) override {
+ const MCSubtargetInfo &/* unused */) override {
Regions.addInstruction(Inst);
}
@@ -88,7 +86,11 @@ void MCACommentConsumer::HandleComment(SMLoc Loc, StringRef CommentText) {
Comment = Comment.drop_front(Position);
if (Comment.consume_front("LLVM-MCA-END")) {
- Regions.endRegion(Loc);
+ // Skip spaces and tabs.
+ Position = Comment.find_first_not_of(" \t");
+ if (Position < Comment.size())
+ Comment = Comment.drop_front(Position);
+ Regions.endRegion(Comment, Loc);
return;
}
@@ -117,7 +119,6 @@ Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions() {
MCACommentConsumer CC(Regions);
Lexer.setCommentConsumer(&CC);
- // Create a target-specific parser and perform the parse.
std::unique_ptr<MCTargetAsmParser> TAP(
TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));
if (!TAP)
@@ -127,7 +128,7 @@ Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions() {
Parser->setTargetParser(*TAP);
Parser->Run(false);
- // Get the assembler dialect from the input. llvm-mca will use this as the
+ // Set the assembler dialect from the input. llvm-mca will use this as the
// default dialect when printing reports.
AssemblerDialect = Parser->getAssemblerDialect();
return Regions;
diff --git a/contrib/llvm/tools/llvm-mca/CodeRegionGenerator.h b/contrib/llvm/tools/llvm-mca/CodeRegionGenerator.h
index 892cafb92686..9a10aa2c148b 100644
--- a/contrib/llvm/tools/llvm-mca/CodeRegionGenerator.h
+++ b/contrib/llvm/tools/llvm-mca/CodeRegionGenerator.h
@@ -1,9 +1,8 @@
//===----------------------- CodeRegionGenerator.h --------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/contrib/llvm/tools/llvm-mca/PipelinePrinter.cpp b/contrib/llvm/tools/llvm-mca/PipelinePrinter.cpp
index 18ef45fc2a65..90d468075996 100644
--- a/contrib/llvm/tools/llvm-mca/PipelinePrinter.cpp
+++ b/contrib/llvm/tools/llvm-mca/PipelinePrinter.cpp
@@ -1,9 +1,8 @@
//===--------------------- PipelinePrinter.cpp ------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/contrib/llvm/tools/llvm-mca/PipelinePrinter.h b/contrib/llvm/tools/llvm-mca/PipelinePrinter.h
index 456026e12df3..004309cd7b8e 100644
--- a/contrib/llvm/tools/llvm-mca/PipelinePrinter.h
+++ b/contrib/llvm/tools/llvm-mca/PipelinePrinter.h
@@ -1,9 +1,8 @@
//===--------------------- PipelinePrinter.h --------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/contrib/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp b/contrib/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp
new file mode 100644
index 000000000000..560c6c6e8a33
--- /dev/null
+++ b/contrib/llvm/tools/llvm-mca/Views/BottleneckAnalysis.cpp
@@ -0,0 +1,624 @@
+//===--------------------- BottleneckAnalysis.cpp ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file implements the functionalities used by the BottleneckAnalysis
+/// to report bottleneck info.
+///
+//===----------------------------------------------------------------------===//
+
+#include "Views/BottleneckAnalysis.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MCA/Support.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormattedStream.h"
+
+namespace llvm {
+namespace mca {
+
+#define DEBUG_TYPE "llvm-mca"
+
+PressureTracker::PressureTracker(const MCSchedModel &Model)
+ : SM(Model),
+ ResourcePressureDistribution(Model.getNumProcResourceKinds(), 0),
+ ProcResID2Mask(Model.getNumProcResourceKinds(), 0),
+ ResIdx2ProcResID(Model.getNumProcResourceKinds(), 0),
+ ProcResID2ResourceUsersIndex(Model.getNumProcResourceKinds(), 0) {
+ computeProcResourceMasks(SM, ProcResID2Mask);
+
+ // Ignore the invalid resource at index zero.
+ unsigned NextResourceUsersIdx = 0;
+ for (unsigned I = 1, E = Model.getNumProcResourceKinds(); I < E; ++I) {
+ const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
+ ProcResID2ResourceUsersIndex[I] = NextResourceUsersIdx;
+ NextResourceUsersIdx += ProcResource.NumUnits;
+ uint64_t ResourceMask = ProcResID2Mask[I];
+ ResIdx2ProcResID[getResourceStateIndex(ResourceMask)] = I;
+ }
+
+ ResourceUsers.resize(NextResourceUsersIdx);
+ std::fill(ResourceUsers.begin(), ResourceUsers.end(),
+ std::make_pair<unsigned, unsigned>(~0U, 0U));
+}
+
+void PressureTracker::getResourceUsers(uint64_t ResourceMask,
+ SmallVectorImpl<User> &Users) const {
+ unsigned Index = getResourceStateIndex(ResourceMask);
+ unsigned ProcResID = ResIdx2ProcResID[Index];
+ const MCProcResourceDesc &PRDesc = *SM.getProcResource(ProcResID);
+ for (unsigned I = 0, E = PRDesc.NumUnits; I < E; ++I) {
+ const User U = getResourceUser(ProcResID, I);
+ if (U.second && IPI.find(U.first) != IPI.end())
+ Users.emplace_back(U);
+ }
+}
+
+void PressureTracker::onInstructionDispatched(unsigned IID) {
+ IPI.insert(std::make_pair(IID, InstructionPressureInfo()));
+}
+
+void PressureTracker::onInstructionExecuted(unsigned IID) { IPI.erase(IID); }
+
+void PressureTracker::handleInstructionIssuedEvent(
+ const HWInstructionIssuedEvent &Event) {
+ unsigned IID = Event.IR.getSourceIndex();
+ using ResourceRef = HWInstructionIssuedEvent::ResourceRef;
+ using ResourceUse = std::pair<ResourceRef, ResourceCycles>;
+ for (const ResourceUse &Use : Event.UsedResources) {
+ const ResourceRef &RR = Use.first;
+ unsigned Index = ProcResID2ResourceUsersIndex[RR.first];
+ Index += countTrailingZeros(RR.second);
+ ResourceUsers[Index] = std::make_pair(IID, Use.second.getNumerator());
+ }
+}
+
+void PressureTracker::updateResourcePressureDistribution(
+ uint64_t CumulativeMask) {
+ while (CumulativeMask) {
+ uint64_t Current = CumulativeMask & (-CumulativeMask);
+ unsigned ResIdx = getResourceStateIndex(Current);
+ unsigned ProcResID = ResIdx2ProcResID[ResIdx];
+ uint64_t Mask = ProcResID2Mask[ProcResID];
+
+ if (Mask == Current) {
+ ResourcePressureDistribution[ProcResID]++;
+ CumulativeMask ^= Current;
+ continue;
+ }
+
+ Mask ^= Current;
+ while (Mask) {
+ uint64_t SubUnit = Mask & (-Mask);
+ ResIdx = getResourceStateIndex(SubUnit);
+ ProcResID = ResIdx2ProcResID[ResIdx];
+ ResourcePressureDistribution[ProcResID]++;
+ Mask ^= SubUnit;
+ }
+
+ CumulativeMask ^= Current;
+ }
+}
+
+void PressureTracker::handlePressureEvent(const HWPressureEvent &Event) {
+ assert(Event.Reason != HWPressureEvent::INVALID &&
+ "Unexpected invalid event!");
+
+ switch (Event.Reason) {
+ default:
+ break;
+
+ case HWPressureEvent::RESOURCES: {
+ const uint64_t ResourceMask = Event.ResourceMask;
+ updateResourcePressureDistribution(Event.ResourceMask);
+
+ for (const InstRef &IR : Event.AffectedInstructions) {
+ const Instruction &IS = *IR.getInstruction();
+ unsigned BusyResources = IS.getCriticalResourceMask() & ResourceMask;
+ if (!BusyResources)
+ continue;
+
+ unsigned IID = IR.getSourceIndex();
+ IPI[IID].ResourcePressureCycles++;
+ }
+ break;
+ }
+
+ case HWPressureEvent::REGISTER_DEPS:
+ for (const InstRef &IR : Event.AffectedInstructions) {
+ unsigned IID = IR.getSourceIndex();
+ IPI[IID].RegisterPressureCycles++;
+ }
+ break;
+
+ case HWPressureEvent::MEMORY_DEPS:
+ for (const InstRef &IR : Event.AffectedInstructions) {
+ unsigned IID = IR.getSourceIndex();
+ IPI[IID].MemoryPressureCycles++;
+ }
+ }
+}
+
+#ifndef NDEBUG
+void DependencyGraph::dumpDependencyEdge(raw_ostream &OS,
+ const DependencyEdge &DepEdge,
+ MCInstPrinter &MCIP) const {
+ unsigned FromIID = DepEdge.FromIID;
+ unsigned ToIID = DepEdge.ToIID;
+ assert(FromIID < ToIID && "Graph should be acyclic!");
+
+ const DependencyEdge::Dependency &DE = DepEdge.Dep;
+ assert(DE.Type != DependencyEdge::DT_INVALID && "Unexpected invalid edge!");
+
+ OS << " FROM: " << FromIID << " TO: " << ToIID << " ";
+ if (DE.Type == DependencyEdge::DT_REGISTER) {
+ OS << " - REGISTER: ";
+ MCIP.printRegName(OS, DE.ResourceOrRegID);
+ } else if (DE.Type == DependencyEdge::DT_MEMORY) {
+ OS << " - MEMORY";
+ } else {
+ assert(DE.Type == DependencyEdge::DT_RESOURCE &&
+ "Unsupported dependency type!");
+ OS << " - RESOURCE MASK: " << DE.ResourceOrRegID;
+ }
+ OS << " - CYCLES: " << DE.Cost << '\n';
+}
+#endif // NDEBUG
+
+void DependencyGraph::initializeRootSet(
+ SmallVectorImpl<unsigned> &RootSet) const {
+ for (unsigned I = 0, E = Nodes.size(); I < E; ++I) {
+ const DGNode &N = Nodes[I];
+ if (N.NumPredecessors == 0 && !N.OutgoingEdges.empty())
+ RootSet.emplace_back(I);
+ }
+}
+
+void DependencyGraph::propagateThroughEdges(
+ SmallVectorImpl<unsigned> &RootSet) {
+ SmallVector<unsigned, 8> ToVisit;
+
+ // A critical sequence is computed as the longest path from a node of the
+ // RootSet to a leaf node (i.e. a node with no successors). The RootSet is
+ // composed of nodes with at least one successor, and no predecessors.
+ //
+ // Each node of the graph starts with an initial default cost of zero. The
+ // cost of a node is a measure of criticality: the higher the cost, the bigger
+ // is the performance impact.
+ //
+ // This algorithm is very similar to a (reverse) Dijkstra. Every iteration of
+ // the inner loop selects (i.e. visits) a node N from a set of `unvisited
+ // nodes`, and then propagates the cost of N to all its neighbors.
+ //
+ // The `unvisited nodes` set initially contains all the nodes from the
+ // RootSet. A node N is added to the `unvisited nodes` if all its
+ // predecessors have been visited already.
+ //
+ // For simplicity, every node tracks the number of unvisited incoming edges in
+ // field `NumVisitedPredecessors`. When the value of that field drops to
+ // zero, then the corresponding node is added to a `ToVisit` set.
+ //
+ // At the end of every iteration of the outer loop, set `ToVisit` becomes our
+ // new `unvisited nodes` set.
+ //
+ // The algorithm terminates when the set of unvisited nodes (i.e. our RootSet)
+ // is empty. This algorithm works under the assumption that the graph is
+ // acyclic.
+ do {
+ for (unsigned IID : RootSet) {
+ const DGNode &N = Nodes[IID];
+ for (const DependencyEdge &DepEdge : N.OutgoingEdges) {
+ unsigned ToIID = DepEdge.ToIID;
+ DGNode &To = Nodes[ToIID];
+ uint64_t Cost = N.Cost + DepEdge.Dep.Cost;
+ // Check if this is the most expensive incoming edge seen so far. In
+ // case, update the total cost of the destination node (ToIID), as well
+ // its field `CriticalPredecessor`.
+ if (Cost > To.Cost) {
+ To.CriticalPredecessor = DepEdge;
+ To.Cost = Cost;
+ To.Depth = N.Depth + 1;
+ }
+ To.NumVisitedPredecessors++;
+ if (To.NumVisitedPredecessors == To.NumPredecessors)
+ ToVisit.emplace_back(ToIID);
+ }
+ }
+
+ std::swap(RootSet, ToVisit);
+ ToVisit.clear();
+ } while (!RootSet.empty());
+}
+
+void DependencyGraph::getCriticalSequence(
+ SmallVectorImpl<const DependencyEdge *> &Seq) const {
+ // At this stage, nodes of the graph have been already visited, and costs have
+ // been propagated through the edges (see method `propagateThroughEdges()`).
+
+ // Identify the node N with the highest cost in the graph. By construction,
+ // that node is the last instruction of our critical sequence.
+ // Field N.Depth would tell us the total length of the sequence.
+ //
+ // To obtain the sequence of critical edges, we simply follow the chain of critical
+ // predecessors starting from node N (field DGNode::CriticalPredecessor).
+ const auto It = std::max_element(
+ Nodes.begin(), Nodes.end(),
+ [](const DGNode &Lhs, const DGNode &Rhs) { return Lhs.Cost < Rhs.Cost; });
+ unsigned IID = std::distance(Nodes.begin(), It);
+ Seq.resize(Nodes[IID].Depth);
+ for (unsigned I = Seq.size(), E = 0; I > E; --I) {
+ const DGNode &N = Nodes[IID];
+ Seq[I - 1] = &N.CriticalPredecessor;
+ IID = N.CriticalPredecessor.FromIID;
+ }
+}
+
+static void printInstruction(formatted_raw_ostream &FOS,
+ const MCSubtargetInfo &STI, MCInstPrinter &MCIP,
+ const MCInst &MCI,
+ bool UseDifferentColor = false) {
+ std::string Instruction;
+ raw_string_ostream InstrStream(Instruction);
+
+ FOS.PadToColumn(14);
+
+ MCIP.printInst(&MCI, InstrStream, "", STI);
+ InstrStream.flush();
+
+ if (UseDifferentColor)
+ FOS.changeColor(raw_ostream::CYAN, true, false);
+ FOS << StringRef(Instruction).ltrim();
+ if (UseDifferentColor)
+ FOS.resetColor();
+}
+
+void BottleneckAnalysis::printCriticalSequence(raw_ostream &OS) const {
+ SmallVector<const DependencyEdge *, 16> Seq;
+ DG.getCriticalSequence(Seq);
+ if (Seq.empty())
+ return;
+
+ OS << "\nCritical sequence based on the simulation:\n\n";
+
+ const DependencyEdge &FirstEdge = *Seq[0];
+ unsigned FromIID = FirstEdge.FromIID % Source.size();
+ unsigned ToIID = FirstEdge.ToIID % Source.size();
+ bool IsLoopCarried = FromIID >= ToIID;
+
+ formatted_raw_ostream FOS(OS);
+ FOS.PadToColumn(14);
+ FOS << "Instruction";
+ FOS.PadToColumn(58);
+ FOS << "Dependency Information";
+
+ bool HasColors = FOS.has_colors();
+
+ unsigned CurrentIID = 0;
+ if (IsLoopCarried) {
+ FOS << "\n +----< " << FromIID << ".";
+ printInstruction(FOS, STI, MCIP, Source[FromIID], HasColors);
+ FOS << "\n |\n | < loop carried > \n |";
+ } else {
+ while (CurrentIID < FromIID) {
+ FOS << "\n " << CurrentIID << ".";
+ printInstruction(FOS, STI, MCIP, Source[CurrentIID]);
+ CurrentIID++;
+ }
+
+ FOS << "\n +----< " << CurrentIID << ".";
+ printInstruction(FOS, STI, MCIP, Source[CurrentIID], HasColors);
+ CurrentIID++;
+ }
+
+ for (const DependencyEdge *&DE : Seq) {
+ ToIID = DE->ToIID % Source.size();
+ unsigned LastIID = CurrentIID > ToIID ? Source.size() : ToIID;
+
+ while (CurrentIID < LastIID) {
+ FOS << "\n | " << CurrentIID << ".";
+ printInstruction(FOS, STI, MCIP, Source[CurrentIID]);
+ CurrentIID++;
+ }
+
+ if (CurrentIID == ToIID) {
+ FOS << "\n +----> " << ToIID << ".";
+ printInstruction(FOS, STI, MCIP, Source[CurrentIID], HasColors);
+ } else {
+ FOS << "\n |\n | < loop carried > \n |"
+ << "\n +----> " << ToIID << ".";
+ printInstruction(FOS, STI, MCIP, Source[ToIID], HasColors);
+ }
+ FOS.PadToColumn(58);
+
+ const DependencyEdge::Dependency &Dep = DE->Dep;
+ if (HasColors)
+ FOS.changeColor(raw_ostream::SAVEDCOLOR, true, false);
+
+ if (Dep.Type == DependencyEdge::DT_REGISTER) {
+ FOS << "## REGISTER dependency: ";
+ if (HasColors)
+ FOS.changeColor(raw_ostream::MAGENTA, true, false);
+ MCIP.printRegName(FOS, Dep.ResourceOrRegID);
+ } else if (Dep.Type == DependencyEdge::DT_MEMORY) {
+ FOS << "## MEMORY dependency.";
+ } else {
+ assert(Dep.Type == DependencyEdge::DT_RESOURCE &&
+ "Unsupported dependency type!");
+ FOS << "## RESOURCE interference: ";
+ if (HasColors)
+ FOS.changeColor(raw_ostream::MAGENTA, true, false);
+ FOS << Tracker.resolveResourceName(Dep.ResourceOrRegID);
+ if (HasColors) {
+ FOS.resetColor();
+ FOS.changeColor(raw_ostream::SAVEDCOLOR, true, false);
+ }
+ FOS << " [ probability: " << ((DE->Frequency * 100) / Iterations)
+ << "% ]";
+ }
+ if (HasColors)
+ FOS.resetColor();
+ ++CurrentIID;
+ }
+
+ while (CurrentIID < Source.size()) {
+ FOS << "\n " << CurrentIID << ".";
+ printInstruction(FOS, STI, MCIP, Source[CurrentIID]);
+ CurrentIID++;
+ }
+
+ FOS << '\n';
+ FOS.flush();
+}
+
+#ifndef NDEBUG
+void DependencyGraph::dump(raw_ostream &OS, MCInstPrinter &MCIP) const {
+ OS << "\nREG DEPS\n";
+ for (const DGNode &Node : Nodes)
+ for (const DependencyEdge &DE : Node.OutgoingEdges)
+ if (DE.Dep.Type == DependencyEdge::DT_REGISTER)
+ dumpDependencyEdge(OS, DE, MCIP);
+
+ OS << "\nMEM DEPS\n";
+ for (const DGNode &Node : Nodes)
+ for (const DependencyEdge &DE : Node.OutgoingEdges)
+ if (DE.Dep.Type == DependencyEdge::DT_MEMORY)
+ dumpDependencyEdge(OS, DE, MCIP);
+
+ OS << "\nRESOURCE DEPS\n";
+ for (const DGNode &Node : Nodes)
+ for (const DependencyEdge &DE : Node.OutgoingEdges)
+ if (DE.Dep.Type == DependencyEdge::DT_RESOURCE)
+ dumpDependencyEdge(OS, DE, MCIP);
+}
+#endif // NDEBUG
+
+void DependencyGraph::addDependency(unsigned From, unsigned To,
+ DependencyEdge::Dependency &&Dep) {
+ DGNode &NodeFrom = Nodes[From];
+ DGNode &NodeTo = Nodes[To];
+ SmallVectorImpl<DependencyEdge> &Vec = NodeFrom.OutgoingEdges;
+
+ auto It = find_if(Vec, [To, Dep](DependencyEdge &DE) {
+ return DE.ToIID == To && DE.Dep.ResourceOrRegID == Dep.ResourceOrRegID;
+ });
+
+ if (It != Vec.end()) {
+ It->Dep.Cost += Dep.Cost;
+ It->Frequency++;
+ return;
+ }
+
+ DependencyEdge DE = {Dep, From, To, 1};
+ Vec.emplace_back(DE);
+ NodeTo.NumPredecessors++;
+}
+
+BottleneckAnalysis::BottleneckAnalysis(const MCSubtargetInfo &sti,
+ MCInstPrinter &Printer,
+ ArrayRef<MCInst> S, unsigned NumIter)
+ : STI(sti), MCIP(Printer), Tracker(STI.getSchedModel()), DG(S.size() * 3),
+ Source(S), Iterations(NumIter), TotalCycles(0),
+ PressureIncreasedBecauseOfResources(false),
+ PressureIncreasedBecauseOfRegisterDependencies(false),
+ PressureIncreasedBecauseOfMemoryDependencies(false),
+ SeenStallCycles(false), BPI() {}
+
+void BottleneckAnalysis::addRegisterDep(unsigned From, unsigned To,
+ unsigned RegID, unsigned Cost) {
+ bool IsLoopCarried = From >= To;
+ unsigned SourceSize = Source.size();
+ if (IsLoopCarried) {
+ Cost *= Iterations / 2;
+ DG.addRegisterDep(From, To + SourceSize, RegID, Cost);
+ DG.addRegisterDep(From + SourceSize, To + (SourceSize * 2), RegID, Cost);
+ return;
+ }
+ DG.addRegisterDep(From + SourceSize, To + SourceSize, RegID, Cost);
+}
+
+void BottleneckAnalysis::addMemoryDep(unsigned From, unsigned To,
+ unsigned Cost) {
+ bool IsLoopCarried = From >= To;
+ unsigned SourceSize = Source.size();
+ if (IsLoopCarried) {
+ Cost *= Iterations / 2;
+ DG.addMemoryDep(From, To + SourceSize, Cost);
+ DG.addMemoryDep(From + SourceSize, To + (SourceSize * 2), Cost);
+ return;
+ }
+ DG.addMemoryDep(From + SourceSize, To + SourceSize, Cost);
+}
+
+void BottleneckAnalysis::addResourceDep(unsigned From, unsigned To,
+ uint64_t Mask, unsigned Cost) {
+ bool IsLoopCarried = From >= To;
+ unsigned SourceSize = Source.size();
+ if (IsLoopCarried) {
+ Cost *= Iterations / 2;
+ DG.addResourceDep(From, To + SourceSize, Mask, Cost);
+ DG.addResourceDep(From + SourceSize, To + (SourceSize * 2), Mask, Cost);
+ return;
+ }
+ DG.addResourceDep(From + SourceSize, To + SourceSize, Mask, Cost);
+}
+
+void BottleneckAnalysis::onEvent(const HWInstructionEvent &Event) {
+ const unsigned IID = Event.IR.getSourceIndex();
+ if (Event.Type == HWInstructionEvent::Dispatched) {
+ Tracker.onInstructionDispatched(IID);
+ return;
+ }
+ if (Event.Type == HWInstructionEvent::Executed) {
+ Tracker.onInstructionExecuted(IID);
+ return;
+ }
+
+ if (Event.Type != HWInstructionEvent::Issued)
+ return;
+
+ const Instruction &IS = *Event.IR.getInstruction();
+ unsigned To = IID % Source.size();
+
+ unsigned Cycles = 2 * Tracker.getResourcePressureCycles(IID);
+ uint64_t ResourceMask = IS.getCriticalResourceMask();
+ SmallVector<std::pair<unsigned, unsigned>, 4> Users;
+ while (ResourceMask) {
+ uint64_t Current = ResourceMask & (-ResourceMask);
+ Tracker.getResourceUsers(Current, Users);
+ for (const std::pair<unsigned, unsigned> &U : Users)
+ addResourceDep(U.first % Source.size(), To, Current, U.second + Cycles);
+ Users.clear();
+ ResourceMask ^= Current;
+ }
+
+ const CriticalDependency &RegDep = IS.getCriticalRegDep();
+ if (RegDep.Cycles) {
+ Cycles = RegDep.Cycles + 2 * Tracker.getRegisterPressureCycles(IID);
+ unsigned From = RegDep.IID % Source.size();
+ addRegisterDep(From, To, RegDep.RegID, Cycles);
+ }
+
+ const CriticalDependency &MemDep = IS.getCriticalMemDep();
+ if (MemDep.Cycles) {
+ Cycles = MemDep.Cycles + 2 * Tracker.getMemoryPressureCycles(IID);
+ unsigned From = MemDep.IID % Source.size();
+ addMemoryDep(From, To, Cycles);
+ }
+
+ Tracker.handleInstructionIssuedEvent(
+ static_cast<const HWInstructionIssuedEvent &>(Event));
+
+ // Check if this is the last simulated instruction.
+ if (IID == ((Iterations * Source.size()) - 1))
+ DG.finalizeGraph();
+}
+
+void BottleneckAnalysis::onEvent(const HWPressureEvent &Event) {
+ assert(Event.Reason != HWPressureEvent::INVALID &&
+ "Unexpected invalid event!");
+
+ Tracker.handlePressureEvent(Event);
+
+ switch (Event.Reason) {
+ default:
+ break;
+
+ case HWPressureEvent::RESOURCES:
+ PressureIncreasedBecauseOfResources = true;
+ break;
+ case HWPressureEvent::REGISTER_DEPS:
+ PressureIncreasedBecauseOfRegisterDependencies = true;
+ break;
+ case HWPressureEvent::MEMORY_DEPS:
+ PressureIncreasedBecauseOfMemoryDependencies = true;
+ break;
+ }
+}
+
+void BottleneckAnalysis::onCycleEnd() {
+ ++TotalCycles;
+
+ bool PressureIncreasedBecauseOfDataDependencies =
+ PressureIncreasedBecauseOfRegisterDependencies ||
+ PressureIncreasedBecauseOfMemoryDependencies;
+ if (!PressureIncreasedBecauseOfResources &&
+ !PressureIncreasedBecauseOfDataDependencies)
+ return;
+
+ ++BPI.PressureIncreaseCycles;
+ if (PressureIncreasedBecauseOfRegisterDependencies)
+ ++BPI.RegisterDependencyCycles;
+ if (PressureIncreasedBecauseOfMemoryDependencies)
+ ++BPI.MemoryDependencyCycles;
+ if (PressureIncreasedBecauseOfDataDependencies)
+ ++BPI.DataDependencyCycles;
+ if (PressureIncreasedBecauseOfResources)
+ ++BPI.ResourcePressureCycles;
+ PressureIncreasedBecauseOfResources = false;
+ PressureIncreasedBecauseOfRegisterDependencies = false;
+ PressureIncreasedBecauseOfMemoryDependencies = false;
+}
+
+void BottleneckAnalysis::printBottleneckHints(raw_ostream &OS) const {
+ if (!SeenStallCycles || !BPI.PressureIncreaseCycles) {
+ OS << "\n\nNo resource or data dependency bottlenecks discovered.\n";
+ return;
+ }
+
+ double PressurePerCycle =
+ (double)BPI.PressureIncreaseCycles * 100 / TotalCycles;
+ double ResourcePressurePerCycle =
+ (double)BPI.ResourcePressureCycles * 100 / TotalCycles;
+ double DDPerCycle = (double)BPI.DataDependencyCycles * 100 / TotalCycles;
+ double RegDepPressurePerCycle =
+ (double)BPI.RegisterDependencyCycles * 100 / TotalCycles;
+ double MemDepPressurePerCycle =
+ (double)BPI.MemoryDependencyCycles * 100 / TotalCycles;
+
+ OS << "\n\nCycles with backend pressure increase [ "
+ << format("%.2f", floor((PressurePerCycle * 100) + 0.5) / 100) << "% ]";
+
+ OS << "\nThroughput Bottlenecks: "
+ << "\n Resource Pressure [ "
+ << format("%.2f", floor((ResourcePressurePerCycle * 100) + 0.5) / 100)
+ << "% ]";
+
+ if (BPI.PressureIncreaseCycles) {
+ ArrayRef<unsigned> Distribution = Tracker.getResourcePressureDistribution();
+ const MCSchedModel &SM = STI.getSchedModel();
+ for (unsigned I = 0, E = Distribution.size(); I < E; ++I) {
+ unsigned ResourceCycles = Distribution[I];
+ if (ResourceCycles) {
+ double Frequency = (double)ResourceCycles * 100 / TotalCycles;
+ const MCProcResourceDesc &PRDesc = *SM.getProcResource(I);
+ OS << "\n - " << PRDesc.Name << " [ "
+ << format("%.2f", floor((Frequency * 100) + 0.5) / 100) << "% ]";
+ }
+ }
+ }
+
+ OS << "\n Data Dependencies: [ "
+ << format("%.2f", floor((DDPerCycle * 100) + 0.5) / 100) << "% ]";
+ OS << "\n - Register Dependencies [ "
+ << format("%.2f", floor((RegDepPressurePerCycle * 100) + 0.5) / 100)
+ << "% ]";
+ OS << "\n - Memory Dependencies [ "
+ << format("%.2f", floor((MemDepPressurePerCycle * 100) + 0.5) / 100)
+ << "% ]\n";
+}
+
+void BottleneckAnalysis::printView(raw_ostream &OS) const {
+ std::string Buffer;
+ raw_string_ostream TempStream(Buffer);
+ printBottleneckHints(TempStream);
+ TempStream.flush();
+ OS << Buffer;
+ printCriticalSequence(OS);
+}
+
+} // namespace mca.
+} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h b/contrib/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h
new file mode 100644
index 000000000000..7564b1a48206
--- /dev/null
+++ b/contrib/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h
@@ -0,0 +1,341 @@
+//===--------------------- BottleneckAnalysis.h -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file implements the bottleneck analysis view.
+///
+/// This view internally observes backend pressure increase events in order to
+/// identify problematic data dependencies and processor resource interferences.
+///
+/// Example of bottleneck analysis report for a dot-product on X86 btver2:
+///
+/// Cycles with backend pressure increase [ 40.76% ]
+/// Throughput Bottlenecks:
+/// Resource Pressure [ 39.34% ]
+/// - JFPA [ 39.34% ]
+/// - JFPU0 [ 39.34% ]
+/// Data Dependencies: [ 1.42% ]
+/// - Register Dependencies [ 1.42% ]
+/// - Memory Dependencies [ 0.00% ]
+///
+/// According to the example, backend pressure increased during the 40.76% of
+/// the simulated cycles. In particular, the major cause of backend pressure
+/// increases was the contention on floating point adder JFPA accessible from
+/// pipeline resource JFPU0.
+///
+/// At the end of each cycle, if pressure on the simulated out-of-order buffers
+/// has increased, a backend pressure event is reported.
+/// In particular, this occurs when there is a delta between the number of uOps
+/// dispatched and the number of uOps issued to the underlying pipelines.
+///
+/// The bottleneck analysis view is also responsible for identifying and printing
+/// the most "critical" sequence of dependent instructions according to the
+/// simulated run.
+///
+/// Below is the critical sequence computed for the dot-product example on
+/// btver2:
+///
+/// Instruction Dependency Information
+/// +----< 2. vhaddps %xmm3, %xmm3, %xmm4
+/// |
+/// | < loop carried >
+/// |
+/// | 0. vmulps %xmm0, %xmm0, %xmm2
+/// +----> 1. vhaddps %xmm2, %xmm2, %xmm3 ## RESOURCE interference: JFPA [ probability: 73% ]
+/// +----> 2. vhaddps %xmm3, %xmm3, %xmm4 ## REGISTER dependency: %xmm3
+/// |
+/// | < loop carried >
+/// |
+/// +----> 1. vhaddps %xmm2, %xmm2, %xmm3 ## RESOURCE interference: JFPA [ probability: 73% ]
+///
+///
+/// The algorithm that computes the critical sequence is very similar to a
+/// critical path analysis.
+///
+/// A dependency graph is used internally to track dependencies between nodes.
+/// Nodes of the graph represent instructions from the input assembly sequence,
+/// and edges of the graph represent data dependencies or processor resource
+/// interferences.
+///
+/// Edges are dynamically 'discovered' by observing instruction state transitions
+/// and backend pressure increase events. Edges are internally ranked based on
+/// their "criticality". A dependency is considered to be critical if it takes a
+/// long time to execute, and if it contributes to backend pressure increases.
+/// Criticality is internally measured in terms of cycles; it is computed for
+/// every edge in the graph as a function of the edge latency and the number of
+/// backend pressure increase cycles contributed by that edge.
+///
+/// At the end of simulation, costs are propagated to nodes through the edges of
+/// the graph, and the most expensive path connecting the root-set (a
+/// set of nodes with no predecessors) to a leaf node is reported as critical
+/// sequence.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H
+#define LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H
+
+#include "Views/View.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCSchedule.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace mca {
+
+class PressureTracker {
+ const MCSchedModel &SM;
+
+ // Resource pressure distribution. There is an element for every processor
+ // resource declared by the scheduling model. Quantities are number of cycles.
+ SmallVector<unsigned, 4> ResourcePressureDistribution;
+
+ // Each processor resource is associated with a so-called processor resource
+ // mask. This vector allows to correlate processor resource IDs with processor
+ // resource masks. There is exactly one element per each processor resource
+ // declared by the scheduling model.
+ SmallVector<uint64_t, 4> ProcResID2Mask;
+
+ // Maps processor resource state indices (returned by calls to
+ // `getResourceStateIndex(Mask)` to processor resource identifiers.
+ SmallVector<unsigned, 4> ResIdx2ProcResID;
+
+ // Maps Processor Resource identifiers to ResourceUsers indices.
+ SmallVector<unsigned, 4> ProcResID2ResourceUsersIndex;
+
+ // Identifies the last user of a processor resource unit.
+ // This vector is updated on every instruction issued event.
+ // There is one entry for every processor resource unit declared by the
+ // processor model. An all_ones value is treated like an invalid instruction
+ // identifier.
+ using User = std::pair<unsigned, unsigned>;
+ SmallVector<User, 4> ResourceUsers;
+
+ struct InstructionPressureInfo {
+ unsigned RegisterPressureCycles;
+ unsigned MemoryPressureCycles;
+ unsigned ResourcePressureCycles;
+ };
+ DenseMap<unsigned, InstructionPressureInfo> IPI;
+
+ void updateResourcePressureDistribution(uint64_t CumulativeMask);
+
+ User getResourceUser(unsigned ProcResID, unsigned UnitID) const {
+ unsigned Index = ProcResID2ResourceUsersIndex[ProcResID];
+ return ResourceUsers[Index + UnitID];
+ }
+
+public:
+ PressureTracker(const MCSchedModel &Model);
+
+ ArrayRef<unsigned> getResourcePressureDistribution() const {
+ return ResourcePressureDistribution;
+ }
+
+ void getResourceUsers(uint64_t ResourceMask,
+ SmallVectorImpl<User> &Users) const;
+
+ unsigned getRegisterPressureCycles(unsigned IID) const {
+ assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!");
+ const InstructionPressureInfo &Info = IPI.find(IID)->second;
+ return Info.RegisterPressureCycles;
+ }
+
+ unsigned getMemoryPressureCycles(unsigned IID) const {
+ assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!");
+ const InstructionPressureInfo &Info = IPI.find(IID)->second;
+ return Info.MemoryPressureCycles;
+ }
+
+ unsigned getResourcePressureCycles(unsigned IID) const {
+ assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!");
+ const InstructionPressureInfo &Info = IPI.find(IID)->second;
+ return Info.ResourcePressureCycles;
+ }
+
+ const char *resolveResourceName(uint64_t ResourceMask) const {
+ unsigned Index = getResourceStateIndex(ResourceMask);
+ unsigned ProcResID = ResIdx2ProcResID[Index];
+ const MCProcResourceDesc &PRDesc = *SM.getProcResource(ProcResID);
+ return PRDesc.Name;
+ }
+
+ void onInstructionDispatched(unsigned IID);
+ void onInstructionExecuted(unsigned IID);
+
+ void handlePressureEvent(const HWPressureEvent &Event);
+ void handleInstructionIssuedEvent(const HWInstructionIssuedEvent &Event);
+};
+
+// A dependency edge.
+struct DependencyEdge {
+ enum DependencyType { DT_INVALID, DT_REGISTER, DT_MEMORY, DT_RESOURCE };
+
+ // Dependency edge descriptor.
+ //
+ // It specifies the dependency type, as well as the edge cost in cycles.
+ struct Dependency {
+ DependencyType Type;
+ uint64_t ResourceOrRegID;
+ uint64_t Cost;
+ };
+ Dependency Dep;
+
+ unsigned FromIID;
+ unsigned ToIID;
+
+ // Used by the bottleneck analysis to compute the interference
+ // probability for processor resources.
+ unsigned Frequency;
+};
+
+// A dependency graph used by the bottleneck analysis to describe data
+// dependencies and processor resource interferences between instructions.
+//
+// There is a node (an instance of struct DGNode) for every instruction in the
+// input assembly sequence. Edges of the graph represent dependencies between
+// instructions.
+//
+// Each edge of the graph is associated with a cost value which is used
+// internally to rank dependency based on their impact on the runtime
+// performance (see field DependencyEdge::Dependency::Cost). In general, the
+// higher the cost of an edge, the higher the impact on performance.
+//
+// The cost of a dependency is a function of both the latency and the number of
+// cycles where the dependency has been seen as critical (i.e. contributing to
+// back-pressure increases).
+//
+// Loop carried dependencies are carefully expanded by the bottleneck analysis
+// to guarantee that the graph stays acyclic. To this end, extra nodes are
+// pre-allocated at construction time to describe instructions from "past and
+// future" iterations. The graph is kept acyclic mainly because it simplifies the
+// complexity of the algorithm that computes the critical sequence.
+class DependencyGraph {
+ struct DGNode {
+ unsigned NumPredecessors;
+ unsigned NumVisitedPredecessors;
+ uint64_t Cost;
+ unsigned Depth;
+
+ DependencyEdge CriticalPredecessor;
+ SmallVector<DependencyEdge, 8> OutgoingEdges;
+ };
+ SmallVector<DGNode, 16> Nodes;
+
+ DependencyGraph(const DependencyGraph &) = delete;
+ DependencyGraph &operator=(const DependencyGraph &) = delete;
+
+ void addDependency(unsigned From, unsigned To,
+ DependencyEdge::Dependency &&DE);
+
+ void initializeRootSet(SmallVectorImpl<unsigned> &RootSet) const;
+ void propagateThroughEdges(SmallVectorImpl<unsigned> &RootSet);
+
+#ifndef NDEBUG
+ void dumpDependencyEdge(raw_ostream &OS, const DependencyEdge &DE,
+ MCInstPrinter &MCIP) const;
+#endif
+
+public:
+ DependencyGraph(unsigned Size) : Nodes(Size) {}
+
+ void addRegisterDep(unsigned From, unsigned To, unsigned RegID,
+ unsigned Cost) {
+ addDependency(From, To, {DependencyEdge::DT_REGISTER, RegID, Cost});
+ }
+
+ void addMemoryDep(unsigned From, unsigned To, unsigned Cost) {
+ addDependency(From, To, {DependencyEdge::DT_MEMORY, /* unused */ 0, Cost});
+ }
+
+ void addResourceDep(unsigned From, unsigned To, uint64_t Mask,
+ unsigned Cost) {
+ addDependency(From, To, {DependencyEdge::DT_RESOURCE, Mask, Cost});
+ }
+
+ // Called by the bottleneck analysis at the end of simulation to propagate
+ // costs through the edges of the graph, and compute a critical path.
+ void finalizeGraph() {
+ SmallVector<unsigned, 16> RootSet;
+ initializeRootSet(RootSet);
+ propagateThroughEdges(RootSet);
+ }
+
+ // Returns a sequence of edges representing the critical sequence based on the
+ // simulated run. It assumes that the graph has already been finalized (i.e.
+ // method `finalizeGraph()` has already been called on this graph).
+ void getCriticalSequence(SmallVectorImpl<const DependencyEdge *> &Seq) const;
+
+#ifndef NDEBUG
+ void dump(raw_ostream &OS, MCInstPrinter &MCIP) const;
+#endif
+};
+
+/// A view that collects and prints a few performance numbers.
+class BottleneckAnalysis : public View {
+ const MCSubtargetInfo &STI;
+ MCInstPrinter &MCIP;
+ PressureTracker Tracker;
+ DependencyGraph DG;
+
+ ArrayRef<MCInst> Source;
+ unsigned Iterations;
+ unsigned TotalCycles;
+
+ bool PressureIncreasedBecauseOfResources;
+ bool PressureIncreasedBecauseOfRegisterDependencies;
+ bool PressureIncreasedBecauseOfMemoryDependencies;
+ // True if throughput was affected by dispatch stalls.
+ bool SeenStallCycles;
+
+ struct BackPressureInfo {
+ // Cycles where backpressure increased.
+ unsigned PressureIncreaseCycles;
+ // Cycles where backpressure increased because of pipeline pressure.
+ unsigned ResourcePressureCycles;
+ // Cycles where backpressure increased because of data dependencies.
+ unsigned DataDependencyCycles;
+ // Cycles where backpressure increased because of register dependencies.
+ unsigned RegisterDependencyCycles;
+ // Cycles where backpressure increased because of memory dependencies.
+ unsigned MemoryDependencyCycles;
+ };
+ BackPressureInfo BPI;
+
+ // Used to populate the dependency graph DG.
+ void addRegisterDep(unsigned From, unsigned To, unsigned RegID, unsigned Cy);
+ void addMemoryDep(unsigned From, unsigned To, unsigned Cy);
+ void addResourceDep(unsigned From, unsigned To, uint64_t Mask, unsigned Cy);
+
+ // Prints a bottleneck message to OS.
+ void printBottleneckHints(raw_ostream &OS) const;
+ void printCriticalSequence(raw_ostream &OS) const;
+
+public:
+ BottleneckAnalysis(const MCSubtargetInfo &STI, MCInstPrinter &MCIP,
+ ArrayRef<MCInst> Sequence, unsigned Iterations);
+
+ void onCycleEnd() override;
+ void onEvent(const HWStallEvent &Event) override { SeenStallCycles = true; }
+ void onEvent(const HWPressureEvent &Event) override;
+ void onEvent(const HWInstructionEvent &Event) override;
+
+ void printView(raw_ostream &OS) const override;
+
+#ifndef NDEBUG
+ void dump(raw_ostream &OS, MCInstPrinter &MCIP) const { DG.dump(OS, MCIP); }
+#endif
+};
+
+} // namespace mca
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp b/contrib/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp
index 2562c82407bf..557b8ba17b17 100644
--- a/contrib/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp
+++ b/contrib/llvm/tools/llvm-mca/Views/DispatchStatistics.cpp
@@ -1,10 +1,9 @@
//===--------------------- DispatchStatistics.cpp ---------------------*- C++
//-*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/contrib/llvm/tools/llvm-mca/Views/DispatchStatistics.h b/contrib/llvm/tools/llvm-mca/Views/DispatchStatistics.h
index 6679c81efe95..07c0f5a4c68f 100644
--- a/contrib/llvm/tools/llvm-mca/Views/DispatchStatistics.h
+++ b/contrib/llvm/tools/llvm-mca/Views/DispatchStatistics.h
@@ -1,9 +1,8 @@
//===--------------------- DispatchStatistics.h -----------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/contrib/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp b/contrib/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp
index 5016afb49e44..1fbffa3e5b69 100644
--- a/contrib/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp
+++ b/contrib/llvm/tools/llvm-mca/Views/InstructionInfoView.cpp
@@ -1,9 +1,8 @@
//===--------------------- InstructionInfoView.cpp --------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -44,6 +43,9 @@ void InstructionInfoView::printView(raw_ostream &OS) const {
const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
unsigned NumMicroOpcodes = SCDesc.NumMicroOps;
unsigned Latency = MCSchedModel::computeInstrLatency(STI, SCDesc);
+ // Add extra latency due to delays in the forwarding data paths.
+ Latency += MCSchedModel::getForwardingDelayCycles(
+ STI.getReadAdvanceEntries(SCDesc));
Optional<double> RThroughput =
MCSchedModel::getReciprocalThroughput(STI, SCDesc);
diff --git a/contrib/llvm/tools/llvm-mca/Views/InstructionInfoView.h b/contrib/llvm/tools/llvm-mca/Views/InstructionInfoView.h
index 3ef95d474490..640d87383436 100644
--- a/contrib/llvm/tools/llvm-mca/Views/InstructionInfoView.h
+++ b/contrib/llvm/tools/llvm-mca/Views/InstructionInfoView.h
@@ -1,9 +1,8 @@
//===--------------------- InstructionInfoView.h ----------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/contrib/llvm/tools/llvm-mca/Views/RegisterFileStatistics.cpp b/contrib/llvm/tools/llvm-mca/Views/RegisterFileStatistics.cpp
index 06202bc41421..58736ee0d18c 100644
--- a/contrib/llvm/tools/llvm-mca/Views/RegisterFileStatistics.cpp
+++ b/contrib/llvm/tools/llvm-mca/Views/RegisterFileStatistics.cpp
@@ -1,9 +1,8 @@
//===--------------------- RegisterFileStatistics.cpp -----------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/contrib/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h b/contrib/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h
index a2c52a668dae..a2273dd48b22 100644
--- a/contrib/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h
+++ b/contrib/llvm/tools/llvm-mca/Views/RegisterFileStatistics.h
@@ -1,9 +1,8 @@
//===--------------------- RegisterFileStatistics.h -------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/contrib/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp b/contrib/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp
index 6df61840437d..38a2478cf4fe 100644
--- a/contrib/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp
+++ b/contrib/llvm/tools/llvm-mca/Views/ResourcePressureView.cpp
@@ -1,9 +1,8 @@
//===--------------------- ResourcePressureView.cpp -------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/contrib/llvm/tools/llvm-mca/Views/ResourcePressureView.h b/contrib/llvm/tools/llvm-mca/Views/ResourcePressureView.h
index 572ce6fe6b70..0fa0b9a36aa3 100644
--- a/contrib/llvm/tools/llvm-mca/Views/ResourcePressureView.h
+++ b/contrib/llvm/tools/llvm-mca/Views/ResourcePressureView.h
@@ -1,9 +1,8 @@
//===--------------------- ResourcePressureView.h ---------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/contrib/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp b/contrib/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp
index 54eb28f1add9..cb4fbae78039 100644
--- a/contrib/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp
+++ b/contrib/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.cpp
@@ -1,9 +1,8 @@
//===--------------------- RetireControlUnitStatistics.cpp ------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/contrib/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h b/contrib/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h
index 02aa13bc444a..1a4d3dec5c56 100644
--- a/contrib/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h
+++ b/contrib/llvm/tools/llvm-mca/Views/RetireControlUnitStatistics.h
@@ -1,9 +1,8 @@
//===--------------------- RetireControlUnitStatistics.h --------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/contrib/llvm/tools/llvm-mca/Views/SchedulerStatistics.cpp b/contrib/llvm/tools/llvm-mca/Views/SchedulerStatistics.cpp
index 670f90127f18..bd0ba350ab68 100644
--- a/contrib/llvm/tools/llvm-mca/Views/SchedulerStatistics.cpp
+++ b/contrib/llvm/tools/llvm-mca/Views/SchedulerStatistics.cpp
@@ -1,9 +1,8 @@
//===--------------------- SchedulerStatistics.cpp --------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -23,7 +22,6 @@ SchedulerStatistics::SchedulerStatistics(const llvm::MCSubtargetInfo &STI)
: SM(STI.getSchedModel()), LQResourceID(0), SQResourceID(0), NumIssued(0),
NumCycles(0), MostRecentLoadDispatched(~0U),
MostRecentStoreDispatched(~0U),
- IssuedPerCycle(STI.getSchedModel().NumProcResourceKinds, 0),
Usage(STI.getSchedModel().NumProcResourceKinds, {0, 0, 0}) {
if (SM.hasExtraProcessorInfo()) {
const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo();
@@ -44,9 +42,10 @@ SchedulerStatistics::SchedulerStatistics(const llvm::MCSubtargetInfo &STI)
// In future we should add a new "memory queue" event type, so that we stop
// making assumptions on how LSUnit internally works (See PR39828).
void SchedulerStatistics::onEvent(const HWInstructionEvent &Event) {
- if (Event.Type == HWInstructionEvent::Issued)
- ++NumIssued;
- else if (Event.Type == HWInstructionEvent::Dispatched) {
+ if (Event.Type == HWInstructionEvent::Issued) {
+ const Instruction &Inst = *Event.IR.getInstruction();
+ NumIssued += Inst.getDesc().NumMicroOps;
+ } else if (Event.Type == HWInstructionEvent::Dispatched) {
const Instruction &Inst = *Event.IR.getInstruction();
const unsigned Index = Event.IR.getSourceIndex();
if (LQResourceID && Inst.getDesc().MayLoad &&
@@ -96,29 +95,25 @@ void SchedulerStatistics::updateHistograms() {
BU.MaxUsedSlots = std::max(BU.MaxUsedSlots, BU.SlotsInUse);
}
- IssuedPerCycle[NumIssued]++;
+ IssueWidthPerCycle[NumIssued]++;
NumIssued = 0;
}
void SchedulerStatistics::printSchedulerStats(raw_ostream &OS) const {
OS << "\n\nSchedulers - "
- << "number of cycles where we saw N instructions issued:\n";
+ << "number of cycles where we saw N micro opcodes issued:\n";
OS << "[# issued], [# cycles]\n";
- const auto It =
- std::max_element(IssuedPerCycle.begin(), IssuedPerCycle.end());
- unsigned Index = std::distance(IssuedPerCycle.begin(), It);
-
bool HasColors = OS.has_colors();
- for (unsigned I = 0, E = IssuedPerCycle.size(); I < E; ++I) {
- unsigned IPC = IssuedPerCycle[I];
- if (!IPC)
- continue;
-
- if (I == Index && HasColors)
+ const auto It =
+ std::max_element(IssueWidthPerCycle.begin(), IssueWidthPerCycle.end());
+ for (const std::pair<unsigned, unsigned> &Entry : IssueWidthPerCycle) {
+ unsigned NumIssued = Entry.first;
+ if (NumIssued == It->first && HasColors)
OS.changeColor(raw_ostream::SAVEDCOLOR, true, false);
- OS << " " << I << ", " << IPC << " ("
+ unsigned IPC = Entry.second;
+ OS << " " << NumIssued << ", " << IPC << " ("
<< format("%.1f", ((double)IPC / NumCycles) * 100) << "%)\n";
if (HasColors)
OS.resetColor();
diff --git a/contrib/llvm/tools/llvm-mca/Views/SchedulerStatistics.h b/contrib/llvm/tools/llvm-mca/Views/SchedulerStatistics.h
index d99a395a726d..32711b4483b4 100644
--- a/contrib/llvm/tools/llvm-mca/Views/SchedulerStatistics.h
+++ b/contrib/llvm/tools/llvm-mca/Views/SchedulerStatistics.h
@@ -1,9 +1,8 @@
//===--------------------- SchedulerStatistics.h ----------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -63,7 +62,9 @@ class SchedulerStatistics final : public View {
uint64_t CumulativeNumUsedSlots;
};
- std::vector<unsigned> IssuedPerCycle;
+ using Histogram = std::map<unsigned, unsigned>;
+ Histogram IssueWidthPerCycle;
+
std::vector<BufferUsage> Usage;
void updateHistograms();
diff --git a/contrib/llvm/tools/llvm-mca/Views/SummaryView.cpp b/contrib/llvm/tools/llvm-mca/Views/SummaryView.cpp
index d8ac709e784d..ef5550048f4c 100644
--- a/contrib/llvm/tools/llvm-mca/Views/SummaryView.cpp
+++ b/contrib/llvm/tools/llvm-mca/Views/SummaryView.cpp
@@ -1,9 +1,8 @@
//===--------------------- SummaryView.cpp -------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -25,11 +24,17 @@ namespace mca {
SummaryView::SummaryView(const MCSchedModel &Model, ArrayRef<MCInst> S,
unsigned Width)
- : SM(Model), Source(S), DispatchWidth(Width), LastInstructionIdx(0),
+ : SM(Model), Source(S), DispatchWidth(Width?Width: Model.IssueWidth),
+ LastInstructionIdx(0),
TotalCycles(0), NumMicroOps(0),
ProcResourceUsage(Model.getNumProcResourceKinds(), 0),
- ProcResourceMasks(Model.getNumProcResourceKinds()) {
+ ProcResourceMasks(Model.getNumProcResourceKinds()),
+ ResIdx2ProcResID(Model.getNumProcResourceKinds(), 0) {
computeProcResourceMasks(SM, ProcResourceMasks);
+ for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) {
+ unsigned Index = getResourceStateIndex(ProcResourceMasks[I]);
+ ResIdx2ProcResID[Index] = I;
+ }
}
void SummaryView::onEvent(const HWInstructionEvent &Event) {
@@ -51,11 +56,8 @@ void SummaryView::onEvent(const HWInstructionEvent &Event) {
NumMicroOps += Desc.NumMicroOps;
for (const std::pair<uint64_t, const ResourceUsage> &RU : Desc.Resources) {
if (RU.second.size()) {
- const auto It = find(ProcResourceMasks, RU.first);
- assert(It != ProcResourceMasks.end() &&
- "Invalid processor resource mask!");
- ProcResourceUsage[std::distance(ProcResourceMasks.begin(), It)] +=
- RU.second.size();
+ unsigned ProcResID = ResIdx2ProcResID[getResourceStateIndex(RU.first)];
+ ProcResourceUsage[ProcResID] += RU.second.size();
}
}
}
@@ -87,5 +89,6 @@ void SummaryView::printView(raw_ostream &OS) const {
TempStream.flush();
OS << Buffer;
}
+
} // namespace mca.
} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-mca/Views/SummaryView.h b/contrib/llvm/tools/llvm-mca/Views/SummaryView.h
index f59fd4233fbe..9be31b7d51bd 100644
--- a/contrib/llvm/tools/llvm-mca/Views/SummaryView.h
+++ b/contrib/llvm/tools/llvm-mca/Views/SummaryView.h
@@ -1,9 +1,8 @@
//===--------------------- SummaryView.h ---------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -46,6 +45,7 @@ class SummaryView : public View {
unsigned TotalCycles;
// The total number of micro opcodes contributed by a block of instructions.
unsigned NumMicroOps;
+
// For each processor resource, this vector stores the cumulative number of
// resource cycles consumed by the analyzed code block.
llvm::SmallVector<unsigned, 8> ProcResourceUsage;
@@ -56,6 +56,9 @@ class SummaryView : public View {
// declared by the scheduling model.
llvm::SmallVector<uint64_t, 8> ProcResourceMasks;
+ // Used to map resource indices to actual processor resource IDs.
+ llvm::SmallVector<unsigned, 8> ResIdx2ProcResID;
+
// Compute the reciprocal throughput for the analyzed code block.
// The reciprocal block throughput is computed as the MAX between:
// - NumMicroOps / DispatchWidth
@@ -68,9 +71,9 @@ public:
void onCycleEnd() override { ++TotalCycles; }
void onEvent(const HWInstructionEvent &Event) override;
-
void printView(llvm::raw_ostream &OS) const override;
};
+
} // namespace mca
} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-mca/Views/TimelineView.cpp b/contrib/llvm/tools/llvm-mca/Views/TimelineView.cpp
index 7d55bbc99c73..fe3f16ba344c 100644
--- a/contrib/llvm/tools/llvm-mca/Views/TimelineView.cpp
+++ b/contrib/llvm/tools/llvm-mca/Views/TimelineView.cpp
@@ -1,9 +1,8 @@
//===--------------------- TimelineView.cpp ---------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \brief
diff --git a/contrib/llvm/tools/llvm-mca/Views/TimelineView.h b/contrib/llvm/tools/llvm-mca/Views/TimelineView.h
index ee981800161c..b63b234293cd 100644
--- a/contrib/llvm/tools/llvm-mca/Views/TimelineView.h
+++ b/contrib/llvm/tools/llvm-mca/Views/TimelineView.h
@@ -1,9 +1,8 @@
//===--------------------- TimelineView.h -----------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \brief
diff --git a/contrib/llvm/tools/llvm-mca/Views/View.cpp b/contrib/llvm/tools/llvm-mca/Views/View.cpp
index 6cfb9dd9f394..8e5c34d2d5c2 100644
--- a/contrib/llvm/tools/llvm-mca/Views/View.cpp
+++ b/contrib/llvm/tools/llvm-mca/Views/View.cpp
@@ -1,9 +1,8 @@
//===----------------------- View.cpp ---------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/contrib/llvm/tools/llvm-mca/Views/View.h b/contrib/llvm/tools/llvm-mca/Views/View.h
index 4b82b0da0d27..3b52511b4d29 100644
--- a/contrib/llvm/tools/llvm-mca/Views/View.h
+++ b/contrib/llvm/tools/llvm-mca/Views/View.h
@@ -1,9 +1,8 @@
//===----------------------- View.h -----------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/contrib/llvm/tools/llvm-mca/llvm-mca.cpp b/contrib/llvm/tools/llvm-mca/llvm-mca.cpp
index 68d63db599d7..b3590b5910ec 100644
--- a/contrib/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/contrib/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -1,9 +1,8 @@
//===-- llvm-mca.cpp - Machine Code Analyzer -------------------*- C++ -* -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -24,6 +23,7 @@
#include "CodeRegion.h"
#include "CodeRegionGenerator.h"
#include "PipelinePrinter.h"
+#include "Views/BottleneckAnalysis.h"
#include "Views/DispatchStatistics.h"
#include "Views/InstructionInfoView.h"
#include "Views/RegisterFileStatistics.h"
@@ -68,8 +68,9 @@ static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
cl::value_desc("filename"));
static cl::opt<std::string>
- ArchName("march", cl::desc("Target architecture. "
- "See -version for available targets"),
+ ArchName("march",
+ cl::desc("Target architecture. "
+ "See -version for available targets"),
cl::cat(ToolOptions));
static cl::opt<std::string>
@@ -101,6 +102,17 @@ static cl::opt<unsigned>
"be used for register mappings"),
cl::cat(ToolOptions), cl::init(0));
+static cl::opt<unsigned>
+ MicroOpQueue("micro-op-queue-size", cl::Hidden,
+ cl::desc("Number of entries in the micro-op queue"),
+ cl::cat(ToolOptions), cl::init(0));
+
+static cl::opt<unsigned>
+ DecoderThroughput("decoder-throughput", cl::Hidden,
+ cl::desc("Maximum throughput from the decoders "
+ "(instructions per cycle)"),
+ cl::cat(ToolOptions), cl::init(0));
+
static cl::opt<bool>
PrintRegisterFileStats("register-file-stats",
cl::desc("Print register file statistics"),
@@ -176,6 +188,11 @@ static cl::opt<bool>
cl::desc("Print all views including hardware statistics"),
cl::cat(ViewOptions), cl::init(false));
+static cl::opt<bool> EnableBottleneckAnalysis(
+ "bottleneck-analysis",
+ cl::desc("Enable bottleneck analysis (disabled by default)"),
+ cl::cat(ViewOptions), cl::init(false));
+
namespace {
const Target *getTarget(const char *ProgName) {
@@ -220,6 +237,7 @@ static void processViewOptions() {
if (EnableAllViews.getNumOccurrences()) {
processOptionImpl(PrintSummaryView, EnableAllViews);
+ processOptionImpl(EnableBottleneckAnalysis, EnableAllViews);
processOptionImpl(PrintResourcePressureView, EnableAllViews);
processOptionImpl(PrintTimelineView, EnableAllViews);
processOptionImpl(PrintInstructionInfoView, EnableAllViews);
@@ -348,6 +366,11 @@ int main(int argc, char **argv) {
return 1;
}
const mca::CodeRegions &Regions = *RegionsOrErr;
+
+ // Early exit if errors were found by the code region parsing logic.
+ if (!Regions.isValid())
+ return 1;
+
if (Regions.empty()) {
WithColor::error() << "no assembly instructions found.\n";
return 1;
@@ -377,18 +400,15 @@ int main(int argc, char **argv) {
const MCSchedModel &SM = STI->getSchedModel();
- unsigned Width = SM.IssueWidth;
- if (DispatchWidth)
- Width = DispatchWidth;
-
// Create an instruction builder.
mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get());
// Create a context to control ownership of the pipeline hardware.
mca::Context MCA(*MRI, *STI);
- mca::PipelineOptions PO(Width, RegisterFileSize, LoadQueueSize,
- StoreQueueSize, AssumeNoAlias);
+ mca::PipelineOptions PO(MicroOpQueue, DecoderThroughput, DispatchWidth,
+ RegisterFileSize, LoadQueueSize, StoreQueueSize,
+ AssumeNoAlias, EnableBottleneckAnalysis);
// Number each region in the sequence.
unsigned RegionIdx = 0;
@@ -423,8 +443,8 @@ int main(int argc, char **argv) {
WithColor::error() << IE.Message << '\n';
IP->printInst(&IE.Inst, SS, "", *STI);
SS.flush();
- WithColor::note() << "instruction: " << InstructionStr
- << '\n';
+ WithColor::note()
+ << "instruction: " << InstructionStr << '\n';
})) {
// Default case.
WithColor::error() << toString(std::move(NewE));
@@ -464,7 +484,13 @@ int main(int argc, char **argv) {
mca::PipelinePrinter Printer(*P);
if (PrintSummaryView)
- Printer.addView(llvm::make_unique<mca::SummaryView>(SM, Insts, Width));
+ Printer.addView(
+ llvm::make_unique<mca::SummaryView>(SM, Insts, DispatchWidth));
+
+ if (EnableBottleneckAnalysis) {
+ Printer.addView(llvm::make_unique<mca::BottleneckAnalysis>(
+ *STI, *IP, Insts, S.getNumIterations()));
+ }
if (PrintInstructionInfoView)
Printer.addView(
diff --git a/contrib/llvm/tools/llvm-modextract/llvm-modextract.cpp b/contrib/llvm/tools/llvm-modextract/llvm-modextract.cpp
index 9fd8340505aa..3adefc5f0d3e 100644
--- a/contrib/llvm/tools/llvm-modextract/llvm-modextract.cpp
+++ b/contrib/llvm/tools/llvm-modextract/llvm-modextract.cpp
@@ -1,9 +1,8 @@
//===-- llvm-modextract.cpp - LLVM module extractor utility ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-nm/llvm-nm.cpp b/contrib/llvm/tools/llvm-nm/llvm-nm.cpp
index 042e284e8369..aa62e6f0209b 100644
--- a/contrib/llvm/tools/llvm-nm/llvm-nm.cpp
+++ b/contrib/llvm/tools/llvm-nm/llvm-nm.cpp
@@ -1,9 +1,8 @@
//===-- llvm-nm.cpp - Symbol table dumping utility for llvm ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -47,12 +46,15 @@ using namespace object;
namespace {
enum OutputFormatTy { bsd, sysv, posix, darwin };
+
+cl::OptionCategory NMCat("llvm-nm Options");
+
cl::opt<OutputFormatTy> OutputFormat(
"format", cl::desc("Specify output format"),
cl::values(clEnumVal(bsd, "BSD format"), clEnumVal(sysv, "System V format"),
clEnumVal(posix, "POSIX.2 format"),
clEnumVal(darwin, "Darwin -m format")),
- cl::init(bsd));
+ cl::init(bsd), cl::cat(NMCat));
cl::alias OutputFormat2("f", cl::desc("Alias for --format"),
cl::aliasopt(OutputFormat));
@@ -60,50 +62,53 @@ cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"),
cl::ZeroOrMore);
cl::opt<bool> UndefinedOnly("undefined-only",
- cl::desc("Show only undefined symbols"));
+ cl::desc("Show only undefined symbols"),
+ cl::cat(NMCat));
cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"),
cl::aliasopt(UndefinedOnly), cl::Grouping);
cl::opt<bool> DynamicSyms("dynamic",
cl::desc("Display the dynamic symbols instead "
- "of normal symbols."));
+ "of normal symbols."),
+ cl::cat(NMCat));
cl::alias DynamicSyms2("D", cl::desc("Alias for --dynamic"),
cl::aliasopt(DynamicSyms), cl::Grouping);
-cl::opt<bool> DefinedOnly("defined-only",
- cl::desc("Show only defined symbols"));
+cl::opt<bool> DefinedOnly("defined-only", cl::desc("Show only defined symbols"),
+ cl::cat(NMCat));
cl::alias DefinedOnly2("U", cl::desc("Alias for --defined-only"),
cl::aliasopt(DefinedOnly), cl::Grouping);
cl::opt<bool> ExternalOnly("extern-only",
cl::desc("Show only external symbols"),
- cl::ZeroOrMore);
+ cl::ZeroOrMore, cl::cat(NMCat));
cl::alias ExternalOnly2("g", cl::desc("Alias for --extern-only"),
cl::aliasopt(ExternalOnly), cl::Grouping,
cl::ZeroOrMore);
-cl::opt<bool> NoWeakSymbols("no-weak",
- cl::desc("Show only non-weak symbols"));
+cl::opt<bool> NoWeakSymbols("no-weak", cl::desc("Show only non-weak symbols"),
+ cl::cat(NMCat));
cl::alias NoWeakSymbols2("W", cl::desc("Alias for --no-weak"),
cl::aliasopt(NoWeakSymbols), cl::Grouping);
-cl::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd"),
- cl::Grouping);
+cl::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd"), cl::Grouping,
+ cl::cat(NMCat));
cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix"),
- cl::Grouping);
+ cl::Grouping, cl::cat(NMCat));
cl::alias Portability("portability", cl::desc("Alias for --format=posix"),
cl::aliasopt(POSIXFormat), cl::NotHidden);
cl::opt<bool> DarwinFormat("m", cl::desc("Alias for --format=darwin"),
- cl::Grouping);
+ cl::Grouping, cl::cat(NMCat));
static cl::list<std::string>
ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
- cl::ZeroOrMore);
+ cl::ZeroOrMore, cl::cat(NMCat));
bool ArchAll = false;
cl::opt<bool> PrintFileName(
"print-file-name",
- cl::desc("Precede each symbol with the object file it came from"));
+ cl::desc("Precede each symbol with the object file it came from"),
+ cl::cat(NMCat));
cl::alias PrintFileNameA("A", cl::desc("Alias for --print-file-name"),
cl::aliasopt(PrintFileName), cl::Grouping);
@@ -111,40 +116,52 @@ cl::alias PrintFileNameo("o", cl::desc("Alias for --print-file-name"),
cl::aliasopt(PrintFileName), cl::Grouping);
cl::opt<bool> DebugSyms("debug-syms",
- cl::desc("Show all symbols, even debugger only"));
+ cl::desc("Show all symbols, even debugger only"),
+ cl::cat(NMCat));
cl::alias DebugSymsa("a", cl::desc("Alias for --debug-syms"),
cl::aliasopt(DebugSyms), cl::Grouping);
-cl::opt<bool> NumericSort("numeric-sort", cl::desc("Sort symbols by address"));
+cl::opt<bool> NumericSort("numeric-sort", cl::desc("Sort symbols by address"),
+ cl::cat(NMCat));
cl::alias NumericSortn("n", cl::desc("Alias for --numeric-sort"),
cl::aliasopt(NumericSort), cl::Grouping);
cl::alias NumericSortv("v", cl::desc("Alias for --numeric-sort"),
cl::aliasopt(NumericSort), cl::Grouping);
-cl::opt<bool> NoSort("no-sort", cl::desc("Show symbols in order encountered"));
+cl::opt<bool> NoSort("no-sort", cl::desc("Show symbols in order encountered"),
+ cl::cat(NMCat));
cl::alias NoSortp("p", cl::desc("Alias for --no-sort"), cl::aliasopt(NoSort),
cl::Grouping);
-cl::opt<bool> Demangle("demangle", cl::desc("Demangle C++ symbol names"));
-cl::alias DemangleC("C", cl::desc("Alias for --demangle"), cl::aliasopt(Demangle),
- cl::Grouping);
+cl::opt<bool> Demangle("demangle", cl::ZeroOrMore,
+ cl::desc("Demangle C++ symbol names"), cl::cat(NMCat));
+cl::alias DemangleC("C", cl::desc("Alias for --demangle"),
+ cl::aliasopt(Demangle), cl::Grouping);
+cl::opt<bool> NoDemangle("no-demangle", cl::init(false), cl::ZeroOrMore,
+ cl::desc("Don't demangle symbol names"),
+ cl::cat(NMCat));
-cl::opt<bool> ReverseSort("reverse-sort", cl::desc("Sort in reverse order"));
+cl::opt<bool> ReverseSort("reverse-sort", cl::desc("Sort in reverse order"),
+ cl::cat(NMCat));
cl::alias ReverseSortr("r", cl::desc("Alias for --reverse-sort"),
cl::aliasopt(ReverseSort), cl::Grouping);
cl::opt<bool> PrintSize("print-size",
- cl::desc("Show symbol size instead of address"));
+ cl::desc("Show symbol size as well as address"),
+ cl::cat(NMCat));
cl::alias PrintSizeS("S", cl::desc("Alias for --print-size"),
cl::aliasopt(PrintSize), cl::Grouping);
bool MachOPrintSizeWarning = false;
-cl::opt<bool> SizeSort("size-sort", cl::desc("Sort symbols by size"));
+cl::opt<bool> SizeSort("size-sort", cl::desc("Sort symbols by size"),
+ cl::cat(NMCat));
cl::opt<bool> WithoutAliases("without-aliases", cl::Hidden,
- cl::desc("Exclude aliases from output"));
+ cl::desc("Exclude aliases from output"),
+ cl::cat(NMCat));
-cl::opt<bool> ArchiveMap("print-armap", cl::desc("Print the archive map"));
+cl::opt<bool> ArchiveMap("print-armap", cl::desc("Print the archive map"),
+ cl::cat(NMCat));
cl::alias ArchiveMaps("M", cl::desc("Alias for --print-armap"),
cl::aliasopt(ArchiveMap), cl::Grouping);
@@ -153,38 +170,45 @@ cl::opt<Radix>
AddressRadix("radix", cl::desc("Radix (o/d/x) for printing symbol Values"),
cl::values(clEnumVal(d, "decimal"), clEnumVal(o, "octal"),
clEnumVal(x, "hexadecimal")),
- cl::init(x));
+ cl::init(x), cl::cat(NMCat));
cl::alias RadixAlias("t", cl::desc("Alias for --radix"),
cl::aliasopt(AddressRadix));
cl::opt<bool> JustSymbolName("just-symbol-name",
- cl::desc("Print just the symbol's name"));
+ cl::desc("Print just the symbol's name"),
+ cl::cat(NMCat));
cl::alias JustSymbolNames("j", cl::desc("Alias for --just-symbol-name"),
cl::aliasopt(JustSymbolName), cl::Grouping);
-// FIXME: This option takes exactly two strings and should be allowed anywhere
-// on the command line. Such that "llvm-nm -s __TEXT __text foo.o" would work.
-// But that does not as the CommandLine Library does not have a way to make
-// this work. For now the "-s __TEXT __text" has to be last on the command
-// line.
-cl::list<std::string> SegSect("s", cl::Positional, cl::ZeroOrMore,
+cl::opt<bool> SpecialSyms("special-syms",
+ cl::desc("No-op. Used for GNU compatibility only"));
+
+cl::list<std::string> SegSect("s", cl::multi_val(2), cl::ZeroOrMore,
+ cl::value_desc("segment section"), cl::Hidden,
cl::desc("Dump only symbols from this segment "
- "and section name, Mach-O only"));
+ "and section name, Mach-O only"),
+ cl::cat(NMCat));
-cl::opt<bool> FormatMachOasHex("x", cl::desc("Print symbol entry in hex, "
- "Mach-O only"), cl::Grouping);
+cl::opt<bool> FormatMachOasHex("x",
+ cl::desc("Print symbol entry in hex, "
+ "Mach-O only"),
+ cl::Grouping, cl::cat(NMCat));
cl::opt<bool> AddDyldInfo("add-dyldinfo",
cl::desc("Add symbols from the dyldinfo not already "
- "in the symbol table, Mach-O only"));
+ "in the symbol table, Mach-O only"),
+ cl::cat(NMCat));
cl::opt<bool> NoDyldInfo("no-dyldinfo",
cl::desc("Don't add any symbols from the dyldinfo, "
- "Mach-O only"));
+ "Mach-O only"),
+ cl::cat(NMCat));
cl::opt<bool> DyldInfoOnly("dyldinfo-only",
cl::desc("Show only symbols from the dyldinfo, "
- "Mach-O only"));
+ "Mach-O only"),
+ cl::cat(NMCat));
cl::opt<bool> NoLLVMBitcode("no-llvm-bc",
- cl::desc("Disable LLVM bitcode reader"));
+ cl::desc("Disable LLVM bitcode reader"),
+ cl::cat(NMCat));
cl::extrahelp HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
@@ -263,6 +287,8 @@ struct NMSymbol {
uint64_t Size;
char TypeChar;
StringRef Name;
+ StringRef SectionName;
+ StringRef TypeName;
BasicSymbolRef Sym;
// The Sym field above points to the native symbol in the object file,
// for Mach-O when we are creating symbols from the dyld info the above
@@ -316,8 +342,7 @@ static char isSymbolList64Bit(SymbolicFile &Obj) {
}
static StringRef CurrentFilename;
-typedef std::vector<NMSymbol> SymbolListT;
-static SymbolListT SymbolList;
+static std::vector<NMSymbol> SymbolList;
static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I);
@@ -326,9 +351,10 @@ static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I);
// the darwin format it produces the same output as darwin's nm(1) -m output
// and when printing Mach-O symbols in hex it produces the same output as
// darwin's nm(1) -x format.
-static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
+static void darwinPrintSymbol(SymbolicFile &Obj, const NMSymbol &S,
char *SymbolAddrStr, const char *printBlanks,
- const char *printDashes, const char *printFormat) {
+ const char *printDashes,
+ const char *printFormat) {
MachO::mach_header H;
MachO::mach_header_64 H_64;
uint32_t Filetype = MachO::MH_OBJECT;
@@ -340,7 +366,7 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
uint64_t NValue = 0;
MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
if (Obj.isIR()) {
- uint32_t SymFlags = I->Sym.getFlags();
+ uint32_t SymFlags = S.Sym.getFlags();
if (SymFlags & SymbolRef::SF_Global)
NType |= MachO::N_EXT;
if (SymFlags & SymbolRef::SF_Hidden)
@@ -362,7 +388,7 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
if (SymFlags & SymbolRef::SF_Weak)
NDesc |= MachO::N_WEAK_DEF;
} else {
- DataRefImpl SymDRI = I->Sym.getRawDataRefImpl();
+ DataRefImpl SymDRI = S.Sym.getRawDataRefImpl();
if (MachO->is64Bit()) {
H_64 = MachO->MachOObjectFile::getHeader64();
Filetype = H_64.filetype;
@@ -375,11 +401,11 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
NStrx = STE_64.n_strx;
NValue = STE_64.n_value;
} else {
- NType = I->NType;
- NSect = I->NSect;
- NDesc = I->NDesc;
+ NType = S.NType;
+ NSect = S.NSect;
+ NDesc = S.NDesc;
NStrx = 0;
- NValue = I->Address;
+ NValue = S.Address;
}
} else {
H = MachO->MachOObjectFile::getHeader();
@@ -393,42 +419,31 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
NStrx = STE.n_strx;
NValue = STE.n_value;
} else {
- NType = I->NType;
- NSect = I->NSect;
- NDesc = I->NDesc;
+ NType = S.NType;
+ NSect = S.NSect;
+ NDesc = S.NDesc;
NStrx = 0;
- NValue = I->Address;
+ NValue = S.Address;
}
}
}
// If we are printing Mach-O symbols in hex do that and return.
if (FormatMachOasHex) {
- char Str[18] = "";
- format(printFormat, NValue).print(Str, sizeof(Str));
- outs() << Str << ' ';
- format("%02x", NType).print(Str, sizeof(Str));
- outs() << Str << ' ';
- format("%02x", NSect).print(Str, sizeof(Str));
- outs() << Str << ' ';
- format("%04x", NDesc).print(Str, sizeof(Str));
- outs() << Str << ' ';
- format("%08x", NStrx).print(Str, sizeof(Str));
- outs() << Str << ' ';
- outs() << I->Name;
+ outs() << format(printFormat, NValue) << ' '
+ << format("%02x %02x %04x %08x", NType, NSect, NDesc, NStrx) << ' '
+ << S.Name;
if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
outs() << " (indirect for ";
- format(printFormat, NValue).print(Str, sizeof(Str));
- outs() << Str << ' ';
+ outs() << format(printFormat, NValue) << ' ';
StringRef IndirectName;
- if (I->Sym.getRawDataRefImpl().p) {
- if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
+ if (S.Sym.getRawDataRefImpl().p) {
+ if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
outs() << "?)";
else
outs() << IndirectName << ")";
- }
- else
- outs() << I->IndirectName << ")";
+ } else
+ outs() << S.IndirectName << ")";
}
outs() << "\n";
return;
@@ -487,9 +502,9 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
break;
}
section_iterator Sec = SectionRef();
- if (I->Sym.getRawDataRefImpl().p) {
+ if (S.Sym.getRawDataRefImpl().p) {
Expected<section_iterator> SecOrErr =
- MachO->getSymbolSection(I->Sym.getRawDataRefImpl());
+ MachO->getSymbolSection(S.Sym.getRawDataRefImpl());
if (!SecOrErr) {
consumeError(SecOrErr.takeError());
outs() << "(?,?) ";
@@ -501,11 +516,12 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
break;
}
} else {
- Sec = I->Section;
+ Sec = S.Section;
}
DataRefImpl Ref = Sec->getRawDataRefImpl();
StringRef SectionName;
- MachO->getSectionName(Ref, SectionName);
+ if (Expected<StringRef> NameOrErr = MachO->getSectionName(Ref))
+ SectionName = *NameOrErr;
StringRef SegmentName = MachO->getSectionFinalSegmentName(Ref);
outs() << "(" << SegmentName << "," << SectionName << ") ";
break;
@@ -541,39 +557,36 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I,
outs() << "non-external ";
}
- if (Filetype == MachO::MH_OBJECT &&
- (NDesc & MachO::N_NO_DEAD_STRIP) == MachO::N_NO_DEAD_STRIP)
- outs() << "[no dead strip] ";
-
- if (Filetype == MachO::MH_OBJECT &&
- ((NType & MachO::N_TYPE) != MachO::N_UNDF) &&
- (NDesc & MachO::N_SYMBOL_RESOLVER) == MachO::N_SYMBOL_RESOLVER)
- outs() << "[symbol resolver] ";
-
- if (Filetype == MachO::MH_OBJECT &&
- ((NType & MachO::N_TYPE) != MachO::N_UNDF) &&
- (NDesc & MachO::N_ALT_ENTRY) == MachO::N_ALT_ENTRY)
- outs() << "[alt entry] ";
+ if (Filetype == MachO::MH_OBJECT) {
+ if (NDesc & MachO::N_NO_DEAD_STRIP)
+ outs() << "[no dead strip] ";
+ if ((NType & MachO::N_TYPE) != MachO::N_UNDF &&
+ NDesc & MachO::N_SYMBOL_RESOLVER)
+ outs() << "[symbol resolver] ";
+ if ((NType & MachO::N_TYPE) != MachO::N_UNDF && NDesc & MachO::N_ALT_ENTRY)
+ outs() << "[alt entry] ";
+ if ((NType & MachO::N_TYPE) != MachO::N_UNDF && NDesc & MachO::N_COLD_FUNC)
+ outs() << "[cold func] ";
+ }
if ((NDesc & MachO::N_ARM_THUMB_DEF) == MachO::N_ARM_THUMB_DEF)
outs() << "[Thumb] ";
if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
- outs() << I->Name << " (for ";
+ outs() << S.Name << " (for ";
StringRef IndirectName;
if (MachO) {
- if (I->Sym.getRawDataRefImpl().p) {
- if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
+ if (S.Sym.getRawDataRefImpl().p) {
+ if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
outs() << "?)";
else
outs() << IndirectName << ")";
- }
- else
- outs() << I->IndirectName << ")";
+ } else
+ outs() << S.IndirectName << ")";
} else
outs() << "?)";
} else
- outs() << I->Name;
+ outs() << S.Name;
if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL &&
(((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) ||
@@ -635,25 +648,24 @@ static const struct DarwinStabName DarwinStabNames[] = {
{MachO::N_ECOMM, "ECOMM"},
{MachO::N_ECOML, "ECOML"},
{MachO::N_LENG, "LENG"},
- {0, nullptr}};
+};
static const char *getDarwinStabString(uint8_t NType) {
- for (unsigned i = 0; DarwinStabNames[i].Name; i++) {
- if (DarwinStabNames[i].NType == NType)
- return DarwinStabNames[i].Name;
- }
+ for (auto I : makeArrayRef(DarwinStabNames))
+ if (I.NType == NType)
+ return I.Name;
return nullptr;
}
// darwinPrintStab() prints the n_sect, n_desc along with a symbolic name of
// a stab n_type value in a Mach-O file.
-static void darwinPrintStab(MachOObjectFile *MachO, SymbolListT::iterator I) {
+static void darwinPrintStab(MachOObjectFile *MachO, const NMSymbol &S) {
MachO::nlist_64 STE_64;
MachO::nlist STE;
uint8_t NType;
uint8_t NSect;
uint16_t NDesc;
- DataRefImpl SymDRI = I->Sym.getRawDataRefImpl();
+ DataRefImpl SymDRI = S.Sym.getRawDataRefImpl();
if (MachO->is64Bit()) {
STE_64 = MachO->getSymbol64TableEntry(SymDRI);
NType = STE_64.n_type;
@@ -666,16 +678,11 @@ static void darwinPrintStab(MachOObjectFile *MachO, SymbolListT::iterator I) {
NDesc = STE.n_desc;
}
- char Str[18] = "";
- format("%02x", NSect).print(Str, sizeof(Str));
- outs() << ' ' << Str << ' ';
- format("%04x", NDesc).print(Str, sizeof(Str));
- outs() << Str << ' ';
+ outs() << format(" %02x %04x ", NSect, NDesc);
if (const char *stabString = getDarwinStabString(NType))
- format("%5.5s", stabString).print(Str, sizeof(Str));
+ outs() << format("%5.5s", stabString);
else
- format(" %02x", NType).print(Str, sizeof(Str));
- outs() << Str;
+ outs() << format(" %02x", NType);
}
static Optional<std::string> demangle(StringRef Name, bool StripUnderscore) {
@@ -780,26 +787,24 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
errs() << "no symbols\n";
}
- for (SymbolListT::iterator I = SymbolList.begin(), E = SymbolList.end();
- I != E; ++I) {
+ for (const NMSymbol &S : SymbolList) {
uint32_t SymFlags;
- std::string Name = I->Name.str();
+ std::string Name = S.Name.str();
MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
if (Demangle) {
- if (Optional<std::string> Opt = demangle(I->Name, MachO))
+ if (Optional<std::string> Opt = demangle(S.Name, MachO))
Name = *Opt;
}
- if (I->Sym.getRawDataRefImpl().p)
- SymFlags = I->Sym.getFlags();
+ if (S.Sym.getRawDataRefImpl().p)
+ SymFlags = S.Sym.getFlags();
else
- SymFlags = I->SymFlags;
+ SymFlags = S.SymFlags;
bool Undefined = SymFlags & SymbolRef::SF_Undefined;
bool Global = SymFlags & SymbolRef::SF_Global;
bool Weak = SymFlags & SymbolRef::SF_Weak;
if ((!Undefined && UndefinedOnly) || (Undefined && DefinedOnly) ||
- (!Global && ExternalOnly) || (SizeSort && !PrintAddress) ||
- (Weak && NoWeakSymbols))
+ (!Global && ExternalOnly) || (Weak && NoWeakSymbols))
continue;
if (PrintFileName)
writeFileName(outs());
@@ -810,32 +815,30 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
continue;
}
- char SymbolAddrStr[18] = "";
- char SymbolSizeStr[18] = "";
+ char SymbolAddrStr[23], SymbolSizeStr[23];
// If the format is SysV or the symbol isn't defined, then print spaces.
- if (OutputFormat == sysv || !symbolIsDefined(*I)) {
+ if (OutputFormat == sysv || !symbolIsDefined(S)) {
if (OutputFormat == posix) {
- format(printFormat, I->Address)
- .print(SymbolAddrStr, sizeof(SymbolAddrStr));
- format(printFormat, I->Size)
- .print(SymbolSizeStr, sizeof(SymbolSizeStr));
+ format(printFormat, S.Address)
+ .print(SymbolAddrStr, sizeof(SymbolAddrStr));
+ format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
} else {
strcpy(SymbolAddrStr, printBlanks);
strcpy(SymbolSizeStr, printBlanks);
}
}
- // Otherwise, print the symbol address and size.
- if (symbolIsDefined(*I)) {
+ if (symbolIsDefined(S)) {
+ // Otherwise, print the symbol address and size.
if (Obj.isIR())
strcpy(SymbolAddrStr, printDashes);
- else if(MachO && I->TypeChar == 'I')
+ else if (MachO && S.TypeChar == 'I')
strcpy(SymbolAddrStr, printBlanks);
else
- format(printFormat, I->Address)
- .print(SymbolAddrStr, sizeof(SymbolAddrStr));
- format(printFormat, I->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
+ format(printFormat, S.Address)
+ .print(SymbolAddrStr, sizeof(SymbolAddrStr));
+ format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
}
// If OutputFormat is darwin or we are printing Mach-O symbols in hex and
@@ -844,43 +847,36 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
// printing Mach-O symbols in hex and not a Mach-O object fall back to
// OutputFormat bsd (see below).
if ((OutputFormat == darwin || FormatMachOasHex) && (MachO || Obj.isIR())) {
- darwinPrintSymbol(Obj, I, SymbolAddrStr, printBlanks, printDashes,
+ darwinPrintSymbol(Obj, S, SymbolAddrStr, printBlanks, printDashes,
printFormat);
} else if (OutputFormat == posix) {
- outs() << Name << " " << I->TypeChar << " ";
- if (MachO)
- outs() << SymbolAddrStr << " " << "0" /* SymbolSizeStr */ << "\n";
- else
- outs() << SymbolAddrStr << " " << SymbolSizeStr << "\n";
+ outs() << Name << " " << S.TypeChar << " " << SymbolAddrStr << " "
+ << (MachO ? "0" : SymbolSizeStr) << "\n";
} else if (OutputFormat == bsd || (OutputFormat == darwin && !MachO)) {
if (PrintAddress)
outs() << SymbolAddrStr << ' ';
- if (PrintSize) {
- outs() << SymbolSizeStr;
- outs() << ' ';
- }
- outs() << I->TypeChar;
- if (I->TypeChar == '-' && MachO)
- darwinPrintStab(MachO, I);
+ if (PrintSize)
+ outs() << SymbolSizeStr << ' ';
+ outs() << S.TypeChar;
+ if (S.TypeChar == '-' && MachO)
+ darwinPrintStab(MachO, S);
outs() << " " << Name;
- if (I->TypeChar == 'I' && MachO) {
+ if (S.TypeChar == 'I' && MachO) {
outs() << " (indirect for ";
- if (I->Sym.getRawDataRefImpl().p) {
+ if (S.Sym.getRawDataRefImpl().p) {
StringRef IndirectName;
- if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
+ if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
outs() << "?)";
else
outs() << IndirectName << ")";
} else
- outs() << I->IndirectName << ")";
+ outs() << S.IndirectName << ")";
}
outs() << "\n";
} else if (OutputFormat == sysv) {
- std::string PaddedName(Name);
- while (PaddedName.length() < 20)
- PaddedName += " ";
- outs() << PaddedName << "|" << SymbolAddrStr << "| " << I->TypeChar
- << " | |" << SymbolSizeStr << "| |\n";
+ outs() << left_justify(Name, 20) << "|" << SymbolAddrStr << "| "
+ << S.TypeChar << " |" << right_justify(S.TypeName, 18) << "|"
+ << SymbolSizeStr << "| |" << S.SectionName << "\n";
}
}
@@ -898,44 +894,35 @@ static char getSymbolNMTypeChar(ELFObjectFileBase &Obj,
return '?';
}
+ uint8_t Binding = SymI->getBinding();
+ if (Binding == ELF::STB_GNU_UNIQUE)
+ return 'u';
+
+ assert(Binding != ELF::STB_WEAK && "STB_WEAK not tested in calling function");
+ if (Binding != ELF::STB_GLOBAL && Binding != ELF::STB_LOCAL)
+ return '?';
+
elf_section_iterator SecI = *SecIOrErr;
if (SecI != Obj.section_end()) {
- switch (SecI->getType()) {
- case ELF::SHT_PROGBITS:
- case ELF::SHT_DYNAMIC:
- switch (SecI->getFlags()) {
- case (ELF::SHF_ALLOC | ELF::SHF_EXECINSTR):
- return 't';
- case (ELF::SHF_TLS | ELF::SHF_ALLOC | ELF::SHF_WRITE):
- case (ELF::SHF_ALLOC | ELF::SHF_WRITE):
- return 'd';
- case ELF::SHF_ALLOC:
- case (ELF::SHF_ALLOC | ELF::SHF_MERGE):
- case (ELF::SHF_ALLOC | ELF::SHF_MERGE | ELF::SHF_STRINGS):
- return 'r';
- }
- break;
- case ELF::SHT_NOBITS:
- return 'b';
- case ELF::SHT_INIT_ARRAY:
- case ELF::SHT_FINI_ARRAY:
+ uint32_t Type = SecI->getType();
+ uint64_t Flags = SecI->getFlags();
+ if (Flags & ELF::SHF_EXECINSTR)
return 't';
- }
- }
+ if (Type == ELF::SHT_NOBITS)
+ return 'b';
+ if (Flags & ELF::SHF_ALLOC)
+ return Flags & ELF::SHF_WRITE ? 'd' : 'r';
- if (SymI->getELFType() == ELF::STT_SECTION) {
- Expected<StringRef> Name = SymI->getName();
- if (!Name) {
- consumeError(Name.takeError());
+ StringRef SecName;
+ if (SecI->getName(SecName))
return '?';
- }
- return StringSwitch<char>(*Name)
- .StartsWith(".debug", 'N')
- .StartsWith(".note", 'n')
- .Default('?');
+ if (SecName.startswith(".debug"))
+ return 'N';
+ if (!(Flags & ELF::SHF_WRITE))
+ return 'n';
}
- return 'n';
+ return '?';
}
static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) {
@@ -967,10 +954,9 @@ static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) {
section_iterator SecI = *SecIOrErr;
const coff_section *Section = Obj.getCOFFSection(*SecI);
Characteristics = Section->Characteristics;
- StringRef SectionName;
- Obj.getSectionName(Section, SectionName);
- if (SectionName.startswith(".idata"))
- return 'i';
+ if (Expected<StringRef> NameOrErr = Obj.getSectionName(Section))
+ if (NameOrErr->startswith(".idata"))
+ return 'i';
}
switch (Symb.getSectionNumber()) {
@@ -1030,7 +1016,8 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) {
return 's';
DataRefImpl Ref = Sec->getRawDataRefImpl();
StringRef SectionName;
- Obj.getSectionName(Ref, SectionName);
+ if (Expected<StringRef> NameOrErr = Obj.getSectionName(Ref))
+ SectionName = *NameOrErr;
StringRef SegmentName = Obj.getSectionFinalSegmentName(Ref);
if (Obj.is64Bit() && Obj.getHeader64().filetype == MachO::MH_KEXT_BUNDLE &&
SegmentName == "__TEXT_EXEC" && SectionName == "__text")
@@ -1074,8 +1061,40 @@ static bool isObject(SymbolicFile &Obj, basic_symbol_iterator I) {
: elf_symbol_iterator(I)->getELFType() == ELF::STT_OBJECT;
}
-static char getNMTypeChar(SymbolicFile &Obj, basic_symbol_iterator I) {
+// For ELF object files, Set TypeName to the symbol typename, to be printed
+// in the 'Type' column of the SYSV format output.
+static StringRef getNMTypeName(SymbolicFile &Obj, basic_symbol_iterator I) {
+ if (isa<ELFObjectFileBase>(&Obj)) {
+ elf_symbol_iterator SymI(I);
+ return SymI->getELFTypeName();
+ }
+ return "";
+}
+
+// Return Posix nm class type tag (single letter), but also set SecName and
+// section and name, to be used in format=sysv output.
+static char getNMSectionTagAndName(SymbolicFile &Obj, basic_symbol_iterator I,
+ StringRef &SecName) {
uint32_t Symflags = I->getFlags();
+ if (isa<ELFObjectFileBase>(&Obj)) {
+ if (Symflags & object::SymbolRef::SF_Absolute)
+ SecName = "*ABS*";
+ else if (Symflags & object::SymbolRef::SF_Common)
+ SecName = "*COM*";
+ else if (Symflags & object::SymbolRef::SF_Undefined)
+ SecName = "*UND*";
+ else {
+ elf_symbol_iterator SymI(I);
+ Expected<elf_section_iterator> SecIOrErr = SymI->getSection();
+ if (!SecIOrErr) {
+ consumeError(SecIOrErr.takeError());
+ return '?';
+ }
+ elf_section_iterator secT = *SecIOrErr;
+ secT->getName(SecName);
+ }
+ }
+
if ((Symflags & object::SymbolRef::SF_Weak) && !isa<MachOObjectFile>(Obj)) {
char Ret = isObject(Obj, I) ? 'v' : 'w';
return (!(Symflags & object::SymbolRef::SF_Undefined)) ? toupper(Ret) : Ret;
@@ -1103,10 +1122,13 @@ static char getNMTypeChar(SymbolicFile &Obj, basic_symbol_iterator I) {
else
Ret = getSymbolNMTypeChar(cast<ELFObjectFileBase>(Obj), I);
- if (Symflags & object::SymbolRef::SF_Global)
- Ret = toupper(Ret);
+ if (!(Symflags & object::SymbolRef::SF_Global))
+ return Ret;
- return Ret;
+ if (Obj.isELF() && ELFSymbolRef(*I).getBinding() == ELF::STB_GNU_UNIQUE)
+ return Ret;
+
+ return toupper(Ret);
}
// getNsectForSegSect() is used to implement the Mach-O "-s segname sectname"
@@ -1120,7 +1142,8 @@ static unsigned getNsectForSegSect(MachOObjectFile *Obj) {
for (auto &S : Obj->sections()) {
DataRefImpl Ref = S.getRawDataRefImpl();
StringRef SectionName;
- Obj->getSectionName(Ref, SectionName);
+ if (Expected<StringRef> NameOrErr = Obj->getSectionName(Ref))
+ SectionName = *NameOrErr;
StringRef SegmentName = Obj->getSectionFinalSegmentName(Ref);
if (SegmentName == SegSect[0] && SectionName == SegSect[1])
return Nsect;
@@ -1155,9 +1178,7 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
error("File format has no dynamic symbol table", Obj.getFileName());
return;
}
- auto DynSymbols = E->getDynamicSymbolIterators();
- Symbols =
- make_range<basic_symbol_iterator>(DynSymbols.begin(), DynSymbols.end());
+ Symbols = E->getDynamicSymbolIterators();
}
std::string NameBuffer;
raw_string_ostream OS(NameBuffer);
@@ -1186,10 +1207,8 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
NMSymbol S = {};
S.Size = 0;
S.Address = 0;
- if (PrintSize) {
- if (isa<ELFObjectFileBase>(&Obj))
- S.Size = ELFSymbolRef(Sym).getSize();
- }
+ if (isa<ELFObjectFileBase>(&Obj))
+ S.Size = ELFSymbolRef(Sym).getSize();
if (PrintAddress && isa<ObjectFile>(Obj)) {
SymbolRef SymRef(Sym);
Expected<uint64_t> AddressOrErr = SymRef.getAddress();
@@ -1199,12 +1218,15 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
}
S.Address = *AddressOrErr;
}
- S.TypeChar = getNMTypeChar(Obj, Sym);
- std::error_code EC = Sym.printName(OS);
- if (EC && MachO)
- OS << "bad string index";
- else
- error(EC);
+ S.TypeName = getNMTypeName(Obj, Sym);
+ S.TypeChar = getNMSectionTagAndName(Obj, Sym, S.SectionName);
+ if (Error E = Sym.printName(OS)) {
+ if (MachO) {
+ OS << "bad string index";
+ consumeError(std::move(E));
+ } else
+ error(std::move(E), Obj.getFileName());
+ }
OS << '\0';
S.Sym = Sym;
SymbolList.push_back(S);
@@ -1270,11 +1292,12 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
bool found = false;
bool ReExport = false;
if (!DyldInfoOnly) {
- for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
- if (SymbolList[J].Address == Entry.address() + BaseSegmentAddress &&
- SymbolList[J].Name == Entry.name())
+ for (const NMSymbol &S : SymbolList)
+ if (S.Address == Entry.address() + BaseSegmentAddress &&
+ S.Name == Entry.name()) {
found = true;
- }
+ break;
+ }
}
if (!found) {
NMSymbol S = {};
@@ -1445,7 +1468,6 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
B.NType = MachO::N_EXT | MachO::N_UNDF;
B.NSect = 0;
B.NDesc = 0;
- B.NDesc = 0;
MachO::SET_LIBRARY_ORDINAL(B.NDesc, Entry.ordinal());
B.IndirectName = StringRef();
B.Name = Entry.symbolName();
@@ -1735,8 +1757,9 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
return;
LLVMContext Context;
- Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(
- BufferOrErr.get()->getMemBufferRef(), NoLLVMBitcode ? nullptr : &Context);
+ LLVMContext *ContextPtr = NoLLVMBitcode ? nullptr : &Context;
+ Expected<std::unique_ptr<Binary>> BinaryOrErr =
+ createBinary(BufferOrErr.get()->getMemBufferRef(), ContextPtr);
if (!BinaryOrErr) {
error(BinaryOrErr.takeError(), Filename);
return;
@@ -1770,7 +1793,8 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
{
Error Err = Error::success();
for (auto &C : A->children(Err)) {
- Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(&Context);
+ Expected<std::unique_ptr<Binary>> ChildOrErr =
+ C.getAsBinary(ContextPtr);
if (!ChildOrErr) {
if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
error(std::move(E), Filename, C);
@@ -1841,7 +1865,7 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
Error Err = Error::success();
for (auto &C : A->children(Err)) {
Expected<std::unique_ptr<Binary>> ChildOrErr =
- C.getAsBinary(&Context);
+ C.getAsBinary(ContextPtr);
if (!ChildOrErr) {
if (auto E = isNotObjectErrorInvalidFileType(
ChildOrErr.takeError())) {
@@ -1912,7 +1936,7 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
Error Err = Error::success();
for (auto &C : A->children(Err)) {
Expected<std::unique_ptr<Binary>> ChildOrErr =
- C.getAsBinary(&Context);
+ C.getAsBinary(ContextPtr);
if (!ChildOrErr) {
if (auto E = isNotObjectErrorInvalidFileType(
ChildOrErr.takeError()))
@@ -1946,10 +1970,8 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
// Either all architectures have been specified or none have been specified
// and this does not contain the host architecture so dump all the slices.
bool moreThanOneArch = UB->getNumberOfObjects() > 1;
- for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
- E = UB->end_objects();
- I != E; ++I) {
- Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
+ for (const MachOUniversalBinary::ObjectForArch &O : UB->objects()) {
+ Expected<std::unique_ptr<ObjectFile>> ObjOrErr = O.getAsObjectFile();
std::string ArchiveName;
std::string ArchitectureName;
ArchiveName.clear();
@@ -1958,28 +1980,28 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
ObjectFile &Obj = *ObjOrErr.get();
if (PrintFileName) {
if (isa<MachOObjectFile>(Obj) && moreThanOneArch)
- ArchitectureName = I->getArchFlagName();
+ ArchitectureName = O.getArchFlagName();
} else {
if (moreThanOneArch)
outs() << "\n";
outs() << Obj.getFileName();
if (isa<MachOObjectFile>(Obj) && moreThanOneArch)
- outs() << " (for architecture " << I->getArchFlagName() << ")";
+ outs() << " (for architecture " << O.getArchFlagName() << ")";
outs() << ":\n";
}
dumpSymbolNamesFromObject(Obj, false, ArchiveName, ArchitectureName);
} else if (auto E = isNotObjectErrorInvalidFileType(
ObjOrErr.takeError())) {
error(std::move(E), Filename, moreThanOneArch ?
- StringRef(I->getArchFlagName()) : StringRef());
+ StringRef(O.getArchFlagName()) : StringRef());
continue;
} else if (Expected<std::unique_ptr<Archive>> AOrErr =
- I->getAsArchive()) {
+ O.getAsArchive()) {
std::unique_ptr<Archive> &A = *AOrErr;
Error Err = Error::success();
for (auto &C : A->children(Err)) {
Expected<std::unique_ptr<Binary>> ChildOrErr =
- C.getAsBinary(&Context);
+ C.getAsBinary(ContextPtr);
if (!ChildOrErr) {
if (auto E = isNotObjectErrorInvalidFileType(
ChildOrErr.takeError()))
@@ -1987,23 +2009,23 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
StringRef(ArchitectureName) : StringRef());
continue;
}
- if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
+ if (SymbolicFile *F = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
if (PrintFileName) {
ArchiveName = A->getFileName();
- if (isa<MachOObjectFile>(O) && moreThanOneArch)
- ArchitectureName = I->getArchFlagName();
+ if (isa<MachOObjectFile>(F) && moreThanOneArch)
+ ArchitectureName = O.getArchFlagName();
} else {
outs() << "\n" << A->getFileName();
- if (isa<MachOObjectFile>(O)) {
- outs() << "(" << O->getFileName() << ")";
+ if (isa<MachOObjectFile>(F)) {
+ outs() << "(" << F->getFileName() << ")";
if (moreThanOneArch)
- outs() << " (for architecture " << I->getArchFlagName()
+ outs() << " (for architecture " << O.getArchFlagName()
<< ")";
} else
- outs() << ":" << O->getFileName();
+ outs() << ":" << F->getFileName();
outs() << ":\n";
}
- dumpSymbolNamesFromObject(*O, false, ArchiveName, ArchitectureName);
+ dumpSymbolNamesFromObject(*F, false, ArchiveName, ArchitectureName);
}
}
if (Err)
@@ -2011,7 +2033,7 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
} else {
consumeError(AOrErr.takeError());
error(Filename + " for architecture " +
- StringRef(I->getArchFlagName()) +
+ StringRef(O.getArchFlagName()) +
" is not a Mach-O file or an archive file",
"Mach-O universal file");
}
@@ -2021,7 +2043,7 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
if (SymbolicFile *O = dyn_cast<SymbolicFile>(&Bin)) {
if (!MachOPrintSizeWarning && PrintSize && isa<MachOObjectFile>(O)) {
WithColor::warning(errs(), ToolName)
- << "sizes with -print-size for Mach-O files are always zero.\n";
+ << "sizes with --print-size for Mach-O files are always zero.\n";
MachOPrintSizeWarning = true;
}
if (!checkMachOAndArchFlags(O, Filename))
@@ -2032,6 +2054,7 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
+ cl::HideUnrelatedOptions(NMCat);
cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n");
// llvm-nm only reads binary files.
@@ -2063,13 +2086,17 @@ int main(int argc, char **argv) {
if (InputFilenames.size() > 1)
MultipleFiles = true;
+ // If both --demangle and --no-demangle are specified then pick the last one.
+ if (NoDemangle.getPosition() > Demangle.getPosition())
+ Demangle = !NoDemangle;
+
for (unsigned i = 0; i < ArchFlags.size(); ++i) {
if (ArchFlags[i] == "all") {
ArchAll = true;
} else {
if (!MachOObjectFile::isValidArch(ArchFlags[i]))
error("Unknown architecture named '" + ArchFlags[i] + "'",
- "for the -arch option");
+ "for the --arch option");
}
}
@@ -2078,7 +2105,7 @@ int main(int argc, char **argv) {
"for the -s option");
if (NoDyldInfo && (AddDyldInfo || DyldInfoOnly))
- error("-no-dyldinfo can't be used with -add-dyldinfo or -dyldinfo-only");
+ error("--no-dyldinfo can't be used with --add-dyldinfo or --dyldinfo-only");
llvm::for_each(InputFilenames, dumpSymbolNamesFromFile);
diff --git a/contrib/llvm/tools/llvm-objcopy/Buffer.cpp b/contrib/llvm/tools/llvm-objcopy/Buffer.cpp
index 8044b023aaad..06b2a20a762f 100644
--- a/contrib/llvm/tools/llvm-objcopy/Buffer.cpp
+++ b/contrib/llvm/tools/llvm-objcopy/Buffer.cpp
@@ -1,16 +1,16 @@
//===- Buffer.cpp ---------------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Buffer.h"
-#include "llvm-objcopy.h"
#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Process.h"
#include <memory>
namespace llvm {
@@ -18,23 +18,51 @@ namespace objcopy {
Buffer::~Buffer() {}
-void FileBuffer::allocate(size_t Size) {
+static Error createEmptyFile(StringRef FileName) {
+ // Create an empty tempfile and atomically swap it in place with the desired
+ // output file.
+ Expected<sys::fs::TempFile> Temp =
+ sys::fs::TempFile::create(FileName + ".temp-empty-%%%%%%%");
+ return Temp ? Temp->keep(FileName) : Temp.takeError();
+}
+
+Error FileBuffer::allocate(size_t Size) {
+ // When a 0-sized file is requested, skip allocation but defer file
+ // creation/truncation until commit() to avoid side effects if something
+ // happens between allocate() and commit().
+ if (Size == 0) {
+ EmptyFile = true;
+ return Error::success();
+ }
+
Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
FileOutputBuffer::create(getName(), Size, FileOutputBuffer::F_executable);
- handleAllErrors(BufferOrErr.takeError(), [this](const ErrorInfoBase &E) {
- error("failed to open " + getName() + ": " + E.message());
- });
+ // FileOutputBuffer::create() returns an Error that is just a wrapper around
+ // std::error_code. Wrap it in FileError to include the actual filename.
+ if (!BufferOrErr)
+ return createFileError(getName(), BufferOrErr.takeError());
Buf = std::move(*BufferOrErr);
+ return Error::success();
}
-Error FileBuffer::commit() { return Buf->commit(); }
+Error FileBuffer::commit() {
+ if (EmptyFile)
+ return createEmptyFile(getName());
+
+ assert(Buf && "allocate() not called before commit()!");
+ Error Err = Buf->commit();
+ // FileOutputBuffer::commit() returns an Error that is just a wrapper around
+ // std::error_code. Wrap it in FileError to include the actual filename.
+ return Err ? createFileError(getName(), std::move(Err)) : std::move(Err);
+}
uint8_t *FileBuffer::getBufferStart() {
return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
}
-void MemBuffer::allocate(size_t Size) {
+Error MemBuffer::allocate(size_t Size) {
Buf = WritableMemoryBuffer::getNewMemBuffer(Size, getName());
+ return Error::success();
}
Error MemBuffer::commit() { return Error::success(); }
diff --git a/contrib/llvm/tools/llvm-objcopy/Buffer.h b/contrib/llvm/tools/llvm-objcopy/Buffer.h
index e5b9c5b2d22b..487d5585c364 100644
--- a/contrib/llvm/tools/llvm-objcopy/Buffer.h
+++ b/contrib/llvm/tools/llvm-objcopy/Buffer.h
@@ -1,9 +1,8 @@
//===- Buffer.h -------------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -28,7 +27,7 @@ class Buffer {
public:
virtual ~Buffer();
- virtual void allocate(size_t Size) = 0;
+ virtual Error allocate(size_t Size) = 0;
virtual uint8_t *getBufferStart() = 0;
virtual Error commit() = 0;
@@ -38,9 +37,12 @@ public:
class FileBuffer : public Buffer {
std::unique_ptr<FileOutputBuffer> Buf;
+ // Indicates that allocate(0) was called, and commit() should create or
+ // truncate a file instead of using a FileOutputBuffer.
+ bool EmptyFile = false;
public:
- void allocate(size_t Size) override;
+ Error allocate(size_t Size) override;
uint8_t *getBufferStart() override;
Error commit() override;
@@ -51,7 +53,7 @@ class MemBuffer : public Buffer {
std::unique_ptr<WritableMemoryBuffer> Buf;
public:
- void allocate(size_t Size) override;
+ Error allocate(size_t Size) override;
uint8_t *getBufferStart() override;
Error commit() override;
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
index 6b386d29979c..4ae46851a66f 100644
--- a/contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
@@ -1,9 +1,8 @@
//===- COFFObjcopy.cpp ----------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -18,6 +17,8 @@
#include "llvm/Object/Binary.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Errc.h"
+#include "llvm/Support/JamCRC.h"
+#include "llvm/Support/Path.h"
#include <cassert>
namespace llvm {
@@ -27,14 +28,104 @@ namespace coff {
using namespace object;
using namespace COFF;
+static bool isDebugSection(const Section &Sec) {
+ return Sec.Name.startswith(".debug");
+}
+
+static uint64_t getNextRVA(const Object &Obj) {
+ if (Obj.getSections().empty())
+ return 0;
+ const Section &Last = Obj.getSections().back();
+ return alignTo(Last.Header.VirtualAddress + Last.Header.VirtualSize,
+ Obj.IsPE ? Obj.PeHeader.SectionAlignment : 1);
+}
+
+static uint32_t getCRC32(StringRef Data) {
+ JamCRC CRC;
+ CRC.update(ArrayRef<char>(Data.data(), Data.size()));
+ // The CRC32 value needs to be complemented because the JamCRC dosn't
+ // finalize the CRC32 value. It also dosn't negate the initial CRC32 value
+ // but it starts by default at 0xFFFFFFFF which is the complement of zero.
+ return ~CRC.getCRC();
+}
+
+static std::vector<uint8_t> createGnuDebugLinkSectionContents(StringRef File) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> LinkTargetOrErr =
+ MemoryBuffer::getFile(File);
+ if (!LinkTargetOrErr)
+ error("'" + File + "': " + LinkTargetOrErr.getError().message());
+ auto LinkTarget = std::move(*LinkTargetOrErr);
+ uint32_t CRC32 = getCRC32(LinkTarget->getBuffer());
+
+ StringRef FileName = sys::path::filename(File);
+ size_t CRCPos = alignTo(FileName.size() + 1, 4);
+ std::vector<uint8_t> Data(CRCPos + 4);
+ memcpy(Data.data(), FileName.data(), FileName.size());
+ support::endian::write32le(Data.data() + CRCPos, CRC32);
+ return Data;
+}
+
+static void addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) {
+ uint32_t StartRVA = getNextRVA(Obj);
+
+ std::vector<Section> Sections;
+ Section Sec;
+ Sec.setOwnedContents(createGnuDebugLinkSectionContents(DebugLinkFile));
+ Sec.Name = ".gnu_debuglink";
+ Sec.Header.VirtualSize = Sec.getContents().size();
+ Sec.Header.VirtualAddress = StartRVA;
+ Sec.Header.SizeOfRawData = alignTo(Sec.Header.VirtualSize,
+ Obj.IsPE ? Obj.PeHeader.FileAlignment : 1);
+ // Sec.Header.PointerToRawData is filled in by the writer.
+ Sec.Header.PointerToRelocations = 0;
+ Sec.Header.PointerToLinenumbers = 0;
+ // Sec.Header.NumberOfRelocations is filled in by the writer.
+ Sec.Header.NumberOfLinenumbers = 0;
+ Sec.Header.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA |
+ IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE;
+ Sections.push_back(Sec);
+ Obj.addSections(Sections);
+}
+
static Error handleArgs(const CopyConfig &Config, Object &Obj) {
+ // Perform the actual section removals.
+ Obj.removeSections([&Config](const Section &Sec) {
+ // Contrary to --only-keep-debug, --only-section fully removes sections that
+ // aren't mentioned.
+ if (!Config.OnlySection.empty() &&
+ !is_contained(Config.OnlySection, Sec.Name))
+ return true;
+
+ if (Config.StripDebug || Config.StripAll || Config.StripAllGNU ||
+ Config.DiscardMode == DiscardType::All || Config.StripUnneeded) {
+ if (isDebugSection(Sec) &&
+ (Sec.Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0)
+ return true;
+ }
+
+ if (is_contained(Config.ToRemove, Sec.Name))
+ return true;
+
+ return false;
+ });
+
+ if (Config.OnlyKeepDebug) {
+ // For --only-keep-debug, we keep all other sections, but remove their
+ // content. The VirtualSize field in the section header is kept intact.
+ Obj.truncateSections([](const Section &Sec) {
+ return !isDebugSection(Sec) && Sec.Name != ".buildid" &&
+ ((Sec.Header.Characteristics &
+ (IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA)) != 0);
+ });
+ }
+
// StripAll removes all symbols and thus also removes all relocations.
if (Config.StripAll || Config.StripAllGNU)
- for (Section &Sec : Obj.Sections)
+ for (Section &Sec : Obj.getMutableSections())
Sec.Relocs.clear();
// If we need to do per-symbol removals, initialize the Referenced field.
- if (Config.StripUnneeded || Config.DiscardAll ||
+ if (Config.StripUnneeded || Config.DiscardMode == DiscardType::All ||
!Config.SymbolsToRemove.empty())
if (Error E = Obj.markSymbols())
return E;
@@ -50,47 +141,74 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
// Explicitly removing a referenced symbol is an error.
if (Sym.Referenced)
reportError(Config.OutputFilename,
- make_error<StringError>(
- "not stripping symbol '" + Sym.Name +
- "' because it is named in a relocation.",
- llvm::errc::invalid_argument));
+ createStringError(llvm::errc::invalid_argument,
+ "not stripping symbol '%s' because it is "
+ "named in a relocation",
+ Sym.Name.str().c_str()));
return true;
}
if (!Sym.Referenced) {
// With --strip-unneeded, GNU objcopy removes all unreferenced local
// symbols, and any unreferenced undefined external.
- if (Config.StripUnneeded &&
- (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC ||
- Sym.Sym.SectionNumber == 0))
- return true;
+ // With --strip-unneeded-symbol we strip only specific unreferenced
+ // local symbol instead of removing all of such.
+ if (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC ||
+ Sym.Sym.SectionNumber == 0)
+ if (Config.StripUnneeded ||
+ is_contained(Config.UnneededSymbolsToRemove, Sym.Name))
+ return true;
// GNU objcopy keeps referenced local symbols and external symbols
// if --discard-all is set, similar to what --strip-unneeded does,
// but undefined local symbols are kept when --discard-all is set.
- if (Config.DiscardAll && Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC &&
+ if (Config.DiscardMode == DiscardType::All &&
+ Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC &&
Sym.Sym.SectionNumber != 0)
return true;
}
return false;
});
+
+ if (!Config.AddGnuDebugLink.empty())
+ addGnuDebugLink(Obj, Config.AddGnuDebugLink);
+
+ if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() ||
+ Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
+ !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() ||
+ !Config.AllocSectionsPrefix.empty() || !Config.AddSection.empty() ||
+ !Config.DumpSection.empty() || !Config.KeepSection.empty() ||
+ !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToKeep.empty() ||
+ !Config.SymbolsToLocalize.empty() || !Config.SymbolsToWeaken.empty() ||
+ !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() ||
+ !Config.SetSectionFlags.empty() || !Config.SymbolsToRename.empty() ||
+ Config.ExtractDWO || Config.KeepFileSymbols || Config.LocalizeHidden ||
+ Config.PreserveDates || Config.StripDWO || Config.StripNonAlloc ||
+ Config.StripSections || Config.Weaken || Config.DecompressDebugSections ||
+ Config.DiscardMode == DiscardType::Locals ||
+ !Config.SymbolsToAdd.empty() || Config.EntryExpr) {
+ return createStringError(llvm::errc::invalid_argument,
+ "option not supported by llvm-objcopy for COFF");
+ }
+
return Error::success();
}
-void executeObjcopyOnBinary(const CopyConfig &Config,
- object::COFFObjectFile &In, Buffer &Out) {
+Error executeObjcopyOnBinary(const CopyConfig &Config, COFFObjectFile &In,
+ Buffer &Out) {
COFFReader Reader(In);
Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
if (!ObjOrErr)
- reportError(Config.InputFilename, ObjOrErr.takeError());
+ return createFileError(Config.InputFilename, ObjOrErr.takeError());
Object *Obj = ObjOrErr->get();
assert(Obj && "Unable to deserialize COFF object");
if (Error E = handleArgs(Config, *Obj))
- reportError(Config.InputFilename, std::move(E));
+ return createFileError(Config.InputFilename, std::move(E));
COFFWriter Writer(*Obj, Out);
if (Error E = Writer.write())
- reportError(Config.OutputFilename, std::move(E));
+ return createFileError(Config.OutputFilename, std::move(E));
+ return Error::success();
}
} // end namespace coff
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h b/contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h
index bf70bd9b4d84..858759e52c4a 100644
--- a/contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h
@@ -1,9 +1,8 @@
//===- COFFObjcopy.h --------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -11,6 +10,7 @@
#define LLVM_TOOLS_OBJCOPY_COFFOBJCOPY_H
namespace llvm {
+class Error;
namespace object {
class COFFObjectFile;
@@ -21,8 +21,8 @@ struct CopyConfig;
class Buffer;
namespace coff {
-void executeObjcopyOnBinary(const CopyConfig &Config,
- object::COFFObjectFile &In, Buffer &Out);
+Error executeObjcopyOnBinary(const CopyConfig &Config,
+ object::COFFObjectFile &In, Buffer &Out);
} // end namespace coff
} // end namespace objcopy
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/Object.cpp b/contrib/llvm/tools/llvm-objcopy/COFF/Object.cpp
index 315d3a778623..b07532c1dc39 100644
--- a/contrib/llvm/tools/llvm-objcopy/COFF/Object.cpp
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/Object.cpp
@@ -1,13 +1,13 @@
//===- Object.cpp ---------------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Object.h"
+#include "llvm/ADT/DenseSet.h"
#include <algorithm>
namespace llvm {
@@ -26,12 +26,8 @@ void Object::addSymbols(ArrayRef<Symbol> NewSymbols) {
void Object::updateSymbols() {
SymbolMap = DenseMap<size_t, Symbol *>(Symbols.size());
- size_t RawSymIndex = 0;
- for (Symbol &Sym : Symbols) {
+ for (Symbol &Sym : Symbols)
SymbolMap[Sym.UniqueId] = &Sym;
- Sym.RawIndex = RawSymIndex;
- RawSymIndex += 1 + Sym.Sym.NumberOfAuxSymbols;
- }
}
const Symbol *Object::findSymbol(size_t UniqueId) const {
@@ -56,15 +52,86 @@ Error Object::markSymbols() {
for (const Relocation &R : Sec.Relocs) {
auto It = SymbolMap.find(R.Target);
if (It == SymbolMap.end())
- return make_error<StringError>("Relocation target " + Twine(R.Target) +
- " not found",
- object_error::invalid_symbol_index);
+ return createStringError(object_error::invalid_symbol_index,
+ "relocation target %zu not found", R.Target);
It->second->Referenced = true;
}
}
return Error::success();
}
+void Object::addSections(ArrayRef<Section> NewSections) {
+ for (Section S : NewSections) {
+ S.UniqueId = NextSectionUniqueId++;
+ Sections.emplace_back(S);
+ }
+ updateSections();
+}
+
+void Object::updateSections() {
+ SectionMap = DenseMap<ssize_t, Section *>(Sections.size());
+ size_t Index = 1;
+ for (Section &S : Sections) {
+ SectionMap[S.UniqueId] = &S;
+ S.Index = Index++;
+ }
+}
+
+const Section *Object::findSection(ssize_t UniqueId) const {
+ auto It = SectionMap.find(UniqueId);
+ if (It == SectionMap.end())
+ return nullptr;
+ return It->second;
+}
+
+void Object::removeSections(function_ref<bool(const Section &)> ToRemove) {
+ DenseSet<ssize_t> AssociatedSections;
+ auto RemoveAssociated = [&AssociatedSections](const Section &Sec) {
+ return AssociatedSections.count(Sec.UniqueId) == 1;
+ };
+ do {
+ DenseSet<ssize_t> RemovedSections;
+ Sections.erase(
+ std::remove_if(std::begin(Sections), std::end(Sections),
+ [ToRemove, &RemovedSections](const Section &Sec) {
+ bool Remove = ToRemove(Sec);
+ if (Remove)
+ RemovedSections.insert(Sec.UniqueId);
+ return Remove;
+ }),
+ std::end(Sections));
+ // Remove all symbols referring to the removed sections.
+ AssociatedSections.clear();
+ Symbols.erase(
+ std::remove_if(
+ std::begin(Symbols), std::end(Symbols),
+ [&RemovedSections, &AssociatedSections](const Symbol &Sym) {
+ // If there are sections that are associative to a removed
+ // section,
+ // remove those as well as nothing will include them (and we can't
+ // leave them dangling).
+ if (RemovedSections.count(Sym.AssociativeComdatTargetSectionId) ==
+ 1)
+ AssociatedSections.insert(Sym.TargetSectionId);
+ return RemovedSections.count(Sym.TargetSectionId) == 1;
+ }),
+ std::end(Symbols));
+ ToRemove = RemoveAssociated;
+ } while (!AssociatedSections.empty());
+ updateSections();
+ updateSymbols();
+}
+
+void Object::truncateSections(function_ref<bool(const Section &)> ToTruncate) {
+ for (Section &Sec : Sections) {
+ if (ToTruncate(Sec)) {
+ Sec.clearContents();
+ Sec.Relocs.clear();
+ Sec.Header.SizeOfRawData = 0;
+ }
+ }
+}
+
} // end namespace coff
} // end namespace objcopy
} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/Object.h b/contrib/llvm/tools/llvm-objcopy/COFF/Object.h
index 7531fb4cf39e..21475b068629 100644
--- a/contrib/llvm/tools/llvm-objcopy/COFF/Object.h
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/Object.h
@@ -1,9 +1,8 @@
//===- Object.h -------------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -12,6 +11,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/BinaryFormat/COFF.h"
@@ -35,15 +35,58 @@ struct Relocation {
struct Section {
object::coff_section Header;
- ArrayRef<uint8_t> Contents;
std::vector<Relocation> Relocs;
StringRef Name;
+ ssize_t UniqueId;
+ size_t Index;
+
+ ArrayRef<uint8_t> getContents() const {
+ if (!OwnedContents.empty())
+ return OwnedContents;
+ return ContentsRef;
+ }
+
+ void setContentsRef(ArrayRef<uint8_t> Data) {
+ OwnedContents.clear();
+ ContentsRef = Data;
+ }
+
+ void setOwnedContents(std::vector<uint8_t> &&Data) {
+ ContentsRef = ArrayRef<uint8_t>();
+ OwnedContents = std::move(Data);
+ }
+
+ void clearContents() {
+ ContentsRef = ArrayRef<uint8_t>();
+ OwnedContents.clear();
+ }
+
+private:
+ ArrayRef<uint8_t> ContentsRef;
+ std::vector<uint8_t> OwnedContents;
+};
+
+struct AuxSymbol {
+ AuxSymbol(ArrayRef<uint8_t> In) {
+ assert(In.size() == sizeof(Opaque));
+ std::copy(In.begin(), In.end(), Opaque);
+ }
+
+ ArrayRef<uint8_t> getRef() const {
+ return ArrayRef<uint8_t>(Opaque, sizeof(Opaque));
+ }
+
+ uint8_t Opaque[sizeof(object::coff_symbol16)];
};
struct Symbol {
object::coff_symbol32 Sym;
StringRef Name;
- ArrayRef<uint8_t> AuxData;
+ std::vector<AuxSymbol> AuxData;
+ StringRef AuxFile;
+ ssize_t TargetSectionId;
+ ssize_t AssociativeComdatTargetSectionId = 0;
+ Optional<size_t> WeakTargetSymbolId;
size_t UniqueId;
size_t RawIndex;
bool Referenced;
@@ -62,7 +105,6 @@ struct Object {
uint32_t BaseOfData = 0; // pe32plus_header lacks this field.
std::vector<object::data_directory> DataDirectories;
- std::vector<Section> Sections;
ArrayRef<Symbol> getSymbols() const { return Symbols; }
// This allows mutating individual Symbols, but not mutating the list
@@ -80,14 +122,35 @@ struct Object {
// all sections.
Error markSymbols();
+ ArrayRef<Section> getSections() const { return Sections; }
+ // This allows mutating individual Sections, but not mutating the list
+ // of symbols itself.
+ iterator_range<std::vector<Section>::iterator> getMutableSections() {
+ return make_range(Sections.begin(), Sections.end());
+ }
+
+ const Section *findSection(ssize_t UniqueId) const;
+
+ void addSections(ArrayRef<Section> NewSections);
+ void removeSections(function_ref<bool(const Section &)> ToRemove);
+ void truncateSections(function_ref<bool(const Section &)> ToTruncate);
+
private:
std::vector<Symbol> Symbols;
DenseMap<size_t, Symbol *> SymbolMap;
size_t NextSymbolUniqueId = 0;
- // Update SymbolMap and RawIndex in each Symbol.
+ std::vector<Section> Sections;
+ DenseMap<ssize_t, Section *> SectionMap;
+
+ ssize_t NextSectionUniqueId = 1; // Allow a UniqueId 0 to mean undefined.
+
+ // Update SymbolMap.
void updateSymbols();
+
+ // Update SectionMap and Index in each Section.
+ void updateSections();
};
// Copy between coff_symbol16 and coff_symbol32.
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/Reader.cpp b/contrib/llvm/tools/llvm-objcopy/COFF/Reader.cpp
index a01768392d7d..1f0ec9fa9691 100644
--- a/contrib/llvm/tools/llvm-objcopy/COFF/Reader.cpp
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/Reader.cpp
@@ -1,17 +1,16 @@
//===- Reader.cpp ---------------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Reader.h"
#include "Object.h"
-#include "llvm-objcopy.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/COFF.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstddef>
@@ -22,6 +21,7 @@ namespace objcopy {
namespace coff {
using namespace object;
+using namespace COFF;
Error COFFReader::readExecutableHeaders(Object &Obj) const {
const dos_header *DH = COFFObj.getDOSHeader();
@@ -59,31 +59,38 @@ Error COFFReader::readExecutableHeaders(Object &Obj) const {
}
Error COFFReader::readSections(Object &Obj) const {
+ std::vector<Section> Sections;
// Section indexing starts from 1.
for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) {
const coff_section *Sec;
if (auto EC = COFFObj.getSection(I, Sec))
return errorCodeToError(EC);
- Obj.Sections.push_back(Section());
- Section &S = Obj.Sections.back();
+ Sections.push_back(Section());
+ Section &S = Sections.back();
S.Header = *Sec;
- if (auto EC = COFFObj.getSectionContents(Sec, S.Contents))
- return errorCodeToError(EC);
+ ArrayRef<uint8_t> Contents;
+ if (Error E = COFFObj.getSectionContents(Sec, Contents))
+ return E;
+ S.setContentsRef(Contents);
ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);
for (const coff_relocation &R : Relocs)
S.Relocs.push_back(R);
- if (auto EC = COFFObj.getSectionName(Sec, S.Name))
- return errorCodeToError(EC);
+ if (Expected<StringRef> NameOrErr = COFFObj.getSectionName(Sec))
+ S.Name = *NameOrErr;
+ else
+ return NameOrErr.takeError();
if (Sec->hasExtendedRelocations())
- return make_error<StringError>("Extended relocations not supported yet",
- object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "extended relocations not supported yet");
}
+ Obj.addSections(Sections);
return Error::success();
}
Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
std::vector<Symbol> Symbols;
Symbols.reserve(COFFObj.getRawNumberOfSymbols());
+ ArrayRef<Section> Sections = Obj.getSections();
for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) {
Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);
if (!SymOrErr)
@@ -101,31 +108,86 @@ Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
*reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr()));
if (auto EC = COFFObj.getSymbolName(SymRef, Sym.Name))
return errorCodeToError(EC);
- Sym.AuxData = COFFObj.getSymbolAuxData(SymRef);
- assert((Sym.AuxData.size() %
- (IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16))) == 0);
+
+ ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef);
+ size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16);
+ assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols());
+ // The auxillary symbols are structs of sizeof(coff_symbol16) each.
+ // In the big object format (where symbols are coff_symbol32), each
+ // auxillary symbol is padded with 2 bytes at the end. Copy each
+ // auxillary symbol to the Sym.AuxData vector. For file symbols,
+ // the whole range of aux symbols are interpreted as one null padded
+ // string instead.
+ if (SymRef.isFileRecord())
+ Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()),
+ AuxData.size())
+ .rtrim('\0');
+ else
+ for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++)
+ Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol)));
+
+ // Find the unique id of the section
+ if (SymRef.getSectionNumber() <=
+ 0) // Special symbol (undefined/absolute/debug)
+ Sym.TargetSectionId = SymRef.getSectionNumber();
+ else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) <
+ Sections.size())
+ Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId;
+ else
+ return createStringError(object_error::parse_failed,
+ "section number out of range");
+ // For section definitions, check if it is comdat associative, and if
+ // it is, find the target section unique id.
+ const coff_aux_section_definition *SD = SymRef.getSectionDefinition();
+ const coff_aux_weak_external *WE = SymRef.getWeakExternal();
+ if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ int32_t Index = SD->getNumber(IsBigObj);
+ if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size())
+ return createStringError(object_error::parse_failed,
+ "unexpected associative section index");
+ Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId;
+ } else if (WE) {
+ // This is a raw symbol index for now, but store it in the Symbol
+ // until we've added them to the Object, which assigns the final
+ // unique ids.
+ Sym.WeakTargetSymbolId = WE->TagIndex;
+ }
I += 1 + SymRef.getNumberOfAuxSymbols();
}
Obj.addSymbols(Symbols);
return Error::success();
}
-Error COFFReader::setRelocTargets(Object &Obj) const {
+Error COFFReader::setSymbolTargets(Object &Obj) const {
std::vector<const Symbol *> RawSymbolTable;
for (const Symbol &Sym : Obj.getSymbols()) {
RawSymbolTable.push_back(&Sym);
for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)
RawSymbolTable.push_back(nullptr);
}
- for (Section &Sec : Obj.Sections) {
+ for (Symbol &Sym : Obj.getMutableSymbols()) {
+ // Convert WeakTargetSymbolId from the original raw symbol index to
+ // a proper unique id.
+ if (Sym.WeakTargetSymbolId) {
+ if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size())
+ return createStringError(object_error::parse_failed,
+ "weak external reference out of range");
+ const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId];
+ if (Target == nullptr)
+ return createStringError(object_error::parse_failed,
+ "invalid SymbolTableIndex");
+ Sym.WeakTargetSymbolId = Target->UniqueId;
+ }
+ }
+ for (Section &Sec : Obj.getMutableSections()) {
for (Relocation &R : Sec.Relocs) {
if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())
- return make_error<StringError>("SymbolTableIndex out of range",
- object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "SymbolTableIndex out of range");
const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];
if (Sym == nullptr)
- return make_error<StringError>("Invalid SymbolTableIndex",
- object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "invalid SymbolTableIndex");
R.Target = Sym->UniqueId;
R.TargetName = Sym->Name;
}
@@ -145,8 +207,8 @@ Expected<std::unique_ptr<Object>> COFFReader::create() const {
Obj->CoffFileHeader = *CFH;
} else {
if (!CBFH)
- return make_error<StringError>("No COFF file header returned",
- object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "no COFF file header returned");
// Only copying the few fields from the bigobj header that we need
// and won't recreate in the end.
Obj->CoffFileHeader.Machine = CBFH->Machine;
@@ -160,7 +222,7 @@ Expected<std::unique_ptr<Object>> COFFReader::create() const {
return std::move(E);
if (Error E = readSymbols(*Obj, IsBigObj))
return std::move(E);
- if (Error E = setRelocTargets(*Obj))
+ if (Error E = setSymbolTargets(*Obj))
return std::move(E);
return std::move(Obj);
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/Reader.h b/contrib/llvm/tools/llvm-objcopy/COFF/Reader.h
index ca7057d08c9f..ec15369db0b8 100644
--- a/contrib/llvm/tools/llvm-objcopy/COFF/Reader.h
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/Reader.h
@@ -1,9 +1,8 @@
//===- Reader.h -------------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -29,7 +28,7 @@ class COFFReader {
Error readExecutableHeaders(Object &Obj) const;
Error readSections(Object &Obj) const;
Error readSymbols(Object &Obj, bool IsBigObj) const;
- Error setRelocTargets(Object &Obj) const;
+ Error setSymbolTargets(Object &Obj) const;
public:
explicit COFFReader(const COFFObjectFile &O) : COFFObj(O) {}
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/Writer.cpp b/contrib/llvm/tools/llvm-objcopy/COFF/Writer.cpp
index 385d43b1bae5..f3bb1ce331f2 100644
--- a/contrib/llvm/tools/llvm-objcopy/COFF/Writer.cpp
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/Writer.cpp
@@ -1,15 +1,13 @@
//===- Writer.cpp ---------------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Writer.h"
#include "Object.h"
-#include "llvm-objcopy.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/COFF.h"
@@ -26,22 +24,75 @@ using namespace object;
using namespace COFF;
Error COFFWriter::finalizeRelocTargets() {
- for (Section &Sec : Obj.Sections) {
+ for (Section &Sec : Obj.getMutableSections()) {
for (Relocation &R : Sec.Relocs) {
const Symbol *Sym = Obj.findSymbol(R.Target);
if (Sym == nullptr)
- return make_error<StringError>("Relocation target " + R.TargetName +
- " (" + Twine(R.Target) +
- ") not found",
- object_error::invalid_symbol_index);
+ return createStringError(object_error::invalid_symbol_index,
+ "relocation target '%s' (%zu) not found",
+ R.TargetName.str().c_str(), R.Target);
R.Reloc.SymbolTableIndex = Sym->RawIndex;
}
}
return Error::success();
}
+Error COFFWriter::finalizeSymbolContents() {
+ for (Symbol &Sym : Obj.getMutableSymbols()) {
+ if (Sym.TargetSectionId <= 0) {
+ // Undefined, or a special kind of symbol. These negative values
+ // are stored in the SectionNumber field which is unsigned.
+ Sym.Sym.SectionNumber = static_cast<uint32_t>(Sym.TargetSectionId);
+ } else {
+ const Section *Sec = Obj.findSection(Sym.TargetSectionId);
+ if (Sec == nullptr)
+ return createStringError(object_error::invalid_symbol_index,
+ "symbol '%s' points to a removed section",
+ Sym.Name.str().c_str());
+ Sym.Sym.SectionNumber = Sec->Index;
+
+ if (Sym.Sym.NumberOfAuxSymbols == 1 &&
+ Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC) {
+ coff_aux_section_definition *SD =
+ reinterpret_cast<coff_aux_section_definition *>(
+ Sym.AuxData[0].Opaque);
+ uint32_t SDSectionNumber;
+ if (Sym.AssociativeComdatTargetSectionId == 0) {
+ // Not a comdat associative section; just set the Number field to
+ // the number of the section itself.
+ SDSectionNumber = Sec->Index;
+ } else {
+ Sec = Obj.findSection(Sym.AssociativeComdatTargetSectionId);
+ if (Sec == nullptr)
+ return createStringError(
+ object_error::invalid_symbol_index,
+ "symbol '%s' is associative to a removed section",
+ Sym.Name.str().c_str());
+ SDSectionNumber = Sec->Index;
+ }
+ // Update the section definition with the new section number.
+ SD->NumberLowPart = static_cast<uint16_t>(SDSectionNumber);
+ SD->NumberHighPart = static_cast<uint16_t>(SDSectionNumber >> 16);
+ }
+ }
+ // Check that we actually have got AuxData to match the weak symbol target
+ // we want to set. Only >= 1 would be required, but only == 1 makes sense.
+ if (Sym.WeakTargetSymbolId && Sym.Sym.NumberOfAuxSymbols == 1) {
+ coff_aux_weak_external *WE =
+ reinterpret_cast<coff_aux_weak_external *>(Sym.AuxData[0].Opaque);
+ const Symbol *Target = Obj.findSymbol(*Sym.WeakTargetSymbolId);
+ if (Target == nullptr)
+ return createStringError(object_error::invalid_symbol_index,
+ "symbol '%s' is missing its weak target",
+ Sym.Name.str().c_str());
+ WE->TagIndex = Target->RawIndex;
+ }
+ }
+ return Error::success();
+}
+
void COFFWriter::layoutSections() {
- for (auto &S : Obj.Sections) {
+ for (auto &S : Obj.getMutableSections()) {
if (S.Header.SizeOfRawData > 0)
S.Header.PointerToRawData = FileSize;
FileSize += S.Header.SizeOfRawData; // For executables, this is already
@@ -58,7 +109,7 @@ void COFFWriter::layoutSections() {
}
size_t COFFWriter::finalizeStringTable() {
- for (auto &S : Obj.Sections)
+ for (const auto &S : Obj.getSections())
if (S.Name.size() > COFF::NameSize)
StrTabBuilder.add(S.Name);
@@ -68,8 +119,9 @@ size_t COFFWriter::finalizeStringTable() {
StrTabBuilder.finalize();
- for (auto &S : Obj.Sections) {
+ for (auto &S : Obj.getMutableSections()) {
if (S.Name.size() > COFF::NameSize) {
+ memset(S.Header.Name, 0, sizeof(S.Header.Name));
snprintf(S.Header.Name, sizeof(S.Header.Name), "/%d",
(int)StrTabBuilder.getOffset(S.Name));
} else {
@@ -89,15 +141,30 @@ size_t COFFWriter::finalizeStringTable() {
template <class SymbolTy>
std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() {
- size_t SymTabSize = Obj.getSymbols().size() * sizeof(SymbolTy);
- for (const auto &S : Obj.getSymbols())
- SymTabSize += S.AuxData.size();
- return std::make_pair(SymTabSize, sizeof(SymbolTy));
+ size_t RawSymIndex = 0;
+ for (auto &S : Obj.getMutableSymbols()) {
+ // Symbols normally have NumberOfAuxSymbols set correctly all the time.
+ // For file symbols, we need to know the output file's symbol size to be
+ // able to calculate the number of slots it occupies.
+ if (!S.AuxFile.empty())
+ S.Sym.NumberOfAuxSymbols =
+ alignTo(S.AuxFile.size(), sizeof(SymbolTy)) / sizeof(SymbolTy);
+ S.RawIndex = RawSymIndex;
+ RawSymIndex += 1 + S.Sym.NumberOfAuxSymbols;
+ }
+ return std::make_pair(RawSymIndex * sizeof(SymbolTy), sizeof(SymbolTy));
}
Error COFFWriter::finalize(bool IsBigObj) {
+ size_t SymTabSize, SymbolSize;
+ std::tie(SymTabSize, SymbolSize) = IsBigObj
+ ? finalizeSymbolTable<coff_symbol32>()
+ : finalizeSymbolTable<coff_symbol16>();
+
if (Error E = finalizeRelocTargets())
return E;
+ if (Error E = finalizeSymbolContents())
+ return E;
size_t SizeOfHeaders = 0;
FileAlignment = 1;
@@ -114,10 +181,10 @@ Error COFFWriter::finalize(bool IsBigObj) {
SizeOfHeaders +=
PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
}
- Obj.CoffFileHeader.NumberOfSections = Obj.Sections.size();
+ Obj.CoffFileHeader.NumberOfSections = Obj.getSections().size();
SizeOfHeaders +=
IsBigObj ? sizeof(coff_bigobj_file_header) : sizeof(coff_file_header);
- SizeOfHeaders += sizeof(coff_section) * Obj.Sections.size();
+ SizeOfHeaders += sizeof(coff_section) * Obj.getSections().size();
SizeOfHeaders = alignTo(SizeOfHeaders, FileAlignment);
Obj.CoffFileHeader.SizeOfOptionalHeader =
@@ -132,8 +199,8 @@ Error COFFWriter::finalize(bool IsBigObj) {
Obj.PeHeader.SizeOfHeaders = SizeOfHeaders;
Obj.PeHeader.SizeOfInitializedData = SizeOfInitializedData;
- if (!Obj.Sections.empty()) {
- const Section &S = Obj.Sections.back();
+ if (!Obj.getSections().empty()) {
+ const Section &S = Obj.getSections().back();
Obj.PeHeader.SizeOfImage =
alignTo(S.Header.VirtualAddress + S.Header.VirtualSize,
Obj.PeHeader.SectionAlignment);
@@ -145,10 +212,6 @@ Error COFFWriter::finalize(bool IsBigObj) {
}
size_t StrTabSize = finalizeStringTable();
- size_t SymTabSize, SymbolSize;
- std::tie(SymTabSize, SymbolSize) = IsBigObj
- ? finalizeSymbolTable<coff_symbol32>()
- : finalizeSymbolTable<coff_symbol16>();
size_t PointerToSymbolTable = FileSize;
// StrTabSize <= 4 is the size of an empty string table, only consisting
@@ -199,7 +262,7 @@ void COFFWriter::writeHeaders(bool IsBigObj) {
BigObjHeader.unused4 = 0;
// The value in Obj.CoffFileHeader.NumberOfSections is truncated, thus
// get the original one instead.
- BigObjHeader.NumberOfSections = Obj.Sections.size();
+ BigObjHeader.NumberOfSections = Obj.getSections().size();
BigObjHeader.PointerToSymbolTable = Obj.CoffFileHeader.PointerToSymbolTable;
BigObjHeader.NumberOfSymbols = Obj.CoffFileHeader.NumberOfSymbols;
@@ -224,23 +287,24 @@ void COFFWriter::writeHeaders(bool IsBigObj) {
Ptr += sizeof(DD);
}
}
- for (const auto &S : Obj.Sections) {
+ for (const auto &S : Obj.getSections()) {
memcpy(Ptr, &S.Header, sizeof(S.Header));
Ptr += sizeof(S.Header);
}
}
void COFFWriter::writeSections() {
- for (const auto &S : Obj.Sections) {
+ for (const auto &S : Obj.getSections()) {
uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData;
- std::copy(S.Contents.begin(), S.Contents.end(), Ptr);
+ ArrayRef<uint8_t> Contents = S.getContents();
+ std::copy(Contents.begin(), Contents.end(), Ptr);
// For executable sections, pad the remainder of the raw data size with
// 0xcc, which is int3 on x86.
if ((S.Header.Characteristics & IMAGE_SCN_CNT_CODE) &&
- S.Header.SizeOfRawData > S.Contents.size())
- memset(Ptr + S.Contents.size(), 0xcc,
- S.Header.SizeOfRawData - S.Contents.size());
+ S.Header.SizeOfRawData > Contents.size())
+ memset(Ptr + Contents.size(), 0xcc,
+ S.Header.SizeOfRawData - Contents.size());
Ptr += S.Header.SizeOfRawData;
for (const auto &R : S.Relocs) {
@@ -257,8 +321,23 @@ template <class SymbolTy> void COFFWriter::writeSymbolStringTables() {
copySymbol<SymbolTy, coff_symbol32>(*reinterpret_cast<SymbolTy *>(Ptr),
S.Sym);
Ptr += sizeof(SymbolTy);
- std::copy(S.AuxData.begin(), S.AuxData.end(), Ptr);
- Ptr += S.AuxData.size();
+ if (!S.AuxFile.empty()) {
+ // For file symbols, just write the string into the aux symbol slots,
+ // assuming that the unwritten parts are initialized to zero in the memory
+ // mapped file.
+ std::copy(S.AuxFile.begin(), S.AuxFile.end(), Ptr);
+ Ptr += S.Sym.NumberOfAuxSymbols * sizeof(SymbolTy);
+ } else {
+ // For other auxillary symbols, write their opaque payload into one symbol
+ // table slot each. For big object files, the symbols are larger than the
+ // opaque auxillary symbol struct and we leave padding at the end of each
+ // entry.
+ for (const AuxSymbol &AuxSym : S.AuxData) {
+ ArrayRef<uint8_t> Ref = AuxSym.getRef();
+ std::copy(Ref.begin(), Ref.end(), Ptr);
+ Ptr += sizeof(SymbolTy);
+ }
+ }
}
if (StrTabBuilder.getSize() > 4 || !Obj.IsPE) {
// Always write a string table in object files, even an empty one.
@@ -271,7 +350,8 @@ Error COFFWriter::write(bool IsBigObj) {
if (Error E = finalize(IsBigObj))
return E;
- Buf.allocate(FileSize);
+ if (Error E = Buf.allocate(FileSize))
+ return E;
writeHeaders(IsBigObj);
writeSections();
@@ -296,15 +376,14 @@ Error COFFWriter::patchDebugDirectory() {
const data_directory *Dir = &Obj.DataDirectories[DEBUG_DIRECTORY];
if (Dir->Size <= 0)
return Error::success();
- for (const auto &S : Obj.Sections) {
+ for (const auto &S : Obj.getSections()) {
if (Dir->RelativeVirtualAddress >= S.Header.VirtualAddress &&
Dir->RelativeVirtualAddress <
S.Header.VirtualAddress + S.Header.SizeOfRawData) {
if (Dir->RelativeVirtualAddress + Dir->Size >
S.Header.VirtualAddress + S.Header.SizeOfRawData)
- return make_error<StringError>(
- "Debug directory extends past end of section",
- object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "debug directory extends past end of section");
size_t Offset = Dir->RelativeVirtualAddress - S.Header.VirtualAddress;
uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData + Offset;
@@ -320,15 +399,15 @@ Error COFFWriter::patchDebugDirectory() {
return Error::success();
}
}
- return make_error<StringError>("Debug directory not found",
- object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "debug directory not found");
}
Error COFFWriter::write() {
- bool IsBigObj = Obj.Sections.size() > MaxNumberOfSections16;
+ bool IsBigObj = Obj.getSections().size() > MaxNumberOfSections16;
if (IsBigObj && Obj.IsPE)
- return make_error<StringError>("Too many sections for executable",
- object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "too many sections for executable");
return write(IsBigObj);
}
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/Writer.h b/contrib/llvm/tools/llvm-objcopy/COFF/Writer.h
index ab66e0cc1134..681a8d5e4a66 100644
--- a/contrib/llvm/tools/llvm-objcopy/COFF/Writer.h
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/Writer.h
@@ -1,9 +1,8 @@
//===- Writer.h -------------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -31,10 +30,11 @@ class COFFWriter {
size_t SizeOfInitializedData;
StringTableBuilder StrTabBuilder;
+ template <class SymbolTy> std::pair<size_t, size_t> finalizeSymbolTable();
Error finalizeRelocTargets();
+ Error finalizeSymbolContents();
void layoutSections();
size_t finalizeStringTable();
- template <class SymbolTy> std::pair<size_t, size_t> finalizeSymbolTable();
Error finalize(bool IsBigObj);
diff --git a/contrib/llvm/tools/llvm-objcopy/CopyConfig.cpp b/contrib/llvm/tools/llvm-objcopy/CopyConfig.cpp
index 3737f571ae61..8d6431b3044f 100644
--- a/contrib/llvm/tools/llvm-objcopy/CopyConfig.cpp
+++ b/contrib/llvm/tools/llvm-objcopy/CopyConfig.cpp
@@ -1,27 +1,26 @@
//===- CopyConfig.cpp -----------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "CopyConfig.h"
-#include "llvm-objcopy.h"
-#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Object/ELFTypes.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compression.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/JamCRC.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/StringSaver.h"
#include <memory>
-#include <string>
namespace llvm {
namespace objcopy {
@@ -93,45 +92,47 @@ public:
StripOptTable() : OptTable(StripInfoTable) {}
};
-enum SectionFlag {
- SecNone = 0,
- SecAlloc = 1 << 0,
- SecLoad = 1 << 1,
- SecNoload = 1 << 2,
- SecReadonly = 1 << 3,
- SecDebug = 1 << 4,
- SecCode = 1 << 5,
- SecData = 1 << 6,
- SecRom = 1 << 7,
- SecMerge = 1 << 8,
- SecStrings = 1 << 9,
- SecContents = 1 << 10,
- SecShare = 1 << 11,
- LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare)
-};
-
} // namespace
static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
return llvm::StringSwitch<SectionFlag>(SectionName)
- .Case("alloc", SectionFlag::SecAlloc)
- .Case("load", SectionFlag::SecLoad)
- .Case("noload", SectionFlag::SecNoload)
- .Case("readonly", SectionFlag::SecReadonly)
- .Case("debug", SectionFlag::SecDebug)
- .Case("code", SectionFlag::SecCode)
- .Case("data", SectionFlag::SecData)
- .Case("rom", SectionFlag::SecRom)
- .Case("merge", SectionFlag::SecMerge)
- .Case("strings", SectionFlag::SecStrings)
- .Case("contents", SectionFlag::SecContents)
- .Case("share", SectionFlag::SecShare)
+ .CaseLower("alloc", SectionFlag::SecAlloc)
+ .CaseLower("load", SectionFlag::SecLoad)
+ .CaseLower("noload", SectionFlag::SecNoload)
+ .CaseLower("readonly", SectionFlag::SecReadonly)
+ .CaseLower("debug", SectionFlag::SecDebug)
+ .CaseLower("code", SectionFlag::SecCode)
+ .CaseLower("data", SectionFlag::SecData)
+ .CaseLower("rom", SectionFlag::SecRom)
+ .CaseLower("merge", SectionFlag::SecMerge)
+ .CaseLower("strings", SectionFlag::SecStrings)
+ .CaseLower("contents", SectionFlag::SecContents)
+ .CaseLower("share", SectionFlag::SecShare)
.Default(SectionFlag::SecNone);
}
-static SectionRename parseRenameSectionValue(StringRef FlagValue) {
+static Expected<SectionFlag>
+parseSectionFlagSet(ArrayRef<StringRef> SectionFlags) {
+ SectionFlag ParsedFlags = SectionFlag::SecNone;
+ for (StringRef Flag : SectionFlags) {
+ SectionFlag ParsedFlag = parseSectionRenameFlag(Flag);
+ if (ParsedFlag == SectionFlag::SecNone)
+ return createStringError(
+ errc::invalid_argument,
+ "unrecognized section flag '%s'. Flags supported for GNU "
+ "compatibility: alloc, load, noload, readonly, debug, code, data, "
+ "rom, share, contents, merge, strings",
+ Flag.str().c_str());
+ ParsedFlags |= ParsedFlag;
+ }
+
+ return ParsedFlags;
+}
+
+static Expected<SectionRename> parseRenameSectionValue(StringRef FlagValue) {
if (!FlagValue.contains('='))
- error("Bad format for --rename-section: missing '='");
+ return createStringError(errc::invalid_argument,
+ "bad format for --rename-section: missing '='");
// Initial split: ".foo" = ".bar,f1,f2,..."
auto Old2New = FlagValue.split('=');
@@ -144,73 +145,210 @@ static SectionRename parseRenameSectionValue(StringRef FlagValue) {
SR.NewName = NameAndFlags[0];
if (NameAndFlags.size() > 1) {
- SectionFlag Flags = SectionFlag::SecNone;
- for (size_t I = 1, Size = NameAndFlags.size(); I < Size; ++I) {
- SectionFlag Flag = parseSectionRenameFlag(NameAndFlags[I]);
- if (Flag == SectionFlag::SecNone)
- error("Unrecognized section flag '" + NameAndFlags[I] +
- "'. Flags supported for GNU compatibility: alloc, load, noload, "
- "readonly, debug, code, data, rom, share, contents, merge, "
- "strings.");
- Flags |= Flag;
- }
-
- SR.NewFlags = 0;
- if (Flags & SectionFlag::SecAlloc)
- *SR.NewFlags |= ELF::SHF_ALLOC;
- if (!(Flags & SectionFlag::SecReadonly))
- *SR.NewFlags |= ELF::SHF_WRITE;
- if (Flags & SectionFlag::SecCode)
- *SR.NewFlags |= ELF::SHF_EXECINSTR;
- if (Flags & SectionFlag::SecMerge)
- *SR.NewFlags |= ELF::SHF_MERGE;
- if (Flags & SectionFlag::SecStrings)
- *SR.NewFlags |= ELF::SHF_STRINGS;
+ Expected<SectionFlag> ParsedFlagSet =
+ parseSectionFlagSet(makeArrayRef(NameAndFlags).drop_front());
+ if (!ParsedFlagSet)
+ return ParsedFlagSet.takeError();
+ SR.NewFlags = *ParsedFlagSet;
}
return SR;
}
+static Expected<SectionFlagsUpdate>
+parseSetSectionFlagValue(StringRef FlagValue) {
+ if (!StringRef(FlagValue).contains('='))
+ return createStringError(errc::invalid_argument,
+ "bad format for --set-section-flags: missing '='");
+
+ // Initial split: ".foo" = "f1,f2,..."
+ auto Section2Flags = StringRef(FlagValue).split('=');
+ SectionFlagsUpdate SFU;
+ SFU.Name = Section2Flags.first;
+
+ // Flags split: "f1" "f2" ...
+ SmallVector<StringRef, 6> SectionFlags;
+ Section2Flags.second.split(SectionFlags, ',');
+ Expected<SectionFlag> ParsedFlagSet = parseSectionFlagSet(SectionFlags);
+ if (!ParsedFlagSet)
+ return ParsedFlagSet.takeError();
+ SFU.NewFlags = *ParsedFlagSet;
+
+ return SFU;
+}
+
+static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue) {
+ // Parse value given with --add-symbol option and create the
+ // new symbol if possible. The value format for --add-symbol is:
+ //
+ // <name>=[<section>:]<value>[,<flags>]
+ //
+ // where:
+ // <name> - symbol name, can be empty string
+ // <section> - optional section name. If not given ABS symbol is created
+ // <value> - symbol value, can be decimal or hexadecimal number prefixed
+ // with 0x.
+ // <flags> - optional flags affecting symbol type, binding or visibility:
+ // The following are currently supported:
+ //
+ // global, local, weak, default, hidden, file, section, object,
+ // indirect-function.
+ //
+ // The following flags are ignored and provided for GNU
+ // compatibility only:
+ //
+ // warning, debug, constructor, indirect, synthetic,
+ // unique-object, before=<symbol>.
+ NewSymbolInfo SI;
+ StringRef Value;
+ std::tie(SI.SymbolName, Value) = FlagValue.split('=');
+ if (Value.empty())
+ return createStringError(
+ errc::invalid_argument,
+ "bad format for --add-symbol, missing '=' after '%s'",
+ SI.SymbolName.str().c_str());
+
+ if (Value.contains(':')) {
+ std::tie(SI.SectionName, Value) = Value.split(':');
+ if (SI.SectionName.empty() || Value.empty())
+ return createStringError(
+ errc::invalid_argument,
+ "bad format for --add-symbol, missing section name or symbol value");
+ }
+
+ SmallVector<StringRef, 6> Flags;
+ Value.split(Flags, ',');
+ if (Flags[0].getAsInteger(0, SI.Value))
+ return createStringError(errc::invalid_argument, "bad symbol value: '%s'",
+ Flags[0].str().c_str());
+
+ using Functor = std::function<void(void)>;
+ SmallVector<StringRef, 6> UnsupportedFlags;
+ for (size_t I = 1, NumFlags = Flags.size(); I < NumFlags; ++I)
+ static_cast<Functor>(
+ StringSwitch<Functor>(Flags[I])
+ .CaseLower("global", [&SI] { SI.Bind = ELF::STB_GLOBAL; })
+ .CaseLower("local", [&SI] { SI.Bind = ELF::STB_LOCAL; })
+ .CaseLower("weak", [&SI] { SI.Bind = ELF::STB_WEAK; })
+ .CaseLower("default", [&SI] { SI.Visibility = ELF::STV_DEFAULT; })
+ .CaseLower("hidden", [&SI] { SI.Visibility = ELF::STV_HIDDEN; })
+ .CaseLower("file", [&SI] { SI.Type = ELF::STT_FILE; })
+ .CaseLower("section", [&SI] { SI.Type = ELF::STT_SECTION; })
+ .CaseLower("object", [&SI] { SI.Type = ELF::STT_OBJECT; })
+ .CaseLower("function", [&SI] { SI.Type = ELF::STT_FUNC; })
+ .CaseLower("indirect-function",
+ [&SI] { SI.Type = ELF::STT_GNU_IFUNC; })
+ .CaseLower("debug", [] {})
+ .CaseLower("constructor", [] {})
+ .CaseLower("warning", [] {})
+ .CaseLower("indirect", [] {})
+ .CaseLower("synthetic", [] {})
+ .CaseLower("unique-object", [] {})
+ .StartsWithLower("before", [] {})
+ .Default([&] { UnsupportedFlags.push_back(Flags[I]); }))();
+ if (!UnsupportedFlags.empty())
+ return createStringError(errc::invalid_argument,
+ "unsupported flag%s for --add-symbol: '%s'",
+ UnsupportedFlags.size() > 1 ? "s" : "",
+ join(UnsupportedFlags, "', '").c_str());
+ return SI;
+}
+
static const StringMap<MachineInfo> ArchMap{
// Name, {EMachine, 64bit, LittleEndian}
{"aarch64", {ELF::EM_AARCH64, true, true}},
{"arm", {ELF::EM_ARM, false, true}},
{"i386", {ELF::EM_386, false, true}},
{"i386:x86-64", {ELF::EM_X86_64, true, true}},
+ {"mips", {ELF::EM_MIPS, false, false}},
{"powerpc:common64", {ELF::EM_PPC64, true, true}},
- {"sparc", {ELF::EM_SPARC, false, true}},
+ {"riscv:rv32", {ELF::EM_RISCV, false, true}},
+ {"riscv:rv64", {ELF::EM_RISCV, true, true}},
+ {"sparc", {ELF::EM_SPARC, false, false}},
+ {"sparcel", {ELF::EM_SPARC, false, true}},
{"x86-64", {ELF::EM_X86_64, true, true}},
};
-static const MachineInfo &getMachineInfo(StringRef Arch) {
+static Expected<const MachineInfo &> getMachineInfo(StringRef Arch) {
auto Iter = ArchMap.find(Arch);
if (Iter == std::end(ArchMap))
- error("Invalid architecture: '" + Arch + "'");
+ return createStringError(errc::invalid_argument,
+ "invalid architecture: '%s'", Arch.str().c_str());
return Iter->getValue();
}
-static const StringMap<MachineInfo> OutputFormatMap{
+struct TargetInfo {
+ FileFormat Format;
+ MachineInfo Machine;
+};
+
+// FIXME: consolidate with the bfd parsing used by lld.
+static const StringMap<MachineInfo> TargetMap{
// Name, {EMachine, 64bit, LittleEndian}
+ // x86
{"elf32-i386", {ELF::EM_386, false, true}},
- {"elf32-powerpcle", {ELF::EM_PPC, false, true}},
{"elf32-x86-64", {ELF::EM_X86_64, false, true}},
- {"elf64-powerpcle", {ELF::EM_PPC64, true, true}},
{"elf64-x86-64", {ELF::EM_X86_64, true, true}},
+ // Intel MCU
+ {"elf32-iamcu", {ELF::EM_IAMCU, false, true}},
+ // ARM
+ {"elf32-littlearm", {ELF::EM_ARM, false, true}},
+ // ARM AArch64
+ {"elf64-aarch64", {ELF::EM_AARCH64, true, true}},
+ {"elf64-littleaarch64", {ELF::EM_AARCH64, true, true}},
+ // RISC-V
+ {"elf32-littleriscv", {ELF::EM_RISCV, false, true}},
+ {"elf64-littleriscv", {ELF::EM_RISCV, true, true}},
+ // PowerPC
+ {"elf32-powerpc", {ELF::EM_PPC, false, false}},
+ {"elf32-powerpcle", {ELF::EM_PPC, false, true}},
+ {"elf64-powerpc", {ELF::EM_PPC64, true, false}},
+ {"elf64-powerpcle", {ELF::EM_PPC64, true, true}},
+ // MIPS
+ {"elf32-bigmips", {ELF::EM_MIPS, false, false}},
+ {"elf32-ntradbigmips", {ELF::EM_MIPS, false, false}},
+ {"elf32-ntradlittlemips", {ELF::EM_MIPS, false, true}},
+ {"elf32-tradbigmips", {ELF::EM_MIPS, false, false}},
+ {"elf32-tradlittlemips", {ELF::EM_MIPS, false, true}},
+ {"elf64-tradbigmips", {ELF::EM_MIPS, true, false}},
+ {"elf64-tradlittlemips", {ELF::EM_MIPS, true, true}},
+ // SPARC
+ {"elf32-sparc", {ELF::EM_SPARC, false, false}},
+ {"elf32-sparcel", {ELF::EM_SPARC, false, true}},
};
-static const MachineInfo &getOutputFormatMachineInfo(StringRef Format) {
- auto Iter = OutputFormatMap.find(Format);
- if (Iter == std::end(OutputFormatMap))
- error("Invalid output format: '" + Format + "'");
- return Iter->getValue();
+static Expected<TargetInfo>
+getOutputTargetInfoByTargetName(StringRef TargetName) {
+ StringRef OriginalTargetName = TargetName;
+ bool IsFreeBSD = TargetName.consume_back("-freebsd");
+ auto Iter = TargetMap.find(TargetName);
+ if (Iter == std::end(TargetMap))
+ return createStringError(errc::invalid_argument,
+ "invalid output format: '%s'",
+ OriginalTargetName.str().c_str());
+ MachineInfo MI = Iter->getValue();
+ if (IsFreeBSD)
+ MI.OSABI = ELF::ELFOSABI_FREEBSD;
+
+ FileFormat Format;
+ if (TargetName.startswith("elf"))
+ Format = FileFormat::ELF;
+ else
+ // This should never happen because `TargetName` is valid (it certainly
+ // exists in the TargetMap).
+ llvm_unreachable("unknown target prefix");
+
+ return {TargetInfo{Format, MI}};
}
-static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols,
- StringRef Filename) {
+static Error addSymbolsFromFile(std::vector<NameOrRegex> &Symbols,
+ BumpPtrAllocator &Alloc, StringRef Filename,
+ bool UseRegex) {
+ StringSaver Saver(Alloc);
SmallVector<StringRef, 16> Lines;
auto BufOrErr = MemoryBuffer::getFile(Filename);
if (!BufOrErr)
- reportError(Filename, BufOrErr.getError());
+ return createFileError(Filename, BufOrErr.getError());
BufOrErr.get()->getBuffer().split(Lines, '\n');
for (StringRef Line : Lines) {
@@ -218,14 +356,62 @@ static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols,
// it's not empty.
auto TrimmedLine = Line.split('#').first.trim();
if (!TrimmedLine.empty())
- Symbols.push_back(TrimmedLine.str());
+ Symbols.emplace_back(Saver.save(TrimmedLine), UseRegex);
}
+
+ return Error::success();
+}
+
+NameOrRegex::NameOrRegex(StringRef Pattern, bool IsRegex) {
+ if (!IsRegex) {
+ Name = Pattern;
+ return;
+ }
+
+ SmallVector<char, 32> Data;
+ R = std::make_shared<Regex>(
+ ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data));
+}
+
+static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename,
+ BumpPtrAllocator &Alloc,
+ StringRef Filename) {
+ StringSaver Saver(Alloc);
+ SmallVector<StringRef, 16> Lines;
+ auto BufOrErr = MemoryBuffer::getFile(Filename);
+ if (!BufOrErr)
+ return createFileError(Filename, BufOrErr.getError());
+
+ BufOrErr.get()->getBuffer().split(Lines, '\n');
+ size_t NumLines = Lines.size();
+ for (size_t LineNo = 0; LineNo < NumLines; ++LineNo) {
+ StringRef TrimmedLine = Lines[LineNo].split('#').first.trim();
+ if (TrimmedLine.empty())
+ continue;
+
+ std::pair<StringRef, StringRef> Pair = Saver.save(TrimmedLine).split(' ');
+ StringRef NewName = Pair.second.trim();
+ if (NewName.empty())
+ return createStringError(errc::invalid_argument,
+ "%s:%zu: missing new symbol name",
+ Filename.str().c_str(), LineNo + 1);
+ SymbolsToRename.insert({Pair.first, NewName});
+ }
+ return Error::success();
+}
+
+template <class T> static ErrorOr<T> getAsInteger(StringRef Val) {
+ T Result;
+ if (Val.getAsInteger(0, Result))
+ return errc::invalid_argument;
+ return Result;
}
// ParseObjcopyOptions returns the config and sets the input arguments. If a
// help flag is set then ParseObjcopyOptions will print the help messege and
// exit.
-DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
+Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
+ DriverConfig DC;
ObjcopyOptTable T;
unsigned MissingArgumentIndex, MissingArgumentCount;
llvm::opt::InputArgList InputArgs =
@@ -250,16 +436,18 @@ DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
SmallVector<const char *, 2> Positional;
for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
- error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
+ return createStringError(errc::invalid_argument, "unknown argument '%s'",
+ Arg->getAsString(InputArgs).c_str());
for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
Positional.push_back(Arg->getValue());
if (Positional.empty())
- error("No input file specified");
+ return createStringError(errc::invalid_argument, "no input file specified");
if (Positional.size() > 2)
- error("Too many positional arguments");
+ return createStringError(errc::invalid_argument,
+ "too many positional arguments");
CopyConfig Config;
Config.InputFilename = Positional[0];
@@ -267,23 +455,50 @@ DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
if (InputArgs.hasArg(OBJCOPY_target) &&
(InputArgs.hasArg(OBJCOPY_input_target) ||
InputArgs.hasArg(OBJCOPY_output_target)))
- error("--target cannot be used with --input-target or --output-target");
+ return createStringError(
+ errc::invalid_argument,
+ "--target cannot be used with --input-target or --output-target");
+ bool UseRegex = InputArgs.hasArg(OBJCOPY_regex);
+ StringRef InputFormat, OutputFormat;
if (InputArgs.hasArg(OBJCOPY_target)) {
- Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
- Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
+ InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
+ OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
} else {
- Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
- Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
+ InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
+ OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
}
- if (Config.InputFormat == "binary") {
+
+ // FIXME: Currently, we ignore the target for non-binary/ihex formats
+ // explicitly specified by -I option (e.g. -Ielf32-x86-64) and guess the
+ // format by llvm::object::createBinary regardless of the option value.
+ Config.InputFormat = StringSwitch<FileFormat>(InputFormat)
+ .Case("binary", FileFormat::Binary)
+ .Case("ihex", FileFormat::IHex)
+ .Default(FileFormat::Unspecified);
+ if (Config.InputFormat == FileFormat::Binary) {
auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
if (BinaryArch.empty())
- error("Specified binary input without specifiying an architecture");
- Config.BinaryArch = getMachineInfo(BinaryArch);
+ return createStringError(
+ errc::invalid_argument,
+ "specified binary input without specifiying an architecture");
+ Expected<const MachineInfo &> MI = getMachineInfo(BinaryArch);
+ if (!MI)
+ return MI.takeError();
+ Config.BinaryArch = *MI;
+ }
+
+ Config.OutputFormat = StringSwitch<FileFormat>(OutputFormat)
+ .Case("binary", FileFormat::Binary)
+ .Case("ihex", FileFormat::IHex)
+ .Default(FileFormat::Unspecified);
+ if (Config.OutputFormat == FileFormat::Unspecified && !OutputFormat.empty()) {
+ Expected<TargetInfo> Target = getOutputTargetInfoByTargetName(OutputFormat);
+ if (!Target)
+ return Target.takeError();
+ Config.OutputFormat = Target->Format;
+ Config.OutputArch = Target->Machine;
}
- if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary")
- Config.OutputArch = getOutputFormatMachineInfo(Config.OutputFormat);
if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
OBJCOPY_compress_debug_sections_eq)) {
@@ -297,14 +512,36 @@ DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
.Case("zlib", DebugCompressionType::Z)
.Default(DebugCompressionType::None);
if (Config.CompressionType == DebugCompressionType::None)
- error("Invalid or unsupported --compress-debug-sections format: " +
- InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq));
- if (!zlib::isAvailable())
- error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress.");
+ return createStringError(
+ errc::invalid_argument,
+ "invalid or unsupported --compress-debug-sections format: %s",
+ InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq)
+ .str()
+ .c_str());
}
+ if (!zlib::isAvailable())
+ return createStringError(
+ errc::invalid_argument,
+ "LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress");
}
Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
+ // The gnu_debuglink's target is expected to not change or else its CRC would
+ // become invalidated and get rejected. We can avoid recalculating the
+ // checksum for every target file inside an archive by precomputing the CRC
+ // here. This prevents a significant amount of I/O.
+ if (!Config.AddGnuDebugLink.empty()) {
+ auto DebugOrErr = MemoryBuffer::getFile(Config.AddGnuDebugLink);
+ if (!DebugOrErr)
+ return createFileError(Config.AddGnuDebugLink, DebugOrErr.getError());
+ auto Debug = std::move(*DebugOrErr);
+ JamCRC CRC;
+ CRC.update(
+ ArrayRef<char>(Debug->getBuffer().data(), Debug->getBuffer().size()));
+ // The CRC32 value needs to be complemented because the JamCRC doesn't
+ // finalize the CRC32 value.
+ Config.GnuDebugLinkCRC32 = ~CRC.getCRC();
+ }
Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir);
if (InputArgs.hasArg(OBJCOPY_build_id_link_input))
Config.BuildIdLinkInput =
@@ -314,27 +551,72 @@ DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
InputArgs.getLastArgValue(OBJCOPY_build_id_link_output);
Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
+ Config.AllocSectionsPrefix =
+ InputArgs.getLastArgValue(OBJCOPY_prefix_alloc_sections);
+ if (auto Arg = InputArgs.getLastArg(OBJCOPY_extract_partition))
+ Config.ExtractPartition = Arg->getValue();
for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
if (!StringRef(Arg->getValue()).contains('='))
- error("Bad format for --redefine-sym");
+ return createStringError(errc::invalid_argument,
+ "bad format for --redefine-sym");
auto Old2New = StringRef(Arg->getValue()).split('=');
if (!Config.SymbolsToRename.insert(Old2New).second)
- error("Multiple redefinition of symbol " + Old2New.first);
+ return createStringError(errc::invalid_argument,
+ "multiple redefinition of symbol '%s'",
+ Old2New.first.str().c_str());
}
+ for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbols))
+ if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc,
+ Arg->getValue()))
+ return std::move(E);
+
for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
- SectionRename SR = parseRenameSectionValue(StringRef(Arg->getValue()));
- if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second)
- error("Multiple renames of section " + SR.OriginalName);
+ Expected<SectionRename> SR =
+ parseRenameSectionValue(StringRef(Arg->getValue()));
+ if (!SR)
+ return SR.takeError();
+ if (!Config.SectionsToRename.try_emplace(SR->OriginalName, *SR).second)
+ return createStringError(errc::invalid_argument,
+ "multiple renames of section '%s'",
+ SR->OriginalName.str().c_str());
+ }
+ for (auto Arg : InputArgs.filtered(OBJCOPY_set_section_flags)) {
+ Expected<SectionFlagsUpdate> SFU =
+ parseSetSectionFlagValue(Arg->getValue());
+ if (!SFU)
+ return SFU.takeError();
+ if (!Config.SetSectionFlags.try_emplace(SFU->Name, *SFU).second)
+ return createStringError(
+ errc::invalid_argument,
+ "--set-section-flags set multiple times for section '%s'",
+ SFU->Name.str().c_str());
+ }
+ // Prohibit combinations of --set-section-flags when the section name is used
+ // by --rename-section, either as a source or a destination.
+ for (const auto &E : Config.SectionsToRename) {
+ const SectionRename &SR = E.second;
+ if (Config.SetSectionFlags.count(SR.OriginalName))
+ return createStringError(
+ errc::invalid_argument,
+ "--set-section-flags=%s conflicts with --rename-section=%s=%s",
+ SR.OriginalName.str().c_str(), SR.OriginalName.str().c_str(),
+ SR.NewName.str().c_str());
+ if (Config.SetSectionFlags.count(SR.NewName))
+ return createStringError(
+ errc::invalid_argument,
+ "--set-section-flags=%s conflicts with --rename-section=%s=%s",
+ SR.NewName.str().c_str(), SR.OriginalName.str().c_str(),
+ SR.NewName.str().c_str());
}
for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
- Config.ToRemove.push_back(Arg->getValue());
+ Config.ToRemove.emplace_back(Arg->getValue(), UseRegex);
for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section))
- Config.KeepSection.push_back(Arg->getValue());
+ Config.KeepSection.emplace_back(Arg->getValue(), UseRegex);
for (auto Arg : InputArgs.filtered(OBJCOPY_only_section))
- Config.OnlySection.push_back(Arg->getValue());
+ Config.OnlySection.emplace_back(Arg->getValue(), UseRegex);
for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
Config.AddSection.push_back(Arg->getValue());
for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
@@ -347,27 +629,71 @@ DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
+ Config.ExtractMainPartition =
+ InputArgs.hasArg(OBJCOPY_extract_main_partition);
Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
- Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all);
+ if (InputArgs.hasArg(OBJCOPY_discard_all, OBJCOPY_discard_locals))
+ Config.DiscardMode =
+ InputArgs.hasFlag(OBJCOPY_discard_all, OBJCOPY_discard_locals)
+ ? DiscardType::All
+ : DiscardType::Locals;
Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
Config.DecompressDebugSections =
InputArgs.hasArg(OBJCOPY_decompress_debug_sections);
+ if (Config.DiscardMode == DiscardType::All)
+ Config.StripDebug = true;
for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
- Config.SymbolsToLocalize.push_back(Arg->getValue());
+ Config.SymbolsToLocalize.emplace_back(Arg->getValue(), UseRegex);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols))
+ if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc,
+ Arg->getValue(), UseRegex))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
- Config.SymbolsToKeepGlobal.push_back(Arg->getValue());
+ Config.SymbolsToKeepGlobal.emplace_back(Arg->getValue(), UseRegex);
for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
- addGlobalSymbolsFromFile(Config.SymbolsToKeepGlobal, Arg->getValue());
+ if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc,
+ Arg->getValue(), UseRegex))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
- Config.SymbolsToGlobalize.push_back(Arg->getValue());
+ Config.SymbolsToGlobalize.emplace_back(Arg->getValue(), UseRegex);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols))
+ if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc,
+ Arg->getValue(), UseRegex))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
- Config.SymbolsToWeaken.push_back(Arg->getValue());
+ Config.SymbolsToWeaken.emplace_back(Arg->getValue(), UseRegex);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols))
+ if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc,
+ Arg->getValue(), UseRegex))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
- Config.SymbolsToRemove.push_back(Arg->getValue());
+ Config.SymbolsToRemove.emplace_back(Arg->getValue(), UseRegex);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbols))
+ if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc,
+ Arg->getValue(), UseRegex))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol))
+ Config.UnneededSymbolsToRemove.emplace_back(Arg->getValue(), UseRegex);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols))
+ if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc,
+ Arg->getValue(), UseRegex))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
- Config.SymbolsToKeep.push_back(Arg->getValue());
+ Config.SymbolsToKeep.emplace_back(Arg->getValue(), UseRegex);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbols))
+ if (Error E = addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc,
+ Arg->getValue(), UseRegex))
+ return std::move(E);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol)) {
+ Expected<NewSymbolInfo> NSI = parseNewSymbolInfo(Arg->getValue());
+ if (!NSI)
+ return NSI.takeError();
+ Config.SymbolsToAdd.push_back(*NSI);
+ }
+
+ Config.AllowBrokenLinks = InputArgs.hasArg(OBJCOPY_allow_broken_links);
Config.DeterministicArchives = InputArgs.hasFlag(
OBJCOPY_enable_deterministic_archives,
@@ -375,24 +701,60 @@ DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
+ if (Config.PreserveDates &&
+ (Config.OutputFilename == "-" || Config.InputFilename == "-"))
+ return createStringError(errc::invalid_argument,
+ "--preserve-dates requires a file");
+
+ for (auto Arg : InputArgs)
+ if (Arg->getOption().matches(OBJCOPY_set_start)) {
+ auto EAddr = getAsInteger<uint64_t>(Arg->getValue());
+ if (!EAddr)
+ return createStringError(
+ EAddr.getError(), "bad entry point address: '%s'", Arg->getValue());
+
+ Config.EntryExpr = [EAddr](uint64_t) { return *EAddr; };
+ } else if (Arg->getOption().matches(OBJCOPY_change_start)) {
+ auto EIncr = getAsInteger<int64_t>(Arg->getValue());
+ if (!EIncr)
+ return createStringError(EIncr.getError(),
+ "bad entry point increment: '%s'",
+ Arg->getValue());
+ auto Expr = Config.EntryExpr ? std::move(Config.EntryExpr)
+ : [](uint64_t A) { return A; };
+ Config.EntryExpr = [Expr, EIncr](uint64_t EAddr) {
+ return Expr(EAddr) + *EIncr;
+ };
+ }
+
if (Config.DecompressDebugSections &&
Config.CompressionType != DebugCompressionType::None) {
- error("Cannot specify --compress-debug-sections at the same time as "
- "--decompress-debug-sections at the same time");
+ return createStringError(
+ errc::invalid_argument,
+ "cannot specify both --compress-debug-sections and "
+ "--decompress-debug-sections");
}
if (Config.DecompressDebugSections && !zlib::isAvailable())
- error("LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress.");
+ return createStringError(
+ errc::invalid_argument,
+ "LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress");
+
+ if (Config.ExtractPartition && Config.ExtractMainPartition)
+ return createStringError(errc::invalid_argument,
+ "cannot specify --extract-partition together with "
+ "--extract-main-partition");
- DriverConfig DC;
DC.CopyConfigs.push_back(std::move(Config));
- return DC;
+ return std::move(DC);
}
// ParseStripOptions returns the config and sets the input arguments. If a
// help flag is set then ParseStripOptions will print the help messege and
// exit.
-DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
+Expected<DriverConfig>
+parseStripOptions(ArrayRef<const char *> ArgsArr,
+ std::function<Error(Error)> ErrorCallback) {
StripOptTable T;
unsigned MissingArgumentIndex, MissingArgumentCount;
llvm::opt::InputArgList InputArgs =
@@ -414,44 +776,65 @@ DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
exit(0);
}
- SmallVector<const char *, 2> Positional;
+ SmallVector<StringRef, 2> Positional;
for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
- error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
+ return createStringError(errc::invalid_argument, "unknown argument '%s'",
+ Arg->getAsString(InputArgs).c_str());
for (auto Arg : InputArgs.filtered(STRIP_INPUT))
Positional.push_back(Arg->getValue());
if (Positional.empty())
- error("No input file specified");
+ return createStringError(errc::invalid_argument, "no input file specified");
if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
- error("Multiple input files cannot be used in combination with -o");
+ return createStringError(
+ errc::invalid_argument,
+ "multiple input files cannot be used in combination with -o");
CopyConfig Config;
+ bool UseRegexp = InputArgs.hasArg(STRIP_regex);
+ Config.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links);
Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
- Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all);
+ if (InputArgs.hasArg(STRIP_discard_all, STRIP_discard_locals))
+ Config.DiscardMode =
+ InputArgs.hasFlag(STRIP_discard_all, STRIP_discard_locals)
+ ? DiscardType::All
+ : DiscardType::Locals;
Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
- Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
+ if (auto Arg = InputArgs.getLastArg(STRIP_strip_all, STRIP_no_strip_all))
+ Config.StripAll = Arg->getOption().getID() == STRIP_strip_all;
Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);
-
- if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll &&
- !Config.StripAllGNU)
- Config.StripAll = true;
+ Config.OnlyKeepDebug = InputArgs.hasArg(STRIP_only_keep_debug);
+ Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);
for (auto Arg : InputArgs.filtered(STRIP_keep_section))
- Config.KeepSection.push_back(Arg->getValue());
+ Config.KeepSection.emplace_back(Arg->getValue(), UseRegexp);
for (auto Arg : InputArgs.filtered(STRIP_remove_section))
- Config.ToRemove.push_back(Arg->getValue());
+ Config.ToRemove.emplace_back(Arg->getValue(), UseRegexp);
+
+ for (auto Arg : InputArgs.filtered(STRIP_strip_symbol))
+ Config.SymbolsToRemove.emplace_back(Arg->getValue(), UseRegexp);
for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
- Config.SymbolsToKeep.push_back(Arg->getValue());
+ Config.SymbolsToKeep.emplace_back(Arg->getValue(), UseRegexp);
+
+ if (!InputArgs.hasArg(STRIP_no_strip_all) && !Config.StripDebug &&
+ !Config.StripUnneeded && Config.DiscardMode == DiscardType::None &&
+ !Config.StripAllGNU && Config.SymbolsToRemove.empty())
+ Config.StripAll = true;
+
+ if (Config.DiscardMode == DiscardType::All)
+ Config.StripDebug = true;
Config.DeterministicArchives =
InputArgs.hasFlag(STRIP_enable_deterministic_archives,
STRIP_disable_deterministic_archives, /*default=*/true);
Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
+ Config.InputFormat = FileFormat::Unspecified;
+ Config.OutputFormat = FileFormat::Unspecified;
DriverConfig DC;
if (Positional.size() == 1) {
@@ -460,14 +843,30 @@ DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
InputArgs.getLastArgValue(STRIP_output, Positional[0]);
DC.CopyConfigs.push_back(std::move(Config));
} else {
- for (const char *Filename : Positional) {
+ StringMap<unsigned> InputFiles;
+ for (StringRef Filename : Positional) {
+ if (InputFiles[Filename]++ == 1) {
+ if (Filename == "-")
+ return createStringError(
+ errc::invalid_argument,
+ "cannot specify '-' as an input file more than once");
+ if (Error E = ErrorCallback(createStringError(
+ errc::invalid_argument, "'%s' was already specified",
+ Filename.str().c_str())))
+ return std::move(E);
+ }
Config.InputFilename = Filename;
Config.OutputFilename = Filename;
DC.CopyConfigs.push_back(Config);
}
}
- return DC;
+ if (Config.PreserveDates && (is_contained(Positional, "-") ||
+ InputArgs.getLastArgValue(STRIP_output) == "-"))
+ return createStringError(errc::invalid_argument,
+ "--preserve-dates requires a file");
+
+ return std::move(DC);
}
} // namespace objcopy
diff --git a/contrib/llvm/tools/llvm-objcopy/CopyConfig.h b/contrib/llvm/tools/llvm-objcopy/CopyConfig.h
index 71a2423ae1c8..aff3631a487c 100644
--- a/contrib/llvm/tools/llvm-objcopy/CopyConfig.h
+++ b/contrib/llvm/tools/llvm-objcopy/CopyConfig.h
@@ -1,9 +1,8 @@
//===- CopyConfig.h -------------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -11,40 +10,110 @@
#define LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Regex.h"
// Necessary for llvm::DebugCompressionType::None
#include "llvm/Target/TargetOptions.h"
-#include <string>
#include <vector>
namespace llvm {
namespace objcopy {
+enum class FileFormat {
+ Unspecified,
+ ELF,
+ Binary,
+ IHex,
+};
+
// This type keeps track of the machine info for various architectures. This
// lets us map architecture names to ELF types and the e_machine value of the
// ELF file.
struct MachineInfo {
+ MachineInfo(uint16_t EM, uint8_t ABI, bool Is64, bool IsLittle)
+ : EMachine(EM), OSABI(ABI), Is64Bit(Is64), IsLittleEndian(IsLittle) {}
+ // Alternative constructor that defaults to NONE for OSABI.
+ MachineInfo(uint16_t EM, bool Is64, bool IsLittle)
+ : MachineInfo(EM, ELF::ELFOSABI_NONE, Is64, IsLittle) {}
+ // Default constructor for unset fields.
+ MachineInfo() : MachineInfo(0, 0, false, false) {}
uint16_t EMachine;
+ uint8_t OSABI;
bool Is64Bit;
bool IsLittleEndian;
};
+// Flags set by --set-section-flags or --rename-section. Interpretation of these
+// is format-specific and not all flags are meaningful for all object file
+// formats. This is a bitmask; many section flags may be set.
+enum SectionFlag {
+ SecNone = 0,
+ SecAlloc = 1 << 0,
+ SecLoad = 1 << 1,
+ SecNoload = 1 << 2,
+ SecReadonly = 1 << 3,
+ SecDebug = 1 << 4,
+ SecCode = 1 << 5,
+ SecData = 1 << 6,
+ SecRom = 1 << 7,
+ SecMerge = 1 << 8,
+ SecStrings = 1 << 9,
+ SecContents = 1 << 10,
+ SecShare = 1 << 11,
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare)
+};
+
struct SectionRename {
StringRef OriginalName;
StringRef NewName;
- Optional<uint64_t> NewFlags;
+ Optional<SectionFlag> NewFlags;
+};
+
+struct SectionFlagsUpdate {
+ StringRef Name;
+ SectionFlag NewFlags;
+};
+
+enum class DiscardType {
+ None, // Default
+ All, // --discard-all (-x)
+ Locals, // --discard-locals (-X)
+};
+
+class NameOrRegex {
+ StringRef Name;
+ // Regex is shared between multiple CopyConfig instances.
+ std::shared_ptr<Regex> R;
+
+public:
+ NameOrRegex(StringRef Pattern, bool IsRegex);
+ bool operator==(StringRef S) const { return R ? R->match(S) : Name == S; }
+ bool operator!=(StringRef S) const { return !operator==(S); }
+};
+
+struct NewSymbolInfo {
+ StringRef SymbolName;
+ StringRef SectionName;
+ uint64_t Value = 0;
+ uint8_t Type = ELF::STT_NOTYPE;
+ uint8_t Bind = ELF::STB_GLOBAL;
+ uint8_t Visibility = ELF::STV_DEFAULT;
};
// Configuration for copying/stripping a single file.
struct CopyConfig {
// Main input/output options
StringRef InputFilename;
- StringRef InputFormat;
+ FileFormat InputFormat;
StringRef OutputFilename;
- StringRef OutputFormat;
+ FileFormat OutputFormat;
// Only applicable for --input-format=binary
MachineInfo BinaryArch;
@@ -53,33 +122,48 @@ struct CopyConfig {
// Advanced options
StringRef AddGnuDebugLink;
+ // Cached gnu_debuglink's target CRC
+ uint32_t GnuDebugLinkCRC32;
StringRef BuildIdLinkDir;
Optional<StringRef> BuildIdLinkInput;
Optional<StringRef> BuildIdLinkOutput;
+ Optional<StringRef> ExtractPartition;
StringRef SplitDWO;
StringRef SymbolsPrefix;
+ StringRef AllocSectionsPrefix;
+ DiscardType DiscardMode = DiscardType::None;
// Repeated options
std::vector<StringRef> AddSection;
std::vector<StringRef> DumpSection;
- std::vector<StringRef> KeepSection;
- std::vector<StringRef> OnlySection;
- std::vector<StringRef> SymbolsToGlobalize;
- std::vector<StringRef> SymbolsToKeep;
- std::vector<StringRef> SymbolsToLocalize;
- std::vector<StringRef> SymbolsToRemove;
- std::vector<StringRef> SymbolsToWeaken;
- std::vector<StringRef> ToRemove;
- std::vector<std::string> SymbolsToKeepGlobal;
+ std::vector<NewSymbolInfo> SymbolsToAdd;
+ std::vector<NameOrRegex> KeepSection;
+ std::vector<NameOrRegex> OnlySection;
+ std::vector<NameOrRegex> SymbolsToGlobalize;
+ std::vector<NameOrRegex> SymbolsToKeep;
+ std::vector<NameOrRegex> SymbolsToLocalize;
+ std::vector<NameOrRegex> SymbolsToRemove;
+ std::vector<NameOrRegex> UnneededSymbolsToRemove;
+ std::vector<NameOrRegex> SymbolsToWeaken;
+ std::vector<NameOrRegex> ToRemove;
+ std::vector<NameOrRegex> SymbolsToKeepGlobal;
// Map options
StringMap<SectionRename> SectionsToRename;
+ StringMap<SectionFlagsUpdate> SetSectionFlags;
StringMap<StringRef> SymbolsToRename;
+ // ELF entry point address expression. The input parameter is an entry point
+ // address in the input ELF file. The entry address in the output file is
+ // calculated with EntryExpr(input_address), when either --set-start or
+ // --change-start is used.
+ std::function<uint64_t(uint64_t)> EntryExpr;
+
// Boolean options
+ bool AllowBrokenLinks = false;
bool DeterministicArchives = true;
- bool DiscardAll = false;
bool ExtractDWO = false;
+ bool ExtractMainPartition = false;
bool KeepFileSymbols = false;
bool LocalizeHidden = false;
bool OnlyKeepDebug = false;
@@ -101,17 +185,21 @@ struct CopyConfig {
// will contain one or more CopyConfigs.
struct DriverConfig {
SmallVector<CopyConfig, 1> CopyConfigs;
+ BumpPtrAllocator Alloc;
};
// ParseObjcopyOptions returns the config and sets the input arguments. If a
// help flag is set then ParseObjcopyOptions will print the help messege and
// exit.
-DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr);
+Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr);
// ParseStripOptions returns the config and sets the input arguments. If a
// help flag is set then ParseStripOptions will print the help messege and
-// exit.
-DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr);
+// exit. ErrorCallback is used to handle recoverable errors. An Error returned
+// by the callback aborts the parsing and is then returned by this function.
+Expected<DriverConfig>
+parseStripOptions(ArrayRef<const char *> ArgsArr,
+ std::function<Error(Error)> ErrorCallback);
} // namespace objcopy
} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
index f5ab8e708267..b366c6e55987 100644
--- a/contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
+++ b/contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
@@ -1,9 +1,8 @@
//===- ELFObjcopy.cpp -----------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -14,6 +13,7 @@
#include "llvm-objcopy.h"
#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
@@ -71,6 +71,44 @@ static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
return !isDWOSection(Sec);
}
+uint64_t getNewShfFlags(SectionFlag AllFlags) {
+ uint64_t NewFlags = 0;
+ if (AllFlags & SectionFlag::SecAlloc)
+ NewFlags |= ELF::SHF_ALLOC;
+ if (!(AllFlags & SectionFlag::SecReadonly))
+ NewFlags |= ELF::SHF_WRITE;
+ if (AllFlags & SectionFlag::SecCode)
+ NewFlags |= ELF::SHF_EXECINSTR;
+ if (AllFlags & SectionFlag::SecMerge)
+ NewFlags |= ELF::SHF_MERGE;
+ if (AllFlags & SectionFlag::SecStrings)
+ NewFlags |= ELF::SHF_STRINGS;
+ return NewFlags;
+}
+
+static uint64_t getSectionFlagsPreserveMask(uint64_t OldFlags,
+ uint64_t NewFlags) {
+ // Preserve some flags which should not be dropped when setting flags.
+ // Also, preserve anything OS/processor dependant.
+ const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE |
+ ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
+ ELF::SHF_MASKOS | ELF::SHF_MASKPROC |
+ ELF::SHF_TLS | ELF::SHF_INFO_LINK;
+ return (OldFlags & PreserveMask) | (NewFlags & ~PreserveMask);
+}
+
+static void setSectionFlagsAndType(SectionBase &Sec, SectionFlag Flags) {
+ Sec.Flags = getSectionFlagsPreserveMask(Sec.Flags, getNewShfFlags(Flags));
+
+ // In GNU objcopy, certain flags promote SHT_NOBITS to SHT_PROGBITS. This rule
+ // may promote more non-ALLOC sections than GNU objcopy, but it is fine as
+ // non-ALLOC SHT_NOBITS sections do not make much sense.
+ if (Sec.Type == SHT_NOBITS &&
+ (!(Sec.Flags & ELF::SHF_ALLOC) ||
+ Flags & (SectionFlag::SecContents | SectionFlag::SecLoad)))
+ Sec.Type = SHT_PROGBITS;
+}
+
static ElfType getOutputElfType(const Binary &Bin) {
// Infer output ELF type from the input ELF object
if (isa<ELFObjectFile<ELF32LE>>(Bin))
@@ -92,12 +130,9 @@ static ElfType getOutputElfType(const MachineInfo &MI) {
return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;
}
-static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
- Object &Obj, Buffer &Buf,
- ElfType OutputElfType) {
- if (Config.OutputFormat == "binary") {
- return llvm::make_unique<BinaryWriter>(Obj, Buf);
- }
+static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config,
+ Object &Obj, Buffer &Buf,
+ ElfType OutputElfType) {
// Depending on the initial ELFT and OutputFormat we need a different Writer.
switch (OutputElfType) {
case ELFT_ELF32LE:
@@ -116,10 +151,27 @@ static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
llvm_unreachable("Invalid output format");
}
+static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
+ Object &Obj, Buffer &Buf,
+ ElfType OutputElfType) {
+ switch (Config.OutputFormat) {
+ case FileFormat::Binary:
+ return llvm::make_unique<BinaryWriter>(Obj, Buf);
+ case FileFormat::IHex:
+ return llvm::make_unique<IHexWriter>(Obj, Buf);
+ default:
+ return createELFWriter(Config, Obj, Buf, OutputElfType);
+ }
+}
+
template <class ELFT>
static Expected<ArrayRef<uint8_t>>
-findBuildID(const object::ELFFile<ELFT> &In) {
- for (const auto &Phdr : unwrapOrError(In.program_headers())) {
+findBuildID(const CopyConfig &Config, const object::ELFFile<ELFT> &In) {
+ auto PhdrsOrErr = In.program_headers();
+ if (auto Err = PhdrsOrErr.takeError())
+ return createFileError(Config.InputFilename, std::move(Err));
+
+ for (const auto &Phdr : *PhdrsOrErr) {
if (Phdr.p_type != PT_NOTE)
continue;
Error Err = Error::success();
@@ -127,58 +179,106 @@ findBuildID(const object::ELFFile<ELFT> &In) {
if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU)
return Note.getDesc();
if (Err)
- return std::move(Err);
+ return createFileError(Config.InputFilename, std::move(Err));
}
- return createStringError(llvm::errc::invalid_argument,
- "Could not find build ID.");
+
+ return createFileError(
+ Config.InputFilename,
+ createStringError(llvm::errc::invalid_argument,
+ "could not find build ID"));
}
static Expected<ArrayRef<uint8_t>>
-findBuildID(const object::ELFObjectFileBase &In) {
+findBuildID(const CopyConfig &Config, const object::ELFObjectFileBase &In) {
if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(&In))
- return findBuildID(*O->getELFFile());
+ return findBuildID(Config, *O->getELFFile());
else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(&In))
- return findBuildID(*O->getELFFile());
+ return findBuildID(Config, *O->getELFFile());
else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(&In))
- return findBuildID(*O->getELFFile());
+ return findBuildID(Config, *O->getELFFile());
else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(&In))
- return findBuildID(*O->getELFFile());
+ return findBuildID(Config, *O->getELFFile());
llvm_unreachable("Bad file format");
}
-static void linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink,
- StringRef Suffix, ArrayRef<uint8_t> BuildIdBytes) {
+template <class... Ts>
+static Error makeStringError(std::error_code EC, const Twine &Msg, Ts &&... Args) {
+ std::string FullMsg = (EC.message() + ": " + Msg).str();
+ return createStringError(EC, FullMsg.c_str(), std::forward<Ts>(Args)...);
+}
+
+#define MODEL_8 "%%%%%%%%"
+#define MODEL_16 MODEL_8 MODEL_8
+#define MODEL_32 (MODEL_16 MODEL_16)
+
+static Error linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink,
+ StringRef Suffix,
+ ArrayRef<uint8_t> BuildIdBytes) {
SmallString<128> Path = Config.BuildIdLinkDir;
sys::path::append(Path, llvm::toHex(BuildIdBytes[0], /*LowerCase*/ true));
if (auto EC = sys::fs::create_directories(Path))
- error("cannot create build ID link directory " + Path + ": " +
- EC.message());
+ return createFileError(
+ Path.str(),
+ makeStringError(EC, "cannot create build ID link directory"));
sys::path::append(Path,
llvm::toHex(BuildIdBytes.slice(1), /*LowerCase*/ true));
Path += Suffix;
- if (auto EC = sys::fs::create_hard_link(ToLink, Path)) {
- // Hard linking failed, try to remove the file first if it exists.
- if (sys::fs::exists(Path))
- sys::fs::remove(Path);
- EC = sys::fs::create_hard_link(ToLink, Path);
- if (EC)
- error("cannot link " + ToLink + " to " + Path + ": " + EC.message());
+ SmallString<128> TmpPath;
+ // create_hard_link races so we need to link to a temporary path but
+ // we want to make sure that we choose a filename that does not exist.
+ // By using 32 model characters we get 128-bits of entropy. It is
+ // unlikely that this string has ever existed before much less exists
+ // on this disk or in the current working directory.
+ // Additionally we prepend the original Path for debugging but also
+ // because it ensures that we're linking within a directory on the same
+ // partition on the same device which is critical. It has the added
+ // win of yet further decreasing the odds of a conflict.
+ sys::fs::createUniquePath(Twine(Path) + "-" + MODEL_32 + ".tmp", TmpPath,
+ /*MakeAbsolute*/ false);
+ if (auto EC = sys::fs::create_hard_link(ToLink, TmpPath)) {
+ Path.push_back('\0');
+ return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(),
+ Path.data());
+ }
+ // We then atomically rename the link into place which will just move the
+ // link. If rename fails something is more seriously wrong so just return
+ // an error.
+ if (auto EC = sys::fs::rename(TmpPath, Path)) {
+ Path.push_back('\0');
+ return makeStringError(EC, "cannot link '%s' to '%s'", ToLink.data(),
+ Path.data());
+ }
+ // If `Path` was already a hard-link to the same underlying file then the
+ // temp file will be left so we need to remove it. Remove will not cause
+ // an error by default if the file is already gone so just blindly remove
+ // it rather than checking.
+ if (auto EC = sys::fs::remove(TmpPath)) {
+ TmpPath.push_back('\0');
+ return makeStringError(EC, "could not remove '%s'", TmpPath.data());
}
+ return Error::success();
}
-static void splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
- StringRef File, ElfType OutputElfType) {
+static Error splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
+ StringRef File, ElfType OutputElfType) {
auto DWOFile = Reader.create();
- DWOFile->removeSections(
- [&](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); });
- if (Config.OutputArch)
+ auto OnlyKeepDWOPred = [&DWOFile](const SectionBase &Sec) {
+ return onlyKeepDWOPred(*DWOFile, Sec);
+ };
+ if (Error E = DWOFile->removeSections(Config.AllowBrokenLinks,
+ OnlyKeepDWOPred))
+ return E;
+ if (Config.OutputArch) {
DWOFile->Machine = Config.OutputArch.getValue().EMachine;
+ DWOFile->OSABI = Config.OutputArch.getValue().OSABI;
+ }
FileBuffer FB(File);
auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType);
- Writer->finalize();
- Writer->write();
+ if (Error E = Writer->finalize())
+ return E;
+ return Writer->write();
}
static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
@@ -186,9 +286,9 @@ static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
for (auto &Sec : Obj.sections()) {
if (Sec.Name == SecName) {
if (Sec.OriginalData.empty())
- return make_error<StringError>("Can't dump section \"" + SecName +
- "\": it has no contents",
- object_error::parse_failed);
+ return createStringError(object_error::parse_failed,
+ "cannot dump section '%s': it has no contents",
+ SecName.str().c_str());
Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
FileOutputBuffer::create(Filename, Sec.OriginalData.size());
if (!BufferOrErr)
@@ -201,149 +301,143 @@ static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
return Error::success();
}
}
- return make_error<StringError>("Section not found",
- object_error::parse_failed);
-}
-
-static bool isCompressed(const SectionBase &Section) {
- const char *Magic = "ZLIB";
- return StringRef(Section.Name).startswith(".zdebug") ||
- (Section.OriginalData.size() > strlen(Magic) &&
- !strncmp(reinterpret_cast<const char *>(Section.OriginalData.data()),
- Magic, strlen(Magic))) ||
- (Section.Flags & ELF::SHF_COMPRESSED);
+ return createStringError(object_error::parse_failed, "section '%s' not found",
+ SecName.str().c_str());
}
static bool isCompressable(const SectionBase &Section) {
- return !isCompressed(Section) && isDebugSection(Section) &&
- Section.Name != ".gdb_index";
+ return !(Section.Flags & ELF::SHF_COMPRESSED) &&
+ StringRef(Section.Name).startswith(".debug");
}
static void replaceDebugSections(
- const CopyConfig &Config, Object &Obj, SectionPred &RemovePred,
+ Object &Obj, SectionPred &RemovePred,
function_ref<bool(const SectionBase &)> shouldReplace,
function_ref<SectionBase *(const SectionBase *)> addSection) {
+ // Build a list of the debug sections we are going to replace.
+ // We can't call `addSection` while iterating over sections,
+ // because it would mutate the sections array.
SmallVector<SectionBase *, 13> ToReplace;
- SmallVector<RelocationSection *, 13> RelocationSections;
- for (auto &Sec : Obj.sections()) {
- if (RelocationSection *R = dyn_cast<RelocationSection>(&Sec)) {
- if (shouldReplace(*R->getSection()))
- RelocationSections.push_back(R);
- continue;
- }
-
+ for (auto &Sec : Obj.sections())
if (shouldReplace(Sec))
ToReplace.push_back(&Sec);
- }
- for (SectionBase *S : ToReplace) {
- SectionBase *NewSection = addSection(S);
+ // Build a mapping from original section to a new one.
+ DenseMap<SectionBase *, SectionBase *> FromTo;
+ for (SectionBase *S : ToReplace)
+ FromTo[S] = addSection(S);
- for (RelocationSection *RS : RelocationSections) {
- if (RS->getSection() == S)
- RS->setSection(NewSection);
- }
- }
+ // Now we want to update the target sections of relocation
+ // sections. Also we will update the relocations themselves
+ // to update the symbol references.
+ for (auto &Sec : Obj.sections())
+ Sec.replaceSectionReferences(FromTo);
RemovePred = [shouldReplace, RemovePred](const SectionBase &Sec) {
return shouldReplace(Sec) || RemovePred(Sec);
};
}
-// This function handles the high level operations of GNU objcopy including
-// handling command line options. It's important to outline certain properties
-// we expect to hold of the command line operations. Any operation that "keeps"
-// should keep regardless of a remove. Additionally any removal should respect
-// any previous removals. Lastly whether or not something is removed shouldn't
-// depend a) on the order the options occur in or b) on some opaque priority
-// system. The only priority is that keeps/copies overrule removes.
-static void handleArgs(const CopyConfig &Config, Object &Obj,
- const Reader &Reader, ElfType OutputElfType) {
-
- if (!Config.SplitDWO.empty()) {
- splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType);
- }
- if (Config.OutputArch)
- Obj.Machine = Config.OutputArch.getValue().EMachine;
+static bool isUnneededSymbol(const Symbol &Sym) {
+ return !Sym.Referenced &&
+ (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
+ Sym.Type != STT_SECTION;
+}
+static Error updateAndRemoveSymbols(const CopyConfig &Config, Object &Obj) {
// TODO: update or remove symbols only if there is an option that affects
// them.
- if (Obj.SymbolTable) {
- Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
- if (!Sym.isCommon() &&
- ((Config.LocalizeHidden &&
- (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
- is_contained(Config.SymbolsToLocalize, Sym.Name)))
- Sym.Binding = STB_LOCAL;
-
- // Note: these two globalize flags have very similar names but different
- // meanings:
- //
- // --globalize-symbol: promote a symbol to global
- // --keep-global-symbol: all symbols except for these should be made local
- //
- // If --globalize-symbol is specified for a given symbol, it will be
- // global in the output file even if it is not included via
- // --keep-global-symbol. Because of that, make sure to check
- // --globalize-symbol second.
- if (!Config.SymbolsToKeepGlobal.empty() &&
- !is_contained(Config.SymbolsToKeepGlobal, Sym.Name) &&
- Sym.getShndx() != SHN_UNDEF)
- Sym.Binding = STB_LOCAL;
-
- if (is_contained(Config.SymbolsToGlobalize, Sym.Name) &&
- Sym.getShndx() != SHN_UNDEF)
- Sym.Binding = STB_GLOBAL;
-
- if (is_contained(Config.SymbolsToWeaken, Sym.Name) &&
- Sym.Binding == STB_GLOBAL)
- Sym.Binding = STB_WEAK;
-
- if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
- Sym.getShndx() != SHN_UNDEF)
- Sym.Binding = STB_WEAK;
-
- const auto I = Config.SymbolsToRename.find(Sym.Name);
- if (I != Config.SymbolsToRename.end())
- Sym.Name = I->getValue();
-
- if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
- Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
- });
-
- // The purpose of this loop is to mark symbols referenced by sections
- // (like GroupSection or RelocationSection). This way, we know which
- // symbols are still 'needed' and which are not.
- if (Config.StripUnneeded) {
- for (auto &Section : Obj.sections())
- Section.markSymbols();
- }
+ if (!Obj.SymbolTable)
+ return Error::success();
+
+ Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
+ // Common and undefined symbols don't make sense as local symbols, and can
+ // even cause crashes if we localize those, so skip them.
+ if (!Sym.isCommon() && Sym.getShndx() != SHN_UNDEF &&
+ ((Config.LocalizeHidden &&
+ (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
+ is_contained(Config.SymbolsToLocalize, Sym.Name)))
+ Sym.Binding = STB_LOCAL;
+
+ // Note: these two globalize flags have very similar names but different
+ // meanings:
+ //
+ // --globalize-symbol: promote a symbol to global
+ // --keep-global-symbol: all symbols except for these should be made local
+ //
+ // If --globalize-symbol is specified for a given symbol, it will be
+ // global in the output file even if it is not included via
+ // --keep-global-symbol. Because of that, make sure to check
+ // --globalize-symbol second.
+ if (!Config.SymbolsToKeepGlobal.empty() &&
+ !is_contained(Config.SymbolsToKeepGlobal, Sym.Name) &&
+ Sym.getShndx() != SHN_UNDEF)
+ Sym.Binding = STB_LOCAL;
+
+ if (is_contained(Config.SymbolsToGlobalize, Sym.Name) &&
+ Sym.getShndx() != SHN_UNDEF)
+ Sym.Binding = STB_GLOBAL;
+
+ if (is_contained(Config.SymbolsToWeaken, Sym.Name) &&
+ Sym.Binding == STB_GLOBAL)
+ Sym.Binding = STB_WEAK;
+
+ if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
+ Sym.getShndx() != SHN_UNDEF)
+ Sym.Binding = STB_WEAK;
+
+ const auto I = Config.SymbolsToRename.find(Sym.Name);
+ if (I != Config.SymbolsToRename.end())
+ Sym.Name = I->getValue();
+
+ if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
+ Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
+ });
+
+ // The purpose of this loop is to mark symbols referenced by sections
+ // (like GroupSection or RelocationSection). This way, we know which
+ // symbols are still 'needed' and which are not.
+ if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() ||
+ !Config.OnlySection.empty()) {
+ for (auto &Section : Obj.sections())
+ Section.markSymbols();
+ }
- Obj.removeSymbols([&](const Symbol &Sym) {
- if (is_contained(Config.SymbolsToKeep, Sym.Name) ||
- (Config.KeepFileSymbols && Sym.Type == STT_FILE))
- return false;
+ auto RemoveSymbolsPred = [&](const Symbol &Sym) {
+ if (is_contained(Config.SymbolsToKeep, Sym.Name) ||
+ (Config.KeepFileSymbols && Sym.Type == STT_FILE))
+ return false;
- if (Config.DiscardAll && Sym.Binding == STB_LOCAL &&
- Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE &&
- Sym.Type != STT_SECTION)
- return true;
+ if ((Config.DiscardMode == DiscardType::All ||
+ (Config.DiscardMode == DiscardType::Locals &&
+ StringRef(Sym.Name).startswith(".L"))) &&
+ Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF &&
+ Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
+ return true;
- if (Config.StripAll || Config.StripAllGNU)
- return true;
+ if (Config.StripAll || Config.StripAllGNU)
+ return true;
- if (is_contained(Config.SymbolsToRemove, Sym.Name))
- return true;
+ if (is_contained(Config.SymbolsToRemove, Sym.Name))
+ return true;
- if (Config.StripUnneeded && !Sym.Referenced &&
- (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
- Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
- return true;
+ if ((Config.StripUnneeded ||
+ is_contained(Config.UnneededSymbolsToRemove, Sym.Name)) &&
+ isUnneededSymbol(Sym))
+ return true;
- return false;
- });
- }
+ // We want to remove undefined symbols if all references have been stripped.
+ if (!Config.OnlySection.empty() && !Sym.Referenced &&
+ Sym.getShndx() == SHN_UNDEF)
+ return true;
+
+ return false;
+ };
+ return Obj.removeSymbols(RemoveSymbolsPred);
+}
+
+static Error replaceAndRemoveSections(const CopyConfig &Config, Object &Obj) {
SectionPred RemovePred = [](const SectionBase &) { return false; };
// Removes:
@@ -383,7 +477,7 @@ static void handleArgs(const CopyConfig &Config, Object &Obj,
if (Config.StripSections) {
RemovePred = [RemovePred](const SectionBase &Sec) {
- return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
+ return RemovePred(Sec) || Sec.ParentSegment == nullptr;
};
}
@@ -399,7 +493,7 @@ static void handleArgs(const CopyConfig &Config, Object &Obj,
return true;
if (&Sec == Obj.SectionNames)
return false;
- return (Sec.Flags & SHF_ALLOC) == 0;
+ return (Sec.Flags & SHF_ALLOC) == 0 && Sec.ParentSegment == nullptr;
};
if (Config.StripAll)
@@ -410,9 +504,21 @@ static void handleArgs(const CopyConfig &Config, Object &Obj,
return false;
if (StringRef(Sec.Name).startswith(".gnu.warning"))
return false;
+ if (Sec.ParentSegment != nullptr)
+ return false;
return (Sec.Flags & SHF_ALLOC) == 0;
};
+ if (Config.ExtractPartition || Config.ExtractMainPartition) {
+ RemovePred = [RemovePred](const SectionBase &Sec) {
+ if (RemovePred(Sec))
+ return true;
+ if (Sec.Type == SHT_LLVM_PART_EHDR || Sec.Type == SHT_LLVM_PART_PHDR)
+ return true;
+ return (Sec.Flags & SHF_ALLOC) != 0 && !Sec.ParentSegment;
+ };
+ }
+
// Explicit copies:
if (!Config.OnlySection.empty()) {
RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
@@ -461,95 +567,210 @@ static void handleArgs(const CopyConfig &Config, Object &Obj,
}
if (Config.CompressionType != DebugCompressionType::None)
- replaceDebugSections(Config, Obj, RemovePred, isCompressable,
+ replaceDebugSections(Obj, RemovePred, isCompressable,
[&Config, &Obj](const SectionBase *S) {
return &Obj.addSection<CompressedSection>(
- *S, Config.CompressionType);
- });
+ *S, Config.CompressionType);
+ });
else if (Config.DecompressDebugSections)
replaceDebugSections(
- Config, Obj, RemovePred,
+ Obj, RemovePred,
[](const SectionBase &S) { return isa<CompressedSection>(&S); },
[&Obj](const SectionBase *S) {
auto CS = cast<CompressedSection>(S);
return &Obj.addSection<DecompressedSection>(*CS);
});
- Obj.removeSections(RemovePred);
+ return Obj.removeSections(Config.AllowBrokenLinks, RemovePred);
+}
- if (!Config.SectionsToRename.empty()) {
+// This function handles the high level operations of GNU objcopy including
+// handling command line options. It's important to outline certain properties
+// we expect to hold of the command line operations. Any operation that "keeps"
+// should keep regardless of a remove. Additionally any removal should respect
+// any previous removals. Lastly whether or not something is removed shouldn't
+// depend a) on the order the options occur in or b) on some opaque priority
+// system. The only priority is that keeps/copies overrule removes.
+static Error handleArgs(const CopyConfig &Config, Object &Obj,
+ const Reader &Reader, ElfType OutputElfType) {
+
+ if (!Config.SplitDWO.empty())
+ if (Error E =
+ splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType))
+ return E;
+
+ if (Config.OutputArch) {
+ Obj.Machine = Config.OutputArch.getValue().EMachine;
+ Obj.OSABI = Config.OutputArch.getValue().OSABI;
+ }
+
+ // It is important to remove the sections first. For example, we want to
+ // remove the relocation sections before removing the symbols. That allows
+ // us to avoid reporting the inappropriate errors about removing symbols
+ // named in relocations.
+ if (Error E = replaceAndRemoveSections(Config, Obj))
+ return E;
+
+ if (Error E = updateAndRemoveSymbols(Config, Obj))
+ return E;
+
+ if (!Config.SectionsToRename.empty() || !Config.AllocSectionsPrefix.empty()) {
+ DenseSet<SectionBase *> PrefixedSections;
for (auto &Sec : Obj.sections()) {
const auto Iter = Config.SectionsToRename.find(Sec.Name);
if (Iter != Config.SectionsToRename.end()) {
const SectionRename &SR = Iter->second;
Sec.Name = SR.NewName;
- if (SR.NewFlags.hasValue()) {
- // Preserve some flags which should not be dropped when setting flags.
- // Also, preserve anything OS/processor dependant.
- const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE |
- ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
- ELF::SHF_MASKOS | ELF::SHF_MASKPROC |
- ELF::SHF_TLS | ELF::SHF_INFO_LINK;
- Sec.Flags = (Sec.Flags & PreserveMask) |
- (SR.NewFlags.getValue() & ~PreserveMask);
+ if (SR.NewFlags.hasValue())
+ setSectionFlagsAndType(Sec, SR.NewFlags.getValue());
+ }
+
+ // Add a prefix to allocated sections and their relocation sections. This
+ // should be done after renaming the section by Config.SectionToRename to
+ // imitate the GNU objcopy behavior.
+ if (!Config.AllocSectionsPrefix.empty()) {
+ if (Sec.Flags & SHF_ALLOC) {
+ Sec.Name = (Config.AllocSectionsPrefix + Sec.Name).str();
+ PrefixedSections.insert(&Sec);
+
+ // Rename relocation sections associated to the allocated sections.
+ // For example, if we rename .text to .prefix.text, we also rename
+ // .rel.text to .rel.prefix.text.
+ //
+ // Dynamic relocation sections (SHT_REL[A] with SHF_ALLOC) are handled
+ // above, e.g., .rela.plt is renamed to .prefix.rela.plt, not
+ // .rela.prefix.plt since GNU objcopy does so.
+ } else if (auto *RelocSec = dyn_cast<RelocationSectionBase>(&Sec)) {
+ auto *TargetSec = RelocSec->getSection();
+ if (TargetSec && (TargetSec->Flags & SHF_ALLOC)) {
+ StringRef prefix;
+ switch (Sec.Type) {
+ case SHT_REL:
+ prefix = ".rel";
+ break;
+ case SHT_RELA:
+ prefix = ".rela";
+ break;
+ default:
+ continue;
+ }
+
+ // If the relocation section comes *after* the target section, we
+ // don't add Config.AllocSectionsPrefix because we've already added
+ // the prefix to TargetSec->Name. Otherwise, if the relocation
+ // section comes *before* the target section, we add the prefix.
+ if (PrefixedSections.count(TargetSec)) {
+ Sec.Name = (prefix + TargetSec->Name).str();
+ } else {
+ const auto Iter = Config.SectionsToRename.find(TargetSec->Name);
+ if (Iter != Config.SectionsToRename.end()) {
+ // Both `--rename-section` and `--prefix-alloc-sections` are
+ // given but the target section is not yet renamed.
+ Sec.Name =
+ (prefix + Config.AllocSectionsPrefix + Iter->second.NewName)
+ .str();
+ } else {
+ Sec.Name =
+ (prefix + Config.AllocSectionsPrefix + TargetSec->Name)
+ .str();
+ }
+ }
+ }
}
}
}
}
- if (!Config.AddSection.empty()) {
- for (const auto &Flag : Config.AddSection) {
- std::pair<StringRef, StringRef> SecPair = Flag.split("=");
- StringRef SecName = SecPair.first;
- StringRef File = SecPair.second;
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
- MemoryBuffer::getFile(File);
- if (!BufOrErr)
- reportError(File, BufOrErr.getError());
- std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
- ArrayRef<uint8_t> Data(
- reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
- Buf->getBufferSize());
- OwnedDataSection &NewSection =
- Obj.addSection<OwnedDataSection>(SecName, Data);
- if (SecName.startswith(".note") && SecName != ".note.GNU-stack")
- NewSection.Type = SHT_NOTE;
+ if (!Config.SetSectionFlags.empty()) {
+ for (auto &Sec : Obj.sections()) {
+ const auto Iter = Config.SetSectionFlags.find(Sec.Name);
+ if (Iter != Config.SetSectionFlags.end()) {
+ const SectionFlagsUpdate &SFU = Iter->second;
+ setSectionFlagsAndType(Sec, SFU.NewFlags);
+ }
}
}
- if (!Config.DumpSection.empty()) {
- for (const auto &Flag : Config.DumpSection) {
- std::pair<StringRef, StringRef> SecPair = Flag.split("=");
- StringRef SecName = SecPair.first;
- StringRef File = SecPair.second;
- if (Error E = dumpSectionToFile(SecName, File, Obj))
- reportError(Config.InputFilename, std::move(E));
- }
+ for (const auto &Flag : Config.AddSection) {
+ std::pair<StringRef, StringRef> SecPair = Flag.split("=");
+ StringRef SecName = SecPair.first;
+ StringRef File = SecPair.second;
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFile(File);
+ if (!BufOrErr)
+ return createFileError(File, errorCodeToError(BufOrErr.getError()));
+ std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
+ ArrayRef<uint8_t> Data(
+ reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
+ Buf->getBufferSize());
+ OwnedDataSection &NewSection =
+ Obj.addSection<OwnedDataSection>(SecName, Data);
+ if (SecName.startswith(".note") && SecName != ".note.GNU-stack")
+ NewSection.Type = SHT_NOTE;
+ }
+
+ for (const auto &Flag : Config.DumpSection) {
+ std::pair<StringRef, StringRef> SecPair = Flag.split("=");
+ StringRef SecName = SecPair.first;
+ StringRef File = SecPair.second;
+ if (Error E = dumpSectionToFile(SecName, File, Obj))
+ return E;
}
if (!Config.AddGnuDebugLink.empty())
- Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink);
+ Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink,
+ Config.GnuDebugLinkCRC32);
+
+ for (const NewSymbolInfo &SI : Config.SymbolsToAdd) {
+ SectionBase *Sec = Obj.findSection(SI.SectionName);
+ uint64_t Value = Sec ? Sec->Addr + SI.Value : SI.Value;
+ Obj.SymbolTable->addSymbol(
+ SI.SymbolName, SI.Bind, SI.Type, Sec, Value, SI.Visibility,
+ Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0);
+ }
+
+ if (Config.EntryExpr)
+ Obj.Entry = Config.EntryExpr(Obj.Entry);
+ return Error::success();
}
-void executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
- Buffer &Out) {
+static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out,
+ ElfType OutputElfType) {
+ std::unique_ptr<Writer> Writer =
+ createWriter(Config, Obj, Out, OutputElfType);
+ if (Error E = Writer->finalize())
+ return E;
+ return Writer->write();
+}
+
+Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
+ Buffer &Out) {
+ IHexReader Reader(&In);
+ std::unique_ptr<Object> Obj = Reader.create();
+ const ElfType OutputElfType =
+ getOutputElfType(Config.OutputArch.getValueOr(Config.BinaryArch));
+ if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType))
+ return E;
+ return writeOutput(Config, *Obj, Out, OutputElfType);
+}
+
+Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
+ Buffer &Out) {
BinaryReader Reader(Config.BinaryArch, &In);
std::unique_ptr<Object> Obj = Reader.create();
// Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch
// (-B<arch>).
- const ElfType OutputElfType = getOutputElfType(
- Config.OutputArch ? Config.OutputArch.getValue() : Config.BinaryArch);
- handleArgs(Config, *Obj, Reader, OutputElfType);
- std::unique_ptr<Writer> Writer =
- createWriter(Config, *Obj, Out, OutputElfType);
- Writer->finalize();
- Writer->write();
+ const ElfType OutputElfType =
+ getOutputElfType(Config.OutputArch.getValueOr(Config.BinaryArch));
+ if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType))
+ return E;
+ return writeOutput(Config, *Obj, Out, OutputElfType);
}
-void executeObjcopyOnBinary(const CopyConfig &Config,
- object::ELFObjectFileBase &In, Buffer &Out) {
- ELFReader Reader(&In);
+Error executeObjcopyOnBinary(const CopyConfig &Config,
+ object::ELFObjectFileBase &In, Buffer &Out) {
+ ELFReader Reader(&In, Config.ExtractPartition);
std::unique_ptr<Object> Obj = Reader.create();
// Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.
const ElfType OutputElfType =
@@ -558,25 +779,36 @@ void executeObjcopyOnBinary(const CopyConfig &Config,
ArrayRef<uint8_t> BuildIdBytes;
if (!Config.BuildIdLinkDir.empty()) {
- BuildIdBytes = unwrapOrError(findBuildID(In));
+ auto BuildIdBytesOrErr = findBuildID(Config, In);
+ if (auto E = BuildIdBytesOrErr.takeError())
+ return E;
+ BuildIdBytes = *BuildIdBytesOrErr;
+
if (BuildIdBytes.size() < 2)
- error("build ID in file '" + Config.InputFilename +
- "' is smaller than two bytes");
+ return createFileError(
+ Config.InputFilename,
+ createStringError(object_error::parse_failed,
+ "build ID is smaller than two bytes"));
}
- if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput) {
- linkToBuildIdDir(Config, Config.InputFilename,
- Config.BuildIdLinkInput.getValue(), BuildIdBytes);
- }
- handleArgs(Config, *Obj, Reader, OutputElfType);
- std::unique_ptr<Writer> Writer =
- createWriter(Config, *Obj, Out, OutputElfType);
- Writer->finalize();
- Writer->write();
- if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput) {
- linkToBuildIdDir(Config, Config.OutputFilename,
- Config.BuildIdLinkOutput.getValue(), BuildIdBytes);
- }
+ if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput)
+ if (Error E =
+ linkToBuildIdDir(Config, Config.InputFilename,
+ Config.BuildIdLinkInput.getValue(), BuildIdBytes))
+ return E;
+
+ if (Error E = handleArgs(Config, *Obj, Reader, OutputElfType))
+ return createFileError(Config.InputFilename, std::move(E));
+
+ if (Error E = writeOutput(Config, *Obj, Out, OutputElfType))
+ return createFileError(Config.InputFilename, std::move(E));
+ if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput)
+ if (Error E =
+ linkToBuildIdDir(Config, Config.OutputFilename,
+ Config.BuildIdLinkOutput.getValue(), BuildIdBytes))
+ return createFileError(Config.OutputFilename, std::move(E));
+
+ return Error::success();
}
} // end namespace elf
diff --git a/contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h b/contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h
index 43f41c00ce5b..e13e237e29c4 100644
--- a/contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h
+++ b/contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h
@@ -1,9 +1,8 @@
//===- ELFObjcopy.h ---------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -11,6 +10,7 @@
#define LLVM_TOOLS_OBJCOPY_ELFOBJCOPY_H
namespace llvm {
+class Error;
class MemoryBuffer;
namespace object {
@@ -22,10 +22,12 @@ struct CopyConfig;
class Buffer;
namespace elf {
-void executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
- Buffer &Out);
-void executeObjcopyOnBinary(const CopyConfig &Config,
- object::ELFObjectFileBase &In, Buffer &Out);
+Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
+ Buffer &Out);
+Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
+ Buffer &Out);
+Error executeObjcopyOnBinary(const CopyConfig &Config,
+ object::ELFObjectFileBase &In, Buffer &Out);
} // end namespace elf
} // end namespace objcopy
diff --git a/contrib/llvm/tools/llvm-objcopy/ELF/Object.cpp b/contrib/llvm/tools/llvm-objcopy/ELF/Object.cpp
index 3d3e029c09eb..fa696380e17c 100644
--- a/contrib/llvm/tools/llvm-objcopy/ELF/Object.cpp
+++ b/contrib/llvm/tools/llvm-objcopy/ELF/Object.cpp
@@ -1,9 +1,8 @@
//===- Object.cpp ---------------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -18,6 +17,7 @@
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/Compression.h"
+#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Path.h"
@@ -25,6 +25,7 @@
#include <cstddef>
#include <cstdint>
#include <iterator>
+#include <unordered_set>
#include <utility>
#include <vector>
@@ -36,8 +37,8 @@ using namespace object;
using namespace ELF;
template <class ELFT> void ELFWriter<ELFT>::writePhdr(const Segment &Seg) {
- uint8_t *B = Buf.getBufferStart();
- B += Obj.ProgramHdrSegment.Offset + Seg.Index * sizeof(Elf_Phdr);
+ uint8_t *B = Buf.getBufferStart() + Obj.ProgramHdrSegment.Offset +
+ Seg.Index * sizeof(Elf_Phdr);
Elf_Phdr &Phdr = *reinterpret_cast<Elf_Phdr *>(B);
Phdr.p_type = Seg.Type;
Phdr.p_flags = Seg.Flags;
@@ -49,15 +50,24 @@ template <class ELFT> void ELFWriter<ELFT>::writePhdr(const Segment &Seg) {
Phdr.p_align = Seg.Align;
}
-void SectionBase::removeSectionReferences(const SectionBase *Sec) {}
-void SectionBase::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {}
+Error SectionBase::removeSectionReferences(
+ bool AllowBrokenLinks,
+ function_ref<bool(const SectionBase *)> ToRemove) {
+ return Error::success();
+}
+
+Error SectionBase::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {
+ return Error::success();
+}
+
void SectionBase::initialize(SectionTableRef SecTable) {}
void SectionBase::finalize() {}
void SectionBase::markSymbols() {}
+void SectionBase::replaceSectionReferences(
+ const DenseMap<SectionBase *, SectionBase *> &) {}
template <class ELFT> void ELFWriter<ELFT>::writeShdr(const SectionBase &Sec) {
- uint8_t *B = Buf.getBufferStart();
- B += Sec.HeaderOffset;
+ uint8_t *B = Buf.getBufferStart() + Sec.HeaderOffset;
Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(B);
Shdr.sh_name = Sec.NameIndex;
Shdr.sh_type = Sec.Type;
@@ -113,30 +123,270 @@ template <class ELFT>
void ELFSectionSizer<ELFT>::visit(DecompressedSection &Sec) {}
void BinarySectionWriter::visit(const SectionIndexSection &Sec) {
- error("Cannot write symbol section index table '" + Sec.Name + "' ");
+ error("cannot write symbol section index table '" + Sec.Name + "' ");
}
void BinarySectionWriter::visit(const SymbolTableSection &Sec) {
- error("Cannot write symbol table '" + Sec.Name + "' out to binary");
+ error("cannot write symbol table '" + Sec.Name + "' out to binary");
}
void BinarySectionWriter::visit(const RelocationSection &Sec) {
- error("Cannot write relocation section '" + Sec.Name + "' out to binary");
+ error("cannot write relocation section '" + Sec.Name + "' out to binary");
}
void BinarySectionWriter::visit(const GnuDebugLinkSection &Sec) {
- error("Cannot write '" + Sec.Name + "' out to binary");
+ error("cannot write '" + Sec.Name + "' out to binary");
}
void BinarySectionWriter::visit(const GroupSection &Sec) {
- error("Cannot write '" + Sec.Name + "' out to binary");
+ error("cannot write '" + Sec.Name + "' out to binary");
}
void SectionWriter::visit(const Section &Sec) {
- if (Sec.Type == SHT_NOBITS)
- return;
- uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
- llvm::copy(Sec.Contents, Buf);
+ if (Sec.Type != SHT_NOBITS)
+ llvm::copy(Sec.Contents, Out.getBufferStart() + Sec.Offset);
+}
+
+static bool addressOverflows32bit(uint64_t Addr) {
+ // Sign extended 32 bit addresses (e.g 0xFFFFFFFF80000000) are ok
+ return Addr > UINT32_MAX && Addr + 0x80000000 > UINT32_MAX;
+}
+
+template <class T> static T checkedGetHex(StringRef S) {
+ T Value;
+ bool Fail = S.getAsInteger(16, Value);
+ assert(!Fail);
+ (void)Fail;
+ return Value;
+}
+
+// Fills exactly Len bytes of buffer with hexadecimal characters
+// representing value 'X'
+template <class T, class Iterator>
+static Iterator utohexstr(T X, Iterator It, size_t Len) {
+ // Fill range with '0'
+ std::fill(It, It + Len, '0');
+
+ for (long I = Len - 1; I >= 0; --I) {
+ unsigned char Mod = static_cast<unsigned char>(X) & 15;
+ *(It + I) = hexdigit(Mod, false);
+ X >>= 4;
+ }
+ assert(X == 0);
+ return It + Len;
+}
+
+uint8_t IHexRecord::getChecksum(StringRef S) {
+ assert((S.size() & 1) == 0);
+ uint8_t Checksum = 0;
+ while (!S.empty()) {
+ Checksum += checkedGetHex<uint8_t>(S.take_front(2));
+ S = S.drop_front(2);
+ }
+ return -Checksum;
+}
+
+IHexLineData IHexRecord::getLine(uint8_t Type, uint16_t Addr,
+ ArrayRef<uint8_t> Data) {
+ IHexLineData Line(getLineLength(Data.size()));
+ assert(Line.size());
+ auto Iter = Line.begin();
+ *Iter++ = ':';
+ Iter = utohexstr(Data.size(), Iter, 2);
+ Iter = utohexstr(Addr, Iter, 4);
+ Iter = utohexstr(Type, Iter, 2);
+ for (uint8_t X : Data)
+ Iter = utohexstr(X, Iter, 2);
+ StringRef S(Line.data() + 1, std::distance(Line.begin() + 1, Iter));
+ Iter = utohexstr(getChecksum(S), Iter, 2);
+ *Iter++ = '\r';
+ *Iter++ = '\n';
+ assert(Iter == Line.end());
+ return Line;
+}
+
+static Error checkRecord(const IHexRecord &R) {
+ switch (R.Type) {
+ case IHexRecord::Data:
+ if (R.HexData.size() == 0)
+ return createStringError(
+ errc::invalid_argument,
+ "zero data length is not allowed for data records");
+ break;
+ case IHexRecord::EndOfFile:
+ break;
+ case IHexRecord::SegmentAddr:
+ // 20-bit segment address. Data length must be 2 bytes
+ // (4 bytes in hex)
+ if (R.HexData.size() != 4)
+ return createStringError(
+ errc::invalid_argument,
+ "segment address data should be 2 bytes in size");
+ break;
+ case IHexRecord::StartAddr80x86:
+ case IHexRecord::StartAddr:
+ if (R.HexData.size() != 8)
+ return createStringError(errc::invalid_argument,
+ "start address data should be 4 bytes in size");
+ // According to Intel HEX specification '03' record
+ // only specifies the code address within the 20-bit
+ // segmented address space of the 8086/80186. This
+ // means 12 high order bits should be zeroes.
+ if (R.Type == IHexRecord::StartAddr80x86 &&
+ R.HexData.take_front(3) != "000")
+ return createStringError(errc::invalid_argument,
+ "start address exceeds 20 bit for 80x86");
+ break;
+ case IHexRecord::ExtendedAddr:
+ // 16-31 bits of linear base address
+ if (R.HexData.size() != 4)
+ return createStringError(
+ errc::invalid_argument,
+ "extended address data should be 2 bytes in size");
+ break;
+ default:
+ // Unknown record type
+ return createStringError(errc::invalid_argument, "unknown record type: %u",
+ static_cast<unsigned>(R.Type));
+ }
+ return Error::success();
+}
+
+// Checks that IHEX line contains valid characters.
+// This allows converting hexadecimal data to integers
+// without extra verification.
+static Error checkChars(StringRef Line) {
+ assert(!Line.empty());
+ if (Line[0] != ':')
+ return createStringError(errc::invalid_argument,
+ "missing ':' in the beginning of line.");
+
+ for (size_t Pos = 1; Pos < Line.size(); ++Pos)
+ if (hexDigitValue(Line[Pos]) == -1U)
+ return createStringError(errc::invalid_argument,
+ "invalid character at position %zu.", Pos + 1);
+ return Error::success();
+}
+
+Expected<IHexRecord> IHexRecord::parse(StringRef Line) {
+ assert(!Line.empty());
+
+ // ':' + Length + Address + Type + Checksum with empty data ':LLAAAATTCC'
+ if (Line.size() < 11)
+ return createStringError(errc::invalid_argument,
+ "line is too short: %zu chars.", Line.size());
+
+ if (Error E = checkChars(Line))
+ return std::move(E);
+
+ IHexRecord Rec;
+ size_t DataLen = checkedGetHex<uint8_t>(Line.substr(1, 2));
+ if (Line.size() != getLength(DataLen))
+ return createStringError(errc::invalid_argument,
+ "invalid line length %zu (should be %zu)",
+ Line.size(), getLength(DataLen));
+
+ Rec.Addr = checkedGetHex<uint16_t>(Line.substr(3, 4));
+ Rec.Type = checkedGetHex<uint8_t>(Line.substr(7, 2));
+ Rec.HexData = Line.substr(9, DataLen * 2);
+
+ if (getChecksum(Line.drop_front(1)) != 0)
+ return createStringError(errc::invalid_argument, "incorrect checksum.");
+ if (Error E = checkRecord(Rec))
+ return std::move(E);
+ return Rec;
+}
+
+static uint64_t sectionPhysicalAddr(const SectionBase *Sec) {
+ Segment *Seg = Sec->ParentSegment;
+ if (Seg && Seg->Type != ELF::PT_LOAD)
+ Seg = nullptr;
+ return Seg ? Seg->PAddr + Sec->OriginalOffset - Seg->OriginalOffset
+ : Sec->Addr;
+}
+
+void IHexSectionWriterBase::writeSection(const SectionBase *Sec,
+ ArrayRef<uint8_t> Data) {
+ assert(Data.size() == Sec->Size);
+ const uint32_t ChunkSize = 16;
+ uint32_t Addr = sectionPhysicalAddr(Sec) & 0xFFFFFFFFU;
+ while (!Data.empty()) {
+ uint64_t DataSize = std::min<uint64_t>(Data.size(), ChunkSize);
+ if (Addr > SegmentAddr + BaseAddr + 0xFFFFU) {
+ if (Addr > 0xFFFFFU) {
+ // Write extended address record, zeroing segment address
+ // if needed.
+ if (SegmentAddr != 0)
+ SegmentAddr = writeSegmentAddr(0U);
+ BaseAddr = writeBaseAddr(Addr);
+ } else {
+ // We can still remain 16-bit
+ SegmentAddr = writeSegmentAddr(Addr);
+ }
+ }
+ uint64_t SegOffset = Addr - BaseAddr - SegmentAddr;
+ assert(SegOffset <= 0xFFFFU);
+ DataSize = std::min(DataSize, 0x10000U - SegOffset);
+ writeData(0, SegOffset, Data.take_front(DataSize));
+ Addr += DataSize;
+ Data = Data.drop_front(DataSize);
+ }
+}
+
+uint64_t IHexSectionWriterBase::writeSegmentAddr(uint64_t Addr) {
+ assert(Addr <= 0xFFFFFU);
+ uint8_t Data[] = {static_cast<uint8_t>((Addr & 0xF0000U) >> 12), 0};
+ writeData(2, 0, Data);
+ return Addr & 0xF0000U;
+}
+
+uint64_t IHexSectionWriterBase::writeBaseAddr(uint64_t Addr) {
+ assert(Addr <= 0xFFFFFFFFU);
+ uint64_t Base = Addr & 0xFFFF0000U;
+ uint8_t Data[] = {static_cast<uint8_t>(Base >> 24),
+ static_cast<uint8_t>((Base >> 16) & 0xFF)};
+ writeData(4, 0, Data);
+ return Base;
+}
+
+void IHexSectionWriterBase::writeData(uint8_t Type, uint16_t Addr,
+ ArrayRef<uint8_t> Data) {
+ Offset += IHexRecord::getLineLength(Data.size());
+}
+
+void IHexSectionWriterBase::visit(const Section &Sec) {
+ writeSection(&Sec, Sec.Contents);
+}
+
+void IHexSectionWriterBase::visit(const OwnedDataSection &Sec) {
+ writeSection(&Sec, Sec.Data);
+}
+
+void IHexSectionWriterBase::visit(const StringTableSection &Sec) {
+ // Check that sizer has already done its work
+ assert(Sec.Size == Sec.StrTabBuilder.getSize());
+ // We are free to pass an invalid pointer to writeSection as long
+ // as we don't actually write any data. The real writer class has
+ // to override this method .
+ writeSection(&Sec, {nullptr, static_cast<size_t>(Sec.Size)});
+}
+
+void IHexSectionWriterBase::visit(const DynamicRelocationSection &Sec) {
+ writeSection(&Sec, Sec.Contents);
+}
+
+void IHexSectionWriter::writeData(uint8_t Type, uint16_t Addr,
+ ArrayRef<uint8_t> Data) {
+ IHexLineData HexData = IHexRecord::getLine(Type, Addr, Data);
+ memcpy(Out.getBufferStart() + Offset, HexData.data(), HexData.size());
+ Offset += HexData.size();
+}
+
+void IHexSectionWriter::visit(const StringTableSection &Sec) {
+ assert(Sec.Size == Sec.StrTabBuilder.getSize());
+ std::vector<uint8_t> Data(Sec.Size);
+ Sec.StrTabBuilder.write(Data.data());
+ writeSection(&Sec, Data);
}
void Section::accept(SectionVisitor &Visitor) const { Visitor.visit(*this); }
@@ -144,8 +394,7 @@ void Section::accept(SectionVisitor &Visitor) const { Visitor.visit(*this); }
void Section::accept(MutableSectionVisitor &Visitor) { Visitor.visit(*this); }
void SectionWriter::visit(const OwnedDataSection &Sec) {
- uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
- llvm::copy(Sec.Data, Buf);
+ llvm::copy(Sec.Data, Out.getBufferStart() + Sec.Offset);
}
static const std::vector<uint8_t> ZlibGnuMagic = {'Z', 'L', 'I', 'B'};
@@ -161,8 +410,7 @@ getDecompressedSizeAndAlignment(ArrayRef<uint8_t> Data) {
const bool IsGnuDebug = isDataGnuCompressed(Data);
const uint64_t DecompressedSize =
IsGnuDebug
- ? support::endian::read64be(reinterpret_cast<const uint64_t *>(
- Data.data() + ZlibGnuMagic.size()))
+ ? support::endian::read64be(Data.data() + ZlibGnuMagic.size())
: reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data.data())->ch_size;
const uint64_t DecompressedAlign =
IsGnuDebug ? 1
@@ -174,13 +422,6 @@ getDecompressedSizeAndAlignment(ArrayRef<uint8_t> Data) {
template <class ELFT>
void ELFSectionWriter<ELFT>::visit(const DecompressedSection &Sec) {
- uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
-
- if (!zlib::isAvailable()) {
- std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), Buf);
- return;
- }
-
const size_t DataOffset = isDataGnuCompressed(Sec.OriginalData)
? (ZlibGnuMagic.size() + sizeof(Sec.Size))
: sizeof(Elf_Chdr_Impl<ELFT>);
@@ -194,11 +435,12 @@ void ELFSectionWriter<ELFT>::visit(const DecompressedSection &Sec) {
static_cast<size_t>(Sec.Size)))
reportError(Sec.Name, std::move(E));
+ uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
std::copy(DecompressedContent.begin(), DecompressedContent.end(), Buf);
}
void BinarySectionWriter::visit(const DecompressedSection &Sec) {
- error("Cannot write compressed section '" + Sec.Name + "' ");
+ error("cannot write compressed section '" + Sec.Name + "' ");
}
void DecompressedSection::accept(SectionVisitor &Visitor) const {
@@ -217,15 +459,22 @@ void OwnedDataSection::accept(MutableSectionVisitor &Visitor) {
Visitor.visit(*this);
}
+void OwnedDataSection::appendHexData(StringRef HexData) {
+ assert((HexData.size() & 1) == 0);
+ while (!HexData.empty()) {
+ Data.push_back(checkedGetHex<uint8_t>(HexData.take_front(2)));
+ HexData = HexData.drop_front(2);
+ }
+ Size = Data.size();
+}
+
void BinarySectionWriter::visit(const CompressedSection &Sec) {
- error("Cannot write compressed section '" + Sec.Name + "' ");
+ error("cannot write compressed section '" + Sec.Name + "' ");
}
template <class ELFT>
void ELFSectionWriter<ELFT>::visit(const CompressedSection &Sec) {
- uint8_t *Buf = Out.getBufferStart();
- Buf += Sec.Offset;
-
+ uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
if (Sec.CompressionType == DebugCompressionType::None) {
std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), Buf);
return;
@@ -255,12 +504,6 @@ CompressedSection::CompressedSection(const SectionBase &Sec,
DebugCompressionType CompressionType)
: SectionBase(Sec), CompressionType(CompressionType),
DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) {
-
- if (!zlib::isAvailable()) {
- CompressionType = DebugCompressionType::None;
- return;
- }
-
if (Error E = zlib::compress(
StringRef(reinterpret_cast<const char *>(OriginalData.data()),
OriginalData.size()),
@@ -299,16 +542,16 @@ void CompressedSection::accept(MutableSectionVisitor &Visitor) {
Visitor.visit(*this);
}
-void StringTableSection::addString(StringRef Name) {
- StrTabBuilder.add(Name);
- Size = StrTabBuilder.getSize();
-}
+void StringTableSection::addString(StringRef Name) { StrTabBuilder.add(Name); }
uint32_t StringTableSection::findIndex(StringRef Name) const {
return StrTabBuilder.getOffset(Name);
}
-void StringTableSection::finalize() { StrTabBuilder.finalize(); }
+void StringTableSection::prepareForLayout() {
+ StrTabBuilder.finalize();
+ Size = StrTabBuilder.getSize();
+}
void SectionWriter::visit(const StringTableSection &Sec) {
Sec.StrTabBuilder.write(Out.getBufferStart() + Sec.Offset);
@@ -325,8 +568,7 @@ void StringTableSection::accept(MutableSectionVisitor &Visitor) {
template <class ELFT>
void ELFSectionWriter<ELFT>::visit(const SectionIndexSection &Sec) {
uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
- auto *IndexesBuffer = reinterpret_cast<Elf_Word *>(Buf);
- llvm::copy(Sec.Indexes, IndexesBuffer);
+ llvm::copy(Sec.Indexes, reinterpret_cast<Elf_Word *>(Buf));
}
void SectionIndexSection::initialize(SectionTableRef SecTable) {
@@ -355,6 +597,11 @@ static bool isValidReservedSectionIndex(uint16_t Index, uint16_t Machine) {
case SHN_COMMON:
return true;
}
+
+ if (Machine == EM_AMDGPU) {
+ return Index == SHN_AMDGPU_LDS;
+ }
+
if (Machine == EM_HEXAGON) {
switch (Index) {
case SHN_HEXAGON_SCOMMON:
@@ -376,21 +623,17 @@ uint16_t Symbol::getShndx() const {
return SHN_XINDEX;
return DefinedIn->Index;
}
- switch (ShndxType) {
- // This means that we don't have a defined section but we do need to
- // output a legitimate section index.
- case SYMBOL_SIMPLE_INDEX:
+
+ if (ShndxType == SYMBOL_SIMPLE_INDEX) {
+ // This means that we don't have a defined section but we do need to
+ // output a legitimate section index.
return SHN_UNDEF;
- case SYMBOL_ABS:
- case SYMBOL_COMMON:
- case SYMBOL_HEXAGON_SCOMMON:
- case SYMBOL_HEXAGON_SCOMMON_2:
- case SYMBOL_HEXAGON_SCOMMON_4:
- case SYMBOL_HEXAGON_SCOMMON_8:
- case SYMBOL_XINDEX:
- return static_cast<uint16_t>(ShndxType);
}
- llvm_unreachable("Symbol with invalid ShndxType encountered");
+
+ assert(ShndxType == SYMBOL_ABS || ShndxType == SYMBOL_COMMON ||
+ (ShndxType >= SYMBOL_LOPROC && ShndxType <= SYMBOL_HIPROC) ||
+ (ShndxType >= SYMBOL_LOOS && ShndxType <= SYMBOL_HIOS));
+ return static_cast<uint16_t>(ShndxType);
}
bool Symbol::isCommon() const { return getShndx() == SHN_COMMON; }
@@ -404,7 +647,7 @@ void SymbolTableSection::assignIndices() {
void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type,
SectionBase *DefinedIn, uint64_t Value,
uint8_t Visibility, uint16_t Shndx,
- uint64_t Size) {
+ uint64_t SymbolSize) {
Symbol Sym;
Sym.Name = Name.str();
Sym.Binding = Bind;
@@ -420,21 +663,28 @@ void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type,
}
Sym.Value = Value;
Sym.Visibility = Visibility;
- Sym.Size = Size;
+ Sym.Size = SymbolSize;
Sym.Index = Symbols.size();
Symbols.emplace_back(llvm::make_unique<Symbol>(Sym));
Size += this->EntrySize;
}
-void SymbolTableSection::removeSectionReferences(const SectionBase *Sec) {
- if (SectionIndexTable == Sec)
+Error SymbolTableSection::removeSectionReferences(
+ bool AllowBrokenLinks,
+ function_ref<bool(const SectionBase *)> ToRemove) {
+ if (ToRemove(SectionIndexTable))
SectionIndexTable = nullptr;
- if (SymbolNames == Sec) {
- error("String table " + SymbolNames->Name +
- " cannot be removed because it is referenced by the symbol table " +
- this->Name);
+ if (ToRemove(SymbolNames)) {
+ if (!AllowBrokenLinks)
+ return createStringError(
+ llvm::errc::invalid_argument,
+ "string table '%s' cannot be removed because it is "
+ "referenced by the symbol table '%s'",
+ SymbolNames->Name.data(), this->Name.data());
+ SymbolNames = nullptr;
}
- removeSymbols([Sec](const Symbol &Sym) { return Sym.DefinedIn == Sec; });
+ return removeSymbols(
+ [ToRemove](const Symbol &Sym) { return ToRemove(Sym.DefinedIn); });
}
void SymbolTableSection::updateSymbols(function_ref<void(Symbol &)> Callable) {
@@ -446,7 +696,7 @@ void SymbolTableSection::updateSymbols(function_ref<void(Symbol &)> Callable) {
assignIndices();
}
-void SymbolTableSection::removeSymbols(
+Error SymbolTableSection::removeSymbols(
function_ref<bool(const Symbol &)> ToRemove) {
Symbols.erase(
std::remove_if(std::begin(Symbols) + 1, std::end(Symbols),
@@ -454,6 +704,14 @@ void SymbolTableSection::removeSymbols(
std::end(Symbols));
Size = Symbols.size() * EntrySize;
assignIndices();
+ return Error::success();
+}
+
+void SymbolTableSection::replaceSectionReferences(
+ const DenseMap<SectionBase *, SectionBase *> &FromTo) {
+ for (std::unique_ptr<Symbol> &Sym : Symbols)
+ if (SectionBase *To = FromTo.lookup(Sym->DefinedIn))
+ Sym->DefinedIn = To;
}
void SymbolTableSection::initialize(SectionTableRef SecTable) {
@@ -467,40 +725,50 @@ void SymbolTableSection::initialize(SectionTableRef SecTable) {
}
void SymbolTableSection::finalize() {
- // Make sure SymbolNames is finalized before getting name indexes.
- SymbolNames->finalize();
-
uint32_t MaxLocalIndex = 0;
- for (auto &Sym : Symbols) {
- Sym->NameIndex = SymbolNames->findIndex(Sym->Name);
+ for (std::unique_ptr<Symbol> &Sym : Symbols) {
+ Sym->NameIndex =
+ SymbolNames == nullptr ? 0 : SymbolNames->findIndex(Sym->Name);
if (Sym->Binding == STB_LOCAL)
MaxLocalIndex = std::max(MaxLocalIndex, Sym->Index);
}
// Now we need to set the Link and Info fields.
- Link = SymbolNames->Index;
+ Link = SymbolNames == nullptr ? 0 : SymbolNames->Index;
Info = MaxLocalIndex + 1;
}
void SymbolTableSection::prepareForLayout() {
- // Add all potential section indexes before file layout so that the section
- // index section has the approprite size.
- if (SectionIndexTable != nullptr) {
- for (const auto &Sym : Symbols) {
- if (Sym->DefinedIn != nullptr && Sym->DefinedIn->Index >= SHN_LORESERVE)
- SectionIndexTable->addIndex(Sym->DefinedIn->Index);
- else
- SectionIndexTable->addIndex(SHN_UNDEF);
- }
- }
+ // Reserve proper amount of space in section index table, so we can
+ // layout sections correctly. We will fill the table with correct
+ // indexes later in fillShdnxTable.
+ if (SectionIndexTable)
+ SectionIndexTable->reserve(Symbols.size());
+
// Add all of our strings to SymbolNames so that SymbolNames has the right
// size before layout is decided.
- for (auto &Sym : Symbols)
- SymbolNames->addString(Sym->Name);
+ // If the symbol names section has been removed, don't try to add strings to
+ // the table.
+ if (SymbolNames != nullptr)
+ for (std::unique_ptr<Symbol> &Sym : Symbols)
+ SymbolNames->addString(Sym->Name);
+}
+
+void SymbolTableSection::fillShndxTable() {
+ if (SectionIndexTable == nullptr)
+ return;
+ // Fill section index table with real section indexes. This function must
+ // be called after assignOffsets.
+ for (const std::unique_ptr<Symbol> &Sym : Symbols) {
+ if (Sym->DefinedIn != nullptr && Sym->DefinedIn->Index >= SHN_LORESERVE)
+ SectionIndexTable->addIndex(Sym->DefinedIn->Index);
+ else
+ SectionIndexTable->addIndex(SHN_UNDEF);
+ }
}
const Symbol *SymbolTableSection::getSymbolByIndex(uint32_t Index) const {
if (Symbols.size() <= Index)
- error("Invalid symbol index: " + Twine(Index));
+ error("invalid symbol index: " + Twine(Index));
return Symbols[Index].get();
}
@@ -511,11 +779,9 @@ Symbol *SymbolTableSection::getSymbolByIndex(uint32_t Index) {
template <class ELFT>
void ELFSectionWriter<ELFT>::visit(const SymbolTableSection &Sec) {
- uint8_t *Buf = Out.getBufferStart();
- Buf += Sec.Offset;
- Elf_Sym *Sym = reinterpret_cast<Elf_Sym *>(Buf);
+ Elf_Sym *Sym = reinterpret_cast<Elf_Sym *>(Out.getBufferStart() + Sec.Offset);
// Loop though symbols setting each entry of the symbol table.
- for (auto &Symbol : Sec.Symbols) {
+ for (const std::unique_ptr<Symbol> &Symbol : Sec.Symbols) {
Sym->st_name = Symbol->NameIndex;
Sym->st_value = Symbol->Value;
Sym->st_size = Symbol->Size;
@@ -535,16 +801,31 @@ void SymbolTableSection::accept(MutableSectionVisitor &Visitor) {
Visitor.visit(*this);
}
-template <class SymTabType>
-void RelocSectionWithSymtabBase<SymTabType>::removeSectionReferences(
- const SectionBase *Sec) {
- if (Symbols == Sec) {
- error("Symbol table " + Symbols->Name +
- " cannot be removed because it is "
- "referenced by the relocation "
- "section " +
- this->Name);
+Error RelocationSection::removeSectionReferences(
+ bool AllowBrokenLinks,
+ function_ref<bool(const SectionBase *)> ToRemove) {
+ if (ToRemove(Symbols)) {
+ if (!AllowBrokenLinks)
+ return createStringError(
+ llvm::errc::invalid_argument,
+ "symbol table '%s' cannot be removed because it is "
+ "referenced by the relocation section '%s'",
+ Symbols->Name.data(), this->Name.data());
+ Symbols = nullptr;
}
+
+ for (const Relocation &R : Relocations) {
+ if (!R.RelocSymbol->DefinedIn || !ToRemove(R.RelocSymbol->DefinedIn))
+ continue;
+ return createStringError(llvm::errc::invalid_argument,
+ "section '%s' cannot be removed: (%s+0x%" PRIx64
+ ") has relocation against symbol '%s'",
+ R.RelocSymbol->DefinedIn->Name.data(),
+ SecToApplyRel->Name.data(), R.Offset,
+ R.RelocSymbol->Name.c_str());
+ }
+
+ return Error::success();
}
template <class SymTabType>
@@ -609,12 +890,15 @@ void RelocationSection::accept(MutableSectionVisitor &Visitor) {
Visitor.visit(*this);
}
-void RelocationSection::removeSymbols(
+Error RelocationSection::removeSymbols(
function_ref<bool(const Symbol &)> ToRemove) {
for (const Relocation &Reloc : Relocations)
if (ToRemove(*Reloc.RelocSymbol))
- error("not stripping symbol '" + Reloc.RelocSymbol->Name +
- "' because it is named in a relocation");
+ return createStringError(
+ llvm::errc::invalid_argument,
+ "not stripping symbol '%s' because it is named in a relocation",
+ Reloc.RelocSymbol->Name.data());
+ return Error::success();
}
void RelocationSection::markSymbols() {
@@ -622,9 +906,15 @@ void RelocationSection::markSymbols() {
Reloc.RelocSymbol->Referenced = true;
}
+void RelocationSection::replaceSectionReferences(
+ const DenseMap<SectionBase *, SectionBase *> &FromTo) {
+ // Update the target section if it was replaced.
+ if (SectionBase *To = FromTo.lookup(SecToApplyRel))
+ SecToApplyRel = To;
+}
+
void SectionWriter::visit(const DynamicRelocationSection &Sec) {
- llvm::copy(Sec.Contents,
- Out.getBufferStart() + Sec.Offset);
+ llvm::copy(Sec.Contents, Out.getBufferStart() + Sec.Offset);
}
void DynamicRelocationSection::accept(SectionVisitor &Visitor) const {
@@ -635,13 +925,38 @@ void DynamicRelocationSection::accept(MutableSectionVisitor &Visitor) {
Visitor.visit(*this);
}
-void Section::removeSectionReferences(const SectionBase *Sec) {
- if (LinkSection == Sec) {
- error("Section " + LinkSection->Name +
- " cannot be removed because it is "
- "referenced by the section " +
- this->Name);
+Error DynamicRelocationSection::removeSectionReferences(
+ bool AllowBrokenLinks, function_ref<bool(const SectionBase *)> ToRemove) {
+ if (ToRemove(Symbols)) {
+ if (!AllowBrokenLinks)
+ return createStringError(
+ llvm::errc::invalid_argument,
+ "symbol table '%s' cannot be removed because it is "
+ "referenced by the relocation section '%s'",
+ Symbols->Name.data(), this->Name.data());
+ Symbols = nullptr;
+ }
+
+ // SecToApplyRel contains a section referenced by sh_info field. It keeps
+ // a section to which the relocation section applies. When we remove any
+ // sections we also remove their relocation sections. Since we do that much
+ // earlier, this assert should never be triggered.
+ assert(!SecToApplyRel || !ToRemove(SecToApplyRel));
+ return Error::success();
+}
+
+Error Section::removeSectionReferences(
+ bool AllowBrokenDependency,
+ function_ref<bool(const SectionBase *)> ToRemove) {
+ if (ToRemove(LinkSection)) {
+ if (!AllowBrokenDependency)
+ return createStringError(llvm::errc::invalid_argument,
+ "section '%s' cannot be removed because it is "
+ "referenced by the section '%s'",
+ LinkSection->Name.data(), this->Name.data());
+ LinkSection = nullptr;
}
+ return Error::success();
}
void GroupSection::finalize() {
@@ -649,13 +964,13 @@ void GroupSection::finalize() {
this->Link = SymTab->Index;
}
-void GroupSection::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {
- if (ToRemove(*Sym)) {
- error("Symbol " + Sym->Name +
- " cannot be removed because it is "
- "referenced by the section " +
- this->Name + "[" + Twine(this->Index) + "]");
- }
+Error GroupSection::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {
+ if (ToRemove(*Sym))
+ return createStringError(llvm::errc::invalid_argument,
+ "symbol '%s' cannot be removed because it is "
+ "referenced by the section '%s[%d]'",
+ Sym->Name.data(), this->Name.data(), this->Index);
+ return Error::success();
}
void GroupSection::markSymbols() {
@@ -663,19 +978,26 @@ void GroupSection::markSymbols() {
Sym->Referenced = true;
}
+void GroupSection::replaceSectionReferences(
+ const DenseMap<SectionBase *, SectionBase *> &FromTo) {
+ for (SectionBase *&Sec : GroupMembers)
+ if (SectionBase *To = FromTo.lookup(Sec))
+ Sec = To;
+}
+
void Section::initialize(SectionTableRef SecTable) {
- if (Link != ELF::SHN_UNDEF) {
- LinkSection =
- SecTable.getSection(Link, "Link field value " + Twine(Link) +
- " in section " + Name + " is invalid");
- if (LinkSection->Type == ELF::SHT_SYMTAB)
- LinkSection = nullptr;
- }
+ if (Link == ELF::SHN_UNDEF)
+ return;
+ LinkSection =
+ SecTable.getSection(Link, "Link field value " + Twine(Link) +
+ " in section " + Name + " is invalid");
+ if (LinkSection->Type == ELF::SHT_SYMTAB)
+ LinkSection = nullptr;
}
void Section::finalize() { this->Link = LinkSection ? LinkSection->Index : 0; }
-void GnuDebugLinkSection::init(StringRef File, StringRef Data) {
+void GnuDebugLinkSection::init(StringRef File) {
FileName = sys::path::filename(File);
// The format for the .gnu_debuglink starts with the file name and is
// followed by a null terminator and then the CRC32 of the file. The CRC32
@@ -690,31 +1012,21 @@ void GnuDebugLinkSection::init(StringRef File, StringRef Data) {
// establish the order that sections should go in. By using the maximum
// possible offset we cause this section to wind up at the end.
OriginalOffset = std::numeric_limits<uint64_t>::max();
- JamCRC CRC;
- CRC.update(ArrayRef<char>(Data.data(), Data.size()));
- // The CRC32 value needs to be complemented because the JamCRC dosn't
- // finalize the CRC32 value. It also dosn't negate the initial CRC32 value
- // but it starts by default at 0xFFFFFFFF which is the complement of zero.
- CRC32 = ~CRC.getCRC();
}
-GnuDebugLinkSection::GnuDebugLinkSection(StringRef File) : FileName(File) {
- // Read in the file to compute the CRC of it.
- auto DebugOrErr = MemoryBuffer::getFile(File);
- if (!DebugOrErr)
- error("'" + File + "': " + DebugOrErr.getError().message());
- auto Debug = std::move(*DebugOrErr);
- init(File, Debug->getBuffer());
+GnuDebugLinkSection::GnuDebugLinkSection(StringRef File,
+ uint32_t PrecomputedCRC)
+ : FileName(File), CRC32(PrecomputedCRC) {
+ init(File);
}
template <class ELFT>
void ELFSectionWriter<ELFT>::visit(const GnuDebugLinkSection &Sec) {
- auto Buf = Out.getBufferStart() + Sec.Offset;
- char *File = reinterpret_cast<char *>(Buf);
+ unsigned char *Buf = Out.getBufferStart() + Sec.Offset;
Elf_Word *CRC =
reinterpret_cast<Elf_Word *>(Buf + Sec.Size - sizeof(Elf_Word));
*CRC = Sec.CRC32;
- llvm::copy(Sec.FileName, File);
+ llvm::copy(Sec.FileName, Buf);
}
void GnuDebugLinkSection::accept(SectionVisitor &Visitor) const {
@@ -730,7 +1042,7 @@ void ELFSectionWriter<ELFT>::visit(const GroupSection &Sec) {
ELF::Elf32_Word *Buf =
reinterpret_cast<ELF::Elf32_Word *>(Out.getBufferStart() + Sec.Offset);
*Buf++ = Sec.FlagWord;
- for (const auto *S : Sec.GroupMembers)
+ for (SectionBase *S : Sec.GroupMembers)
support::endian::write32<ELFT::TargetEndianness>(Buf++, S->Index);
}
@@ -750,6 +1062,20 @@ static bool sectionWithinSegment(const SectionBase &Section,
// segments and ensures that the section "belongs" to the second segment and
// not the first.
uint64_t SecSize = Section.Size ? Section.Size : 1;
+
+ if (Section.Type == SHT_NOBITS) {
+ if (!(Section.Flags & SHF_ALLOC))
+ return false;
+
+ bool SectionIsTLS = Section.Flags & SHF_TLS;
+ bool SegmentIsTLS = Segment.Type == PT_TLS;
+ if (SectionIsTLS != SegmentIsTLS)
+ return false;
+
+ return Segment.VAddr <= Section.Addr &&
+ Segment.VAddr + Segment.MemSize >= Section.Addr + SecSize;
+ }
+
return Segment.Offset <= Section.OriginalOffset &&
Segment.Offset + Segment.FileSize >= Section.OriginalOffset + SecSize;
}
@@ -781,7 +1107,7 @@ static bool compareSegmentsByPAddr(const Segment *A, const Segment *B) {
return A->Index < B->Index;
}
-void BinaryELFBuilder::initFileHeader() {
+void BasicELFBuilder::initFileHeader() {
Obj->Flags = 0x0;
Obj->Type = ET_REL;
Obj->OSABI = ELFOSABI_NONE;
@@ -791,9 +1117,9 @@ void BinaryELFBuilder::initFileHeader() {
Obj->Version = 1;
}
-void BinaryELFBuilder::initHeaderSegment() { Obj->ElfHdrSegment.Index = 0; }
+void BasicELFBuilder::initHeaderSegment() { Obj->ElfHdrSegment.Index = 0; }
-StringTableSection *BinaryELFBuilder::addStrTab() {
+StringTableSection *BasicELFBuilder::addStrTab() {
auto &StrTab = Obj->addSection<StringTableSection>();
StrTab.Name = ".strtab";
@@ -801,7 +1127,7 @@ StringTableSection *BinaryELFBuilder::addStrTab() {
return &StrTab;
}
-SymbolTableSection *BinaryELFBuilder::addSymTab(StringTableSection *StrTab) {
+SymbolTableSection *BasicELFBuilder::addSymTab(StringTableSection *StrTab) {
auto &SymTab = Obj->addSection<SymbolTableSection>();
SymTab.Name = ".symtab";
@@ -814,6 +1140,11 @@ SymbolTableSection *BinaryELFBuilder::addSymTab(StringTableSection *StrTab) {
return &SymTab;
}
+void BasicELFBuilder::initSections() {
+ for (auto &Section : Obj->sections())
+ Section.initialize(Obj->sections());
+}
+
void BinaryELFBuilder::addData(SymbolTableSection *SymTab) {
auto Data = ArrayRef<uint8_t>(
reinterpret_cast<const uint8_t *>(MemBuf->getBufferStart()),
@@ -837,25 +1168,75 @@ void BinaryELFBuilder::addData(SymbolTableSection *SymTab) {
/*Value=*/DataSection.Size, STV_DEFAULT, SHN_ABS, 0);
}
-void BinaryELFBuilder::initSections() {
- for (auto &Section : Obj->sections()) {
- Section.initialize(Obj->sections());
+std::unique_ptr<Object> BinaryELFBuilder::build() {
+ initFileHeader();
+ initHeaderSegment();
+
+ SymbolTableSection *SymTab = addSymTab(addStrTab());
+ initSections();
+ addData(SymTab);
+
+ return std::move(Obj);
+}
+
+// Adds sections from IHEX data file. Data should have been
+// fully validated by this time.
+void IHexELFBuilder::addDataSections() {
+ OwnedDataSection *Section = nullptr;
+ uint64_t SegmentAddr = 0, BaseAddr = 0;
+ uint32_t SecNo = 1;
+
+ for (const IHexRecord &R : Records) {
+ uint64_t RecAddr;
+ switch (R.Type) {
+ case IHexRecord::Data:
+ // Ignore empty data records
+ if (R.HexData.empty())
+ continue;
+ RecAddr = R.Addr + SegmentAddr + BaseAddr;
+ if (!Section || Section->Addr + Section->Size != RecAddr)
+ // OriginalOffset field is only used to sort section properly, so
+ // instead of keeping track of real offset in IHEX file, we use
+ // section number.
+ Section = &Obj->addSection<OwnedDataSection>(
+ ".sec" + std::to_string(SecNo++), RecAddr,
+ ELF::SHF_ALLOC | ELF::SHF_WRITE, SecNo);
+ Section->appendHexData(R.HexData);
+ break;
+ case IHexRecord::EndOfFile:
+ break;
+ case IHexRecord::SegmentAddr:
+ // 20-bit segment address.
+ SegmentAddr = checkedGetHex<uint16_t>(R.HexData) << 4;
+ break;
+ case IHexRecord::StartAddr80x86:
+ case IHexRecord::StartAddr:
+ Obj->Entry = checkedGetHex<uint32_t>(R.HexData);
+ assert(Obj->Entry <= 0xFFFFFU);
+ break;
+ case IHexRecord::ExtendedAddr:
+ // 16-31 bits of linear base address
+ BaseAddr = checkedGetHex<uint16_t>(R.HexData) << 16;
+ break;
+ default:
+ llvm_unreachable("unknown record type");
+ }
}
}
-std::unique_ptr<Object> BinaryELFBuilder::build() {
+std::unique_ptr<Object> IHexELFBuilder::build() {
initFileHeader();
initHeaderSegment();
StringTableSection *StrTab = addStrTab();
- SymbolTableSection *SymTab = addSymTab(StrTab);
+ addSymTab(StrTab);
initSections();
- addData(SymTab);
+ addDataSections();
return std::move(Obj);
}
template <class ELFT> void ELFBuilder<ELFT>::setParentSegment(Segment &Child) {
- for (auto &Parent : Obj.segments()) {
+ for (Segment &Parent : Obj.segments()) {
// Every segment will overlap with itself but we don't want a segment to
// be it's own parent so we avoid that situation.
if (&Child != &Parent && segmentOverlapsSegment(Child, Parent)) {
@@ -870,23 +1251,43 @@ template <class ELFT> void ELFBuilder<ELFT>::setParentSegment(Segment &Child) {
}
}
-template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() {
+template <class ELFT> void ELFBuilder<ELFT>::findEhdrOffset() {
+ if (!ExtractPartition)
+ return;
+
+ for (const SectionBase &Section : Obj.sections()) {
+ if (Section.Type == SHT_LLVM_PART_EHDR &&
+ Section.Name == *ExtractPartition) {
+ EhdrOffset = Section.Offset;
+ return;
+ }
+ }
+ error("could not find partition named '" + *ExtractPartition + "'");
+}
+
+template <class ELFT>
+void ELFBuilder<ELFT>::readProgramHeaders(const ELFFile<ELFT> &HeadersFile) {
uint32_t Index = 0;
- for (const auto &Phdr : unwrapOrError(ElfFile.program_headers())) {
- ArrayRef<uint8_t> Data{ElfFile.base() + Phdr.p_offset,
+ for (const auto &Phdr : unwrapOrError(HeadersFile.program_headers())) {
+ if (Phdr.p_offset + Phdr.p_filesz > HeadersFile.getBufSize())
+ error("program header with offset 0x" + Twine::utohexstr(Phdr.p_offset) +
+ " and file size 0x" + Twine::utohexstr(Phdr.p_filesz) +
+ " goes past the end of the file");
+
+ ArrayRef<uint8_t> Data{HeadersFile.base() + Phdr.p_offset,
(size_t)Phdr.p_filesz};
Segment &Seg = Obj.addSegment(Data);
Seg.Type = Phdr.p_type;
Seg.Flags = Phdr.p_flags;
- Seg.OriginalOffset = Phdr.p_offset;
- Seg.Offset = Phdr.p_offset;
+ Seg.OriginalOffset = Phdr.p_offset + EhdrOffset;
+ Seg.Offset = Phdr.p_offset + EhdrOffset;
Seg.VAddr = Phdr.p_vaddr;
Seg.PAddr = Phdr.p_paddr;
Seg.FileSize = Phdr.p_filesz;
Seg.MemSize = Phdr.p_memsz;
Seg.Align = Phdr.p_align;
Seg.Index = Index++;
- for (auto &Section : Obj.sections()) {
+ for (SectionBase &Section : Obj.sections()) {
if (sectionWithinSegment(Section, Seg)) {
Seg.addSection(&Section);
if (!Section.ParentSegment ||
@@ -899,8 +1300,9 @@ template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() {
auto &ElfHdr = Obj.ElfHdrSegment;
ElfHdr.Index = Index++;
+ ElfHdr.OriginalOffset = ElfHdr.Offset = EhdrOffset;
- const auto &Ehdr = *ElfFile.getHeader();
+ const auto &Ehdr = *HeadersFile.getHeader();
auto &PrHdr = Obj.ProgramHdrSegment;
PrHdr.Type = PT_PHDR;
PrHdr.Flags = 0;
@@ -908,7 +1310,7 @@ template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() {
// Whereas this works automatically for ElfHdr, here OriginalOffset is
// always non-zero and to ensure the equation we assign the same value to
// VAddr as well.
- PrHdr.OriginalOffset = PrHdr.Offset = PrHdr.VAddr = Ehdr.e_phoff;
+ PrHdr.OriginalOffset = PrHdr.Offset = PrHdr.VAddr = EhdrOffset + Ehdr.e_phoff;
PrHdr.PAddr = 0;
PrHdr.FileSize = PrHdr.MemSize = Ehdr.e_phentsize * Ehdr.e_phnum;
// The spec requires us to naturally align all the fields.
@@ -917,7 +1319,7 @@ template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() {
// Now we do an O(n^2) loop through the segments in order to match up
// segments.
- for (auto &Child : Obj.segments())
+ for (Segment &Child : Obj.segments())
setParentSegment(Child);
setParentSegment(ElfHdr);
setParentSegment(PrHdr);
@@ -925,22 +1327,25 @@ template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() {
template <class ELFT>
void ELFBuilder<ELFT>::initGroupSection(GroupSection *GroupSec) {
- auto SecTable = Obj.sections();
+ if (GroupSec->Align % sizeof(ELF::Elf32_Word) != 0)
+ error("invalid alignment " + Twine(GroupSec->Align) + " of group section '" +
+ GroupSec->Name + "'");
+ SectionTableRef SecTable = Obj.sections();
auto SymTab = SecTable.template getSectionOfType<SymbolTableSection>(
GroupSec->Link,
- "Link field value " + Twine(GroupSec->Link) + " in section " +
- GroupSec->Name + " is invalid",
- "Link field value " + Twine(GroupSec->Link) + " in section " +
- GroupSec->Name + " is not a symbol table");
- auto Sym = SymTab->getSymbolByIndex(GroupSec->Info);
+ "link field value '" + Twine(GroupSec->Link) + "' in section '" +
+ GroupSec->Name + "' is invalid",
+ "link field value '" + Twine(GroupSec->Link) + "' in section '" +
+ GroupSec->Name + "' is not a symbol table");
+ Symbol *Sym = SymTab->getSymbolByIndex(GroupSec->Info);
if (!Sym)
- error("Info field value " + Twine(GroupSec->Info) + " in section " +
- GroupSec->Name + " is not a valid symbol index");
+ error("info field value '" + Twine(GroupSec->Info) + "' in section '" +
+ GroupSec->Name + "' is not a valid symbol index");
GroupSec->setSymTab(SymTab);
GroupSec->setSymbol(Sym);
if (GroupSec->Contents.size() % sizeof(ELF::Elf32_Word) ||
GroupSec->Contents.empty())
- error("The content of the section " + GroupSec->Name + " is malformed");
+ error("the content of the section " + GroupSec->Name + " is malformed");
const ELF::Elf32_Word *Word =
reinterpret_cast<const ELF::Elf32_Word *>(GroupSec->Contents.data());
const ELF::Elf32_Word *End =
@@ -949,8 +1354,8 @@ void ELFBuilder<ELFT>::initGroupSection(GroupSection *GroupSec) {
for (; Word != End; ++Word) {
uint32_t Index = support::endian::read32<ELFT::TargetEndianness>(Word);
GroupSec->addMember(SecTable.getSection(
- Index, "Group member index " + Twine(Index) + " in section " +
- GroupSec->Name + " is invalid"));
+ Index, "group member index " + Twine(Index) + " in section '" +
+ GroupSec->Name + "' is invalid"));
}
}
@@ -967,31 +1372,31 @@ void ELFBuilder<ELFT>::initSymbolTable(SymbolTableSection *SymTab) {
if (Sym.st_shndx == SHN_XINDEX) {
if (SymTab->getShndxTable() == nullptr)
- error("Symbol '" + Name +
- "' has index SHN_XINDEX but no SHT_SYMTAB_SHNDX section exists.");
+ error("symbol '" + Name +
+ "' has index SHN_XINDEX but no SHT_SYMTAB_SHNDX section exists");
if (ShndxData.data() == nullptr) {
const Elf_Shdr &ShndxSec =
*unwrapOrError(ElfFile.getSection(SymTab->getShndxTable()->Index));
ShndxData = unwrapOrError(
ElfFile.template getSectionContentsAsArray<Elf_Word>(&ShndxSec));
if (ShndxData.size() != Symbols.size())
- error("Symbol section index table does not have the same number of "
- "entries as the symbol table.");
+ error("symbol section index table does not have the same number of "
+ "entries as the symbol table");
}
Elf_Word Index = ShndxData[&Sym - Symbols.begin()];
DefSection = Obj.sections().getSection(
Index,
- "Symbol '" + Name + "' has invalid section index " + Twine(Index));
+ "symbol '" + Name + "' has invalid section index " + Twine(Index));
} else if (Sym.st_shndx >= SHN_LORESERVE) {
if (!isValidReservedSectionIndex(Sym.st_shndx, Obj.Machine)) {
error(
- "Symbol '" + Name +
+ "symbol '" + Name +
"' has unsupported value greater than or equal to SHN_LORESERVE: " +
Twine(Sym.st_shndx));
}
} else if (Sym.st_shndx != SHN_UNDEF) {
DefSection = Obj.sections().getSection(
- Sym.st_shndx, "Symbol '" + Name +
+ Sym.st_shndx, "symbol '" + Name +
"' is defined has invalid section index " +
Twine(Sym.st_shndx));
}
@@ -1086,7 +1491,8 @@ SectionBase &ELFBuilder<ELFT>::makeSection(const Elf_Shdr &Shdr) {
default: {
Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
- if (isDataGnuCompressed(Data) || (Shdr.sh_flags & ELF::SHF_COMPRESSED)) {
+ StringRef Name = unwrapOrError(ElfFile.getSectionName(&Shdr));
+ if (Name.startswith(".zdebug") || (Shdr.sh_flags & ELF::SHF_COMPRESSED)) {
uint64_t DecompressedSize, DecompressedAlign;
std::tie(DecompressedSize, DecompressedAlign) =
getDecompressedSizeAndAlignment<ELFT>(Data);
@@ -1123,7 +1529,9 @@ template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() {
ArrayRef<uint8_t>(ElfFile.base() + Shdr.sh_offset,
(Shdr.sh_type == SHT_NOBITS) ? 0 : Shdr.sh_size);
}
+}
+template <class ELFT> void ELFBuilder<ELFT>::readSections() {
// If a section index table exists we'll need to initialize it before we
// initialize the symbol table because the symbol table might need to
// reference it.
@@ -1157,11 +1565,34 @@ template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() {
initGroupSection(GroupSec);
}
}
+
+ uint32_t ShstrIndex = ElfFile.getHeader()->e_shstrndx;
+ if (ShstrIndex == SHN_XINDEX)
+ ShstrIndex = unwrapOrError(ElfFile.getSection(0))->sh_link;
+
+ if (ShstrIndex == SHN_UNDEF)
+ Obj.HadShdrs = false;
+ else
+ Obj.SectionNames =
+ Obj.sections().template getSectionOfType<StringTableSection>(
+ ShstrIndex,
+ "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " +
+ " is invalid",
+ "e_shstrndx field value " + Twine(ShstrIndex) + " in elf header " +
+ " is not a string table");
}
template <class ELFT> void ELFBuilder<ELFT>::build() {
- const auto &Ehdr = *ElfFile.getHeader();
+ readSectionHeaders();
+ findEhdrOffset();
+
+ // The ELFFile whose ELF headers and program headers are copied into the
+ // output file. Normally the same as ElfFile, but if we're extracting a
+ // loadable partition it will point to the partition's headers.
+ ELFFile<ELFT> HeadersFile = unwrapOrError(ELFFile<ELFT>::create(toStringRef(
+ {ElfFile.base() + EhdrOffset, ElfFile.getBufSize() - EhdrOffset})));
+ auto &Ehdr = *HeadersFile.getHeader();
Obj.OSABI = Ehdr.e_ident[EI_OSABI];
Obj.ABIVersion = Ehdr.e_ident[EI_ABIVERSION];
Obj.Type = Ehdr.e_type;
@@ -1170,25 +1601,8 @@ template <class ELFT> void ELFBuilder<ELFT>::build() {
Obj.Entry = Ehdr.e_entry;
Obj.Flags = Ehdr.e_flags;
- readSectionHeaders();
- readProgramHeaders();
-
- uint32_t ShstrIndex = Ehdr.e_shstrndx;
- if (ShstrIndex == SHN_XINDEX)
- ShstrIndex = unwrapOrError(ElfFile.getSection(0))->sh_link;
-
- Obj.SectionNames =
- Obj.sections().template getSectionOfType<StringTableSection>(
- ShstrIndex,
- "e_shstrndx field value " + Twine(Ehdr.e_shstrndx) +
- " in elf header " + " is invalid",
- "e_shstrndx field value " + Twine(Ehdr.e_shstrndx) +
- " in elf header " + " is not a string table");
-}
-
-// A generic size function which computes sizes of any random access range.
-template <class R> size_t size(R &&Range) {
- return static_cast<size_t>(std::end(Range) - std::begin(Range));
+ readSections();
+ readProgramHeaders(HeadersFile);
}
Writer::~Writer() {}
@@ -1199,31 +1613,61 @@ std::unique_ptr<Object> BinaryReader::create() const {
return BinaryELFBuilder(MInfo.EMachine, MemBuf).build();
}
+Expected<std::vector<IHexRecord>> IHexReader::parse() const {
+ SmallVector<StringRef, 16> Lines;
+ std::vector<IHexRecord> Records;
+ bool HasSections = false;
+
+ MemBuf->getBuffer().split(Lines, '\n');
+ Records.reserve(Lines.size());
+ for (size_t LineNo = 1; LineNo <= Lines.size(); ++LineNo) {
+ StringRef Line = Lines[LineNo - 1].trim();
+ if (Line.empty())
+ continue;
+
+ Expected<IHexRecord> R = IHexRecord::parse(Line);
+ if (!R)
+ return parseError(LineNo, R.takeError());
+ if (R->Type == IHexRecord::EndOfFile)
+ break;
+ HasSections |= (R->Type == IHexRecord::Data);
+ Records.push_back(*R);
+ }
+ if (!HasSections)
+ return parseError(-1U, "no sections");
+
+ return std::move(Records);
+}
+
+std::unique_ptr<Object> IHexReader::create() const {
+ std::vector<IHexRecord> Records = unwrapOrError(parse());
+ return IHexELFBuilder(Records).build();
+}
+
std::unique_ptr<Object> ELFReader::create() const {
auto Obj = llvm::make_unique<Object>();
if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {
- ELFBuilder<ELF32LE> Builder(*O, *Obj);
+ ELFBuilder<ELF32LE> Builder(*O, *Obj, ExtractPartition);
Builder.build();
return Obj;
} else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) {
- ELFBuilder<ELF64LE> Builder(*O, *Obj);
+ ELFBuilder<ELF64LE> Builder(*O, *Obj, ExtractPartition);
Builder.build();
return Obj;
} else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) {
- ELFBuilder<ELF32BE> Builder(*O, *Obj);
+ ELFBuilder<ELF32BE> Builder(*O, *Obj, ExtractPartition);
Builder.build();
return Obj;
} else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) {
- ELFBuilder<ELF64BE> Builder(*O, *Obj);
+ ELFBuilder<ELF64BE> Builder(*O, *Obj, ExtractPartition);
Builder.build();
return Obj;
}
- error("Invalid file type");
+ error("invalid file type");
}
template <class ELFT> void ELFWriter<ELFT>::writeEhdr() {
- uint8_t *B = Buf.getBufferStart();
- Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(B);
+ Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf.getBufferStart());
std::fill(Ehdr.e_ident, Ehdr.e_ident + 16, 0);
Ehdr.e_ident[EI_MAG0] = 0x7f;
Ehdr.e_ident[EI_MAG1] = 'E';
@@ -1247,7 +1691,7 @@ template <class ELFT> void ELFWriter<ELFT>::writeEhdr() {
Ehdr.e_phentsize = (Ehdr.e_phnum != 0) ? sizeof(Elf_Phdr) : 0;
Ehdr.e_flags = Obj.Flags;
Ehdr.e_ehsize = sizeof(Elf_Ehdr);
- if (WriteSectionHeaders && size(Obj.sections()) != 0) {
+ if (WriteSectionHeaders && Obj.sections().size() != 0) {
Ehdr.e_shentsize = sizeof(Elf_Shdr);
Ehdr.e_shoff = Obj.SHOffset;
// """
@@ -1256,7 +1700,7 @@ template <class ELFT> void ELFWriter<ELFT>::writeEhdr() {
// number of section header table entries is contained in the sh_size field
// of the section header at index 0.
// """
- auto Shnum = size(Obj.sections()) + 1;
+ auto Shnum = Obj.sections().size() + 1;
if (Shnum >= SHN_LORESERVE)
Ehdr.e_shnum = 0;
else
@@ -1285,17 +1729,17 @@ template <class ELFT> void ELFWriter<ELFT>::writePhdrs() {
}
template <class ELFT> void ELFWriter<ELFT>::writeShdrs() {
- uint8_t *B = Buf.getBufferStart() + Obj.SHOffset;
// This reference serves to write the dummy section header at the begining
// of the file. It is not used for anything else
- Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(B);
+ Elf_Shdr &Shdr =
+ *reinterpret_cast<Elf_Shdr *>(Buf.getBufferStart() + Obj.SHOffset);
Shdr.sh_name = 0;
Shdr.sh_type = SHT_NULL;
Shdr.sh_flags = 0;
Shdr.sh_addr = 0;
Shdr.sh_offset = 0;
// See writeEhdr for why we do this.
- uint64_t Shnum = size(Obj.sections()) + 1;
+ uint64_t Shnum = Obj.sections().size() + 1;
if (Shnum >= SHN_LORESERVE)
Shdr.sh_size = Shnum;
else
@@ -1309,16 +1753,44 @@ template <class ELFT> void ELFWriter<ELFT>::writeShdrs() {
Shdr.sh_addralign = 0;
Shdr.sh_entsize = 0;
- for (auto &Sec : Obj.sections())
+ for (SectionBase &Sec : Obj.sections())
writeShdr(Sec);
}
template <class ELFT> void ELFWriter<ELFT>::writeSectionData() {
- for (auto &Sec : Obj.sections())
- Sec.accept(*SecWriter);
+ for (SectionBase &Sec : Obj.sections())
+ // Segments are responsible for writing their contents, so only write the
+ // section data if the section is not in a segment. Note that this renders
+ // sections in segments effectively immutable.
+ if (Sec.ParentSegment == nullptr)
+ Sec.accept(*SecWriter);
+}
+
+template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() {
+ for (Segment &Seg : Obj.segments()) {
+ uint8_t *B = Buf.getBufferStart() + Seg.Offset;
+ assert(Seg.FileSize == Seg.getContents().size() &&
+ "Segment size must match contents size");
+ std::memcpy(B, Seg.getContents().data(), Seg.FileSize);
+ }
+
+ // Iterate over removed sections and overwrite their old data with zeroes.
+ for (auto &Sec : Obj.removedSections()) {
+ Segment *Parent = Sec.ParentSegment;
+ if (Parent == nullptr || Sec.Type == SHT_NOBITS || Sec.Size == 0)
+ continue;
+ uint64_t Offset =
+ Sec.OriginalOffset - Parent->OriginalOffset + Parent->Offset;
+ std::memset(Buf.getBufferStart() + Offset, 0, Sec.Size);
+ }
}
-void Object::removeSections(std::function<bool(const SectionBase &)> ToRemove) {
+template <class ELFT>
+ELFWriter<ELFT>::ELFWriter(Object &Obj, Buffer &Buf, bool WSH)
+ : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs) {}
+
+Error Object::removeSections(bool AllowBrokenLinks,
+ std::function<bool(const SectionBase &)> ToRemove) {
auto Iter = std::stable_partition(
std::begin(Sections), std::end(Sections), [=](const SecPtr &Sec) {
@@ -1339,32 +1811,55 @@ void Object::removeSections(std::function<bool(const SectionBase &)> ToRemove) {
// Now make sure there are no remaining references to the sections that will
// be removed. Sometimes it is impossible to remove a reference so we emit
// an error here instead.
+ std::unordered_set<const SectionBase *> RemoveSections;
+ RemoveSections.reserve(std::distance(Iter, std::end(Sections)));
for (auto &RemoveSec : make_range(Iter, std::end(Sections))) {
for (auto &Segment : Segments)
Segment->removeSection(RemoveSec.get());
- for (auto &KeepSec : make_range(std::begin(Sections), Iter))
- KeepSec->removeSectionReferences(RemoveSec.get());
+ RemoveSections.insert(RemoveSec.get());
}
- // Now finally get rid of them all togethor.
+
+ // For each section that remains alive, we want to remove the dead references.
+ // This either might update the content of the section (e.g. remove symbols
+ // from symbol table that belongs to removed section) or trigger an error if
+ // a live section critically depends on a section being removed somehow
+ // (e.g. the removed section is referenced by a relocation).
+ for (auto &KeepSec : make_range(std::begin(Sections), Iter)) {
+ if (Error E = KeepSec->removeSectionReferences(AllowBrokenLinks,
+ [&RemoveSections](const SectionBase *Sec) {
+ return RemoveSections.find(Sec) != RemoveSections.end();
+ }))
+ return E;
+ }
+
+ // Transfer removed sections into the Object RemovedSections container for use
+ // later.
+ std::move(Iter, Sections.end(), std::back_inserter(RemovedSections));
+ // Now finally get rid of them all together.
Sections.erase(Iter, std::end(Sections));
+ return Error::success();
}
-void Object::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {
- if (!SymbolTable)
- return;
-
- for (const SecPtr &Sec : Sections)
- Sec->removeSymbols(ToRemove);
+Error Object::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {
+ if (SymbolTable)
+ for (const SecPtr &Sec : Sections)
+ if (Error E = Sec->removeSymbols(ToRemove))
+ return E;
+ return Error::success();
}
void Object::sortSections() {
- // Put all sections in offset order. Maintain the ordering as closely as
- // possible while meeting that demand however.
- auto CompareSections = [](const SecPtr &A, const SecPtr &B) {
+ // Use stable_sort to maintain the original ordering as closely as possible.
+ llvm::stable_sort(Sections, [](const SecPtr &A, const SecPtr &B) {
+ // Put SHT_GROUP sections first, since group section headers must come
+ // before the sections they contain. This also matches what GNU objcopy
+ // does.
+ if (A->Type != B->Type &&
+ (A->Type == ELF::SHT_GROUP || B->Type == ELF::SHT_GROUP))
+ return A->Type == ELF::SHT_GROUP;
+ // For all other sections, sort by offset order.
return A->OriginalOffset < B->OriginalOffset;
- };
- std::stable_sort(std::begin(this->Sections), std::end(this->Sections),
- CompareSections);
+ });
}
static uint64_t alignToAddr(uint64_t Offset, uint64_t Addr, uint64_t Align) {
@@ -1382,14 +1877,13 @@ static uint64_t alignToAddr(uint64_t Offset, uint64_t Addr, uint64_t Align) {
// Orders segments such that if x = y->ParentSegment then y comes before x.
static void orderSegments(std::vector<Segment *> &Segments) {
- std::stable_sort(std::begin(Segments), std::end(Segments),
- compareSegmentsByOffset);
+ llvm::stable_sort(Segments, compareSegmentsByOffset);
}
// This function finds a consistent layout for a list of segments starting from
// an Offset. It assumes that Segments have been sorted by OrderSegments and
// returns an Offset one past the end of the last segment.
-static uint64_t LayoutSegments(std::vector<Segment *> &Segments,
+static uint64_t layoutSegments(std::vector<Segment *> &Segments,
uint64_t Offset) {
assert(std::is_sorted(std::begin(Segments), std::end(Segments),
compareSegmentsByOffset));
@@ -1398,20 +1892,20 @@ static uint64_t LayoutSegments(std::vector<Segment *> &Segments,
// then it's acceptable, but not ideal, to simply move it to after the
// segments. So we can simply layout segments one after the other accounting
// for alignment.
- for (auto &Segment : Segments) {
+ for (Segment *Seg : Segments) {
// We assume that segments have been ordered by OriginalOffset and Index
// such that a parent segment will always come before a child segment in
// OrderedSegments. This means that the Offset of the ParentSegment should
// already be set and we can set our offset relative to it.
- if (Segment->ParentSegment != nullptr) {
- auto Parent = Segment->ParentSegment;
- Segment->Offset =
- Parent->Offset + Segment->OriginalOffset - Parent->OriginalOffset;
+ if (Seg->ParentSegment != nullptr) {
+ Segment *Parent = Seg->ParentSegment;
+ Seg->Offset =
+ Parent->Offset + Seg->OriginalOffset - Parent->OriginalOffset;
} else {
- Offset = alignToAddr(Offset, Segment->VAddr, Segment->Align);
- Segment->Offset = Offset;
+ Offset = alignToAddr(Offset, Seg->VAddr, Seg->Align);
+ Seg->Offset = Offset;
}
- Offset = std::max(Offset, Segment->Offset + Segment->FileSize);
+ Offset = std::max(Offset, Seg->Offset + Seg->FileSize);
}
return Offset;
}
@@ -1448,10 +1942,9 @@ static uint64_t layoutSections(Range Sections, uint64_t Offset) {
}
template <class ELFT> void ELFWriter<ELFT>::initEhdrSegment() {
- auto &ElfHdr = Obj.ElfHdrSegment;
+ Segment &ElfHdr = Obj.ElfHdrSegment;
ElfHdr.Type = PT_PHDR;
ElfHdr.Flags = 0;
- ElfHdr.OriginalOffset = ElfHdr.Offset = 0;
ElfHdr.VAddr = 0;
ElfHdr.PAddr = 0;
ElfHdr.FileSize = ElfHdr.MemSize = sizeof(Elf_Ehdr);
@@ -1463,7 +1956,7 @@ template <class ELFT> void ELFWriter<ELFT>::assignOffsets() {
// so that we know that anytime ->ParentSegment is set that segment has
// already had its offset properly set.
std::vector<Segment *> OrderedSegments;
- for (auto &Segment : Obj.segments())
+ for (Segment &Segment : Obj.segments())
OrderedSegments.push_back(&Segment);
OrderedSegments.push_back(&Obj.ElfHdrSegment);
OrderedSegments.push_back(&Obj.ProgramHdrSegment);
@@ -1472,7 +1965,7 @@ template <class ELFT> void ELFWriter<ELFT>::assignOffsets() {
// Since the ELF Header (ElfHdrSegment) must be at the start of the file,
// we start at offset 0.
uint64_t Offset = 0;
- Offset = LayoutSegments(OrderedSegments, Offset);
+ Offset = layoutSegments(OrderedSegments, Offset);
Offset = layoutSections(Obj.sections(), Offset);
// If we need to write the section header table out then we need to align the
// Offset so that SHOffset is valid.
@@ -1484,28 +1977,32 @@ template <class ELFT> void ELFWriter<ELFT>::assignOffsets() {
template <class ELFT> size_t ELFWriter<ELFT>::totalSize() const {
// We already have the section header offset so we can calculate the total
// size by just adding up the size of each section header.
- auto NullSectionSize = WriteSectionHeaders ? sizeof(Elf_Shdr) : 0;
- return Obj.SHOffset + size(Obj.sections()) * sizeof(Elf_Shdr) +
- NullSectionSize;
+ if (!WriteSectionHeaders)
+ return Obj.SHOffset;
+ size_t ShdrCount = Obj.sections().size() + 1; // Includes null shdr.
+ return Obj.SHOffset + ShdrCount * sizeof(Elf_Shdr);
}
-template <class ELFT> void ELFWriter<ELFT>::write() {
+template <class ELFT> Error ELFWriter<ELFT>::write() {
+ // Segment data must be written first, so that the ELF header and program
+ // header tables can overwrite it, if covered by a segment.
+ writeSegmentData();
writeEhdr();
writePhdrs();
writeSectionData();
if (WriteSectionHeaders)
writeShdrs();
- if (auto E = Buf.commit())
- reportError(Buf.getName(), errorToErrorCode(std::move(E)));
+ return Buf.commit();
}
-template <class ELFT> void ELFWriter<ELFT>::finalize() {
+template <class ELFT> Error ELFWriter<ELFT>::finalize() {
// It could happen that SectionNames has been removed and yet the user wants
// a section header table output. We need to throw an error if a user tries
// to do that.
if (Obj.SectionNames == nullptr && WriteSectionHeaders)
- error("Cannot write section header table because section header string "
- "table was removed.");
+ return createStringError(llvm::errc::invalid_argument,
+ "cannot write section header table because "
+ "section header string table was removed");
Obj.sortSections();
@@ -1513,8 +2010,8 @@ template <class ELFT> void ELFWriter<ELFT>::finalize() {
// if we need large indexes or not. We can assign indexes first and check as
// we go to see if we will actully need large indexes.
bool NeedsLargeIndexes = false;
- if (size(Obj.sections()) >= SHN_LORESERVE) {
- auto Sections = Obj.sections();
+ if (Obj.sections().size() >= SHN_LORESERVE) {
+ SectionTableRef Sections = Obj.sections();
NeedsLargeIndexes =
std::any_of(Sections.begin() + SHN_LORESERVE, Sections.end(),
[](const SectionBase &Sec) { return Sec.HasSymbol; });
@@ -1536,9 +2033,12 @@ template <class ELFT> void ELFWriter<ELFT>::finalize() {
// Since we don't need SectionIndexTable we should remove it and all
// references to it.
if (Obj.SectionIndexTable != nullptr) {
- Obj.removeSections([this](const SectionBase &Sec) {
- return &Sec == Obj.SectionIndexTable;
- });
+ // We do not support sections referring to the section index table.
+ if (Error E = Obj.removeSections(false /*AllowBrokenLinks*/,
+ [this](const SectionBase &Sec) {
+ return &Sec == Obj.SectionIndexTable;
+ }))
+ return E;
}
}
@@ -1567,15 +2067,23 @@ template <class ELFT> void ELFWriter<ELFT>::finalize() {
if (Obj.SymbolTable != nullptr)
Obj.SymbolTable->prepareForLayout();
+ // Now that all strings are added we want to finalize string table builders,
+ // because that affects section sizes which in turn affects section offsets.
+ for (SectionBase &Sec : Obj.sections())
+ if (auto StrTab = dyn_cast<StringTableSection>(&Sec))
+ StrTab->prepareForLayout();
+
assignOffsets();
- // Finalize SectionNames first so that we can assign name indexes.
- if (Obj.SectionNames != nullptr)
- Obj.SectionNames->finalize();
+ // layoutSections could have modified section indexes, so we need
+ // to fill the index table after assignOffsets.
+ if (Obj.SymbolTable != nullptr)
+ Obj.SymbolTable->fillShndxTable();
+
// Finally now that all offsets and indexes have been set we can finalize any
// remaining issues.
uint64_t Offset = Obj.SHOffset + sizeof(Elf_Shdr);
- for (auto &Section : Obj.sections()) {
+ for (SectionBase &Section : Obj.sections()) {
Section.HeaderOffset = Offset;
Offset += sizeof(Elf_Shdr);
if (WriteSectionHeaders)
@@ -1583,21 +2091,20 @@ template <class ELFT> void ELFWriter<ELFT>::finalize() {
Section.finalize();
}
- Buf.allocate(totalSize());
+ if (Error E = Buf.allocate(totalSize()))
+ return E;
SecWriter = llvm::make_unique<ELFSectionWriter<ELFT>>(Buf);
+ return Error::success();
}
-void BinaryWriter::write() {
- for (auto &Section : Obj.sections()) {
- if ((Section.Flags & SHF_ALLOC) == 0)
- continue;
- Section.accept(*SecWriter);
- }
- if (auto E = Buf.commit())
- reportError(Buf.getName(), errorToErrorCode(std::move(E)));
+Error BinaryWriter::write() {
+ for (auto &Section : Obj.sections())
+ if (Section.Flags & SHF_ALLOC)
+ Section.accept(*SecWriter);
+ return Buf.commit();
}
-void BinaryWriter::finalize() {
+Error BinaryWriter::finalize() {
// TODO: Create a filter range to construct OrderedSegments from so that this
// code can be deduped with assignOffsets above. This should also solve the
// todo below for LayoutSections.
@@ -1606,11 +2113,9 @@ void BinaryWriter::finalize() {
// already had it's offset properly set. We only want to consider the segments
// that will affect layout of allocated sections so we only add those.
std::vector<Segment *> OrderedSegments;
- for (auto &Section : Obj.sections()) {
- if ((Section.Flags & SHF_ALLOC) != 0 && Section.ParentSegment != nullptr) {
+ for (SectionBase &Section : Obj.sections())
+ if ((Section.Flags & SHF_ALLOC) != 0 && Section.ParentSegment != nullptr)
OrderedSegments.push_back(Section.ParentSegment);
- }
- }
// For binary output, we're going to use physical addresses instead of
// virtual addresses, since a binary output is used for cases like ROM
@@ -1622,8 +2127,7 @@ void BinaryWriter::finalize() {
for (Segment *Seg : OrderedSegments)
Seg->PAddr = Seg->VAddr;
- std::stable_sort(std::begin(OrderedSegments), std::end(OrderedSegments),
- compareSegmentsByPAddr);
+ llvm::stable_sort(OrderedSegments, compareSegmentsByPAddr);
// Because we add a ParentSegment for each section we might have duplicate
// segments in OrderedSegments. If there were duplicates then LayoutSegments
@@ -1638,8 +2142,8 @@ void BinaryWriter::finalize() {
// our layout algorithm to proceed as expected while not writing out the gap
// at the start.
if (!OrderedSegments.empty()) {
- auto Seg = OrderedSegments[0];
- auto Sec = Seg->firstSection();
+ Segment *Seg = OrderedSegments[0];
+ const SectionBase *Sec = Seg->firstSection();
auto Diff = Sec->OriginalOffset - Seg->OriginalOffset;
Seg->OriginalOffset += Diff;
// The size needs to be shrunk as well.
@@ -1648,7 +2152,7 @@ void BinaryWriter::finalize() {
// section.
Seg->PAddr += Diff;
uint64_t LowestPAddr = Seg->PAddr;
- for (auto &Segment : OrderedSegments) {
+ for (Segment *Segment : OrderedSegments) {
Segment->Offset = Segment->PAddr - LowestPAddr;
Offset = std::max(Offset, Segment->Offset + Segment->FileSize);
}
@@ -1659,11 +2163,9 @@ void BinaryWriter::finalize() {
// not hold. Then pass such a range to LayoutSections instead of constructing
// AllocatedSections here.
std::vector<SectionBase *> AllocatedSections;
- for (auto &Section : Obj.sections()) {
- if ((Section.Flags & SHF_ALLOC) == 0)
- continue;
- AllocatedSections.push_back(&Section);
- }
+ for (SectionBase &Section : Obj.sections())
+ if (Section.Flags & SHF_ALLOC)
+ AllocatedSections.push_back(&Section);
layoutSections(make_pointee_range(AllocatedSections), Offset);
// Now that every section has been laid out we just need to compute the total
@@ -1671,13 +2173,117 @@ void BinaryWriter::finalize() {
// LayoutSections, because we want to truncate the last segment to the end of
// its last section, to match GNU objcopy's behaviour.
TotalSize = 0;
- for (const auto &Section : AllocatedSections) {
+ for (SectionBase *Section : AllocatedSections)
if (Section->Type != SHT_NOBITS)
TotalSize = std::max(TotalSize, Section->Offset + Section->Size);
- }
- Buf.allocate(TotalSize);
+ if (Error E = Buf.allocate(TotalSize))
+ return E;
SecWriter = llvm::make_unique<BinarySectionWriter>(Buf);
+ return Error::success();
+}
+
+bool IHexWriter::SectionCompare::operator()(const SectionBase *Lhs,
+ const SectionBase *Rhs) const {
+ return (sectionPhysicalAddr(Lhs) & 0xFFFFFFFFU) <
+ (sectionPhysicalAddr(Rhs) & 0xFFFFFFFFU);
+}
+
+uint64_t IHexWriter::writeEntryPointRecord(uint8_t *Buf) {
+ IHexLineData HexData;
+ uint8_t Data[4] = {};
+ // We don't write entry point record if entry is zero.
+ if (Obj.Entry == 0)
+ return 0;
+
+ if (Obj.Entry <= 0xFFFFFU) {
+ Data[0] = ((Obj.Entry & 0xF0000U) >> 12) & 0xFF;
+ support::endian::write(&Data[2], static_cast<uint16_t>(Obj.Entry),
+ support::big);
+ HexData = IHexRecord::getLine(IHexRecord::StartAddr80x86, 0, Data);
+ } else {
+ support::endian::write(Data, static_cast<uint32_t>(Obj.Entry),
+ support::big);
+ HexData = IHexRecord::getLine(IHexRecord::StartAddr, 0, Data);
+ }
+ memcpy(Buf, HexData.data(), HexData.size());
+ return HexData.size();
+}
+
+uint64_t IHexWriter::writeEndOfFileRecord(uint8_t *Buf) {
+ IHexLineData HexData = IHexRecord::getLine(IHexRecord::EndOfFile, 0, {});
+ memcpy(Buf, HexData.data(), HexData.size());
+ return HexData.size();
+}
+
+Error IHexWriter::write() {
+ IHexSectionWriter Writer(Buf);
+ // Write sections.
+ for (const SectionBase *Sec : Sections)
+ Sec->accept(Writer);
+
+ uint64_t Offset = Writer.getBufferOffset();
+ // Write entry point address.
+ Offset += writeEntryPointRecord(Buf.getBufferStart() + Offset);
+ // Write EOF.
+ Offset += writeEndOfFileRecord(Buf.getBufferStart() + Offset);
+ assert(Offset == TotalSize);
+ return Buf.commit();
+}
+
+Error IHexWriter::checkSection(const SectionBase &Sec) {
+ uint64_t Addr = sectionPhysicalAddr(&Sec);
+ if (addressOverflows32bit(Addr) || addressOverflows32bit(Addr + Sec.Size - 1))
+ return createStringError(
+ errc::invalid_argument,
+ "Section '%s' address range [0x%llx, 0x%llx] is not 32 bit", Sec.Name.c_str(),
+ Addr, Addr + Sec.Size - 1);
+ return Error::success();
+}
+
+Error IHexWriter::finalize() {
+ bool UseSegments = false;
+ auto ShouldWrite = [](const SectionBase &Sec) {
+ return (Sec.Flags & ELF::SHF_ALLOC) && (Sec.Type != ELF::SHT_NOBITS);
+ };
+ auto IsInPtLoad = [](const SectionBase &Sec) {
+ return Sec.ParentSegment && Sec.ParentSegment->Type == ELF::PT_LOAD;
+ };
+
+ // We can't write 64-bit addresses.
+ if (addressOverflows32bit(Obj.Entry))
+ return createStringError(errc::invalid_argument,
+ "Entry point address 0x%llx overflows 32 bits.",
+ Obj.Entry);
+
+ // If any section we're to write has segment then we
+ // switch to using physical addresses. Otherwise we
+ // use section virtual address.
+ for (auto &Section : Obj.sections())
+ if (ShouldWrite(Section) && IsInPtLoad(Section)) {
+ UseSegments = true;
+ break;
+ }
+
+ for (auto &Section : Obj.sections())
+ if (ShouldWrite(Section) && (!UseSegments || IsInPtLoad(Section))) {
+ if (Error E = checkSection(Section))
+ return E;
+ Sections.insert(&Section);
+ }
+
+ IHexSectionWriterBase LengthCalc(Buf);
+ for (const SectionBase *Sec : Sections)
+ Sec->accept(LengthCalc);
+
+ // We need space to write section records + StartAddress record
+ // (if start adress is not zero) + EndOfFile record.
+ TotalSize = LengthCalc.getBufferOffset() +
+ (Obj.Entry ? IHexRecord::getLineLength(4) : 0) +
+ IHexRecord::getLineLength(0);
+ if (Error E = Buf.allocate(TotalSize))
+ return E;
+ return Error::success();
}
template class ELFBuilder<ELF64LE>;
diff --git a/contrib/llvm/tools/llvm-objcopy/ELF/Object.h b/contrib/llvm/tools/llvm-objcopy/ELF/Object.h
index e5730cd543ee..f3df93b9662f 100644
--- a/contrib/llvm/tools/llvm-objcopy/ELF/Object.h
+++ b/contrib/llvm/tools/llvm-objcopy/ELF/Object.h
@@ -1,9 +1,8 @@
//===- Object.h -------------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -18,8 +17,8 @@
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/Errc.h"
#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/JamCRC.h"
#include <cstddef>
#include <cstdint>
#include <functional>
@@ -60,6 +59,7 @@ public:
iterator begin() { return iterator(Sections.data()); }
iterator end() { return iterator(Sections.data() + Sections.size()); }
+ size_t size() const { return Sections.size(); }
SectionBase *getSection(uint32_t Index, Twine ErrMsg);
@@ -108,7 +108,7 @@ protected:
Buffer &Out;
public:
- virtual ~SectionWriter(){};
+ virtual ~SectionWriter() = default;
void visit(const Section &Sec) override;
void visit(const OwnedDataSection &Sec) override;
@@ -169,6 +169,8 @@ public:
#define MAKE_SEC_WRITER_FRIEND \
friend class SectionWriter; \
+ friend class IHexSectionWriterBase; \
+ friend class IHexSectionWriter; \
template <class ELFT> friend class ELFSectionWriter; \
template <class ELFT> friend class ELFSectionSizer;
@@ -187,6 +189,118 @@ public:
explicit BinarySectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
};
+using IHexLineData = SmallVector<char, 64>;
+
+struct IHexRecord {
+ // Memory address of the record.
+ uint16_t Addr;
+ // Record type (see below).
+ uint16_t Type;
+ // Record data in hexadecimal form.
+ StringRef HexData;
+
+ // Helper method to get file length of the record
+ // including newline character
+ static size_t getLength(size_t DataSize) {
+ // :LLAAAATT[DD...DD]CC'
+ return DataSize * 2 + 11;
+ }
+
+ // Gets length of line in a file (getLength + CRLF).
+ static size_t getLineLength(size_t DataSize) {
+ return getLength(DataSize) + 2;
+ }
+
+ // Given type, address and data returns line which can
+ // be written to output file.
+ static IHexLineData getLine(uint8_t Type, uint16_t Addr,
+ ArrayRef<uint8_t> Data);
+
+ // Parses the line and returns record if possible.
+ // Line should be trimmed from whitespace characters.
+ static Expected<IHexRecord> parse(StringRef Line);
+
+ // Calculates checksum of stringified record representation
+ // S must NOT contain leading ':' and trailing whitespace
+ // characters
+ static uint8_t getChecksum(StringRef S);
+
+ enum Type {
+ // Contains data and a 16-bit starting address for the data.
+ // The byte count specifies number of data bytes in the record.
+ Data = 0,
+ // Must occur exactly once per file in the last line of the file.
+ // The data field is empty (thus byte count is 00) and the address
+ // field is typically 0000.
+ EndOfFile = 1,
+ // The data field contains a 16-bit segment base address (thus byte
+ // count is always 02) compatible with 80x86 real mode addressing.
+ // The address field (typically 0000) is ignored. The segment address
+ // from the most recent 02 record is multiplied by 16 and added to each
+ // subsequent data record address to form the physical starting address
+ // for the data. This allows addressing up to one megabyte of address
+ // space.
+ SegmentAddr = 2,
+ // or 80x86 processors, specifies the initial content of the CS:IP
+ // registers. The address field is 0000, the byte count is always 04,
+ // the first two data bytes are the CS value, the latter two are the
+ // IP value.
+ StartAddr80x86 = 3,
+ // Allows for 32 bit addressing (up to 4GiB). The record's address field
+ // is ignored (typically 0000) and its byte count is always 02. The two
+ // data bytes (big endian) specify the upper 16 bits of the 32 bit
+ // absolute address for all subsequent type 00 records
+ ExtendedAddr = 4,
+ // The address field is 0000 (not used) and the byte count is always 04.
+ // The four data bytes represent a 32-bit address value. In the case of
+ // 80386 and higher CPUs, this address is loaded into the EIP register.
+ StartAddr = 5,
+ // We have no other valid types
+ InvalidType = 6
+ };
+};
+
+// Base class for IHexSectionWriter. This class implements writing algorithm,
+// but doesn't actually write records. It is used for output buffer size
+// calculation in IHexWriter::finalize.
+class IHexSectionWriterBase : public BinarySectionWriter {
+ // 20-bit segment address
+ uint32_t SegmentAddr = 0;
+ // Extended linear address
+ uint32_t BaseAddr = 0;
+
+ // Write segment address corresponding to 'Addr'
+ uint64_t writeSegmentAddr(uint64_t Addr);
+ // Write extended linear (base) address corresponding to 'Addr'
+ uint64_t writeBaseAddr(uint64_t Addr);
+
+protected:
+ // Offset in the output buffer
+ uint64_t Offset = 0;
+
+ void writeSection(const SectionBase *Sec, ArrayRef<uint8_t> Data);
+ virtual void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data);
+
+public:
+ explicit IHexSectionWriterBase(Buffer &Buf) : BinarySectionWriter(Buf) {}
+
+ uint64_t getBufferOffset() const { return Offset; }
+ void visit(const Section &Sec) final;
+ void visit(const OwnedDataSection &Sec) final;
+ void visit(const StringTableSection &Sec) override;
+ void visit(const DynamicRelocationSection &Sec) final;
+ using BinarySectionWriter::visit;
+};
+
+// Real IHEX section writer
+class IHexSectionWriter : public IHexSectionWriterBase {
+public:
+ IHexSectionWriter(Buffer &Buf) : IHexSectionWriterBase(Buf) {}
+
+ void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data) override;
+ void visit(const StringTableSection &Sec) override;
+};
+
class Writer {
protected:
Object &Obj;
@@ -194,8 +308,8 @@ protected:
public:
virtual ~Writer();
- virtual void finalize() = 0;
- virtual void write() = 0;
+ virtual Error finalize() = 0;
+ virtual Error write() = 0;
Writer(Object &O, Buffer &B) : Obj(O), Buf(B) {}
};
@@ -216,6 +330,7 @@ private:
void writePhdrs();
void writeShdrs();
void writeSectionData();
+ void writeSegmentData();
void assignOffsets();
@@ -225,12 +340,11 @@ private:
public:
virtual ~ELFWriter() {}
- bool WriteSectionHeaders = true;
+ bool WriteSectionHeaders;
- void finalize() override;
- void write() override;
- ELFWriter(Object &Obj, Buffer &Buf, bool WSH)
- : Writer(Obj, Buf), WriteSectionHeaders(WSH) {}
+ Error finalize() override;
+ Error write() override;
+ ELFWriter(Object &Obj, Buffer &Buf, bool WSH);
};
class BinaryWriter : public Writer {
@@ -241,11 +355,30 @@ private:
public:
~BinaryWriter() {}
- void finalize() override;
- void write() override;
+ Error finalize() override;
+ Error write() override;
BinaryWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}
};
+class IHexWriter : public Writer {
+ struct SectionCompare {
+ bool operator()(const SectionBase *Lhs, const SectionBase *Rhs) const;
+ };
+
+ std::set<const SectionBase *, SectionCompare> Sections;
+ size_t TotalSize;
+
+ Error checkSection(const SectionBase &Sec);
+ uint64_t writeEntryPointRecord(uint8_t *Buf);
+ uint64_t writeEndOfFileRecord(uint8_t *Buf);
+
+public:
+ ~IHexWriter() {}
+ Error finalize() override;
+ Error write() override;
+ IHexWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}
+};
+
class SectionBase {
public:
std::string Name;
@@ -274,11 +407,16 @@ public:
virtual void initialize(SectionTableRef SecTable);
virtual void finalize();
- virtual void removeSectionReferences(const SectionBase *Sec);
- virtual void removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
+ // Remove references to these sections. The list of sections must be sorted.
+ virtual Error
+ removeSectionReferences(bool AllowBrokenLinks,
+ function_ref<bool(const SectionBase *)> ToRemove);
+ virtual Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
virtual void accept(SectionVisitor &Visitor) const = 0;
virtual void accept(MutableSectionVisitor &Visitor) = 0;
virtual void markSymbols();
+ virtual void
+ replaceSectionReferences(const DenseMap<SectionBase *, SectionBase *> &);
};
class Segment {
@@ -322,6 +460,8 @@ public:
void removeSection(const SectionBase *Sec) { Sections.erase(Sec); }
void addSection(const SectionBase *Sec) { Sections.insert(Sec); }
+
+ ArrayRef<uint8_t> getContents() const { return Contents; }
};
class Section : public SectionBase {
@@ -335,7 +475,8 @@ public:
void accept(SectionVisitor &Visitor) const override;
void accept(MutableSectionVisitor &Visitor) override;
- void removeSectionReferences(const SectionBase *Sec) override;
+ Error removeSectionReferences(bool AllowBrokenLinks,
+ function_ref<bool(const SectionBase *)> ToRemove) override;
void initialize(SectionTableRef SecTable) override;
void finalize() override;
};
@@ -354,6 +495,16 @@ public:
OriginalOffset = std::numeric_limits<uint64_t>::max();
}
+ OwnedDataSection(const Twine &SecName, uint64_t SecAddr, uint64_t SecFlags,
+ uint64_t SecOff) {
+ Name = SecName.str();
+ Type = ELF::SHT_PROGBITS;
+ Addr = SecAddr;
+ Flags = SecFlags;
+ OriginalOffset = SecOff;
+ }
+
+ void appendHexData(StringRef HexData);
void accept(SectionVisitor &Sec) const override;
void accept(MutableSectionVisitor &Visitor) override;
};
@@ -421,7 +572,7 @@ public:
void addString(StringRef Name);
uint32_t findIndex(StringRef Name) const;
- void finalize() override;
+ void prepareForLayout();
void accept(SectionVisitor &Visitor) const override;
void accept(MutableSectionVisitor &Visitor) override;
@@ -440,10 +591,15 @@ enum SymbolShndxType {
SYMBOL_SIMPLE_INDEX = 0,
SYMBOL_ABS = ELF::SHN_ABS,
SYMBOL_COMMON = ELF::SHN_COMMON,
+ SYMBOL_LOPROC = ELF::SHN_LOPROC,
+ SYMBOL_AMDGPU_LDS = ELF::SHN_AMDGPU_LDS,
SYMBOL_HEXAGON_SCOMMON = ELF::SHN_HEXAGON_SCOMMON,
SYMBOL_HEXAGON_SCOMMON_2 = ELF::SHN_HEXAGON_SCOMMON_2,
SYMBOL_HEXAGON_SCOMMON_4 = ELF::SHN_HEXAGON_SCOMMON_4,
SYMBOL_HEXAGON_SCOMMON_8 = ELF::SHN_HEXAGON_SCOMMON_8,
+ SYMBOL_HIPROC = ELF::SHN_HIPROC,
+ SYMBOL_LOOS = ELF::SHN_LOOS,
+ SYMBOL_HIOS = ELF::SHN_HIOS,
SYMBOL_XINDEX = ELF::SHN_XINDEX,
};
@@ -474,9 +630,14 @@ private:
public:
virtual ~SectionIndexSection() {}
void addIndex(uint32_t Index) {
- Indexes.push_back(Index);
- Size += 4;
+ assert(Size > 0);
+ Indexes.push_back(Index);
}
+
+ void reserve(size_t NumSymbols) {
+ Indexes.reserve(NumSymbols);
+ Size = NumSymbols * 4;
+ }
void setSymTab(SymbolTableSection *SymTab) { Symbols = SymTab; }
void initialize(SectionTableRef SecTable) override;
void finalize() override;
@@ -509,7 +670,7 @@ public:
void addSymbol(Twine Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn,
uint64_t Value, uint8_t Visibility, uint16_t Shndx,
- uint64_t Size);
+ uint64_t SymbolSize);
void prepareForLayout();
// An 'empty' symbol table still contains a null symbol.
bool empty() const { return Symbols.size() == 1; }
@@ -517,17 +678,21 @@ public:
SectionIndexTable = ShndxTable;
}
const SectionIndexSection *getShndxTable() const { return SectionIndexTable; }
+ void fillShndxTable();
const SectionBase *getStrTab() const { return SymbolNames; }
const Symbol *getSymbolByIndex(uint32_t Index) const;
Symbol *getSymbolByIndex(uint32_t Index);
void updateSymbols(function_ref<void(Symbol &)> Callable);
- void removeSectionReferences(const SectionBase *Sec) override;
+ Error removeSectionReferences(bool AllowBrokenLinks,
+ function_ref<bool(const SectionBase *)> ToRemove) override;
void initialize(SectionTableRef SecTable) override;
void finalize() override;
void accept(SectionVisitor &Visitor) const override;
void accept(MutableSectionVisitor &Visitor) override;
- void removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
+ Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
+ void replaceSectionReferences(
+ const DenseMap<SectionBase *, SectionBase *> &FromTo) override;
static bool classof(const SectionBase *S) {
return S->Type == ELF::SHT_SYMTAB;
@@ -567,14 +732,14 @@ public:
// that code between the two symbol table types.
template <class SymTabType>
class RelocSectionWithSymtabBase : public RelocationSectionBase {
- SymTabType *Symbols = nullptr;
void setSymTab(SymTabType *SymTab) { Symbols = SymTab; }
protected:
RelocSectionWithSymtabBase() = default;
+ SymTabType *Symbols = nullptr;
+
public:
- void removeSectionReferences(const SectionBase *Sec) override;
void initialize(SectionTableRef SecTable) override;
void finalize() override;
};
@@ -589,8 +754,12 @@ public:
void addRelocation(Relocation Rel) { Relocations.push_back(Rel); }
void accept(SectionVisitor &Visitor) const override;
void accept(MutableSectionVisitor &Visitor) override;
- void removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
+ Error removeSectionReferences(bool AllowBrokenLinks,
+ function_ref<bool(const SectionBase *)> ToRemove) override;
+ Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
void markSymbols() override;
+ void replaceSectionReferences(
+ const DenseMap<SectionBase *, SectionBase *> &FromTo) override;
static bool classof(const SectionBase *S) {
if (S->Flags & ELF::SHF_ALLOC)
@@ -624,8 +793,10 @@ public:
void accept(SectionVisitor &) const override;
void accept(MutableSectionVisitor &Visitor) override;
void finalize() override;
- void removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
+ Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
void markSymbols() override;
+ void replaceSectionReferences(
+ const DenseMap<SectionBase *, SectionBase *> &FromTo) override;
static bool classof(const SectionBase *S) {
return S->Type == ELF::SHT_GROUP;
@@ -662,6 +833,9 @@ public:
void accept(SectionVisitor &) const override;
void accept(MutableSectionVisitor &Visitor) override;
+ Error removeSectionReferences(
+ bool AllowBrokenLinks,
+ function_ref<bool(const SectionBase *)> ToRemove) override;
static bool classof(const SectionBase *S) {
if (!(S->Flags & ELF::SHF_ALLOC))
@@ -677,11 +851,11 @@ private:
StringRef FileName;
uint32_t CRC32;
- void init(StringRef File, StringRef Data);
+ void init(StringRef File);
public:
// If we add this section from an external source we can use this ctor.
- explicit GnuDebugLinkSection(StringRef File);
+ explicit GnuDebugLinkSection(StringRef File, uint32_t PrecomputedCRC);
void accept(SectionVisitor &Visitor) const override;
void accept(MutableSectionVisitor &Visitor) override;
};
@@ -697,21 +871,41 @@ using object::ELFFile;
using object::ELFObjectFile;
using object::OwningBinary;
-class BinaryELFBuilder {
+class BasicELFBuilder {
+protected:
uint16_t EMachine;
- MemoryBuffer *MemBuf;
std::unique_ptr<Object> Obj;
void initFileHeader();
void initHeaderSegment();
StringTableSection *addStrTab();
SymbolTableSection *addSymTab(StringTableSection *StrTab);
- void addData(SymbolTableSection *SymTab);
void initSections();
public:
+ BasicELFBuilder(uint16_t EM)
+ : EMachine(EM), Obj(llvm::make_unique<Object>()) {}
+};
+
+class BinaryELFBuilder : public BasicELFBuilder {
+ MemoryBuffer *MemBuf;
+ void addData(SymbolTableSection *SymTab);
+
+public:
BinaryELFBuilder(uint16_t EM, MemoryBuffer *MB)
- : EMachine(EM), MemBuf(MB), Obj(llvm::make_unique<Object>()) {}
+ : BasicELFBuilder(EM), MemBuf(MB) {}
+
+ std::unique_ptr<Object> build();
+};
+
+class IHexELFBuilder : public BasicELFBuilder {
+ const std::vector<IHexRecord> &Records;
+
+ void addDataSections();
+
+public:
+ IHexELFBuilder(const std::vector<IHexRecord> &Records)
+ : BasicELFBuilder(ELF::EM_386), Records(Records) {}
std::unique_ptr<Object> build();
};
@@ -724,17 +918,23 @@ private:
const ELFFile<ELFT> &ElfFile;
Object &Obj;
+ size_t EhdrOffset = 0;
+ Optional<StringRef> ExtractPartition;
void setParentSegment(Segment &Child);
- void readProgramHeaders();
+ void readProgramHeaders(const ELFFile<ELFT> &HeadersFile);
void initGroupSection(GroupSection *GroupSec);
void initSymbolTable(SymbolTableSection *SymTab);
void readSectionHeaders();
+ void readSections();
+ void findEhdrOffset();
SectionBase &makeSection(const Elf_Shdr &Shdr);
public:
- ELFBuilder(const ELFObjectFile<ELFT> &ElfObj, Object &Obj)
- : ElfFile(*ElfObj.getELFFile()), Obj(Obj) {}
+ ELFBuilder(const ELFObjectFile<ELFT> &ElfObj, Object &Obj,
+ Optional<StringRef> ExtractPartition)
+ : ElfFile(*ElfObj.getELFFile()), Obj(Obj),
+ ExtractPartition(ExtractPartition) {}
void build();
};
@@ -749,12 +949,36 @@ public:
std::unique_ptr<Object> create() const override;
};
+class IHexReader : public Reader {
+ MemoryBuffer *MemBuf;
+
+ Expected<std::vector<IHexRecord>> parse() const;
+ Error parseError(size_t LineNo, Error E) const {
+ return LineNo == -1U
+ ? createFileError(MemBuf->getBufferIdentifier(), std::move(E))
+ : createFileError(MemBuf->getBufferIdentifier(), LineNo,
+ std::move(E));
+ }
+ template <typename... Ts>
+ Error parseError(size_t LineNo, char const *Fmt, const Ts &... Vals) const {
+ Error E = createStringError(errc::invalid_argument, Fmt, Vals...);
+ return parseError(LineNo, std::move(E));
+ }
+
+public:
+ IHexReader(MemoryBuffer *MB) : MemBuf(MB) {}
+
+ std::unique_ptr<Object> create() const override;
+};
+
class ELFReader : public Reader {
Binary *Bin;
+ Optional<StringRef> ExtractPartition;
public:
std::unique_ptr<Object> create() const override;
- explicit ELFReader(Binary *B) : Bin(B) {}
+ explicit ELFReader(Binary *B, Optional<StringRef> ExtractPartition)
+ : Bin(B), ExtractPartition(ExtractPartition) {}
};
class Object {
@@ -764,6 +988,7 @@ private:
std::vector<SecPtr> Sections;
std::vector<SegPtr> Segments;
+ std::vector<SecPtr> RemovedSections;
public:
template <class T>
@@ -792,6 +1017,7 @@ public:
uint32_t Version;
uint32_t Flags;
+ bool HadShdrs = true;
StringTableSection *SectionNames = nullptr;
SymbolTableSection *SymbolTable = nullptr;
SectionIndexSection *SectionIndexTable = nullptr;
@@ -801,11 +1027,19 @@ public:
ConstRange<SectionBase> sections() const {
return make_pointee_range(Sections);
}
+ SectionBase *findSection(StringRef Name) {
+ auto SecIt =
+ find_if(Sections, [&](const SecPtr &Sec) { return Sec->Name == Name; });
+ return SecIt == Sections.end() ? nullptr : SecIt->get();
+ }
+ SectionTableRef removedSections() { return SectionTableRef(RemovedSections); }
+
Range<Segment> segments() { return make_pointee_range(Segments); }
ConstRange<Segment> segments() const { return make_pointee_range(Segments); }
- void removeSections(std::function<bool(const SectionBase &)> ToRemove);
- void removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
+ Error removeSections(bool AllowBrokenLinks,
+ std::function<bool(const SectionBase &)> ToRemove);
+ Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
template <class T, class... Ts> T &addSection(Ts &&... Args) {
auto Sec = llvm::make_unique<T>(std::forward<Ts>(Args)...);
auto Ptr = Sec.get();
diff --git a/contrib/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/contrib/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
new file mode 100644
index 000000000000..19343b65dd1e
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
@@ -0,0 +1,68 @@
+//===- MachOObjcopy.cpp -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachOObjcopy.h"
+#include "../CopyConfig.h"
+#include "MachOReader.h"
+#include "MachOWriter.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace objcopy {
+namespace macho {
+
+using namespace object;
+
+static Error handleArgs(const CopyConfig &Config, Object &Obj) {
+ if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() ||
+ Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
+ !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() ||
+ !Config.AllocSectionsPrefix.empty() || !Config.AddSection.empty() ||
+ !Config.DumpSection.empty() || !Config.KeepSection.empty() ||
+ !Config.OnlySection.empty() || !Config.SymbolsToGlobalize.empty() ||
+ !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() ||
+ !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() ||
+ !Config.SectionsToRename.empty() || !Config.SymbolsToRename.empty() ||
+ !Config.UnneededSymbolsToRemove.empty() ||
+ !Config.SetSectionFlags.empty() || !Config.ToRemove.empty() ||
+ Config.ExtractDWO || Config.KeepFileSymbols || Config.LocalizeHidden ||
+ Config.PreserveDates || Config.StripDWO || Config.StripNonAlloc ||
+ Config.StripSections || Config.Weaken || Config.DecompressDebugSections ||
+ Config.StripDebug || Config.StripNonAlloc || Config.StripSections ||
+ Config.StripUnneeded || Config.DiscardMode != DiscardType::None ||
+ !Config.SymbolsToAdd.empty() || Config.EntryExpr) {
+ return createStringError(llvm::errc::invalid_argument,
+ "option not supported by llvm-objcopy for MachO");
+ }
+
+ return Error::success();
+}
+
+Error executeObjcopyOnBinary(const CopyConfig &Config,
+ object::MachOObjectFile &In, Buffer &Out) {
+ MachOReader Reader(In);
+ std::unique_ptr<Object> O = Reader.create();
+ if (!O)
+ return createFileError(
+ Config.InputFilename,
+ createStringError(object_error::parse_failed,
+ "unable to deserialize MachO object"));
+
+ if (Error E = handleArgs(Config, *O))
+ return createFileError(Config.InputFilename, std::move(E));
+
+ MachOWriter Writer(*O, In.is64Bit(), In.isLittleEndian(), Out);
+ if (auto E = Writer.finalize())
+ return E;
+ return Writer.write();
+}
+
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h b/contrib/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h
new file mode 100644
index 000000000000..f34e361db7ea
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h
@@ -0,0 +1,31 @@
+//===- MachOObjcopy.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_OBJCOPY_MACHOOBJCOPY_H
+#define LLVM_TOOLS_OBJCOPY_MACHOOBJCOPY_H
+
+namespace llvm {
+class Error;
+
+namespace object {
+class MachOObjectFile;
+class MachOUniversalBinary;
+} // end namespace object
+
+namespace objcopy {
+struct CopyConfig;
+class Buffer;
+
+namespace macho {
+Error executeObjcopyOnBinary(const CopyConfig &Config,
+ object::MachOObjectFile &In, Buffer &Out);
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_MACHOOBJCOPY_H
diff --git a/contrib/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp b/contrib/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp
new file mode 100644
index 000000000000..d31293034608
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp
@@ -0,0 +1,241 @@
+//===- MachOReader.cpp ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachOReader.h"
+#include "../llvm-objcopy.h"
+#include "Object.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Object/MachO.h"
+#include <memory>
+
+namespace llvm {
+namespace objcopy {
+namespace macho {
+
+void MachOReader::readHeader(Object &O) const {
+ O.Header.Magic = MachOObj.getHeader().magic;
+ O.Header.CPUType = MachOObj.getHeader().cputype;
+ O.Header.CPUSubType = MachOObj.getHeader().cpusubtype;
+ O.Header.FileType = MachOObj.getHeader().filetype;
+ O.Header.NCmds = MachOObj.getHeader().ncmds;
+ O.Header.SizeOfCmds = MachOObj.getHeader().sizeofcmds;
+ O.Header.Flags = MachOObj.getHeader().flags;
+}
+
+template <typename SectionType>
+Section constructSectionCommon(SectionType Sec) {
+ Section S;
+ S.Sectname =
+ StringRef(Sec.sectname, strnlen(Sec.sectname, sizeof(Sec.sectname)))
+ .str();
+ S.Segname =
+ StringRef(Sec.segname, strnlen(Sec.segname, sizeof(Sec.sectname))).str();
+ S.Addr = Sec.addr;
+ S.Size = Sec.size;
+ S.Offset = Sec.offset;
+ S.Align = Sec.align;
+ S.RelOff = Sec.reloff;
+ S.NReloc = Sec.nreloc;
+ S.Flags = Sec.flags;
+ S.Reserved1 = Sec.reserved1;
+ S.Reserved2 = Sec.reserved2;
+ S.Reserved3 = 0;
+ return S;
+}
+
+template <typename SectionType> Section constructSection(SectionType Sec);
+
+template <> Section constructSection(MachO::section Sec) {
+ return constructSectionCommon(Sec);
+}
+
+template <> Section constructSection(MachO::section_64 Sec) {
+ Section S = constructSectionCommon(Sec);
+ S.Reserved3 = Sec.reserved3;
+ return S;
+}
+
+// TODO: get rid of reportError and make MachOReader return Expected<> instead.
+template <typename SectionType, typename SegmentType>
+std::vector<Section>
+extractSections(const object::MachOObjectFile::LoadCommandInfo &LoadCmd,
+ const object::MachOObjectFile &MachOObj,
+ size_t &NextSectionIndex) {
+ auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize;
+ const SectionType *Curr =
+ reinterpret_cast<const SectionType *>(LoadCmd.Ptr + sizeof(SegmentType));
+ std::vector<Section> Sections;
+ for (; reinterpret_cast<const void *>(Curr) < End; Curr++) {
+ if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) {
+ SectionType Sec;
+ memcpy((void *)&Sec, Curr, sizeof(SectionType));
+ MachO::swapStruct(Sec);
+ Sections.push_back(constructSection(Sec));
+ } else {
+ Sections.push_back(constructSection(*Curr));
+ }
+
+ Section &S = Sections.back();
+
+ Expected<object::SectionRef> SecRef =
+ MachOObj.getSection(NextSectionIndex++);
+ if (!SecRef)
+ reportError(MachOObj.getFileName(), SecRef.takeError());
+
+ if (Expected<ArrayRef<uint8_t>> E =
+ MachOObj.getSectionContents(SecRef->getRawDataRefImpl()))
+ S.Content =
+ StringRef(reinterpret_cast<const char *>(E->data()), E->size());
+ else
+ reportError(MachOObj.getFileName(), E.takeError());
+
+ S.Relocations.reserve(S.NReloc);
+ for (auto RI = MachOObj.section_rel_begin(SecRef->getRawDataRefImpl()),
+ RE = MachOObj.section_rel_end(SecRef->getRawDataRefImpl());
+ RI != RE; ++RI) {
+ RelocationInfo R;
+ R.Symbol = nullptr; // We'll fill this field later.
+ R.Info = MachOObj.getRelocation(RI->getRawDataRefImpl());
+ R.Scattered = MachOObj.isRelocationScattered(R.Info);
+ S.Relocations.push_back(R);
+ }
+
+ assert(S.NReloc == S.Relocations.size() &&
+ "Incorrect number of relocations");
+ }
+ return Sections;
+}
+
+void MachOReader::readLoadCommands(Object &O) const {
+ // For MachO sections indices start from 1.
+ size_t NextSectionIndex = 1;
+ for (auto LoadCmd : MachOObj.load_commands()) {
+ LoadCommand LC;
+ switch (LoadCmd.C.cmd) {
+ case MachO::LC_SEGMENT:
+ LC.Sections = extractSections<MachO::section, MachO::segment_command>(
+ LoadCmd, MachOObj, NextSectionIndex);
+ break;
+ case MachO::LC_SEGMENT_64:
+ LC.Sections =
+ extractSections<MachO::section_64, MachO::segment_command_64>(
+ LoadCmd, MachOObj, NextSectionIndex);
+ break;
+ case MachO::LC_SYMTAB:
+ O.SymTabCommandIndex = O.LoadCommands.size();
+ break;
+ case MachO::LC_DYLD_INFO:
+ case MachO::LC_DYLD_INFO_ONLY:
+ O.DyLdInfoCommandIndex = O.LoadCommands.size();
+ break;
+ }
+#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
+ case MachO::LCName: \
+ memcpy((void *)&(LC.MachOLoadCommand.LCStruct##_data), LoadCmd.Ptr, \
+ sizeof(MachO::LCStruct)); \
+ if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost) \
+ MachO::swapStruct(LC.MachOLoadCommand.LCStruct##_data); \
+ LC.Payload = ArrayRef<uint8_t>( \
+ reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) + \
+ sizeof(MachO::LCStruct), \
+ LoadCmd.C.cmdsize - sizeof(MachO::LCStruct)); \
+ break;
+
+ switch (LoadCmd.C.cmd) {
+ default:
+ memcpy((void *)&(LC.MachOLoadCommand.load_command_data), LoadCmd.Ptr,
+ sizeof(MachO::load_command));
+ if (MachOObj.isLittleEndian() != sys::IsLittleEndianHost)
+ MachO::swapStruct(LC.MachOLoadCommand.load_command_data);
+ LC.Payload = ArrayRef<uint8_t>(
+ reinterpret_cast<uint8_t *>(const_cast<char *>(LoadCmd.Ptr)) +
+ sizeof(MachO::load_command),
+ LoadCmd.C.cmdsize - sizeof(MachO::load_command));
+ break;
+#include "llvm/BinaryFormat/MachO.def"
+ }
+ O.LoadCommands.push_back(std::move(LC));
+ }
+}
+
+template <typename nlist_t>
+SymbolEntry constructSymbolEntry(StringRef StrTable, const nlist_t &nlist) {
+ assert(nlist.n_strx < StrTable.size() &&
+ "n_strx exceeds the size of the string table");
+ SymbolEntry SE;
+ SE.Name = StringRef(StrTable.data() + nlist.n_strx).str();
+ SE.n_type = nlist.n_type;
+ SE.n_sect = nlist.n_sect;
+ SE.n_desc = nlist.n_desc;
+ SE.n_value = nlist.n_value;
+ return SE;
+}
+
+void MachOReader::readSymbolTable(Object &O) const {
+ StringRef StrTable = MachOObj.getStringTableData();
+ for (auto Symbol : MachOObj.symbols()) {
+ SymbolEntry SE =
+ (MachOObj.is64Bit()
+ ? constructSymbolEntry(
+ StrTable,
+ MachOObj.getSymbol64TableEntry(Symbol.getRawDataRefImpl()))
+ : constructSymbolEntry(
+ StrTable,
+ MachOObj.getSymbolTableEntry(Symbol.getRawDataRefImpl())));
+
+ O.SymTable.Symbols.push_back(llvm::make_unique<SymbolEntry>(SE));
+ }
+}
+
+void MachOReader::setSymbolInRelocationInfo(Object &O) const {
+ for (auto &LC : O.LoadCommands)
+ for (auto &Sec : LC.Sections)
+ for (auto &Reloc : Sec.Relocations)
+ if (!Reloc.Scattered) {
+ auto *Info = reinterpret_cast<MachO::relocation_info *>(&Reloc.Info);
+ Reloc.Symbol = O.SymTable.getSymbolByIndex(Info->r_symbolnum);
+ }
+}
+
+void MachOReader::readRebaseInfo(Object &O) const {
+ O.Rebases.Opcodes = MachOObj.getDyldInfoRebaseOpcodes();
+}
+
+void MachOReader::readBindInfo(Object &O) const {
+ O.Binds.Opcodes = MachOObj.getDyldInfoBindOpcodes();
+}
+
+void MachOReader::readWeakBindInfo(Object &O) const {
+ O.WeakBinds.Opcodes = MachOObj.getDyldInfoWeakBindOpcodes();
+}
+
+void MachOReader::readLazyBindInfo(Object &O) const {
+ O.LazyBinds.Opcodes = MachOObj.getDyldInfoLazyBindOpcodes();
+}
+
+void MachOReader::readExportInfo(Object &O) const {
+ O.Exports.Trie = MachOObj.getDyldInfoExportsTrie();
+}
+
+std::unique_ptr<Object> MachOReader::create() const {
+ auto Obj = llvm::make_unique<Object>();
+ readHeader(*Obj);
+ readLoadCommands(*Obj);
+ readSymbolTable(*Obj);
+ setSymbolInRelocationInfo(*Obj);
+ readRebaseInfo(*Obj);
+ readBindInfo(*Obj);
+ readWeakBindInfo(*Obj);
+ readLazyBindInfo(*Obj);
+ readExportInfo(*Obj);
+ return Obj;
+}
+
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/MachO/MachOReader.h b/contrib/llvm/tools/llvm-objcopy/MachO/MachOReader.h
new file mode 100644
index 000000000000..795e5cc2363d
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/MachO/MachOReader.h
@@ -0,0 +1,48 @@
+//===- MachOReader.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachOObjcopy.h"
+#include "Object.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Object/MachO.h"
+#include <memory>
+
+namespace llvm {
+namespace objcopy {
+namespace macho {
+
+// The hierarchy of readers is responsible for parsing different inputs:
+// raw binaries and regular MachO object files.
+class Reader {
+public:
+ virtual ~Reader(){};
+ virtual std::unique_ptr<Object> create() const = 0;
+};
+
+class MachOReader : public Reader {
+ const object::MachOObjectFile &MachOObj;
+
+ void readHeader(Object &O) const;
+ void readLoadCommands(Object &O) const;
+ void readSymbolTable(Object &O) const;
+ void setSymbolInRelocationInfo(Object &O) const;
+ void readRebaseInfo(Object &O) const;
+ void readBindInfo(Object &O) const;
+ void readWeakBindInfo(Object &O) const;
+ void readLazyBindInfo(Object &O) const;
+ void readExportInfo(Object &O) const;
+
+public:
+ explicit MachOReader(const object::MachOObjectFile &Obj) : MachOObj(Obj) {}
+
+ std::unique_ptr<Object> create() const override;
+};
+
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp b/contrib/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp
new file mode 100644
index 000000000000..74200c5aa62a
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp
@@ -0,0 +1,590 @@
+//===- MachOWriter.cpp ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachOWriter.h"
+#include "Object.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <memory>
+
+namespace llvm {
+namespace objcopy {
+namespace macho {
+
+size_t MachOWriter::headerSize() const {
+ return Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
+}
+
+size_t MachOWriter::loadCommandsSize() const { return O.Header.SizeOfCmds; }
+
+size_t MachOWriter::symTableSize() const {
+ return O.SymTable.Symbols.size() *
+ (Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist));
+}
+
+size_t MachOWriter::totalSize() const {
+ // Going from tail to head and looking for an appropriate "anchor" to
+ // calculate the total size assuming that all the offsets are either valid
+ // ("true") or 0 (0 indicates that the corresponding part is missing).
+
+ SmallVector<size_t, 7> Ends;
+ if (O.SymTabCommandIndex) {
+ const MachO::symtab_command &SymTabCommand =
+ O.LoadCommands[*O.SymTabCommandIndex]
+ .MachOLoadCommand.symtab_command_data;
+ if (SymTabCommand.symoff) {
+ assert((SymTabCommand.nsyms == O.SymTable.Symbols.size()) &&
+ "Incorrect number of symbols");
+ Ends.push_back(SymTabCommand.symoff + symTableSize());
+ }
+ if (SymTabCommand.stroff) {
+ assert((SymTabCommand.strsize == StrTableBuilder.getSize()) &&
+ "Incorrect string table size");
+ Ends.push_back(SymTabCommand.stroff + SymTabCommand.strsize);
+ }
+ }
+ if (O.DyLdInfoCommandIndex) {
+ const MachO::dyld_info_command &DyLdInfoCommand =
+ O.LoadCommands[*O.DyLdInfoCommandIndex]
+ .MachOLoadCommand.dyld_info_command_data;
+ if (DyLdInfoCommand.rebase_off) {
+ assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) &&
+ "Incorrect rebase opcodes size");
+ Ends.push_back(DyLdInfoCommand.rebase_off + DyLdInfoCommand.rebase_size);
+ }
+ if (DyLdInfoCommand.bind_off) {
+ assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) &&
+ "Incorrect bind opcodes size");
+ Ends.push_back(DyLdInfoCommand.bind_off + DyLdInfoCommand.bind_size);
+ }
+ if (DyLdInfoCommand.weak_bind_off) {
+ assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) &&
+ "Incorrect weak bind opcodes size");
+ Ends.push_back(DyLdInfoCommand.weak_bind_off +
+ DyLdInfoCommand.weak_bind_size);
+ }
+ if (DyLdInfoCommand.lazy_bind_off) {
+ assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) &&
+ "Incorrect lazy bind opcodes size");
+ Ends.push_back(DyLdInfoCommand.lazy_bind_off +
+ DyLdInfoCommand.lazy_bind_size);
+ }
+ if (DyLdInfoCommand.export_off) {
+ assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) &&
+ "Incorrect trie size");
+ Ends.push_back(DyLdInfoCommand.export_off + DyLdInfoCommand.export_size);
+ }
+ }
+
+ // Otherwise, use the last section / reloction.
+ for (const auto &LC : O.LoadCommands)
+ for (const auto &S : LC.Sections) {
+ Ends.push_back(S.Offset + S.Size);
+ if (S.RelOff)
+ Ends.push_back(S.RelOff +
+ S.NReloc * sizeof(MachO::any_relocation_info));
+ }
+
+ if (!Ends.empty())
+ return *std::max_element(Ends.begin(), Ends.end());
+
+ // Otherwise, we have only Mach header and load commands.
+ return headerSize() + loadCommandsSize();
+}
+
+void MachOWriter::writeHeader() {
+ MachO::mach_header_64 Header;
+
+ Header.magic = O.Header.Magic;
+ Header.cputype = O.Header.CPUType;
+ Header.cpusubtype = O.Header.CPUSubType;
+ Header.filetype = O.Header.FileType;
+ Header.ncmds = O.Header.NCmds;
+ Header.sizeofcmds = O.Header.SizeOfCmds;
+ Header.flags = O.Header.Flags;
+ Header.reserved = O.Header.Reserved;
+
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(Header);
+
+ auto HeaderSize =
+ Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
+ memcpy(B.getBufferStart(), &Header, HeaderSize);
+}
+
+void MachOWriter::updateSymbolIndexes() {
+ uint32_t Index = 0;
+ for (auto &Symbol : O.SymTable.Symbols) {
+ Symbol->Index = Index;
+ Index++;
+ }
+}
+
+void MachOWriter::writeLoadCommands() {
+ uint8_t *Begin = B.getBufferStart() + headerSize();
+ for (const auto &LC : O.LoadCommands) {
+ // Construct a load command.
+ MachO::macho_load_command MLC = LC.MachOLoadCommand;
+ switch (MLC.load_command_data.cmd) {
+ case MachO::LC_SEGMENT:
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(MLC.segment_command_data);
+ memcpy(Begin, &MLC.segment_command_data, sizeof(MachO::segment_command));
+ Begin += sizeof(MachO::segment_command);
+
+ for (const auto &Sec : LC.Sections)
+ writeSectionInLoadCommand<MachO::section>(Sec, Begin);
+ continue;
+ case MachO::LC_SEGMENT_64:
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(MLC.segment_command_64_data);
+ memcpy(Begin, &MLC.segment_command_64_data,
+ sizeof(MachO::segment_command_64));
+ Begin += sizeof(MachO::segment_command_64);
+
+ for (const auto &Sec : LC.Sections)
+ writeSectionInLoadCommand<MachO::section_64>(Sec, Begin);
+ continue;
+ }
+
+#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
+ case MachO::LCName: \
+ assert(sizeof(MachO::LCStruct) + LC.Payload.size() == \
+ MLC.load_command_data.cmdsize); \
+ if (IsLittleEndian != sys::IsLittleEndianHost) \
+ MachO::swapStruct(MLC.LCStruct##_data); \
+ memcpy(Begin, &MLC.LCStruct##_data, sizeof(MachO::LCStruct)); \
+ Begin += sizeof(MachO::LCStruct); \
+ memcpy(Begin, LC.Payload.data(), LC.Payload.size()); \
+ Begin += LC.Payload.size(); \
+ break;
+
+ // Copy the load command as it is.
+ switch (MLC.load_command_data.cmd) {
+ default:
+ assert(sizeof(MachO::load_command) + LC.Payload.size() ==
+ MLC.load_command_data.cmdsize);
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(MLC.load_command_data);
+ memcpy(Begin, &MLC.load_command_data, sizeof(MachO::load_command));
+ Begin += sizeof(MachO::load_command);
+ memcpy(Begin, LC.Payload.data(), LC.Payload.size());
+ Begin += LC.Payload.size();
+ break;
+#include "llvm/BinaryFormat/MachO.def"
+ }
+ }
+}
+
+template <typename StructType>
+void MachOWriter::writeSectionInLoadCommand(const Section &Sec, uint8_t *&Out) {
+ StructType Temp;
+ assert(Sec.Segname.size() <= sizeof(Temp.segname) && "too long segment name");
+ assert(Sec.Sectname.size() <= sizeof(Temp.sectname) &&
+ "too long section name");
+ memset(&Temp, 0, sizeof(StructType));
+ memcpy(Temp.segname, Sec.Segname.data(), Sec.Segname.size());
+ memcpy(Temp.sectname, Sec.Sectname.data(), Sec.Sectname.size());
+ Temp.addr = Sec.Addr;
+ Temp.size = Sec.Size;
+ Temp.offset = Sec.Offset;
+ Temp.align = Sec.Align;
+ Temp.reloff = Sec.RelOff;
+ Temp.nreloc = Sec.NReloc;
+ Temp.flags = Sec.Flags;
+ Temp.reserved1 = Sec.Reserved1;
+ Temp.reserved2 = Sec.Reserved2;
+
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(Temp);
+ memcpy(Out, &Temp, sizeof(StructType));
+ Out += sizeof(StructType);
+}
+
+void MachOWriter::writeSections() {
+ for (const auto &LC : O.LoadCommands)
+ for (const auto &Sec : LC.Sections) {
+ if (Sec.isVirtualSection())
+ continue;
+
+ assert(Sec.Offset && "Section offset can not be zero");
+ assert((Sec.Size == Sec.Content.size()) && "Incorrect section size");
+ memcpy(B.getBufferStart() + Sec.Offset, Sec.Content.data(),
+ Sec.Content.size());
+ for (size_t Index = 0; Index < Sec.Relocations.size(); ++Index) {
+ auto RelocInfo = Sec.Relocations[Index];
+ if (!RelocInfo.Scattered) {
+ auto *Info =
+ reinterpret_cast<MachO::relocation_info *>(&RelocInfo.Info);
+ Info->r_symbolnum = RelocInfo.Symbol->Index;
+ }
+
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(
+ reinterpret_cast<MachO::any_relocation_info &>(RelocInfo.Info));
+ memcpy(B.getBufferStart() + Sec.RelOff +
+ Index * sizeof(MachO::any_relocation_info),
+ &RelocInfo.Info, sizeof(RelocInfo.Info));
+ }
+ }
+}
+
+template <typename NListType>
+void writeNListEntry(const SymbolEntry &SE, bool IsLittleEndian, char *&Out,
+ uint32_t Nstrx) {
+ NListType ListEntry;
+ ListEntry.n_strx = Nstrx;
+ ListEntry.n_type = SE.n_type;
+ ListEntry.n_sect = SE.n_sect;
+ ListEntry.n_desc = SE.n_desc;
+ ListEntry.n_value = SE.n_value;
+
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(ListEntry);
+ memcpy(Out, reinterpret_cast<const char *>(&ListEntry), sizeof(NListType));
+ Out += sizeof(NListType);
+}
+
+void MachOWriter::writeSymbolTable() {
+ if (!O.SymTabCommandIndex)
+ return;
+ const MachO::symtab_command &SymTabCommand =
+ O.LoadCommands[*O.SymTabCommandIndex]
+ .MachOLoadCommand.symtab_command_data;
+
+ uint8_t *StrTable = (uint8_t *)B.getBufferStart() + SymTabCommand.stroff;
+ StrTableBuilder.write(StrTable);
+}
+
+void MachOWriter::writeStringTable() {
+ if (!O.SymTabCommandIndex)
+ return;
+ const MachO::symtab_command &SymTabCommand =
+ O.LoadCommands[*O.SymTabCommandIndex]
+ .MachOLoadCommand.symtab_command_data;
+
+ char *SymTable = (char *)B.getBufferStart() + SymTabCommand.symoff;
+ for (auto Iter = O.SymTable.Symbols.begin(), End = O.SymTable.Symbols.end();
+ Iter != End; Iter++) {
+ SymbolEntry *Sym = Iter->get();
+ auto Nstrx = StrTableBuilder.getOffset(Sym->Name);
+
+ if (Is64Bit)
+ writeNListEntry<MachO::nlist_64>(*Sym, IsLittleEndian, SymTable, Nstrx);
+ else
+ writeNListEntry<MachO::nlist>(*Sym, IsLittleEndian, SymTable, Nstrx);
+ }
+}
+
+void MachOWriter::writeRebaseInfo() {
+ if (!O.DyLdInfoCommandIndex)
+ return;
+ const MachO::dyld_info_command &DyLdInfoCommand =
+ O.LoadCommands[*O.DyLdInfoCommandIndex]
+ .MachOLoadCommand.dyld_info_command_data;
+ char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.rebase_off;
+ assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) &&
+ "Incorrect rebase opcodes size");
+ memcpy(Out, O.Rebases.Opcodes.data(), O.Rebases.Opcodes.size());
+}
+
+void MachOWriter::writeBindInfo() {
+ if (!O.DyLdInfoCommandIndex)
+ return;
+ const MachO::dyld_info_command &DyLdInfoCommand =
+ O.LoadCommands[*O.DyLdInfoCommandIndex]
+ .MachOLoadCommand.dyld_info_command_data;
+ char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.bind_off;
+ assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) &&
+ "Incorrect bind opcodes size");
+ memcpy(Out, O.Binds.Opcodes.data(), O.Binds.Opcodes.size());
+}
+
+void MachOWriter::writeWeakBindInfo() {
+ if (!O.DyLdInfoCommandIndex)
+ return;
+ const MachO::dyld_info_command &DyLdInfoCommand =
+ O.LoadCommands[*O.DyLdInfoCommandIndex]
+ .MachOLoadCommand.dyld_info_command_data;
+ char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.weak_bind_off;
+ assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) &&
+ "Incorrect weak bind opcodes size");
+ memcpy(Out, O.WeakBinds.Opcodes.data(), O.WeakBinds.Opcodes.size());
+}
+
+void MachOWriter::writeLazyBindInfo() {
+ if (!O.DyLdInfoCommandIndex)
+ return;
+ const MachO::dyld_info_command &DyLdInfoCommand =
+ O.LoadCommands[*O.DyLdInfoCommandIndex]
+ .MachOLoadCommand.dyld_info_command_data;
+ char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.lazy_bind_off;
+ assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) &&
+ "Incorrect lazy bind opcodes size");
+ memcpy(Out, O.LazyBinds.Opcodes.data(), O.LazyBinds.Opcodes.size());
+}
+
+void MachOWriter::writeExportInfo() {
+ if (!O.DyLdInfoCommandIndex)
+ return;
+ const MachO::dyld_info_command &DyLdInfoCommand =
+ O.LoadCommands[*O.DyLdInfoCommandIndex]
+ .MachOLoadCommand.dyld_info_command_data;
+ char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.export_off;
+ assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) &&
+ "Incorrect export trie size");
+ memcpy(Out, O.Exports.Trie.data(), O.Exports.Trie.size());
+}
+
+void MachOWriter::writeTail() {
+ typedef void (MachOWriter::*WriteHandlerType)(void);
+ typedef std::pair<uint64_t, WriteHandlerType> WriteOperation;
+ SmallVector<WriteOperation, 7> Queue;
+
+ if (O.SymTabCommandIndex) {
+ const MachO::symtab_command &SymTabCommand =
+ O.LoadCommands[*O.SymTabCommandIndex]
+ .MachOLoadCommand.symtab_command_data;
+ if (SymTabCommand.symoff)
+ Queue.push_back({SymTabCommand.symoff, &MachOWriter::writeSymbolTable});
+ if (SymTabCommand.stroff)
+ Queue.push_back({SymTabCommand.stroff, &MachOWriter::writeStringTable});
+ }
+
+ if (O.DyLdInfoCommandIndex) {
+ const MachO::dyld_info_command &DyLdInfoCommand =
+ O.LoadCommands[*O.DyLdInfoCommandIndex]
+ .MachOLoadCommand.dyld_info_command_data;
+ if (DyLdInfoCommand.rebase_off)
+ Queue.push_back(
+ {DyLdInfoCommand.rebase_off, &MachOWriter::writeRebaseInfo});
+ if (DyLdInfoCommand.bind_off)
+ Queue.push_back({DyLdInfoCommand.bind_off, &MachOWriter::writeBindInfo});
+ if (DyLdInfoCommand.weak_bind_off)
+ Queue.push_back(
+ {DyLdInfoCommand.weak_bind_off, &MachOWriter::writeWeakBindInfo});
+ if (DyLdInfoCommand.lazy_bind_off)
+ Queue.push_back(
+ {DyLdInfoCommand.lazy_bind_off, &MachOWriter::writeLazyBindInfo});
+ if (DyLdInfoCommand.export_off)
+ Queue.push_back(
+ {DyLdInfoCommand.export_off, &MachOWriter::writeExportInfo});
+ }
+
+ llvm::sort(Queue, [](const WriteOperation &LHS, const WriteOperation &RHS) {
+ return LHS.first < RHS.first;
+ });
+
+ for (auto WriteOp : Queue)
+ (this->*WriteOp.second)();
+}
+
+void MachOWriter::updateSizeOfCmds() {
+ auto Size = 0;
+ for (const auto &LC : O.LoadCommands) {
+ auto &MLC = LC.MachOLoadCommand;
+ auto cmd = MLC.load_command_data.cmd;
+
+ switch (cmd) {
+ case MachO::LC_SEGMENT:
+ Size += sizeof(MachO::segment_command) +
+ sizeof(MachO::section) * LC.Sections.size();
+ continue;
+ case MachO::LC_SEGMENT_64:
+ Size += sizeof(MachO::segment_command_64) +
+ sizeof(MachO::section_64) * LC.Sections.size();
+ continue;
+ }
+
+ switch (cmd) {
+#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
+ case MachO::LCName: \
+ Size += sizeof(MachO::LCStruct); \
+ break;
+#include "llvm/BinaryFormat/MachO.def"
+#undef HANDLE_LOAD_COMMAND
+ }
+ }
+
+ O.Header.SizeOfCmds = Size;
+}
+
+// Updates the index and the number of local/external/undefined symbols. Here we
+// assume that MLC is a LC_DYSYMTAB and the nlist entries in the symbol table
+// are already sorted by the those types.
+void MachOWriter::updateDySymTab(MachO::macho_load_command &MLC) {
+ uint32_t NumLocalSymbols = 0;
+ auto Iter = O.SymTable.Symbols.begin();
+ auto End = O.SymTable.Symbols.end();
+ for (; Iter != End; Iter++) {
+ if ((*Iter)->n_type & (MachO::N_EXT | MachO::N_PEXT))
+ break;
+
+ NumLocalSymbols++;
+ }
+
+ uint32_t NumExtDefSymbols = 0;
+ for (; Iter != End; Iter++) {
+ if (((*Iter)->n_type & MachO::N_TYPE) == MachO::N_UNDF)
+ break;
+
+ NumExtDefSymbols++;
+ }
+
+ MLC.dysymtab_command_data.ilocalsym = 0;
+ MLC.dysymtab_command_data.nlocalsym = NumLocalSymbols;
+ MLC.dysymtab_command_data.iextdefsym = NumLocalSymbols;
+ MLC.dysymtab_command_data.nextdefsym = NumExtDefSymbols;
+ MLC.dysymtab_command_data.iundefsym = NumLocalSymbols + NumExtDefSymbols;
+ MLC.dysymtab_command_data.nundefsym =
+ O.SymTable.Symbols.size() - (NumLocalSymbols + NumExtDefSymbols);
+}
+
+// Recomputes and updates offset and size fields in load commands and sections
+// since they could be modified.
+Error MachOWriter::layout() {
+ auto SizeOfCmds = loadCommandsSize();
+ auto Offset = headerSize() + SizeOfCmds;
+ O.Header.NCmds = O.LoadCommands.size();
+ O.Header.SizeOfCmds = SizeOfCmds;
+
+ // Lay out sections.
+ for (auto &LC : O.LoadCommands) {
+ uint64_t FileOff = Offset;
+ uint64_t VMSize = 0;
+ uint64_t FileOffsetInSegment = 0;
+ for (auto &Sec : LC.Sections) {
+ if (!Sec.isVirtualSection()) {
+ auto FilePaddingSize =
+ OffsetToAlignment(FileOffsetInSegment, 1ull << Sec.Align);
+ Sec.Offset = Offset + FileOffsetInSegment + FilePaddingSize;
+ Sec.Size = Sec.Content.size();
+ FileOffsetInSegment += FilePaddingSize + Sec.Size;
+ }
+
+ VMSize = std::max(VMSize, Sec.Addr + Sec.Size);
+ }
+
+ // TODO: Handle the __PAGEZERO segment.
+ auto &MLC = LC.MachOLoadCommand;
+ switch (MLC.load_command_data.cmd) {
+ case MachO::LC_SEGMENT:
+ MLC.segment_command_data.cmdsize =
+ sizeof(MachO::segment_command) +
+ sizeof(MachO::section) * LC.Sections.size();
+ MLC.segment_command_data.nsects = LC.Sections.size();
+ MLC.segment_command_data.fileoff = FileOff;
+ MLC.segment_command_data.vmsize = VMSize;
+ MLC.segment_command_data.filesize = FileOffsetInSegment;
+ break;
+ case MachO::LC_SEGMENT_64:
+ MLC.segment_command_64_data.cmdsize =
+ sizeof(MachO::segment_command_64) +
+ sizeof(MachO::section_64) * LC.Sections.size();
+ MLC.segment_command_64_data.nsects = LC.Sections.size();
+ MLC.segment_command_64_data.fileoff = FileOff;
+ MLC.segment_command_64_data.vmsize = VMSize;
+ MLC.segment_command_64_data.filesize = FileOffsetInSegment;
+ break;
+ }
+
+ Offset += FileOffsetInSegment;
+ }
+
+ // Lay out relocations.
+ for (auto &LC : O.LoadCommands)
+ for (auto &Sec : LC.Sections) {
+ Sec.RelOff = Sec.Relocations.empty() ? 0 : Offset;
+ Sec.NReloc = Sec.Relocations.size();
+ Offset += sizeof(MachO::any_relocation_info) * Sec.NReloc;
+ }
+
+ // Lay out tail stuff.
+ auto NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
+ for (auto &LC : O.LoadCommands) {
+ auto &MLC = LC.MachOLoadCommand;
+ auto cmd = MLC.load_command_data.cmd;
+ switch (cmd) {
+ case MachO::LC_SYMTAB:
+ MLC.symtab_command_data.nsyms = O.SymTable.Symbols.size();
+ MLC.symtab_command_data.strsize = StrTableBuilder.getSize();
+ MLC.symtab_command_data.symoff = Offset;
+ Offset += NListSize * MLC.symtab_command_data.nsyms;
+ MLC.symtab_command_data.stroff = Offset;
+ Offset += MLC.symtab_command_data.strsize;
+ break;
+ case MachO::LC_DYSYMTAB: {
+ if (MLC.dysymtab_command_data.ntoc != 0 ||
+ MLC.dysymtab_command_data.nmodtab != 0 ||
+ MLC.dysymtab_command_data.nextrefsyms != 0 ||
+ MLC.dysymtab_command_data.nlocrel != 0 ||
+ MLC.dysymtab_command_data.nextrel != 0)
+ return createStringError(llvm::errc::not_supported,
+ "shared library is not yet supported");
+
+ if (MLC.dysymtab_command_data.nindirectsyms != 0)
+ return createStringError(llvm::errc::not_supported,
+ "indirect symbol table is not yet supported");
+
+ updateDySymTab(MLC);
+ break;
+ }
+ case MachO::LC_SEGMENT:
+ case MachO::LC_SEGMENT_64:
+ case MachO::LC_VERSION_MIN_MACOSX:
+ case MachO::LC_BUILD_VERSION:
+ case MachO::LC_ID_DYLIB:
+ case MachO::LC_LOAD_DYLIB:
+ case MachO::LC_UUID:
+ case MachO::LC_SOURCE_VERSION:
+ // Nothing to update.
+ break;
+ default:
+ // Abort if it's unsupported in order to prevent corrupting the object.
+ return createStringError(llvm::errc::not_supported,
+ "unsupported load command (cmd=0x%x)", cmd);
+ }
+ }
+
+ return Error::success();
+}
+
+void MachOWriter::constructStringTable() {
+ for (std::unique_ptr<SymbolEntry> &Sym : O.SymTable.Symbols)
+ StrTableBuilder.add(Sym->Name);
+ StrTableBuilder.finalize();
+}
+
+Error MachOWriter::finalize() {
+ updateSizeOfCmds();
+ constructStringTable();
+
+ if (auto E = layout())
+ return E;
+
+ return Error::success();
+}
+
+Error MachOWriter::write() {
+ if (Error E = B.allocate(totalSize()))
+ return E;
+ memset(B.getBufferStart(), 0, totalSize());
+ writeHeader();
+ updateSymbolIndexes();
+ writeLoadCommands();
+ writeSections();
+ writeTail();
+ return B.commit();
+}
+
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/MachO/MachOWriter.h b/contrib/llvm/tools/llvm-objcopy/MachO/MachOWriter.h
new file mode 100644
index 000000000000..ecf12d62de2c
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/MachO/MachOWriter.h
@@ -0,0 +1,64 @@
+//===- MachOWriter.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "../Buffer.h"
+#include "MachOObjcopy.h"
+#include "Object.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Object/MachO.h"
+
+namespace llvm {
+class Error;
+
+namespace objcopy {
+namespace macho {
+
+class MachOWriter {
+ Object &O;
+ bool Is64Bit;
+ bool IsLittleEndian;
+ Buffer &B;
+ StringTableBuilder StrTableBuilder{StringTableBuilder::MachO};
+
+ size_t headerSize() const;
+ size_t loadCommandsSize() const;
+ size_t symTableSize() const;
+ size_t strTableSize() const;
+
+ void updateDySymTab(MachO::macho_load_command &MLC);
+ void updateSizeOfCmds();
+ void updateSymbolIndexes();
+ void constructStringTable();
+ Error layout();
+
+ void writeHeader();
+ void writeLoadCommands();
+ template <typename StructType>
+ void writeSectionInLoadCommand(const Section &Sec, uint8_t *&Out);
+ void writeSections();
+ void writeSymbolTable();
+ void writeStringTable();
+ void writeRebaseInfo();
+ void writeBindInfo();
+ void writeWeakBindInfo();
+ void writeLazyBindInfo();
+ void writeExportInfo();
+ void writeTail();
+
+public:
+ MachOWriter(Object &O, bool Is64Bit, bool IsLittleEndian, Buffer &B)
+ : O(O), Is64Bit(Is64Bit), IsLittleEndian(IsLittleEndian), B(B) {}
+
+ size_t totalSize() const;
+ Error finalize();
+ Error write();
+};
+
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/MachO/Object.cpp b/contrib/llvm/tools/llvm-objcopy/MachO/Object.cpp
new file mode 100644
index 000000000000..264f39c28ed2
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/MachO/Object.cpp
@@ -0,0 +1,15 @@
+#include "Object.h"
+#include "../llvm-objcopy.h"
+
+namespace llvm {
+namespace objcopy {
+namespace macho {
+
+const SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) const {
+ assert(Index < Symbols.size() && "invalid symbol index");
+ return Symbols[Index].get();
+}
+
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/MachO/Object.h b/contrib/llvm/tools/llvm-objcopy/MachO/Object.h
new file mode 100644
index 000000000000..ed85fcbc47f7
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/MachO/Object.h
@@ -0,0 +1,232 @@
+//===- Object.h - Mach-O object file model ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJCOPY_MACHO_OBJECT_H
+#define LLVM_OBJCOPY_MACHO_OBJECT_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/ObjectYAML/DWARFYAML.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace llvm {
+namespace objcopy {
+namespace macho {
+
+struct MachHeader {
+ uint32_t Magic;
+ uint32_t CPUType;
+ uint32_t CPUSubType;
+ uint32_t FileType;
+ uint32_t NCmds;
+ uint32_t SizeOfCmds;
+ uint32_t Flags;
+ uint32_t Reserved = 0;
+};
+
+struct RelocationInfo;
+struct Section {
+ std::string Sectname;
+ std::string Segname;
+ uint64_t Addr;
+ uint64_t Size;
+ uint32_t Offset;
+ uint32_t Align;
+ uint32_t RelOff;
+ uint32_t NReloc;
+ uint32_t Flags;
+ uint32_t Reserved1;
+ uint32_t Reserved2;
+ uint32_t Reserved3;
+
+ StringRef Content;
+ std::vector<RelocationInfo> Relocations;
+
+ MachO::SectionType getType() const {
+ return static_cast<MachO::SectionType>(Flags & MachO::SECTION_TYPE);
+ }
+
+ bool isVirtualSection() const {
+ return (getType() == MachO::S_ZEROFILL ||
+ getType() == MachO::S_GB_ZEROFILL ||
+ getType() == MachO::S_THREAD_LOCAL_ZEROFILL);
+ }
+};
+
+struct LoadCommand {
+ // The type MachO::macho_load_command is defined in llvm/BinaryFormat/MachO.h
+ // and it is a union of all the structs corresponding to various load
+ // commands.
+ MachO::macho_load_command MachOLoadCommand;
+
+ // The raw content of the payload of the load command (located right after the
+ // corresponding struct). In some cases it is either empty or can be
+ // copied-over without digging into its structure.
+ ArrayRef<uint8_t> Payload;
+
+ // Some load commands can contain (inside the payload) an array of sections,
+ // though the contents of the sections are stored separately. The struct
+ // Section describes only sections' metadata and where to find the
+ // corresponding content inside the binary.
+ std::vector<Section> Sections;
+};
+
+// A symbol information. Fields which starts with "n_" are same as them in the
+// nlist.
+struct SymbolEntry {
+ std::string Name;
+ uint32_t Index;
+ uint8_t n_type;
+ uint8_t n_sect;
+ uint16_t n_desc;
+ uint64_t n_value;
+};
+
+/// The location of the symbol table inside the binary is described by LC_SYMTAB
+/// load command.
+struct SymbolTable {
+ std::vector<std::unique_ptr<SymbolEntry>> Symbols;
+
+ const SymbolEntry *getSymbolByIndex(uint32_t Index) const;
+};
+
+/// The location of the string table inside the binary is described by LC_SYMTAB
+/// load command.
+struct StringTable {
+ std::vector<std::string> Strings;
+};
+
+struct RelocationInfo {
+ const SymbolEntry *Symbol;
+ // True if Info is a scattered_relocation_info.
+ bool Scattered;
+ MachO::any_relocation_info Info;
+};
+
+/// The location of the rebase info inside the binary is described by
+/// LC_DYLD_INFO load command. Dyld rebases an image whenever dyld loads it at
+/// an address different from its preferred address. The rebase information is
+/// a stream of byte sized opcodes whose symbolic names start with
+/// REBASE_OPCODE_. Conceptually the rebase information is a table of tuples:
+/// <seg-index, seg-offset, type>
+/// The opcodes are a compressed way to encode the table by only
+/// encoding when a column changes. In addition simple patterns
+/// like "every n'th offset for m times" can be encoded in a few
+/// bytes.
+struct RebaseInfo {
+ // At the moment we do not parse this info (and it is simply copied over),
+ // but the proper support will be added later.
+ ArrayRef<uint8_t> Opcodes;
+};
+
+/// The location of the bind info inside the binary is described by
+/// LC_DYLD_INFO load command. Dyld binds an image during the loading process,
+/// if the image requires any pointers to be initialized to symbols in other
+/// images. The bind information is a stream of byte sized opcodes whose
+/// symbolic names start with BIND_OPCODE_. Conceptually the bind information is
+/// a table of tuples: <seg-index, seg-offset, type, symbol-library-ordinal,
+/// symbol-name, addend> The opcodes are a compressed way to encode the table by
+/// only encoding when a column changes. In addition simple patterns like for
+/// runs of pointers initialized to the same value can be encoded in a few
+/// bytes.
+struct BindInfo {
+ // At the moment we do not parse this info (and it is simply copied over),
+ // but the proper support will be added later.
+ ArrayRef<uint8_t> Opcodes;
+};
+
+/// The location of the weak bind info inside the binary is described by
+/// LC_DYLD_INFO load command. Some C++ programs require dyld to unique symbols
+/// so that all images in the process use the same copy of some code/data. This
+/// step is done after binding. The content of the weak_bind info is an opcode
+/// stream like the bind_info. But it is sorted alphabetically by symbol name.
+/// This enable dyld to walk all images with weak binding information in order
+/// and look for collisions. If there are no collisions, dyld does no updating.
+/// That means that some fixups are also encoded in the bind_info. For
+/// instance, all calls to "operator new" are first bound to libstdc++.dylib
+/// using the information in bind_info. Then if some image overrides operator
+/// new that is detected when the weak_bind information is processed and the
+/// call to operator new is then rebound.
+struct WeakBindInfo {
+ // At the moment we do not parse this info (and it is simply copied over),
+ // but the proper support will be added later.
+ ArrayRef<uint8_t> Opcodes;
+};
+
+/// The location of the lazy bind info inside the binary is described by
+/// LC_DYLD_INFO load command. Some uses of external symbols do not need to be
+/// bound immediately. Instead they can be lazily bound on first use. The
+/// lazy_bind contains a stream of BIND opcodes to bind all lazy symbols. Normal
+/// use is that dyld ignores the lazy_bind section when loading an image.
+/// Instead the static linker arranged for the lazy pointer to initially point
+/// to a helper function which pushes the offset into the lazy_bind area for the
+/// symbol needing to be bound, then jumps to dyld which simply adds the offset
+/// to lazy_bind_off to get the information on what to bind.
+struct LazyBindInfo {
+ ArrayRef<uint8_t> Opcodes;
+};
+
+/// The location of the export info inside the binary is described by
+/// LC_DYLD_INFO load command. The symbols exported by a dylib are encoded in a
+/// trie. This is a compact representation that factors out common prefixes. It
+/// also reduces LINKEDIT pages in RAM because it encodes all information (name,
+/// address, flags) in one small, contiguous range. The export area is a stream
+/// of nodes. The first node sequentially is the start node for the trie. Nodes
+/// for a symbol start with a uleb128 that is the length of the exported symbol
+/// information for the string so far. If there is no exported symbol, the node
+/// starts with a zero byte. If there is exported info, it follows the length.
+/// First is a uleb128 containing flags. Normally, it is followed by
+/// a uleb128 encoded offset which is location of the content named
+/// by the symbol from the mach_header for the image. If the flags
+/// is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is
+/// a uleb128 encoded library ordinal, then a zero terminated
+/// UTF8 string. If the string is zero length, then the symbol
+/// is re-export from the specified dylib with the same name.
+/// If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following
+/// the flags is two uleb128s: the stub offset and the resolver offset.
+/// The stub is used by non-lazy pointers. The resolver is used
+/// by lazy pointers and must be called to get the actual address to use.
+/// After the optional exported symbol information is a byte of
+/// how many edges (0-255) that this node has leaving it,
+/// followed by each edge.
+/// Each edge is a zero terminated UTF8 of the addition chars
+/// in the symbol, followed by a uleb128 offset for the node that
+/// edge points to.
+struct ExportInfo {
+ ArrayRef<uint8_t> Trie;
+};
+
+struct Object {
+ MachHeader Header;
+ std::vector<LoadCommand> LoadCommands;
+
+ SymbolTable SymTable;
+ StringTable StrTable;
+
+ RebaseInfo Rebases;
+ BindInfo Binds;
+ WeakBindInfo WeakBinds;
+ LazyBindInfo LazyBinds;
+ ExportInfo Exports;
+
+ /// The index of LC_SYMTAB load command if present.
+ Optional<size_t> SymTabCommandIndex;
+ /// The index of LC_DYLD_INFO or LC_DYLD_INFO_ONLY load command if present.
+ Optional<size_t> DyLdInfoCommandIndex;
+};
+
+} // end namespace macho
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_OBJCOPY_MACHO_OBJECT_H
diff --git a/contrib/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/contrib/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index 1f7e64e4091c..5fce4fbde539 100644
--- a/contrib/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/contrib/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -1,13 +1,20 @@
include "llvm/Option/OptParser.td"
multiclass Eq<string name, string help> {
- def NAME : Separate<["--", "-"], name>;
- def NAME #_eq : Joined<["--", "-"], name #"=">,
+ def NAME : Separate<["--"], name>;
+ def NAME #_eq : Joined<["--"], name #"=">,
Alias<!cast<Separate>(NAME)>,
HelpText<help>;
}
-def help : Flag<["-", "--"], "help">;
+def help : Flag<["--"], "help">;
+def h : Flag<["-"], "h">, Alias<help>;
+
+def allow_broken_links
+ : Flag<["--"], "allow-broken-links">,
+ HelpText<"Allow llvm-objcopy to remove sections even if it would leave "
+ "invalid section references. The appropriate sh_link fields "
+ "will be set to zero.">;
defm binary_architecture
: Eq<"binary-architecture", "Used when transforming an architecture-less "
@@ -26,13 +33,13 @@ defm output_target : Eq<"output-target", "Format of the output file">,
Values<"binary">;
def O : JoinedOrSeparate<["-"], "O">, Alias<output_target>;
-def compress_debug_sections : Flag<["--", "-"], "compress-debug-sections">;
+def compress_debug_sections : Flag<["--"], "compress-debug-sections">;
def compress_debug_sections_eq
- : Joined<["--", "-"], "compress-debug-sections=">,
+ : Joined<["--"], "compress-debug-sections=">,
MetaVarName<"[ zlib | zlib-gnu ]">,
HelpText<"Compress DWARF debug sections using specified style. Supported "
"styles: 'zlib-gnu' and 'zlib'">;
-def decompress_debug_sections : Flag<["-", "--"], "decompress-debug-sections">,
+def decompress_debug_sections : Flag<["--"], "decompress-debug-sections">,
HelpText<"Decompress DWARF debug sections.">;
defm split_dwo
: Eq<"split-dwo", "Equivalent to extract-dwo on the input file to "
@@ -40,7 +47,7 @@ defm split_dwo
MetaVarName<"dwo-file">;
def enable_deterministic_archives
- : Flag<["-", "--"], "enable-deterministic-archives">,
+ : Flag<["--"], "enable-deterministic-archives">,
HelpText<"Enable deterministic mode when copying archives (use zero for "
"UIDs, GIDs, and timestamps).">;
def D : Flag<["-"], "D">,
@@ -48,14 +55,14 @@ def D : Flag<["-"], "D">,
HelpText<"Alias for --enable-deterministic-archives">;
def disable_deterministic_archives
- : Flag<["-", "--"], "disable-deterministic-archives">,
+ : Flag<["--"], "disable-deterministic-archives">,
HelpText<"Disable deterministic mode when copying archives (use real "
"values for UIDs, GIDs, and timestamps).">;
def U : Flag<["-"], "U">,
Alias<disable_deterministic_archives>,
HelpText<"Alias for --disable-deterministic-archives">;
-def preserve_dates : Flag<["-", "--"], "preserve-dates">,
+def preserve_dates : Flag<["--"], "preserve-dates">,
HelpText<"Preserve access and modification timestamps">;
def p : Flag<["-"], "p">, Alias<preserve_dates>;
@@ -76,6 +83,16 @@ defm rename_section
defm redefine_symbol
: Eq<"redefine-sym", "Change the name of a symbol old to new">,
MetaVarName<"old=new">;
+defm redefine_symbols
+ : Eq<"redefine-syms",
+ "Reads a list of symbol pairs from <filename> and runs as if "
+ "--redefine-sym=<old>=<new> is set for each one. <filename> "
+ "contains two symbols per line separated with whitespace and may "
+ "contain comments beginning with '#'. Leading and trailing "
+ "whitespace is stripped from each line. May be repeated to read "
+ "symbols from many files.">,
+ MetaVarName<"filename">;
+
defm keep_section : Eq<"keep-section", "Keep <section>">,
MetaVarName<"section">;
defm only_section : Eq<"only-section", "Remove all but <section>">,
@@ -86,39 +103,76 @@ defm add_section
"Make a section named <section> with the contents of <file>.">,
MetaVarName<"section=file">;
-def strip_all
- : Flag<["-", "--"], "strip-all">,
- HelpText<
- "Remove non-allocated sections other than .gnu.warning* sections">;
+defm set_section_flags
+ : Eq<"set-section-flags",
+ "Set section flags for a given section. Flags supported for GNU "
+ "compatibility: alloc, load, noload, readonly, debug, code, data, "
+ "rom, share, contents, merge, strings.">,
+ MetaVarName<"section=flag1[,flag2,...]">;
+
+def strip_all : Flag<["--"], "strip-all">,
+ HelpText<"Remove non-allocated sections outside segments. "
+ ".gnu.warning* sections are not removed">;
def S : Flag<["-"], "S">, Alias<strip_all>;
-def strip_all_gnu : Flag<["-", "--"], "strip-all-gnu">,
+def strip_all_gnu : Flag<["--"], "strip-all-gnu">,
HelpText<"Compatible with GNU objcopy's --strip-all">;
-def strip_debug : Flag<["-", "--"], "strip-debug">,
+def strip_debug : Flag<["--"], "strip-debug">,
HelpText<"Remove all debug information">;
-def strip_dwo : Flag<["-", "--"], "strip-dwo">,
+def g : Flag<["-"], "g">, Alias<strip_debug>,
+ HelpText<"Alias for --strip-debug">;
+def strip_dwo : Flag<["--"], "strip-dwo">,
HelpText<"Remove all DWARF .dwo sections from file">;
-def strip_sections : Flag<["-", "--"], "strip-sections">,
- HelpText<"Remove all section headers">;
-def strip_non_alloc : Flag<["-", "--"], "strip-non-alloc">,
- HelpText<"Remove all non-allocated sections">;
-def strip_unneeded : Flag<["-", "--"], "strip-unneeded">,
+def strip_sections
+ : Flag<["--"], "strip-sections">,
+ HelpText<"Remove all section headers and all sections not in segments">;
+def strip_non_alloc
+ : Flag<["--"], "strip-non-alloc">,
+ HelpText<"Remove all non-allocated sections outside segments">;
+def strip_unneeded : Flag<["--"], "strip-unneeded">,
HelpText<"Remove all symbols not needed by relocations">;
+defm strip_unneeded_symbol
+ : Eq<"strip-unneeded-symbol",
+ "Remove symbol <symbol> if it is not needed by relocations">,
+ MetaVarName<"symbol">;
+defm strip_unneeded_symbols
+ : Eq<"strip-unneeded-symbols",
+ "Reads a list of symbols from <filename> and removes them "
+ "if they are not needed by relocations">,
+ MetaVarName<"filename">;
def extract_dwo
- : Flag<["-", "--"], "extract-dwo">,
+ : Flag<["--"], "extract-dwo">,
HelpText<
"Remove all sections that are not DWARF .dwo sections from file">;
+defm extract_partition
+ : Eq<"extract-partition", "Extract named partition from input file">,
+ MetaVarName<"name">;
+def extract_main_partition
+ : Flag<["--"], "extract-main-partition">,
+ HelpText<"Extract main partition from the input file">;
+
def localize_hidden
- : Flag<["-", "--"], "localize-hidden">,
+ : Flag<["--"], "localize-hidden">,
HelpText<
"Mark all symbols that have hidden or internal visibility as local">;
defm localize_symbol : Eq<"localize-symbol", "Mark <symbol> as local">,
MetaVarName<"symbol">;
+defm localize_symbols
+ : Eq<"localize-symbols",
+ "Reads a list of symbols from <filename> and marks them local.">,
+ MetaVarName<"filename">;
+
def L : JoinedOrSeparate<["-"], "L">, Alias<localize_symbol>;
defm globalize_symbol : Eq<"globalize-symbol", "Mark <symbol> as global">,
MetaVarName<"symbol">;
+
+defm globalize_symbols
+ : Eq<"globalize-symbols",
+ "Reads a list of symbols from <filename> and marks them global.">,
+ MetaVarName<"filename">;
+
defm keep_global_symbol
: Eq<"keep-global-symbol",
"Convert all symbols except <symbol> to local. May be repeated to "
@@ -137,23 +191,51 @@ defm keep_global_symbols
defm weaken_symbol : Eq<"weaken-symbol", "Mark <symbol> as weak">,
MetaVarName<"symbol">;
+defm weaken_symbols
+ : Eq<"weaken-symbols",
+ "Reads a list of symbols from <filename> and marks them weak.">,
+ MetaVarName<"filename">;
+
def W : JoinedOrSeparate<["-"], "W">, Alias<weaken_symbol>;
-def weaken : Flag<["-", "--"], "weaken">,
+def weaken : Flag<["--"], "weaken">,
HelpText<"Mark all global symbols as weak">;
+
+def discard_locals : Flag<["--"], "discard-locals">,
+ HelpText<"Remove compiler-generated local symbols, (e.g. "
+ "symbols starting with .L)">;
+def X : Flag<["-"], "X">, Alias<discard_locals>;
+
def discard_all
- : Flag<["-", "--"], "discard-all">,
+ : Flag<["--"], "discard-all">,
HelpText<"Remove all local symbols except file and section symbols">;
def x : Flag<["-"], "x">, Alias<discard_all>;
defm strip_symbol : Eq<"strip-symbol", "Remove symbol <symbol>">,
MetaVarName<"symbol">;
+defm strip_symbols
+ : Eq<"strip-symbols",
+ "Reads a list of symbols from <filename> and removes them.">,
+ MetaVarName<"filename">;
+
def N : JoinedOrSeparate<["-"], "N">, Alias<strip_symbol>;
defm keep_symbol : Eq<"keep-symbol", "Do not remove symbol <symbol>">,
MetaVarName<"symbol">;
def K : JoinedOrSeparate<["-"], "K">, Alias<keep_symbol>;
+
+defm keep_symbols
+ : Eq<"keep-symbols",
+ "Reads a list of symbols from <filename> and runs as if "
+ "--keep-symbol=<symbol> is set for each one. <filename> "
+ "contains one symbol per line and may contain comments beginning with "
+ "'#'. Leading and trailing whitespace is stripped from each line. May "
+ "be repeated to read symbols from many files.">,
+ MetaVarName<"filename">;
+
def only_keep_debug
- : Flag<["-", "--"], "only-keep-debug">,
- HelpText<"Currently ignored. Only for compatibility with GNU objcopy.">;
-def keep_file_symbols : Flag<["-", "--"], "keep-file-symbols">,
+ : Flag<["--"], "only-keep-debug">,
+ HelpText<"Clear sections that would not be stripped by --strip-debug. "
+ "Currently only implemented for COFF.">;
+
+def keep_file_symbols : Flag<["--"], "keep-file-symbols">,
HelpText<"Do not remove file symbols">;
defm dump_section
: Eq<"dump-section",
@@ -163,7 +245,11 @@ defm prefix_symbols
: Eq<"prefix-symbols", "Add <prefix> to the start of every symbol name">,
MetaVarName<"prefix">;
-def version : Flag<["-", "--"], "version">,
+defm prefix_alloc_sections
+ : Eq<"prefix-alloc-sections", "Add <prefix> to the start of every allocated section name">,
+ MetaVarName<"prefix">;
+
+def version : Flag<["--"], "version">,
HelpText<"Print the version and exit.">;
def V : Flag<["-"], "V">, Alias<version>;
defm build_id_link_dir
@@ -178,3 +264,25 @@ defm build_id_link_output
: Eq<"build-id-link-output", "Hard-link the output to <dir>/xx/xxx<suffix> "
"name derived from hex build ID">,
MetaVarName<"suffix">;
+
+def regex
+ : Flag<["--"], "regex">,
+ HelpText<"Permit regular expressions in name comparison">;
+
+defm set_start : Eq<"set-start", "Set the start address to <addr>. Overrides "
+ "any previous --change-start or --adjust-start values.">,
+ MetaVarName<"addr">;
+defm change_start : Eq<"change-start", "Add <incr> to the start address. Can be "
+ "specified multiple times, all values will be applied "
+ "cumulatively.">,
+ MetaVarName<"incr">;
+def adjust_start : JoinedOrSeparate<["--"], "adjust-start">,
+ Alias<change_start>;
+
+defm add_symbol
+ : Eq<"add-symbol", "Add new symbol <name> to .symtab. Accepted flags: "
+ "global, local, weak, default, hidden, file, section, object, "
+ "function, indirect-function. Accepted but ignored for "
+ "compatibility: debug, constructor, warning, indirect, synthetic, "
+ "unique-object, before.">,
+ MetaVarName<"name=[section:]value[,flags]">;
diff --git a/contrib/llvm/tools/llvm-objcopy/StripOpts.td b/contrib/llvm/tools/llvm-objcopy/StripOpts.td
index fa98e27e9321..1d06bb3dfb38 100644
--- a/contrib/llvm/tools/llvm-objcopy/StripOpts.td
+++ b/contrib/llvm/tools/llvm-objcopy/StripOpts.td
@@ -1,16 +1,23 @@
include "llvm/Option/OptParser.td"
multiclass Eq<string name, string help> {
- def NAME : Separate<["--", "-"], name>;
- def NAME #_eq : Joined<["--", "-"], name #"=">,
+ def NAME : Separate<["--"], name>;
+ def NAME #_eq : Joined<["--"], name #"=">,
Alias<!cast<Separate>(NAME)>,
HelpText<help>;
}
-def help : Flag<["-", "--"], "help">;
+def help : Flag<["--"], "help">;
+def h : Flag<["-"], "h">, Alias<help>;
+
+def allow_broken_links
+ : Flag<["--"], "allow-broken-links">,
+ HelpText<"Allow llvm-strip to remove sections even if it would leave "
+ "invalid section references. The appropriate sh_link fields "
+ "will be set to zero.">;
def enable_deterministic_archives
- : Flag<["-", "--"], "enable-deterministic-archives">,
+ : Flag<["--"], "enable-deterministic-archives">,
HelpText<"Enable deterministic mode when stripping archives (use zero "
"for UIDs, GIDs, and timestamps).">;
def D : Flag<["-"], "D">,
@@ -18,50 +25,72 @@ def D : Flag<["-"], "D">,
HelpText<"Alias for --enable-deterministic-archives">;
def disable_deterministic_archives
- : Flag<["-", "--"], "disable-deterministic-archives">,
+ : Flag<["--"], "disable-deterministic-archives">,
HelpText<"Disable deterministic mode when stripping archives (use real "
"values for UIDs, GIDs, and timestamps).">;
def U : Flag<["-"], "U">,
Alias<disable_deterministic_archives>,
HelpText<"Alias for --disable-deterministic-archives">;
-defm output : Eq<"o", "Write output to <file>">, MetaVarName<"output">;
+def output : JoinedOrSeparate<["-"], "o">, HelpText<"Write output to <file>">;
-def preserve_dates : Flag<["-", "--"], "preserve-dates">,
+def preserve_dates : Flag<["--"], "preserve-dates">,
HelpText<"Preserve access and modification timestamps">;
def p : Flag<["-"], "p">, Alias<preserve_dates>;
-def strip_all
- : Flag<["-", "--"], "strip-all">,
- HelpText<
- "Remove non-allocated sections other than .gnu.warning* sections">;
+def strip_all : Flag<["--"], "strip-all">,
+ HelpText<"Remove non-allocated sections outside segments. "
+ ".gnu.warning* sections are not removed">;
def s : Flag<["-"], "s">, Alias<strip_all>;
+def no_strip_all : Flag<["--"], "no-strip-all">,
+ HelpText<"Disable --strip-all">;
-def strip_all_gnu : Flag<["-", "--"], "strip-all-gnu">,
+def strip_all_gnu : Flag<["--"], "strip-all-gnu">,
HelpText<"Compatible with GNU strip's --strip-all">;
-def strip_debug : Flag<["-", "--"], "strip-debug">,
+def strip_debug : Flag<["--"], "strip-debug">,
HelpText<"Remove debugging symbols only">;
def d : Flag<["-"], "d">, Alias<strip_debug>;
def g : Flag<["-"], "g">, Alias<strip_debug>;
def S : Flag<["-"], "S">, Alias<strip_debug>;
-def strip_unneeded : Flag<["-", "--"], "strip-unneeded">,
+def strip_unneeded : Flag<["--"], "strip-unneeded">,
HelpText<"Remove all symbols not needed by relocations">;
defm remove_section : Eq<"remove-section", "Remove <section>">,
MetaVarName<"section">;
def R : JoinedOrSeparate<["-"], "R">, Alias<remove_section>;
+defm strip_symbol : Eq<"strip-symbol", "Strip <symbol>">,
+ MetaVarName<"symbol">;
+def N : JoinedOrSeparate<["-"], "N">, Alias<strip_symbol>;
+
defm keep_section : Eq<"keep-section", "Keep <section>">,
MetaVarName<"section">;
defm keep_symbol : Eq<"keep-symbol", "Do not remove symbol <symbol>">,
MetaVarName<"symbol">;
+def keep_file_symbols : Flag<["--"], "keep-file-symbols">,
+ HelpText<"Do not remove file symbols">;
+
def K : JoinedOrSeparate<["-"], "K">, Alias<keep_symbol>;
+def only_keep_debug
+ : Flag<["--"], "only-keep-debug">,
+ HelpText<"Clear sections that would not be stripped by --strip-debug. "
+ "Currently only implemented for COFF.">;
+
+def discard_locals : Flag<["--"], "discard-locals">,
+ HelpText<"Remove compiler-generated local symbols, (e.g. "
+ "symbols starting with .L)">;
+def X : Flag<["-"], "X">, Alias<discard_locals>;
+
def discard_all
- : Flag<["-", "--"], "discard-all">,
+ : Flag<["--"], "discard-all">,
HelpText<"Remove all local symbols except file and section symbols">;
def x : Flag<["-"], "x">, Alias<discard_all>;
-def version : Flag<["-", "--"], "version">,
+def regex
+ : Flag<["--"], "regex">,
+ HelpText<"Permit regular expressions in name comparison">;
+
+def version : Flag<["--"], "version">,
HelpText<"Print the version and exit.">;
def V : Flag<["-"], "V">, Alias<version>;
diff --git a/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
index fb1ff18b015b..e9372176e43b 100644
--- a/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -1,17 +1,17 @@
//===- llvm-objcopy.cpp ---------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm-objcopy.h"
#include "Buffer.h"
-#include "COFF/COFFObjcopy.h"
#include "CopyConfig.h"
#include "ELF/ELFObjcopy.h"
+#include "COFF/COFFObjcopy.h"
+#include "MachO/MachOObjcopy.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
@@ -24,6 +24,7 @@
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ELFTypes.h"
#include "llvm/Object/Error.h"
+#include "llvm/Object/MachO.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
@@ -52,16 +53,23 @@ namespace objcopy {
StringRef ToolName;
LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
- WithColor::error(errs(), ToolName) << Message << ".\n";
- errs().flush();
+ WithColor::error(errs(), ToolName) << Message << "\n";
+ exit(1);
+}
+
+LLVM_ATTRIBUTE_NORETURN void error(Error E) {
+ assert(E);
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ logAllUnhandledErrors(std::move(E), OS);
+ OS.flush();
+ WithColor::error(errs(), ToolName) << Buf;
exit(1);
}
LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
assert(EC);
- WithColor::error(errs(), ToolName)
- << "'" << File << "': " << EC.message() << ".\n";
- exit(1);
+ error(createFileError(File, EC));
}
LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
@@ -74,6 +82,12 @@ LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
exit(1);
}
+ErrorSuccess reportWarning(Error E) {
+ assert(E);
+ WithColor::warning(errs(), ToolName) << toString(std::move(E));
+ return Error::success();
+}
+
} // end namespace objcopy
} // end namespace llvm
@@ -87,10 +101,13 @@ static Error deepWriteArchive(StringRef ArcName,
ArrayRef<NewArchiveMember> NewMembers,
bool WriteSymtab, object::Archive::Kind Kind,
bool Deterministic, bool Thin) {
- Error E =
- writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin);
- if (!Thin || E)
- return E;
+ if (Error E = writeArchive(ArcName, NewMembers, WriteSymtab, Kind,
+ Deterministic, Thin))
+ return createFileError(ArcName, std::move(E));
+
+ if (!Thin)
+ return Error::success();
+
for (const NewArchiveMember &Member : NewMembers) {
// Internally, FileBuffer will use the buffer created by
// FileOutputBuffer::create, for regular files (that is the case for
@@ -101,132 +118,212 @@ static Error deepWriteArchive(StringRef ArcName,
// NewArchiveMember still requires them even though writeArchive does not
// write them on disk.
FileBuffer FB(Member.MemberName);
- FB.allocate(Member.Buf->getBufferSize());
+ if (Error E = FB.allocate(Member.Buf->getBufferSize()))
+ return E;
std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
FB.getBufferStart());
- if (auto E = FB.commit())
+ if (Error E = FB.commit())
return E;
}
return Error::success();
}
+/// The function executeObjcopyOnIHex does the dispatch based on the format
+/// of the output specified by the command line options.
+static Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
+ Buffer &Out) {
+ // TODO: support output formats other than ELF.
+ return elf::executeObjcopyOnIHex(Config, In, Out);
+}
+
/// The function executeObjcopyOnRawBinary does the dispatch based on the format
/// of the output specified by the command line options.
-static void executeObjcopyOnRawBinary(const CopyConfig &Config,
- MemoryBuffer &In, Buffer &Out) {
- // TODO: llvm-objcopy should parse CopyConfig.OutputFormat to recognize
- // formats other than ELF / "binary" and invoke
- // elf::executeObjcopyOnRawBinary, macho::executeObjcopyOnRawBinary or
- // coff::executeObjcopyOnRawBinary accordingly.
- return elf::executeObjcopyOnRawBinary(Config, In, Out);
+static Error executeObjcopyOnRawBinary(const CopyConfig &Config,
+ MemoryBuffer &In, Buffer &Out) {
+ switch (Config.OutputFormat) {
+ case FileFormat::ELF:
+ // FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the
+ // output format is binary/ihex or it's not given. This behavior differs from
+ // GNU objcopy. See https://bugs.llvm.org/show_bug.cgi?id=42171 for details.
+ case FileFormat::Binary:
+ case FileFormat::IHex:
+ case FileFormat::Unspecified:
+ return elf::executeObjcopyOnRawBinary(Config, In, Out);
+ }
+
+ llvm_unreachable("unsupported output format");
}
/// The function executeObjcopyOnBinary does the dispatch based on the format
/// of the input binary (ELF, MachO or COFF).
-static void executeObjcopyOnBinary(const CopyConfig &Config, object::Binary &In,
- Buffer &Out) {
+static Error executeObjcopyOnBinary(const CopyConfig &Config,
+ object::Binary &In, Buffer &Out) {
if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In))
return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out);
else if (auto *COFFBinary = dyn_cast<object::COFFObjectFile>(&In))
return coff::executeObjcopyOnBinary(Config, *COFFBinary, Out);
+ else if (auto *MachOBinary = dyn_cast<object::MachOObjectFile>(&In))
+ return macho::executeObjcopyOnBinary(Config, *MachOBinary, Out);
else
- error("Unsupported object file format");
+ return createStringError(object_error::invalid_file_type,
+ "unsupported object file format");
}
-static void executeObjcopyOnArchive(const CopyConfig &Config,
- const Archive &Ar) {
+static Error executeObjcopyOnArchive(const CopyConfig &Config,
+ const Archive &Ar) {
std::vector<NewArchiveMember> NewArchiveMembers;
Error Err = Error::success();
for (const Archive::Child &Child : Ar.children(Err)) {
- Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
- if (!ChildOrErr)
- reportError(Ar.getFileName(), ChildOrErr.takeError());
- Binary *Bin = ChildOrErr->get();
-
Expected<StringRef> ChildNameOrErr = Child.getName();
if (!ChildNameOrErr)
- reportError(Ar.getFileName(), ChildNameOrErr.takeError());
+ return createFileError(Ar.getFileName(), ChildNameOrErr.takeError());
+
+ Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
+ if (!ChildOrErr)
+ return createFileError(Ar.getFileName() + "(" + *ChildNameOrErr + ")",
+ ChildOrErr.takeError());
MemBuffer MB(ChildNameOrErr.get());
- executeObjcopyOnBinary(Config, *Bin, MB);
+ if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MB))
+ return E;
Expected<NewArchiveMember> Member =
NewArchiveMember::getOldMember(Child, Config.DeterministicArchives);
if (!Member)
- reportError(Ar.getFileName(), Member.takeError());
+ return createFileError(Ar.getFileName(), Member.takeError());
Member->Buf = MB.releaseMemoryBuffer();
Member->MemberName = Member->Buf->getBufferIdentifier();
NewArchiveMembers.push_back(std::move(*Member));
}
-
if (Err)
- reportError(Config.InputFilename, std::move(Err));
- if (Error E = deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
- Ar.hasSymbolTable(), Ar.kind(),
- Config.DeterministicArchives, Ar.isThin()))
- reportError(Config.OutputFilename, std::move(E));
+ return createFileError(Config.InputFilename, std::move(Err));
+
+ return deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
+ Ar.hasSymbolTable(), Ar.kind(),
+ Config.DeterministicArchives, Ar.isThin());
}
-static void restoreDateOnFile(StringRef Filename,
- const sys::fs::file_status &Stat) {
+static Error restoreStatOnFile(StringRef Filename,
+ const sys::fs::file_status &Stat,
+ bool PreserveDates) {
int FD;
+ // Writing to stdout should not be treated as an error here, just
+ // do not set access/modification times or permissions.
+ if (Filename == "-")
+ return Error::success();
+
if (auto EC =
sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting))
- reportError(Filename, EC);
+ return createFileError(Filename, EC);
+
+ if (PreserveDates)
+ if (auto EC = sys::fs::setLastAccessAndModificationTime(
+ FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
+ return createFileError(Filename, EC);
- if (auto EC = sys::fs::setLastAccessAndModificationTime(
- FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
- reportError(Filename, EC);
+ sys::fs::file_status OStat;
+ if (std::error_code EC = sys::fs::status(FD, OStat))
+ return createFileError(Filename, EC);
+ if (OStat.type() == sys::fs::file_type::regular_file)
+#ifdef _WIN32
+ if (auto EC = sys::fs::setPermissions(
+ Filename, static_cast<sys::fs::perms>(Stat.permissions() &
+ ~sys::fs::getUmask())))
+#else
+ if (auto EC = sys::fs::setPermissions(
+ FD, static_cast<sys::fs::perms>(Stat.permissions() &
+ ~sys::fs::getUmask())))
+#endif
+ return createFileError(Filename, EC);
if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
- reportError(Filename, EC);
+ return createFileError(Filename, EC);
+
+ return Error::success();
}
/// The function executeObjcopy does the higher level dispatch based on the type
/// of input (raw binary, archive or single object file) and takes care of the
/// format-agnostic modifications, i.e. preserving dates.
-static void executeObjcopy(const CopyConfig &Config) {
+static Error executeObjcopy(const CopyConfig &Config) {
sys::fs::file_status Stat;
- if (Config.PreserveDates)
+ if (Config.InputFilename != "-") {
if (auto EC = sys::fs::status(Config.InputFilename, Stat))
- reportError(Config.InputFilename, EC);
+ return createFileError(Config.InputFilename, EC);
+ } else {
+ Stat.permissions(static_cast<sys::fs::perms>(0777));
+ }
- if (Config.InputFormat == "binary") {
- auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename);
+ typedef Error (*ProcessRawFn)(const CopyConfig &, MemoryBuffer &, Buffer &);
+ ProcessRawFn ProcessRaw;
+ switch (Config.InputFormat) {
+ case FileFormat::Binary:
+ ProcessRaw = executeObjcopyOnRawBinary;
+ break;
+ case FileFormat::IHex:
+ ProcessRaw = executeObjcopyOnIHex;
+ break;
+ default:
+ ProcessRaw = nullptr;
+ }
+
+ if (ProcessRaw) {
+ auto BufOrErr = MemoryBuffer::getFileOrSTDIN(Config.InputFilename);
if (!BufOrErr)
- reportError(Config.InputFilename, BufOrErr.getError());
+ return createFileError(Config.InputFilename, BufOrErr.getError());
FileBuffer FB(Config.OutputFilename);
- executeObjcopyOnRawBinary(Config, *BufOrErr->get(), FB);
+ if (Error E = ProcessRaw(Config, *BufOrErr->get(), FB))
+ return E;
} else {
Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
createBinary(Config.InputFilename);
if (!BinaryOrErr)
- reportError(Config.InputFilename, BinaryOrErr.takeError());
+ return createFileError(Config.InputFilename, BinaryOrErr.takeError());
if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) {
- executeObjcopyOnArchive(Config, *Ar);
+ if (Error E = executeObjcopyOnArchive(Config, *Ar))
+ return E;
} else {
FileBuffer FB(Config.OutputFilename);
- executeObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB);
+ if (Error E = executeObjcopyOnBinary(Config,
+ *BinaryOrErr.get().getBinary(), FB))
+ return E;
}
}
- if (Config.PreserveDates) {
- restoreDateOnFile(Config.OutputFilename, Stat);
- if (!Config.SplitDWO.empty())
- restoreDateOnFile(Config.SplitDWO, Stat);
+ if (Error E =
+ restoreStatOnFile(Config.OutputFilename, Stat, Config.PreserveDates))
+ return E;
+
+ if (!Config.SplitDWO.empty()) {
+ Stat.permissions(static_cast<sys::fs::perms>(0666));
+ if (Error E =
+ restoreStatOnFile(Config.SplitDWO, Stat, Config.PreserveDates))
+ return E;
}
+
+ return Error::success();
}
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
ToolName = argv[0];
- DriverConfig DriverConfig;
- if (sys::path::stem(ToolName).contains("strip"))
- DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc));
- else
- DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc));
- for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs)
- executeObjcopy(CopyConfig);
+ bool IsStrip = sys::path::stem(ToolName).contains("strip");
+ Expected<DriverConfig> DriverConfig =
+ IsStrip ? parseStripOptions(makeArrayRef(argv + 1, argc), reportWarning)
+ : parseObjcopyOptions(makeArrayRef(argv + 1, argc));
+ if (!DriverConfig) {
+ logAllUnhandledErrors(DriverConfig.takeError(),
+ WithColor::error(errs(), ToolName));
+ return 1;
+ }
+ for (const CopyConfig &CopyConfig : DriverConfig->CopyConfigs) {
+ if (Error E = executeObjcopy(CopyConfig)) {
+ logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName));
+ return 1;
+ }
+ }
+
+ return 0;
}
diff --git a/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.h b/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.h
index d8edf3e29ee0..18a789ca1f83 100644
--- a/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.h
+++ b/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.h
@@ -1,9 +1,8 @@
//===- llvm-objcopy.h -------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -20,6 +19,7 @@ namespace llvm {
namespace objcopy {
LLVM_ATTRIBUTE_NORETURN extern void error(Twine Message);
+LLVM_ATTRIBUTE_NORETURN extern void error(Error E);
LLVM_ATTRIBUTE_NORETURN extern void reportError(StringRef File, Error E);
LLVM_ATTRIBUTE_NORETURN extern void reportError(StringRef File,
std::error_code EC);
diff --git a/contrib/llvm/tools/llvm-objdump/COFFDump.cpp b/contrib/llvm/tools/llvm-objdump/COFFDump.cpp
index 55607ec299be..1ba0a68902c9 100644
--- a/contrib/llvm/tools/llvm-objdump/COFFDump.cpp
+++ b/contrib/llvm/tools/llvm-objdump/COFFDump.cpp
@@ -1,9 +1,8 @@
//===-- COFFDump.cpp - COFF-specific dumper ---------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -25,10 +24,10 @@
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
-using namespace llvm;
-using namespace object;
+using namespace llvm::object;
using namespace llvm::Win64EH;
+namespace llvm {
// Returns the name of the unwind code.
static StringRef getUnwindCodeTypeName(uint8_t Code) {
switch(Code) {
@@ -156,70 +155,68 @@ static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
}
// Given a symbol sym this functions returns the address and section of it.
-static std::error_code
-resolveSectionAndAddress(const COFFObjectFile *Obj, const SymbolRef &Sym,
- const coff_section *&ResolvedSection,
- uint64_t &ResolvedAddr) {
+static Error resolveSectionAndAddress(const COFFObjectFile *Obj,
+ const SymbolRef &Sym,
+ const coff_section *&ResolvedSection,
+ uint64_t &ResolvedAddr) {
Expected<uint64_t> ResolvedAddrOrErr = Sym.getAddress();
if (!ResolvedAddrOrErr)
- return errorToErrorCode(ResolvedAddrOrErr.takeError());
+ return ResolvedAddrOrErr.takeError();
ResolvedAddr = *ResolvedAddrOrErr;
Expected<section_iterator> Iter = Sym.getSection();
if (!Iter)
- return errorToErrorCode(Iter.takeError());
+ return Iter.takeError();
ResolvedSection = Obj->getCOFFSection(**Iter);
- return std::error_code();
+ return Error::success();
}
// Given a vector of relocations for a section and an offset into this section
// the function returns the symbol used for the relocation at the offset.
-static std::error_code resolveSymbol(const std::vector<RelocationRef> &Rels,
+static Error resolveSymbol(const std::vector<RelocationRef> &Rels,
uint64_t Offset, SymbolRef &Sym) {
for (auto &R : Rels) {
uint64_t Ofs = R.getOffset();
if (Ofs == Offset) {
Sym = *R.getSymbol();
- return std::error_code();
+ return Error::success();
}
}
- return object_error::parse_failed;
+ return make_error<BinaryError>();
}
// Given a vector of relocations for a section and an offset into this section
// the function resolves the symbol used for the relocation at the offset and
// returns the section content and the address inside the content pointed to
// by the symbol.
-static std::error_code
+static Error
getSectionContents(const COFFObjectFile *Obj,
const std::vector<RelocationRef> &Rels, uint64_t Offset,
ArrayRef<uint8_t> &Contents, uint64_t &Addr) {
SymbolRef Sym;
- if (std::error_code EC = resolveSymbol(Rels, Offset, Sym))
- return EC;
+ if (Error E = resolveSymbol(Rels, Offset, Sym))
+ return E;
const coff_section *Section;
- if (std::error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr))
- return EC;
- if (std::error_code EC = Obj->getSectionContents(Section, Contents))
- return EC;
- return std::error_code();
+ if (Error E = resolveSectionAndAddress(Obj, Sym, Section, Addr))
+ return E;
+ return Obj->getSectionContents(Section, Contents);
}
// Given a vector of relocations for a section and an offset into this section
// the function returns the name of the symbol used for the relocation at the
// offset.
-static std::error_code resolveSymbolName(const std::vector<RelocationRef> &Rels,
- uint64_t Offset, StringRef &Name) {
+static Error resolveSymbolName(const std::vector<RelocationRef> &Rels,
+ uint64_t Offset, StringRef &Name) {
SymbolRef Sym;
- if (std::error_code EC = resolveSymbol(Rels, Offset, Sym))
+ if (Error EC = resolveSymbol(Rels, Offset, Sym))
return EC;
Expected<StringRef> NameOrErr = Sym.getName();
if (!NameOrErr)
- return errorToErrorCode(NameOrErr.takeError());
+ return NameOrErr.takeError();
Name = *NameOrErr;
- return std::error_code();
+ return Error::success();
}
-static void printCOFFSymbolAddress(llvm::raw_ostream &Out,
+static void printCOFFSymbolAddress(raw_ostream &Out,
const std::vector<RelocationRef> &Rels,
uint64_t Offset, uint32_t Disp) {
StringRef Sym;
@@ -469,6 +466,18 @@ static bool getPDataSection(const COFFObjectFile *Obj,
return false;
}
+Error getCOFFRelocationValueString(const COFFObjectFile *Obj,
+ const RelocationRef &Rel,
+ SmallVectorImpl<char> &Result) {
+ symbol_iterator SymI = Rel.getSymbol();
+ Expected<StringRef> SymNameOrErr = SymI->getName();
+ if (!SymNameOrErr)
+ return SymNameOrErr.takeError();
+ StringRef SymName = *SymNameOrErr;
+ Result.append(SymName.begin(), SymName.end());
+ return Error::success();
+}
+
static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) {
// The casts to int are required in order to output the value as number.
// Without the casts the value would be interpreted as char data (which
@@ -578,7 +587,7 @@ static void printRuntimeFunctionRels(const COFFObjectFile *Obj,
printWin64EHUnwindInfo(UI);
}
-void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
+void printCOFFUnwindInfo(const COFFObjectFile *Obj) {
if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64) {
WithColor::error(errs(), "llvm-objdump")
<< "unsupported image machine type "
@@ -607,7 +616,7 @@ void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
}
}
-void llvm::printCOFFFileHeader(const object::ObjectFile *Obj) {
+void printCOFFFileHeader(const object::ObjectFile *Obj) {
const COFFObjectFile *file = dyn_cast<const COFFObjectFile>(Obj);
printTLSDirectory(file);
printLoadConfiguration(file);
@@ -615,7 +624,7 @@ void llvm::printCOFFFileHeader(const object::ObjectFile *Obj) {
printExportTable(file);
}
-void llvm::printCOFFSymbolTable(const object::COFFImportFile *i) {
+void printCOFFSymbolTable(const object::COFFImportFile *i) {
unsigned Index = 0;
bool IsCode = i->getCOFFImportHeader()->getType() == COFF::IMPORT_CODE;
@@ -623,7 +632,7 @@ void llvm::printCOFFSymbolTable(const object::COFFImportFile *i) {
std::string Name;
raw_string_ostream NS(Name);
- Sym.printName(NS);
+ cantFail(Sym.printName(NS));
NS.flush();
outs() << "[" << format("%2d", Index) << "]"
@@ -638,11 +647,11 @@ void llvm::printCOFFSymbolTable(const object::COFFImportFile *i) {
}
}
-void llvm::printCOFFSymbolTable(const COFFObjectFile *coff) {
+void printCOFFSymbolTable(const COFFObjectFile *coff) {
for (unsigned SI = 0, SE = coff->getNumberOfSymbols(); SI != SE; ++SI) {
Expected<COFFSymbolRef> Symbol = coff->getSymbol(SI);
StringRef Name;
- error(errorToErrorCode(Symbol.takeError()));
+ error(Symbol.takeError());
error(coff->getSymbolName(*Symbol, Name));
outs() << "[" << format("%2d", SI) << "]"
@@ -709,3 +718,4 @@ void llvm::printCOFFSymbolTable(const COFFObjectFile *coff) {
}
}
}
+} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-objdump/ELFDump.cpp b/contrib/llvm/tools/llvm-objdump/ELFDump.cpp
index b17a15a0d8fc..9c4d67d0f1bd 100644
--- a/contrib/llvm/tools/llvm-objdump/ELFDump.cpp
+++ b/contrib/llvm/tools/llvm-objdump/ELFDump.cpp
@@ -1,9 +1,8 @@
//===-- ELFDump.cpp - ELF-specific dumper -----------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -13,23 +12,22 @@
//===----------------------------------------------------------------------===//
#include "llvm-objdump.h"
+#include "llvm/Demangle/Demangle.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-using namespace llvm;
using namespace llvm::object;
+namespace llvm {
template <class ELFT>
-Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> *Elf) {
- typedef ELFFile<ELFT> ELFO;
-
+static Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> *Elf) {
auto DynamicEntriesOrError = Elf->dynamicEntries();
if (!DynamicEntriesOrError)
return DynamicEntriesOrError.takeError();
- for (const typename ELFO::Elf_Dyn &Dyn : *DynamicEntriesOrError) {
+ for (const typename ELFT::Dyn &Dyn : *DynamicEntriesOrError) {
if (Dyn.d_tag == ELF::DT_STRTAB) {
auto MappedAddrOrError = Elf->toMappedAddr(Dyn.getPtr());
if (!MappedAddrOrError)
@@ -43,7 +41,7 @@ Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> *Elf) {
if (!SectionsOrError)
return SectionsOrError.takeError();
- for (const typename ELFO::Elf_Shdr &Sec : *SectionsOrError) {
+ for (const typename ELFT::Shdr &Sec : *SectionsOrError) {
if (Sec.sh_type == ELF::SHT_DYNSYM)
return Elf->getStringTableForSymtab(Sec);
}
@@ -52,40 +50,135 @@ Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> *Elf) {
}
template <class ELFT>
-void printDynamicSection(const ELFFile<ELFT> *Elf, StringRef Filename) {
- auto ProgramHeaderOrError = Elf->program_headers();
- if (!ProgramHeaderOrError)
- report_error(Filename, ProgramHeaderOrError.takeError());
+static Error getRelocationValueString(const ELFObjectFile<ELFT> *Obj,
+ const RelocationRef &RelRef,
+ SmallVectorImpl<char> &Result) {
+ const ELFFile<ELFT> &EF = *Obj->getELFFile();
+ DataRefImpl Rel = RelRef.getRawDataRefImpl();
+ auto SecOrErr = EF.getSection(Rel.d.a);
+ if (!SecOrErr)
+ return SecOrErr.takeError();
- auto DynamicEntriesOrError = Elf->dynamicEntries();
- if (!DynamicEntriesOrError)
- report_error(Filename, DynamicEntriesOrError.takeError());
+ int64_t Addend = 0;
+ // If there is no Symbol associated with the relocation, we set the undef
+ // boolean value to 'true'. This will prevent us from calling functions that
+ // requires the relocation to be associated with a symbol.
+ //
+ // In SHT_REL case we would need to read the addend from section data.
+ // GNU objdump does not do that and we just follow for simplicity atm.
+ bool Undef = false;
+ if ((*SecOrErr)->sh_type == ELF::SHT_RELA) {
+ const typename ELFT::Rela *ERela = Obj->getRela(Rel);
+ Addend = ERela->r_addend;
+ Undef = ERela->getSymbol(false) == 0;
+ } else if ((*SecOrErr)->sh_type != ELF::SHT_REL) {
+ return make_error<BinaryError>();
+ }
+
+ // Default scheme is to print Target, as well as "+ <addend>" for nonzero
+ // addend. Should be acceptable for all normal purposes.
+ std::string FmtBuf;
+ raw_string_ostream Fmt(FmtBuf);
+
+ if (!Undef) {
+ symbol_iterator SI = RelRef.getSymbol();
+ const typename ELFT::Sym *Sym = Obj->getSymbol(SI->getRawDataRefImpl());
+ if (Sym->getType() == ELF::STT_SECTION) {
+ Expected<section_iterator> SymSI = SI->getSection();
+ if (!SymSI)
+ return SymSI.takeError();
+ const typename ELFT::Shdr *SymSec =
+ Obj->getSection((*SymSI)->getRawDataRefImpl());
+ auto SecName = EF.getSectionName(SymSec);
+ if (!SecName)
+ return SecName.takeError();
+ Fmt << *SecName;
+ } else {
+ Expected<StringRef> SymName = SI->getName();
+ if (!SymName)
+ return SymName.takeError();
+ if (Demangle)
+ Fmt << demangle(*SymName);
+ else
+ Fmt << *SymName;
+ }
+ } else {
+ Fmt << "*ABS*";
+ }
+
+ if (Addend != 0)
+ Fmt << (Addend < 0 ? "" : "+") << Addend;
+ Fmt.flush();
+ Result.append(FmtBuf.begin(), FmtBuf.end());
+ return Error::success();
+}
+Error getELFRelocationValueString(const ELFObjectFileBase *Obj,
+ const RelocationRef &Rel,
+ SmallVectorImpl<char> &Result) {
+ if (auto *ELF32LE = dyn_cast<ELF32LEObjectFile>(Obj))
+ return getRelocationValueString(ELF32LE, Rel, Result);
+ if (auto *ELF64LE = dyn_cast<ELF64LEObjectFile>(Obj))
+ return getRelocationValueString(ELF64LE, Rel, Result);
+ if (auto *ELF32BE = dyn_cast<ELF32BEObjectFile>(Obj))
+ return getRelocationValueString(ELF32BE, Rel, Result);
+ auto *ELF64BE = cast<ELF64BEObjectFile>(Obj);
+ return getRelocationValueString(ELF64BE, Rel, Result);
+}
+
+template <class ELFT>
+static uint64_t getSectionLMA(const ELFFile<ELFT> *Obj,
+ const object::ELFSectionRef &Sec) {
+ auto PhdrRangeOrErr = Obj->program_headers();
+ if (!PhdrRangeOrErr)
+ report_fatal_error(toString(PhdrRangeOrErr.takeError()));
+
+ // Search for a PT_LOAD segment containing the requested section. Use this
+ // segment's p_addr to calculate the section's LMA.
+ for (const typename ELFT::Phdr &Phdr : *PhdrRangeOrErr)
+ if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_vaddr <= Sec.getAddress()) &&
+ (Phdr.p_vaddr + Phdr.p_memsz > Sec.getAddress()))
+ return Sec.getAddress() - Phdr.p_vaddr + Phdr.p_paddr;
+
+ // Return section's VMA if it isn't in a PT_LOAD segment.
+ return Sec.getAddress();
+}
+
+uint64_t getELFSectionLMA(const object::ELFSectionRef &Sec) {
+ if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Sec.getObject()))
+ return getSectionLMA(ELFObj->getELFFile(), Sec);
+ else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Sec.getObject()))
+ return getSectionLMA(ELFObj->getELFFile(), Sec);
+ else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Sec.getObject()))
+ return getSectionLMA(ELFObj->getELFFile(), Sec);
+ const auto *ELFObj = cast<ELF64BEObjectFile>(Sec.getObject());
+ return getSectionLMA(ELFObj->getELFFile(), Sec);
+}
+
+template <class ELFT>
+void printDynamicSection(const ELFFile<ELFT> *Elf, StringRef Filename) {
+ ArrayRef<typename ELFT::Dyn> DynamicEntries =
+ unwrapOrError(Elf->dynamicEntries(), Filename);
outs() << "Dynamic Section:\n";
- for (const auto &Dyn : *DynamicEntriesOrError) {
+ for (const typename ELFT::Dyn &Dyn : DynamicEntries) {
if (Dyn.d_tag == ELF::DT_NULL)
continue;
- StringRef Str = StringRef(Elf->getDynamicTagAsString(Dyn.d_tag));
-
- if (Str.empty()) {
- std::string HexStr = utohexstr(static_cast<uint64_t>(Dyn.d_tag), true);
- outs() << format(" 0x%-19s", HexStr.c_str());
- } else {
- // We use "-21" in order to match GNU objdump's output.
- outs() << format(" %-21s", Str.data());
- }
+ std::string Str = Elf->getDynamicTagAsString(Dyn.d_tag);
+ outs() << format(" %-21s", Str.c_str());
const char *Fmt =
ELFT::Is64Bits ? "0x%016" PRIx64 "\n" : "0x%08" PRIx64 "\n";
- if (Dyn.d_tag == ELF::DT_NEEDED) {
+ if (Dyn.d_tag == ELF::DT_NEEDED || Dyn.d_tag == ELF::DT_RPATH ||
+ Dyn.d_tag == ELF::DT_RUNPATH || Dyn.d_tag == ELF::DT_SONAME ||
+ Dyn.d_tag == ELF::DT_AUXILIARY || Dyn.d_tag == ELF::DT_FILTER) {
Expected<StringRef> StrTabOrErr = getDynamicStrTab(Elf);
if (StrTabOrErr) {
const char *Data = StrTabOrErr.get().data();
outs() << (Data + Dyn.d_un.d_val) << "\n";
continue;
}
- warn(errorToErrorCode(StrTabOrErr.takeError()).message());
+ warn(toString(StrTabOrErr.takeError()));
consumeError(StrTabOrErr.takeError());
}
outs() << format(Fmt, (uint64_t)Dyn.d_un.d_val);
@@ -93,13 +186,11 @@ void printDynamicSection(const ELFFile<ELFT> *Elf, StringRef Filename) {
}
template <class ELFT> void printProgramHeaders(const ELFFile<ELFT> *o) {
- typedef ELFFile<ELFT> ELFO;
outs() << "Program Header:\n";
auto ProgramHeaderOrError = o->program_headers();
if (!ProgramHeaderOrError)
- report_fatal_error(
- errorToErrorCode(ProgramHeaderOrError.takeError()).message());
- for (const typename ELFO::Elf_Phdr &Phdr : *ProgramHeaderOrError) {
+ report_fatal_error(toString(ProgramHeaderOrError.takeError()));
+ for (const typename ELFT::Phdr &Phdr : *ProgramHeaderOrError) {
switch (Phdr.p_type) {
case ELF::PT_DYNAMIC:
outs() << " DYNAMIC ";
@@ -157,7 +248,86 @@ template <class ELFT> void printProgramHeaders(const ELFFile<ELFT> *o) {
outs() << "\n";
}
-void llvm::printELFFileHeader(const object::ObjectFile *Obj) {
+template <class ELFT>
+void printSymbolVersionDependency(ArrayRef<uint8_t> Contents,
+ StringRef StrTab) {
+ outs() << "Version References:\n";
+
+ const uint8_t *Buf = Contents.data();
+ while (Buf) {
+ auto *Verneed = reinterpret_cast<const typename ELFT::Verneed *>(Buf);
+ outs() << " required from "
+ << StringRef(StrTab.drop_front(Verneed->vn_file).data()) << ":\n";
+
+ const uint8_t *BufAux = Buf + Verneed->vn_aux;
+ while (BufAux) {
+ auto *Vernaux = reinterpret_cast<const typename ELFT::Vernaux *>(BufAux);
+ outs() << " "
+ << format("0x%08" PRIx32 " ", (uint32_t)Vernaux->vna_hash)
+ << format("0x%02" PRIx16 " ", (uint16_t)Vernaux->vna_flags)
+ << format("%02" PRIu16 " ", (uint16_t)Vernaux->vna_other)
+ << StringRef(StrTab.drop_front(Vernaux->vna_name).data()) << '\n';
+ BufAux = Vernaux->vna_next ? BufAux + Vernaux->vna_next : nullptr;
+ }
+ Buf = Verneed->vn_next ? Buf + Verneed->vn_next : nullptr;
+ }
+}
+
+template <class ELFT>
+void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr,
+ ArrayRef<uint8_t> Contents,
+ StringRef StrTab) {
+ outs() << "Version definitions:\n";
+
+ const uint8_t *Buf = Contents.data();
+ uint32_t VerdefIndex = 1;
+ // sh_info contains the number of entries in the SHT_GNU_verdef section. To
+ // make the index column have consistent width, we should insert blank spaces
+ // according to sh_info.
+ uint16_t VerdefIndexWidth = std::to_string(Shdr.sh_info).size();
+ while (Buf) {
+ auto *Verdef = reinterpret_cast<const typename ELFT::Verdef *>(Buf);
+ outs() << format_decimal(VerdefIndex++, VerdefIndexWidth) << " "
+ << format("0x%02" PRIx16 " ", (uint16_t)Verdef->vd_flags)
+ << format("0x%08" PRIx32 " ", (uint32_t)Verdef->vd_hash);
+
+ const uint8_t *BufAux = Buf + Verdef->vd_aux;
+ uint16_t VerdauxIndex = 0;
+ while (BufAux) {
+ auto *Verdaux = reinterpret_cast<const typename ELFT::Verdaux *>(BufAux);
+ if (VerdauxIndex)
+ outs() << std::string(VerdefIndexWidth + 17, ' ');
+ outs() << StringRef(StrTab.drop_front(Verdaux->vda_name).data()) << '\n';
+ BufAux = Verdaux->vda_next ? BufAux + Verdaux->vda_next : nullptr;
+ ++VerdauxIndex;
+ }
+ Buf = Verdef->vd_next ? Buf + Verdef->vd_next : nullptr;
+ }
+}
+
+template <class ELFT>
+void printSymbolVersionInfo(const ELFFile<ELFT> *Elf, StringRef FileName) {
+ ArrayRef<typename ELFT::Shdr> Sections =
+ unwrapOrError(Elf->sections(), FileName);
+ for (const typename ELFT::Shdr &Shdr : Sections) {
+ if (Shdr.sh_type != ELF::SHT_GNU_verneed &&
+ Shdr.sh_type != ELF::SHT_GNU_verdef)
+ continue;
+
+ ArrayRef<uint8_t> Contents =
+ unwrapOrError(Elf->getSectionContents(&Shdr), FileName);
+ const typename ELFT::Shdr *StrTabSec =
+ unwrapOrError(Elf->getSection(Shdr.sh_link), FileName);
+ StringRef StrTab = unwrapOrError(Elf->getStringTable(StrTabSec), FileName);
+
+ if (Shdr.sh_type == ELF::SHT_GNU_verneed)
+ printSymbolVersionDependency<ELFT>(Contents, StrTab);
+ else
+ printSymbolVersionDefinition<ELFT>(Shdr, Contents, StrTab);
+ }
+}
+
+void printELFFileHeader(const object::ObjectFile *Obj) {
if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
printProgramHeaders(ELFObj->getELFFile());
else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
@@ -168,7 +338,7 @@ void llvm::printELFFileHeader(const object::ObjectFile *Obj) {
printProgramHeaders(ELFObj->getELFFile());
}
-void llvm::printELFDynamicSection(const object::ObjectFile *Obj) {
+void printELFDynamicSection(const object::ObjectFile *Obj) {
if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
printDynamicSection(ELFObj->getELFFile(), Obj->getFileName());
else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
@@ -178,3 +348,15 @@ void llvm::printELFDynamicSection(const object::ObjectFile *Obj) {
else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj))
printDynamicSection(ELFObj->getELFFile(), Obj->getFileName());
}
+
+void printELFSymbolVersionInfo(const object::ObjectFile *Obj) {
+ if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
+ printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName());
+ else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
+ printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName());
+ else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
+ printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName());
+ else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj))
+ printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName());
+}
+} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-objdump/MachODump.cpp b/contrib/llvm/tools/llvm-objdump/MachODump.cpp
index 5ef7058ec9da..58ff7be4543c 100644
--- a/contrib/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/contrib/llvm/tools/llvm-objdump/MachODump.cpp
@@ -1,9 +1,8 @@
//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -56,83 +55,140 @@ extern "C" {
}
#endif
-using namespace llvm;
-using namespace object;
+using namespace llvm::object;
+
+namespace llvm {
+
+cl::OptionCategory MachOCat("llvm-objdump MachO Specific Options");
+
+extern cl::opt<bool> ArchiveHeaders;
+extern cl::opt<bool> Disassemble;
+extern cl::opt<bool> DisassembleAll;
+extern cl::opt<DIDumpType> DwarfDumpType;
+extern cl::list<std::string> FilterSections;
+extern cl::list<std::string> MAttrs;
+extern cl::opt<std::string> MCPU;
+extern cl::opt<bool> NoShowRawInsn;
+extern cl::opt<bool> NoLeadingAddr;
+extern cl::opt<bool> PrintImmHex;
+extern cl::opt<bool> PrivateHeaders;
+extern cl::opt<bool> Relocations;
+extern cl::opt<bool> SectionHeaders;
+extern cl::opt<bool> SectionContents;
+extern cl::opt<bool> SymbolTable;
+extern cl::opt<std::string> TripleName;
+extern cl::opt<bool> UnwindInfo;
+
+cl::opt<bool>
+ FirstPrivateHeader("private-header",
+ cl::desc("Display only the first format specific file "
+ "header"),
+ cl::cat(MachOCat));
+
+cl::opt<bool> ExportsTrie("exports-trie",
+ cl::desc("Display mach-o exported symbols"),
+ cl::cat(MachOCat));
+
+cl::opt<bool> Rebase("rebase", cl::desc("Display mach-o rebasing info"),
+ cl::cat(MachOCat));
+
+cl::opt<bool> Bind("bind", cl::desc("Display mach-o binding info"),
+ cl::cat(MachOCat));
+
+cl::opt<bool> LazyBind("lazy-bind",
+ cl::desc("Display mach-o lazy binding info"),
+ cl::cat(MachOCat));
+
+cl::opt<bool> WeakBind("weak-bind",
+ cl::desc("Display mach-o weak binding info"),
+ cl::cat(MachOCat));
static cl::opt<bool>
- UseDbg("g",
- cl::desc("Print line information from debug info if available"));
+ UseDbg("g", cl::Grouping,
+ cl::desc("Print line information from debug info if available"),
+ cl::cat(MachOCat));
static cl::opt<std::string> DSYMFile("dsym",
- cl::desc("Use .dSYM file for debug info"));
+ cl::desc("Use .dSYM file for debug info"),
+ cl::cat(MachOCat));
static cl::opt<bool> FullLeadingAddr("full-leading-addr",
- cl::desc("Print full leading address"));
+ cl::desc("Print full leading address"),
+ cl::cat(MachOCat));
static cl::opt<bool> NoLeadingHeaders("no-leading-headers",
- cl::desc("Print no leading headers"));
+ cl::desc("Print no leading headers"),
+ cl::cat(MachOCat));
-cl::opt<bool> llvm::UniversalHeaders("universal-headers",
- cl::desc("Print Mach-O universal headers "
- "(requires -macho)"));
+cl::opt<bool> UniversalHeaders("universal-headers",
+ cl::desc("Print Mach-O universal headers "
+ "(requires -macho)"),
+ cl::cat(MachOCat));
cl::opt<bool>
ArchiveMemberOffsets("archive-member-offsets",
cl::desc("Print the offset to each archive member for "
"Mach-O archives (requires -macho and "
- "-archive-headers)"));
-
-cl::opt<bool>
- llvm::IndirectSymbols("indirect-symbols",
- cl::desc("Print indirect symbol table for Mach-O "
- "objects (requires -macho)"));
+ "-archive-headers)"),
+ cl::cat(MachOCat));
-cl::opt<bool>
- llvm::DataInCode("data-in-code",
- cl::desc("Print the data in code table for Mach-O objects "
- "(requires -macho)"));
-
-cl::opt<bool>
- llvm::LinkOptHints("link-opt-hints",
- cl::desc("Print the linker optimization hints for "
- "Mach-O objects (requires -macho)"));
-
-cl::opt<bool>
- llvm::InfoPlist("info-plist",
- cl::desc("Print the info plist section as strings for "
- "Mach-O objects (requires -macho)"));
+cl::opt<bool> IndirectSymbols("indirect-symbols",
+ cl::desc("Print indirect symbol table for Mach-O "
+ "objects (requires -macho)"),
+ cl::cat(MachOCat));
cl::opt<bool>
- llvm::DylibsUsed("dylibs-used",
- cl::desc("Print the shared libraries used for linked "
- "Mach-O files (requires -macho)"));
+ DataInCode("data-in-code",
+ cl::desc("Print the data in code table for Mach-O objects "
+ "(requires -macho)"),
+ cl::cat(MachOCat));
+
+cl::opt<bool> LinkOptHints("link-opt-hints",
+ cl::desc("Print the linker optimization hints for "
+ "Mach-O objects (requires -macho)"),
+ cl::cat(MachOCat));
+
+cl::opt<bool> InfoPlist("info-plist",
+ cl::desc("Print the info plist section as strings for "
+ "Mach-O objects (requires -macho)"),
+ cl::cat(MachOCat));
+
+cl::opt<bool> DylibsUsed("dylibs-used",
+ cl::desc("Print the shared libraries used for linked "
+ "Mach-O files (requires -macho)"),
+ cl::cat(MachOCat));
cl::opt<bool>
- llvm::DylibId("dylib-id",
- cl::desc("Print the shared library's id for the dylib Mach-O "
- "file (requires -macho)"));
+ DylibId("dylib-id",
+ cl::desc("Print the shared library's id for the dylib Mach-O "
+ "file (requires -macho)"),
+ cl::cat(MachOCat));
cl::opt<bool>
- llvm::NonVerbose("non-verbose",
- cl::desc("Print the info for Mach-O objects in "
- "non-verbose or numeric form (requires -macho)"));
+ NonVerbose("non-verbose",
+ cl::desc("Print the info for Mach-O objects in "
+ "non-verbose or numeric form (requires -macho)"),
+ cl::cat(MachOCat));
cl::opt<bool>
- llvm::ObjcMetaData("objc-meta-data",
- cl::desc("Print the Objective-C runtime meta data for "
- "Mach-O files (requires -macho)"));
+ ObjcMetaData("objc-meta-data",
+ cl::desc("Print the Objective-C runtime meta data for "
+ "Mach-O files (requires -macho)"),
+ cl::cat(MachOCat));
-cl::opt<std::string> llvm::DisSymName(
+cl::opt<std::string> DisSymName(
"dis-symname",
- cl::desc("disassemble just this symbol's instructions (requires -macho)"));
+ cl::desc("disassemble just this symbol's instructions (requires -macho)"),
+ cl::cat(MachOCat));
static cl::opt<bool> NoSymbolicOperands(
"no-symbolic-operands",
- cl::desc("do not symbolic operands when disassembling (requires -macho)"));
+ cl::desc("do not symbolic operands when disassembling (requires -macho)"),
+ cl::cat(MachOCat));
static cl::list<std::string>
ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
- cl::ZeroOrMore);
+ cl::ZeroOrMore, cl::cat(MachOCat));
bool ArchAll = false;
@@ -142,7 +198,7 @@ static const Target *GetTarget(const MachOObjectFile *MachOObj,
const char **McpuDefault,
const Target **ThumbTarget) {
// Figure out the target triple.
- llvm::Triple TT(TripleName);
+ Triple TT(TripleName);
if (TripleName.empty()) {
TT = MachOObj->getArchTriple(McpuDefault);
TripleName = TT.str();
@@ -151,7 +207,7 @@ static const Target *GetTarget(const MachOObjectFile *MachOObj,
if (TT.getArch() == Triple::arm) {
// We've inferred a 32-bit ARM target from the object file. All MachO CPUs
// that support ARM are also capable of Thumb mode.
- llvm::Triple ThumbTriple = TT;
+ Triple ThumbTriple = TT;
std::string ThumbName = (Twine("thumb") + TT.getArchName().substr(3)).str();
ThumbTriple.setArchName(ThumbName);
ThumbTripleName = ThumbTriple.str();
@@ -180,11 +236,11 @@ struct SymbolSorter {
bool operator()(const SymbolRef &A, const SymbolRef &B) {
Expected<SymbolRef::Type> ATypeOrErr = A.getType();
if (!ATypeOrErr)
- report_error(A.getObject()->getFileName(), ATypeOrErr.takeError());
+ report_error(ATypeOrErr.takeError(), A.getObject()->getFileName());
SymbolRef::Type AType = *ATypeOrErr;
Expected<SymbolRef::Type> BTypeOrErr = B.getType();
if (!BTypeOrErr)
- report_error(B.getObject()->getFileName(), BTypeOrErr.takeError());
+ report_error(BTypeOrErr.takeError(), B.getObject()->getFileName());
SymbolRef::Type BType = *BTypeOrErr;
uint64_t AAddr = (AType != SymbolRef::ST_Function) ? 0 : A.getValue();
uint64_t BAddr = (BType != SymbolRef::ST_Function) ? 0 : B.getValue();
@@ -308,11 +364,10 @@ static void getSectionsAndSymbols(MachOObjectFile *MachOObj,
std::vector<SymbolRef> &Symbols,
SmallVectorImpl<uint64_t> &FoundFns,
uint64_t &BaseSegmentAddress) {
+ const StringRef FileName = MachOObj->getFileName();
for (const SymbolRef &Symbol : MachOObj->symbols()) {
- Expected<StringRef> SymName = Symbol.getName();
- if (!SymName)
- report_error(MachOObj->getFileName(), SymName.takeError());
- if (!SymName->startswith("ltmp"))
+ StringRef SymName = unwrapOrError(Symbol.getName(), FileName);
+ if (!SymName.startswith("ltmp"))
Symbols.push_back(Symbol);
}
@@ -342,6 +397,254 @@ static void getSectionsAndSymbols(MachOObjectFile *MachOObj,
}
}
+static void printRelocationTargetName(const MachOObjectFile *O,
+ const MachO::any_relocation_info &RE,
+ raw_string_ostream &Fmt) {
+ // Target of a scattered relocation is an address. In the interest of
+ // generating pretty output, scan through the symbol table looking for a
+ // symbol that aligns with that address. If we find one, print it.
+ // Otherwise, we just print the hex address of the target.
+ const StringRef FileName = O->getFileName();
+ if (O->isRelocationScattered(RE)) {
+ uint32_t Val = O->getPlainRelocationSymbolNum(RE);
+
+ for (const SymbolRef &Symbol : O->symbols()) {
+ uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName);
+ if (Addr != Val)
+ continue;
+ Fmt << unwrapOrError(Symbol.getName(), FileName);
+ return;
+ }
+
+ // If we couldn't find a symbol that this relocation refers to, try
+ // to find a section beginning instead.
+ for (const SectionRef &Section : ToolSectionFilter(*O)) {
+ StringRef Name;
+ uint64_t Addr = Section.getAddress();
+ if (Addr != Val)
+ continue;
+ if (std::error_code EC = Section.getName(Name))
+ report_error(errorCodeToError(EC), O->getFileName());
+ Fmt << Name;
+ return;
+ }
+
+ Fmt << format("0x%x", Val);
+ return;
+ }
+
+ StringRef S;
+ bool isExtern = O->getPlainRelocationExternal(RE);
+ uint64_t Val = O->getPlainRelocationSymbolNum(RE);
+
+ if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND) {
+ Fmt << format("0x%0" PRIx64, Val);
+ return;
+ }
+
+ if (isExtern) {
+ symbol_iterator SI = O->symbol_begin();
+ advance(SI, Val);
+ S = unwrapOrError(SI->getName(), FileName);
+ } else {
+ section_iterator SI = O->section_begin();
+ // Adjust for the fact that sections are 1-indexed.
+ if (Val == 0) {
+ Fmt << "0 (?,?)";
+ return;
+ }
+ uint32_t I = Val - 1;
+ while (I != 0 && SI != O->section_end()) {
+ --I;
+ advance(SI, 1);
+ }
+ if (SI == O->section_end())
+ Fmt << Val << " (?,?)";
+ else
+ SI->getName(S);
+ }
+
+ Fmt << S;
+}
+
+Error getMachORelocationValueString(const MachOObjectFile *Obj,
+ const RelocationRef &RelRef,
+ SmallVectorImpl<char> &Result) {
+ DataRefImpl Rel = RelRef.getRawDataRefImpl();
+ MachO::any_relocation_info RE = Obj->getRelocation(Rel);
+
+ unsigned Arch = Obj->getArch();
+
+ std::string FmtBuf;
+ raw_string_ostream Fmt(FmtBuf);
+ unsigned Type = Obj->getAnyRelocationType(RE);
+ bool IsPCRel = Obj->getAnyRelocationPCRel(RE);
+
+ // Determine any addends that should be displayed with the relocation.
+ // These require decoding the relocation type, which is triple-specific.
+
+ // X86_64 has entirely custom relocation types.
+ if (Arch == Triple::x86_64) {
+ switch (Type) {
+ case MachO::X86_64_RELOC_GOT_LOAD:
+ case MachO::X86_64_RELOC_GOT: {
+ printRelocationTargetName(Obj, RE, Fmt);
+ Fmt << "@GOT";
+ if (IsPCRel)
+ Fmt << "PCREL";
+ break;
+ }
+ case MachO::X86_64_RELOC_SUBTRACTOR: {
+ DataRefImpl RelNext = Rel;
+ Obj->moveRelocationNext(RelNext);
+ MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
+
+ // X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type
+ // X86_64_RELOC_UNSIGNED.
+ // NOTE: Scattered relocations don't exist on x86_64.
+ unsigned RType = Obj->getAnyRelocationType(RENext);
+ if (RType != MachO::X86_64_RELOC_UNSIGNED)
+ report_error(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after "
+ "X86_64_RELOC_SUBTRACTOR.");
+
+ // The X86_64_RELOC_UNSIGNED contains the minuend symbol;
+ // X86_64_RELOC_SUBTRACTOR contains the subtrahend.
+ printRelocationTargetName(Obj, RENext, Fmt);
+ Fmt << "-";
+ printRelocationTargetName(Obj, RE, Fmt);
+ break;
+ }
+ case MachO::X86_64_RELOC_TLV:
+ printRelocationTargetName(Obj, RE, Fmt);
+ Fmt << "@TLV";
+ if (IsPCRel)
+ Fmt << "P";
+ break;
+ case MachO::X86_64_RELOC_SIGNED_1:
+ printRelocationTargetName(Obj, RE, Fmt);
+ Fmt << "-1";
+ break;
+ case MachO::X86_64_RELOC_SIGNED_2:
+ printRelocationTargetName(Obj, RE, Fmt);
+ Fmt << "-2";
+ break;
+ case MachO::X86_64_RELOC_SIGNED_4:
+ printRelocationTargetName(Obj, RE, Fmt);
+ Fmt << "-4";
+ break;
+ default:
+ printRelocationTargetName(Obj, RE, Fmt);
+ break;
+ }
+ // X86 and ARM share some relocation types in common.
+ } else if (Arch == Triple::x86 || Arch == Triple::arm ||
+ Arch == Triple::ppc) {
+ // Generic relocation types...
+ switch (Type) {
+ case MachO::GENERIC_RELOC_PAIR: // prints no info
+ return Error::success();
+ case MachO::GENERIC_RELOC_SECTDIFF: {
+ DataRefImpl RelNext = Rel;
+ Obj->moveRelocationNext(RelNext);
+ MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
+
+ // X86 sect diff's must be followed by a relocation of type
+ // GENERIC_RELOC_PAIR.
+ unsigned RType = Obj->getAnyRelocationType(RENext);
+
+ if (RType != MachO::GENERIC_RELOC_PAIR)
+ report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
+ "GENERIC_RELOC_SECTDIFF.");
+
+ printRelocationTargetName(Obj, RE, Fmt);
+ Fmt << "-";
+ printRelocationTargetName(Obj, RENext, Fmt);
+ break;
+ }
+ }
+
+ if (Arch == Triple::x86 || Arch == Triple::ppc) {
+ switch (Type) {
+ case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
+ DataRefImpl RelNext = Rel;
+ Obj->moveRelocationNext(RelNext);
+ MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
+
+ // X86 sect diff's must be followed by a relocation of type
+ // GENERIC_RELOC_PAIR.
+ unsigned RType = Obj->getAnyRelocationType(RENext);
+ if (RType != MachO::GENERIC_RELOC_PAIR)
+ report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
+ "GENERIC_RELOC_LOCAL_SECTDIFF.");
+
+ printRelocationTargetName(Obj, RE, Fmt);
+ Fmt << "-";
+ printRelocationTargetName(Obj, RENext, Fmt);
+ break;
+ }
+ case MachO::GENERIC_RELOC_TLV: {
+ printRelocationTargetName(Obj, RE, Fmt);
+ Fmt << "@TLV";
+ if (IsPCRel)
+ Fmt << "P";
+ break;
+ }
+ default:
+ printRelocationTargetName(Obj, RE, Fmt);
+ }
+ } else { // ARM-specific relocations
+ switch (Type) {
+ case MachO::ARM_RELOC_HALF:
+ case MachO::ARM_RELOC_HALF_SECTDIFF: {
+ // Half relocations steal a bit from the length field to encode
+ // whether this is an upper16 or a lower16 relocation.
+ bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1;
+
+ if (isUpper)
+ Fmt << ":upper16:(";
+ else
+ Fmt << ":lower16:(";
+ printRelocationTargetName(Obj, RE, Fmt);
+
+ DataRefImpl RelNext = Rel;
+ Obj->moveRelocationNext(RelNext);
+ MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
+
+ // ARM half relocs must be followed by a relocation of type
+ // ARM_RELOC_PAIR.
+ unsigned RType = Obj->getAnyRelocationType(RENext);
+ if (RType != MachO::ARM_RELOC_PAIR)
+ report_error(Obj->getFileName(), "Expected ARM_RELOC_PAIR after "
+ "ARM_RELOC_HALF");
+
+ // NOTE: The half of the target virtual address is stashed in the
+ // address field of the secondary relocation, but we can't reverse
+ // engineer the constant offset from it without decoding the movw/movt
+ // instruction to find the other half in its immediate field.
+
+ // ARM_RELOC_HALF_SECTDIFF encodes the second section in the
+ // symbol/section pointer of the follow-on relocation.
+ if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
+ Fmt << "-";
+ printRelocationTargetName(Obj, RENext, Fmt);
+ }
+
+ Fmt << ")";
+ break;
+ }
+ default: {
+ printRelocationTargetName(Obj, RE, Fmt);
+ }
+ }
+ }
+ } else
+ printRelocationTargetName(Obj, RE, Fmt);
+
+ Fmt.flush();
+ Result.append(FmtBuf.begin(), FmtBuf.end());
+ return Error::success();
+}
+
static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,
uint32_t n, uint32_t count,
uint32_t stride, uint64_t addr) {
@@ -389,10 +692,7 @@ static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,
if (indirect_symbol < Symtab.nsyms) {
symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol);
SymbolRef Symbol = *Sym;
- Expected<StringRef> SymName = Symbol.getName();
- if (!SymName)
- report_error(O->getFileName(), SymName.takeError());
- outs() << *SymName;
+ outs() << unwrapOrError(Symbol.getName(), O->getFileName());
} else {
outs() << "?";
}
@@ -500,6 +800,7 @@ static void PrintRType(const uint64_t cputype, const unsigned r_type) {
outs() << arm_r_types[r_type];
break;
case MachO::CPU_TYPE_ARM64:
+ case MachO::CPU_TYPE_ARM64_32:
outs() << arm64_r_types[r_type];
break;
default:
@@ -510,9 +811,8 @@ static void PrintRType(const uint64_t cputype, const unsigned r_type) {
static void PrintRLength(const uint64_t cputype, const unsigned r_type,
const unsigned r_length, const bool previous_arm_half){
if (cputype == MachO::CPU_TYPE_ARM &&
- (r_type == llvm::MachO::ARM_RELOC_HALF ||
- r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF ||
- previous_arm_half == true)) {
+ (r_type == MachO::ARM_RELOC_HALF ||
+ r_type == MachO::ARM_RELOC_HALF_SECTDIFF || previous_arm_half == true)) {
if ((r_length & 0x1) == 0)
outs() << "lo/";
else
@@ -573,9 +873,8 @@ static void PrintRelocationEntries(const MachOObjectFile *O,
if (verbose) {
// scattered: address
if ((cputype == MachO::CPU_TYPE_I386 &&
- r_type == llvm::MachO::GENERIC_RELOC_PAIR) ||
- (cputype == MachO::CPU_TYPE_ARM &&
- r_type == llvm::MachO::ARM_RELOC_PAIR))
+ r_type == MachO::GENERIC_RELOC_PAIR) ||
+ (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR))
outs() << " ";
else
outs() << format("%08x ", (unsigned int)r_address);
@@ -597,29 +896,27 @@ static void PrintRelocationEntries(const MachOObjectFile *O,
outs() << format("True 0x%08x", (unsigned int)r_value);
if (previous_sectdiff == false) {
if ((cputype == MachO::CPU_TYPE_ARM &&
- r_type == llvm::MachO::ARM_RELOC_PAIR))
+ r_type == MachO::ARM_RELOC_PAIR))
outs() << format(" half = 0x%04x ", (unsigned int)r_address);
- }
- else if (cputype == MachO::CPU_TYPE_ARM &&
- sectdiff_r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF)
+ } else if (cputype == MachO::CPU_TYPE_ARM &&
+ sectdiff_r_type == MachO::ARM_RELOC_HALF_SECTDIFF)
outs() << format(" other_half = 0x%04x ", (unsigned int)r_address);
if ((cputype == MachO::CPU_TYPE_I386 &&
- (r_type == llvm::MachO::GENERIC_RELOC_SECTDIFF ||
- r_type == llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) ||
+ (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
+ r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) ||
(cputype == MachO::CPU_TYPE_ARM &&
- (sectdiff_r_type == llvm::MachO::ARM_RELOC_SECTDIFF ||
- sectdiff_r_type == llvm::MachO::ARM_RELOC_LOCAL_SECTDIFF ||
- sectdiff_r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF))) {
- previous_sectdiff = true;
- sectdiff_r_type = r_type;
- }
- else {
+ (sectdiff_r_type == MachO::ARM_RELOC_SECTDIFF ||
+ sectdiff_r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
+ sectdiff_r_type == MachO::ARM_RELOC_HALF_SECTDIFF))) {
+ previous_sectdiff = true;
+ sectdiff_r_type = r_type;
+ } else {
previous_sectdiff = false;
sectdiff_r_type = 0;
}
if (cputype == MachO::CPU_TYPE_ARM &&
- (r_type == llvm::MachO::ARM_RELOC_HALF ||
- r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF))
+ (r_type == MachO::ARM_RELOC_HALF ||
+ r_type == MachO::ARM_RELOC_HALF_SECTDIFF))
previous_arm_half = true;
else
previous_arm_half = false;
@@ -635,8 +932,7 @@ static void PrintRelocationEntries(const MachOObjectFile *O,
else {
if (verbose) {
// plain: address
- if (cputype == MachO::CPU_TYPE_ARM &&
- r_type == llvm::MachO::ARM_RELOC_PAIR)
+ if (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR)
outs() << " ";
else
outs() << format("%08x ", (unsigned int)r_address);
@@ -678,28 +974,27 @@ static void PrintRelocationEntries(const MachOObjectFile *O,
outs() << "False ";
// plain: symbolnum/value
- if (cputype == MachO::CPU_TYPE_ARM &&
- r_type == llvm::MachO::ARM_RELOC_PAIR)
+ if (cputype == MachO::CPU_TYPE_ARM && r_type == MachO::ARM_RELOC_PAIR)
outs() << format("other_half = 0x%04x\n", (unsigned int)r_address);
- else if (cputype == MachO::CPU_TYPE_ARM64 &&
- r_type == llvm::MachO::ARM64_RELOC_ADDEND)
+ else if ((cputype == MachO::CPU_TYPE_ARM64 ||
+ cputype == MachO::CPU_TYPE_ARM64_32) &&
+ r_type == MachO::ARM64_RELOC_ADDEND)
outs() << format("addend = 0x%06x\n", (unsigned int)r_symbolnum);
else {
outs() << format("%d ", r_symbolnum);
- if (r_symbolnum == llvm::MachO::R_ABS)
+ if (r_symbolnum == MachO::R_ABS)
outs() << "R_ABS\n";
else {
// in this case, r_symbolnum is actually a 1-based section number
uint32_t nsects = O->section_end()->getRawDataRefImpl().d.a;
if (r_symbolnum > 0 && r_symbolnum <= nsects) {
- llvm::object::DataRefImpl DRI;
+ object::DataRefImpl DRI;
DRI.d.a = r_symbolnum-1;
StringRef SegName = O->getSectionFinalSegmentName(DRI);
- StringRef SectName;
- if (O->getSectionName(DRI, SectName))
- outs() << "(?,?)\n";
+ if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))
+ outs() << "(" << SegName << "," << *NameOrErr << ")\n";
else
- outs() << "(" << SegName << "," << SectName << ")\n";
+ outs() << "(?,?)\n";
}
else {
outs() << "(?,?)\n";
@@ -708,8 +1003,8 @@ static void PrintRelocationEntries(const MachOObjectFile *O,
}
}
if (cputype == MachO::CPU_TYPE_ARM &&
- (r_type == llvm::MachO::ARM_RELOC_HALF ||
- r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF))
+ (r_type == MachO::ARM_RELOC_HALF ||
+ r_type == MachO::ARM_RELOC_HALF_SECTDIFF))
previous_arm_half = true;
else
previous_arm_half = false;
@@ -752,13 +1047,12 @@ static void PrintRelocations(const MachOObjectFile *O, const bool verbose) {
DataRefImpl DRI;
DRI.d.a = J;
const StringRef SegName = O->getSectionFinalSegmentName(DRI);
- StringRef SectName;
- if (O->getSectionName(DRI, SectName))
+ if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))
+ outs() << "Relocation information (" << SegName << "," << *NameOrErr
+ << format(") %u entries", Sec.nreloc);
+ else
outs() << "Relocation information (" << SegName << ",?) "
<< format("%u entries", Sec.nreloc);
- else
- outs() << "Relocation information (" << SegName << ","
- << SectName << format(") %u entries", Sec.nreloc);
outs() << "\naddress pcrel length extern type scattered "
"symbolnum/value\n";
PrintRelocationEntries(O, O->section_rel_begin(DRI),
@@ -773,13 +1067,12 @@ static void PrintRelocations(const MachOObjectFile *O, const bool verbose) {
DataRefImpl DRI;
DRI.d.a = J;
const StringRef SegName = O->getSectionFinalSegmentName(DRI);
- StringRef SectName;
- if (O->getSectionName(DRI, SectName))
+ if (Expected<StringRef> NameOrErr = O->getSectionName(DRI))
+ outs() << "Relocation information (" << SegName << "," << *NameOrErr
+ << format(") %u entries", Sec.nreloc);
+ else
outs() << "Relocation information (" << SegName << ",?) "
<< format("%u entries", Sec.nreloc);
- else
- outs() << "Relocation information (" << SegName << ","
- << SectName << format(") %u entries", Sec.nreloc);
outs() << "\naddress pcrel length extern type scattered "
"symbolnum/value\n";
PrintRelocationEntries(O, O->section_rel_begin(DRI),
@@ -913,7 +1206,16 @@ static void PrintDylibs(MachOObjectFile *O, bool JustId) {
outs() << " current version "
<< ((dl.dylib.current_version >> 16) & 0xffff) << "."
<< ((dl.dylib.current_version >> 8) & 0xff) << "."
- << (dl.dylib.current_version & 0xff) << ")\n";
+ << (dl.dylib.current_version & 0xff);
+ if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)
+ outs() << ", weak";
+ if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)
+ outs() << ", reexport";
+ if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
+ outs() << ", upward";
+ if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)
+ outs() << ", lazy";
+ outs() << ")\n";
}
} else {
outs() << "\tBad offset (" << dl.dylib.name << ") for name of ";
@@ -942,18 +1244,13 @@ typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;
static void CreateSymbolAddressMap(MachOObjectFile *O,
SymbolAddressMap *AddrMap) {
// Create a map of symbol addresses to symbol names.
+ const StringRef FileName = O->getFileName();
for (const SymbolRef &Symbol : O->symbols()) {
- Expected<SymbolRef::Type> STOrErr = Symbol.getType();
- if (!STOrErr)
- report_error(O->getFileName(), STOrErr.takeError());
- SymbolRef::Type ST = *STOrErr;
+ SymbolRef::Type ST = unwrapOrError(Symbol.getType(), FileName);
if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
ST == SymbolRef::ST_Other) {
uint64_t Address = Symbol.getValue();
- Expected<StringRef> SymNameOrErr = Symbol.getName();
- if (!SymNameOrErr)
- report_error(O->getFileName(), SymNameOrErr.takeError());
- StringRef SymName = *SymNameOrErr;
+ StringRef SymName = unwrapOrError(Symbol.getName(), FileName);
if (!SymName.startswith(".objc"))
(*AddrMap)[Address] = SymName;
}
@@ -1186,10 +1483,8 @@ static void DumpLiteralPointerSection(MachOObjectFile *O,
});
if (Reloc != Relocs.end()) {
symbol_iterator RelocSym = Reloc->second;
- Expected<StringRef> SymName = RelocSym->getName();
- if (!SymName)
- report_error(O->getFileName(), SymName.takeError());
- outs() << "external relocation entry for symbol:" << *SymName << "\n";
+ StringRef SymName = unwrapOrError(RelocSym->getName(), O->getFileName());
+ outs() << "external relocation entry for symbol:" << SymName << "\n";
continue;
}
@@ -1220,8 +1515,8 @@ static void DumpLiteralPointerSection(MachOObjectFile *O,
section_type = Sec.flags & MachO::SECTION_TYPE;
}
- StringRef BytesStr;
- Sect->getContents(BytesStr);
+ StringRef BytesStr = unwrapOrError(Sect->getContents(), O->getFileName());
+
const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
switch (section_type) {
@@ -1333,10 +1628,7 @@ static void DumpInitTermPointerSection(MachOObjectFile *O,
});
if (Reloc != Relocs.end()) {
symbol_iterator RelocSym = Reloc->second;
- Expected<StringRef> SymName = RelocSym->getName();
- if (!SymName)
- report_error(O->getFileName(), SymName.takeError());
- outs() << " " << *SymName;
+ outs() << " " << unwrapOrError(RelocSym->getName(), O->getFileName());
} else {
SymbolName = GuessSymbolName(p, AddrMap);
if (SymbolName)
@@ -1438,8 +1730,8 @@ static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
}
uint32_t section_type = section_flags & MachO::SECTION_TYPE;
- StringRef BytesStr;
- Section.getContents(BytesStr);
+ StringRef BytesStr =
+ unwrapOrError(Section.getContents(), O->getFileName());
const char *sect = reinterpret_cast<const char *>(BytesStr.data());
uint32_t sect_size = BytesStr.size();
uint64_t sect_addr = Section.getAddress();
@@ -1523,8 +1815,8 @@ static void DumpInfoPlistSectionContents(StringRef Filename,
if (SegName == "__TEXT" && SectName == "__info_plist") {
if (!NoLeadingHeaders)
outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
- StringRef BytesStr;
- Section.getContents(BytesStr);
+ StringRef BytesStr =
+ unwrapOrError(Section.getContents(), O->getFileName());
const char *sect = reinterpret_cast<const char *>(BytesStr.data());
outs() << format("%.*s", BytesStr.size(), sect) << "\n";
return;
@@ -1609,8 +1901,8 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
// the error message.
if (Disassemble || IndirectSymbols || !FilterSections.empty() || UnwindInfo)
if (Error Err = MachOOF->checkSymbolTable())
- report_error(ArchiveName, FileName, std::move(Err), ArchitectureName);
-
+ report_error(std::move(Err), ArchiveName, FileName, ArchitectureName);
+
if (DisassembleAll) {
for (const SectionRef &Section : MachOOF->sections()) {
StringRef SectName;
@@ -1774,6 +2066,21 @@ static void printCPUType(uint32_t cputype, uint32_t cpusubtype) {
outs() << " cputype CPU_TYPE_ARM64\n";
outs() << " cpusubtype CPU_SUBTYPE_ARM64_ALL\n";
break;
+ case MachO::CPU_SUBTYPE_ARM64E:
+ outs() << " cputype CPU_TYPE_ARM64\n";
+ outs() << " cpusubtype CPU_SUBTYPE_ARM64E\n";
+ break;
+ default:
+ printUnknownCPUType(cputype, cpusubtype);
+ break;
+ }
+ break;
+ case MachO::CPU_TYPE_ARM64_32:
+ switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_ARM64_32_V8:
+ outs() << " cputype CPU_TYPE_ARM64_32\n";
+ outs() << " cpusubtype CPU_SUBTYPE_ARM64_32_V8\n";
+ break;
default:
printUnknownCPUType(cputype, cpusubtype);
break;
@@ -1862,10 +2169,8 @@ static void printArchiveChild(StringRef Filename, const Archive::Child &C,
StringRef ArchitectureName = StringRef()) {
if (print_offset)
outs() << C.getChildOffset() << "\t";
- Expected<sys::fs::perms> ModeOrErr = C.getAccessMode();
- if (!ModeOrErr)
- report_error(Filename, C, ModeOrErr.takeError(), ArchitectureName);
- sys::fs::perms Mode = ModeOrErr.get();
+ sys::fs::perms Mode =
+ unwrapOrError(C.getAccessMode(), Filename, C, ArchitectureName);
if (verbose) {
// FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG.
// But there is nothing in sys::fs::perms for S_IFMT or S_IFREG.
@@ -1883,20 +2188,11 @@ static void printArchiveChild(StringRef Filename, const Archive::Child &C,
outs() << format("0%o ", Mode);
}
- Expected<unsigned> UIDOrErr = C.getUID();
- if (!UIDOrErr)
- report_error(Filename, C, UIDOrErr.takeError(), ArchitectureName);
- unsigned UID = UIDOrErr.get();
- outs() << format("%3d/", UID);
- Expected<unsigned> GIDOrErr = C.getGID();
- if (!GIDOrErr)
- report_error(Filename, C, GIDOrErr.takeError(), ArchitectureName);
- unsigned GID = GIDOrErr.get();
- outs() << format("%-3d ", GID);
- Expected<uint64_t> Size = C.getRawSize();
- if (!Size)
- report_error(Filename, C, Size.takeError(), ArchitectureName);
- outs() << format("%5" PRId64, Size.get()) << " ";
+ outs() << format(
+ "%3d/%-3d %5" PRId64 " ",
+ unwrapOrError(C.getUID(), Filename, C, ArchitectureName),
+ unwrapOrError(C.getGID(), Filename, C, ArchitectureName),
+ unwrapOrError(C.getRawSize(), Filename, C, ArchitectureName));
StringRef RawLastModified = C.getRawLastModified();
if (verbose) {
@@ -1919,21 +2215,15 @@ static void printArchiveChild(StringRef Filename, const Archive::Child &C,
Expected<StringRef> NameOrErr = C.getName();
if (!NameOrErr) {
consumeError(NameOrErr.takeError());
- Expected<StringRef> NameOrErr = C.getRawName();
- if (!NameOrErr)
- report_error(Filename, C, NameOrErr.takeError(), ArchitectureName);
- StringRef RawName = NameOrErr.get();
- outs() << RawName << "\n";
+ outs() << unwrapOrError(C.getRawName(), Filename, C, ArchitectureName)
+ << "\n";
} else {
StringRef Name = NameOrErr.get();
outs() << Name << "\n";
}
} else {
- Expected<StringRef> NameOrErr = C.getRawName();
- if (!NameOrErr)
- report_error(Filename, C, NameOrErr.takeError(), ArchitectureName);
- StringRef RawName = NameOrErr.get();
- outs() << RawName << "\n";
+ outs() << unwrapOrError(C.getRawName(), Filename, C, ArchitectureName)
+ << "\n";
}
}
@@ -1941,12 +2231,11 @@ static void printArchiveHeaders(StringRef Filename, Archive *A, bool verbose,
bool print_offset,
StringRef ArchitectureName = StringRef()) {
Error Err = Error::success();
- ;
for (const auto &C : A->children(Err, false))
printArchiveChild(Filename, C, verbose, print_offset, ArchitectureName);
if (Err)
- report_error(StringRef(), Filename, std::move(Err), ArchitectureName);
+ report_error(std::move(Err), StringRef(), Filename, ArchitectureName);
}
static bool ValidateArchFlags() {
@@ -1970,15 +2259,15 @@ static bool ValidateArchFlags() {
// -arch flags selecting just those slices as specified by them and also parses
// archive files. Then for each individual Mach-O file ProcessMachO() is
// called to process the file based on the command line options.
-void llvm::parseInputMachO(StringRef Filename) {
+void parseInputMachO(StringRef Filename) {
if (!ValidateArchFlags())
return;
// Attempt to open the binary.
Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);
if (!BinaryOrErr) {
- if (auto E = isNotObjectErrorInvalidFileType(BinaryOrErr.takeError()))
- report_error(Filename, std::move(E));
+ if (Error E = isNotObjectErrorInvalidFileType(BinaryOrErr.takeError()))
+ report_error(std::move(E), Filename);
else
outs() << Filename << ": is not an object file\n";
return;
@@ -1994,8 +2283,8 @@ void llvm::parseInputMachO(StringRef Filename) {
for (auto &C : A->children(Err)) {
Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
if (!ChildOrErr) {
- if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
- report_error(Filename, C, std::move(E));
+ if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
+ report_error(std::move(E), Filename, C);
continue;
}
if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
@@ -2005,7 +2294,7 @@ void llvm::parseInputMachO(StringRef Filename) {
}
}
if (Err)
- report_error(Filename, std::move(Err));
+ report_error(std::move(Err), Filename);
return;
}
if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {
@@ -2026,7 +2315,7 @@ void llvm::parseInputMachO(StringRef Filename) {
llvm_unreachable("Input object can't be invalid at this point");
}
-void llvm::parseInputMachO(MachOUniversalBinary *UB) {
+void parseInputMachO(MachOUniversalBinary *UB) {
if (!ValidateArchFlags())
return;
@@ -2055,13 +2344,12 @@ void llvm::parseInputMachO(MachOUniversalBinary *UB) {
ObjectFile &O = *ObjOrErr.get();
if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
ProcessMachO(Filename, MachOOF, "", ArchitectureName);
- } else if (auto E = isNotObjectErrorInvalidFileType(
- ObjOrErr.takeError())) {
- report_error(Filename, StringRef(), std::move(E),
- ArchitectureName);
+ } else if (Error E = isNotObjectErrorInvalidFileType(
+ ObjOrErr.takeError())) {
+ report_error(std::move(E), Filename, StringRef(), ArchitectureName);
continue;
} else if (Expected<std::unique_ptr<Archive>> AOrErr =
- I->getAsArchive()) {
+ I->getAsArchive()) {
std::unique_ptr<Archive> &A = *AOrErr;
outs() << "Archive : " << Filename;
if (!ArchitectureName.empty())
@@ -2074,8 +2362,8 @@ void llvm::parseInputMachO(MachOUniversalBinary *UB) {
for (auto &C : A->children(Err)) {
Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
if (!ChildOrErr) {
- if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
- report_error(Filename, C, std::move(E), ArchitectureName);
+ if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
+ report_error(std::move(E), Filename, C, ArchitectureName);
continue;
}
if (MachOObjectFile *O =
@@ -2083,7 +2371,7 @@ void llvm::parseInputMachO(MachOUniversalBinary *UB) {
ProcessMachO(Filename, O, O->getFileName(), ArchitectureName);
}
if (Err)
- report_error(Filename, std::move(Err));
+ report_error(std::move(Err), Filename);
} else {
consumeError(AOrErr.takeError());
error("Mach-O universal file: " + Filename + " for " +
@@ -2116,11 +2404,11 @@ void llvm::parseInputMachO(MachOUniversalBinary *UB) {
ObjectFile &O = *ObjOrErr.get();
if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
ProcessMachO(Filename, MachOOF);
- } else if (auto E = isNotObjectErrorInvalidFileType(
- ObjOrErr.takeError())) {
- report_error(Filename, std::move(E));
+ } else if (Error E =
+ isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
+ report_error(std::move(E), Filename);
} else if (Expected<std::unique_ptr<Archive>> AOrErr =
- I->getAsArchive()) {
+ I->getAsArchive()) {
std::unique_ptr<Archive> &A = *AOrErr;
outs() << "Archive : " << Filename << "\n";
if (ArchiveHeaders)
@@ -2130,8 +2418,9 @@ void llvm::parseInputMachO(MachOUniversalBinary *UB) {
for (auto &C : A->children(Err)) {
Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
if (!ChildOrErr) {
- if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
- report_error(Filename, C, std::move(E));
+ if (Error E =
+ isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
+ report_error(std::move(E), Filename, C);
continue;
}
if (MachOObjectFile *O =
@@ -2139,7 +2428,7 @@ void llvm::parseInputMachO(MachOUniversalBinary *UB) {
ProcessMachO(Filename, O, O->getFileName());
}
if (Err)
- report_error(Filename, std::move(Err));
+ report_error(std::move(Err), Filename);
} else {
consumeError(AOrErr.takeError());
error("Mach-O universal file: " + Filename + " for architecture " +
@@ -2164,11 +2453,10 @@ void llvm::parseInputMachO(MachOUniversalBinary *UB) {
ObjectFile &Obj = *ObjOrErr.get();
if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&Obj))
ProcessMachO(Filename, MachOOF, "", ArchitectureName);
- } else if (auto E = isNotObjectErrorInvalidFileType(
- ObjOrErr.takeError())) {
- report_error(StringRef(), Filename, std::move(E), ArchitectureName);
- } else if (Expected<std::unique_ptr<Archive>> AOrErr =
- I->getAsArchive()) {
+ } else if (Error E =
+ isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) {
+ report_error(std::move(E), StringRef(), Filename, ArchitectureName);
+ } else if (Expected<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {
std::unique_ptr<Archive> &A = *AOrErr;
outs() << "Archive : " << Filename;
if (!ArchitectureName.empty())
@@ -2181,8 +2469,8 @@ void llvm::parseInputMachO(MachOUniversalBinary *UB) {
for (auto &C : A->children(Err)) {
Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
if (!ChildOrErr) {
- if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
- report_error(Filename, C, std::move(E), ArchitectureName);
+ if (Error E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
+ report_error(std::move(E), Filename, C, ArchitectureName);
continue;
}
if (MachOObjectFile *O =
@@ -2193,7 +2481,7 @@ void llvm::parseInputMachO(MachOUniversalBinary *UB) {
}
}
if (Err)
- report_error(Filename, std::move(Err));
+ report_error(std::move(Err), Filename);
} else {
consumeError(AOrErr.takeError());
error("Mach-O universal file: " + Filename + " for architecture " +
@@ -2308,12 +2596,9 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
}
}
if (reloc_found && isExtern) {
- Expected<StringRef> SymName = Symbol.getName();
- if (!SymName)
- report_error(info->O->getFileName(), SymName.takeError());
- const char *name = SymName->data();
op_info->AddSymbol.Present = 1;
- op_info->AddSymbol.Name = name;
+ op_info->AddSymbol.Name =
+ unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
// For i386 extern relocation entries the value in the instruction is
// the offset from the symbol, and value is already set in op_info->Value.
return 1;
@@ -2372,10 +2657,8 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
// is the offset from the external symbol.
if (info->O->getAnyRelocationPCRel(RE))
op_info->Value -= Pc + Offset + Size;
- Expected<StringRef> SymName = Symbol.getName();
- if (!SymName)
- report_error(info->O->getFileName(), SymName.takeError());
- const char *name = SymName->data();
+ const char *name =
+ unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
op_info->AddSymbol.Present = 1;
op_info->AddSymbol.Name = name;
return 1;
@@ -2412,10 +2695,8 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
// is the offset from the external symbol.
if (info->O->getAnyRelocationPCRel(RE))
op_info->Value -= Pc + Offset + Size;
- Expected<StringRef> SymName = Symbol.getName();
- if (!SymName)
- report_error(info->O->getFileName(), SymName.takeError());
- const char *name = SymName->data();
+ const char *name =
+ unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
unsigned Type = info->O->getAnyRelocationType(RE);
if (Type == MachO::X86_64_RELOC_SUBTRACTOR) {
DataRefImpl RelNext = Rel;
@@ -2429,10 +2710,7 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
op_info->SubtractSymbol.Name = name;
symbol_iterator RelocSymNext = info->O->getSymbolByIndex(SymbolNum);
Symbol = *RelocSymNext;
- Expected<StringRef> SymNameNext = Symbol.getName();
- if (!SymNameNext)
- report_error(info->O->getFileName(), SymNameNext.takeError());
- name = SymNameNext->data();
+ name = unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
}
}
// TODO: add the VariantKinds to op_info->VariantKind for relocation types
@@ -2501,10 +2779,8 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
}
if (isExtern) {
- Expected<StringRef> SymName = Symbol.getName();
- if (!SymName)
- report_error(info->O->getFileName(), SymName.takeError());
- const char *name = SymName->data();
+ const char *name =
+ unwrapOrError(Symbol.getName(), info->O->getFileName()).data();
op_info->AddSymbol.Present = 1;
op_info->AddSymbol.Name = name;
switch (r_type) {
@@ -2620,10 +2896,9 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
// NOTE: Scattered relocations don't exist on arm64.
if (!info->O->getPlainRelocationExternal(RE))
return 0;
- Expected<StringRef> SymName = Reloc->getSymbol()->getName();
- if (!SymName)
- report_error(info->O->getFileName(), SymName.takeError());
- const char *name = SymName->data();
+ const char *name =
+ unwrapOrError(Reloc->getSymbol()->getName(), info->O->getFileName())
+ .data();
op_info->AddSymbol.Present = 1;
op_info->AddSymbol.Name = name;
@@ -2749,12 +3024,8 @@ static const char *GuessIndirectSymbol(uint64_t ReferenceValue,
info->O->getIndirectSymbolTableEntry(Dysymtab, index);
if (indirect_symbol < Symtab.nsyms) {
symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
- SymbolRef Symbol = *Sym;
- Expected<StringRef> SymName = Symbol.getName();
- if (!SymName)
- report_error(info->O->getFileName(), SymName.takeError());
- const char *name = SymName->data();
- return name;
+ return unwrapOrError(Sym->getName(), info->O->getFileName())
+ .data();
}
}
}
@@ -2784,12 +3055,8 @@ static const char *GuessIndirectSymbol(uint64_t ReferenceValue,
info->O->getIndirectSymbolTableEntry(Dysymtab, index);
if (indirect_symbol < Symtab.nsyms) {
symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
- SymbolRef Symbol = *Sym;
- Expected<StringRef> SymName = Symbol.getName();
- if (!SymName)
- report_error(info->O->getFileName(), SymName.takeError());
- const char *name = SymName->data();
- return name;
+ return unwrapOrError(Sym->getName(), info->O->getFileName())
+ .data();
}
}
}
@@ -2960,8 +3227,8 @@ static const char *get_pointer_64(uint64_t Address, uint32_t &offset,
S = (*(info->Sections))[SectIdx];
offset = Address - SectAddress;
left = SectSize - offset;
- StringRef SectContents;
- ((*(info->Sections))[SectIdx]).getContents(SectContents);
+ StringRef SectContents = unwrapOrError(
+ ((*(info->Sections))[SectIdx]).getContents(), info->O->getFileName());
return SectContents.data() + offset;
}
}
@@ -3015,10 +3282,7 @@ static const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
const char *SymbolName = nullptr;
if (reloc_found && isExtern) {
n_value = Symbol.getValue();
- Expected<StringRef> NameOrError = Symbol.getName();
- if (!NameOrError)
- report_error(info->O->getFileName(), NameOrError.takeError());
- StringRef Name = *NameOrError;
+ StringRef Name = unwrapOrError(Symbol.getName(), info->O->getFileName());
if (!Name.empty()) {
SymbolName = Name.data();
return SymbolName;
@@ -3767,8 +4031,7 @@ walk_pointer_list_64(const char *listname, const SectionRef S,
StringRef SegName = O->getSectionFinalSegmentName(Ref);
outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
- StringRef BytesStr;
- S.getContents(BytesStr);
+ StringRef BytesStr = unwrapOrError(S.getContents(), O->getFileName());
const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint64_t)) {
@@ -3818,8 +4081,7 @@ walk_pointer_list_32(const char *listname, const SectionRef S,
StringRef SegName = O->getSectionFinalSegmentName(Ref);
outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
- StringRef BytesStr;
- S.getContents(BytesStr);
+ StringRef BytesStr = unwrapOrError(S.getContents(), O->getFileName());
const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint32_t)) {
@@ -6970,32 +7232,78 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
raw_ostream &DebugOut = nulls();
#endif
+ // Try to find debug info and set up the DIContext for it.
std::unique_ptr<DIContext> diContext;
- ObjectFile *DbgObj = MachOOF;
+ std::unique_ptr<Binary> DSYMBinary;
std::unique_ptr<MemoryBuffer> DSYMBuf;
- // Try to find debug info and set up the DIContext for it.
if (UseDbg) {
+ ObjectFile *DbgObj = MachOOF;
+
// A separate DSym file path was specified, parse it as a macho file,
// get the sections and supply it to the section name parsing machinery.
if (!DSYMFile.empty()) {
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
MemoryBuffer::getFileOrSTDIN(DSYMFile);
if (std::error_code EC = BufOrErr.getError()) {
- report_error(DSYMFile, errorCodeToError(EC));
+ report_error(errorCodeToError(EC), DSYMFile);
return;
}
- Expected<std::unique_ptr<MachOObjectFile>> DbgObjCheck =
- ObjectFile::createMachOObjectFile(BufOrErr.get()->getMemBufferRef());
+ // We need to keep the file alive, because we're replacing DbgObj with it.
+ DSYMBuf = std::move(BufOrErr.get());
- if (Error E = DbgObjCheck.takeError()) {
- report_error(DSYMFile, std::move(E));
+ Expected<std::unique_ptr<Binary>> BinaryOrErr =
+ createBinary(DSYMBuf.get()->getMemBufferRef());
+ if (!BinaryOrErr) {
+ report_error(BinaryOrErr.takeError(), DSYMFile);
return;
}
- DbgObj = DbgObjCheck.get().release();
- // We need to keep the file alive, because we're replacing DbgObj with it.
- DSYMBuf = std::move(BufOrErr.get());
+ // We need to keep the Binary elive with the buffer
+ DSYMBinary = std::move(BinaryOrErr.get());
+
+ if (ObjectFile *O = dyn_cast<ObjectFile>(DSYMBinary.get())) {
+ // this is a Mach-O object file, use it
+ if (MachOObjectFile *MachDSYM = dyn_cast<MachOObjectFile>(&*O)) {
+ DbgObj = MachDSYM;
+ }
+ else {
+ WithColor::error(errs(), "llvm-objdump")
+ << DSYMFile << " is not a Mach-O file type.\n";
+ return;
+ }
+ }
+ else if (auto UB = dyn_cast<MachOUniversalBinary>(DSYMBinary.get())){
+ // this is a Universal Binary, find a Mach-O for this architecture
+ uint32_t CPUType, CPUSubType;
+ const char *ArchFlag;
+ if (MachOOF->is64Bit()) {
+ const MachO::mach_header_64 H_64 = MachOOF->getHeader64();
+ CPUType = H_64.cputype;
+ CPUSubType = H_64.cpusubtype;
+ } else {
+ const MachO::mach_header H = MachOOF->getHeader();
+ CPUType = H.cputype;
+ CPUSubType = H.cpusubtype;
+ }
+ Triple T = MachOObjectFile::getArchTriple(CPUType, CPUSubType, nullptr,
+ &ArchFlag);
+ Expected<std::unique_ptr<MachOObjectFile>> MachDSYM =
+ UB->getObjectForArch(ArchFlag);
+ if (!MachDSYM) {
+ report_error(MachDSYM.takeError(), DSYMFile);
+ return;
+ }
+
+ // We need to keep the Binary elive with the buffer
+ DbgObj = &*MachDSYM.get();
+ DSYMBinary = std::move(*MachDSYM);
+ }
+ else {
+ WithColor::error(errs(), "llvm-objdump")
+ << DSYMFile << " is not a Mach-O or Universal file type.\n";
+ return;
+ }
}
// Setup the DIContext
@@ -7016,10 +7324,9 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
if (SegmentName != DisSegName)
continue;
- StringRef BytesStr;
- Sections[SectIdx].getContents(BytesStr);
- ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(BytesStr.data()),
- BytesStr.size());
+ StringRef BytesStr =
+ unwrapOrError(Sections[SectIdx].getContents(), Filename);
+ ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(BytesStr);
uint64_t SectAddress = Sections[SectIdx].getAddress();
bool symbolTableWorked = false;
@@ -7029,17 +7336,13 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
SymbolAddressMap AddrMap;
bool DisSymNameFound = false;
for (const SymbolRef &Symbol : MachOOF->symbols()) {
- Expected<SymbolRef::Type> STOrErr = Symbol.getType();
- if (!STOrErr)
- report_error(MachOOF->getFileName(), STOrErr.takeError());
- SymbolRef::Type ST = *STOrErr;
+ SymbolRef::Type ST =
+ unwrapOrError(Symbol.getType(), MachOOF->getFileName());
if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
ST == SymbolRef::ST_Other) {
uint64_t Address = Symbol.getValue();
- Expected<StringRef> SymNameOrErr = Symbol.getName();
- if (!SymNameOrErr)
- report_error(MachOOF->getFileName(), SymNameOrErr.takeError());
- StringRef SymName = *SymNameOrErr;
+ StringRef SymName =
+ unwrapOrError(Symbol.getName(), MachOOF->getFileName());
AddrMap[Address] = SymName;
if (!DisSymName.empty() && DisSymName == SymName)
DisSymNameFound = true;
@@ -7076,15 +7379,10 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
// Disassemble symbol by symbol.
for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {
- Expected<StringRef> SymNameOrErr = Symbols[SymIdx].getName();
- if (!SymNameOrErr)
- report_error(MachOOF->getFileName(), SymNameOrErr.takeError());
- StringRef SymName = *SymNameOrErr;
-
- Expected<SymbolRef::Type> STOrErr = Symbols[SymIdx].getType();
- if (!STOrErr)
- report_error(MachOOF->getFileName(), STOrErr.takeError());
- SymbolRef::Type ST = *STOrErr;
+ StringRef SymName =
+ unwrapOrError(Symbols[SymIdx].getName(), MachOOF->getFileName());
+ SymbolRef::Type ST =
+ unwrapOrError(Symbols[SymIdx].getType(), MachOOF->getFileName());
if (ST != SymbolRef::ST_Function && ST != SymbolRef::ST_Data)
continue;
@@ -7137,10 +7435,8 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
uint64_t NextSym = 0;
uint64_t NextSymIdx = SymIdx + 1;
while (Symbols.size() > NextSymIdx) {
- Expected<SymbolRef::Type> STOrErr = Symbols[NextSymIdx].getType();
- if (!STOrErr)
- report_error(MachOOF->getFileName(), STOrErr.takeError());
- SymbolRef::Type NextSymType = *STOrErr;
+ SymbolRef::Type NextSymType = unwrapOrError(
+ Symbols[NextSymIdx].getType(), MachOOF->getFileName());
if (NextSymType == SymbolRef::ST_Function) {
containsNextSym =
Sections[SectIdx].containsSymbol(Symbols[NextSymIdx]);
@@ -7243,7 +7539,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
// Print debug info.
if (diContext) {
- DILineInfo dli = diContext->getLineInfoForAddress(PC);
+ DILineInfo dli = diContext->getLineInfoForAddress({PC, SectIdx});
// Print valid line info if it changed.
if (dli != lastLine && dli.Line != 0)
outs() << "\t## " << dli.FileName << ':' << dli.Line << ':'
@@ -7415,10 +7711,7 @@ static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,
const RelocationRef &Reloc, uint64_t Addr,
StringRef &Name, uint64_t &Addend) {
if (Reloc.getSymbol() != Obj->symbol_end()) {
- Expected<StringRef> NameOrErr = Reloc.getSymbol()->getName();
- if (!NameOrErr)
- report_error(Obj->getFileName(), NameOrErr.takeError());
- Name = *NameOrErr;
+ Name = unwrapOrError(Reloc.getSymbol()->getName(), Obj->getFileName());
Addend = Addr;
return;
}
@@ -7440,16 +7733,11 @@ static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,
// Go back one so that SymbolAddress <= Addr.
--Sym;
- auto SectOrErr = Sym->second.getSection();
- if (!SectOrErr)
- report_error(Obj->getFileName(), SectOrErr.takeError());
- section_iterator SymSection = *SectOrErr;
+ section_iterator SymSection =
+ unwrapOrError(Sym->second.getSection(), Obj->getFileName());
if (RelocSection == *SymSection) {
// There's a valid symbol in the same section before this reference.
- Expected<StringRef> NameOrErr = Sym->second.getName();
- if (!NameOrErr)
- report_error(Obj->getFileName(), NameOrErr.takeError());
- Name = *NameOrErr;
+ Name = unwrapOrError(Sym->second.getName(), Obj->getFileName());
Addend = Addr - Sym->first;
return;
}
@@ -7490,9 +7778,8 @@ printMachOCompactUnwindSection(const MachOObjectFile *Obj,
uint32_t PointerSize = Is64 ? sizeof(uint64_t) : sizeof(uint32_t);
uint32_t EntrySize = 3 * PointerSize + 2 * sizeof(uint32_t);
- StringRef Contents;
- CompactUnwind.getContents(Contents);
-
+ StringRef Contents =
+ unwrapOrError(CompactUnwind.getContents(), Obj->getFileName());
SmallVector<CompactUnwindEntry, 4> CompactUnwinds;
// First populate the initial raw offsets, encodings and so on from the entry.
@@ -7633,8 +7920,8 @@ static void printMachOUnwindInfoSection(const MachOObjectFile *Obj,
outs() << "Contents of __unwind_info section:\n";
- StringRef Contents;
- UnwindInfo.getContents(Contents);
+ StringRef Contents =
+ unwrapOrError(UnwindInfo.getContents(), Obj->getFileName());
ptrdiff_t Pos = 0;
//===----------------------------------
@@ -7801,7 +8088,7 @@ static void printMachOUnwindInfoSection(const MachOObjectFile *Obj,
}
}
-void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) {
+void printMachOUnwindInfo(const MachOObjectFile *Obj) {
std::map<uint64_t, SymbolRef> Symbols;
for (const SymbolRef &SymRef : Obj->symbols()) {
// Discard any undefined or absolute symbols. They're not going to take part
@@ -7917,6 +8204,20 @@ static void PrintMachHeader(uint32_t magic, uint32_t cputype,
case MachO::CPU_SUBTYPE_ARM64_ALL:
outs() << " ALL";
break;
+ case MachO::CPU_SUBTYPE_ARM64E:
+ outs() << " E";
+ break;
+ default:
+ outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
+ break;
+ }
+ break;
+ case MachO::CPU_TYPE_ARM64_32:
+ outs() << " ARM64_32";
+ switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_ARM64_32_V8:
+ outs() << " V8";
+ break;
default:
outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
break;
@@ -9485,7 +9786,8 @@ static void PrintThreadCommand(MachO::thread_command t, const char *Ptr,
begin += count * sizeof(uint32_t);
}
}
- } else if (cputype == MachO::CPU_TYPE_ARM64) {
+ } else if (cputype == MachO::CPU_TYPE_ARM64 ||
+ cputype == MachO::CPU_TYPE_ARM64_32) {
while (begin < end) {
if (end - begin > (ptrdiff_t)sizeof(uint32_t)) {
memcpy((char *)&flavor, begin, sizeof(uint32_t));
@@ -9790,12 +10092,12 @@ static void PrintMachHeader(const MachOObjectFile *Obj, bool verbose) {
}
}
-void llvm::printMachOFileHeader(const object::ObjectFile *Obj) {
+void printMachOFileHeader(const object::ObjectFile *Obj) {
const MachOObjectFile *file = dyn_cast<const MachOObjectFile>(Obj);
PrintMachHeader(file, !NonVerbose);
}
-void llvm::printMachOLoadCommands(const object::ObjectFile *Obj) {
+void printMachOLoadCommands(const object::ObjectFile *Obj) {
const MachOObjectFile *file = dyn_cast<const MachOObjectFile>(Obj);
uint32_t filetype = 0;
uint32_t cputype = 0;
@@ -9817,7 +10119,7 @@ void llvm::printMachOLoadCommands(const object::ObjectFile *Obj) {
// export trie dumping
//===----------------------------------------------------------------------===//
-void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) {
+void printMachOExportsTrie(const object::MachOObjectFile *Obj) {
uint64_t BaseSegmentAddress = 0;
for (const auto &Command : Obj->load_commands()) {
if (Command.C.cmd == MachO::LC_SEGMENT) {
@@ -9835,7 +10137,7 @@ void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) {
}
}
Error Err = Error::success();
- for (const llvm::object::ExportEntry &Entry : Obj->exports(Err)) {
+ for (const object::ExportEntry &Entry : Obj->exports(Err)) {
uint64_t Flags = Entry.flags();
bool ReExport = (Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
bool WeakDef = (Flags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
@@ -9889,17 +10191,17 @@ void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) {
outs() << "\n";
}
if (Err)
- report_error(Obj->getFileName(), std::move(Err));
+ report_error(std::move(Err), Obj->getFileName());
}
//===----------------------------------------------------------------------===//
// rebase table dumping
//===----------------------------------------------------------------------===//
-void llvm::printMachORebaseTable(object::MachOObjectFile *Obj) {
+void printMachORebaseTable(object::MachOObjectFile *Obj) {
outs() << "segment section address type\n";
Error Err = Error::success();
- for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable(Err)) {
+ for (const object::MachORebaseEntry &Entry : Obj->rebaseTable(Err)) {
StringRef SegmentName = Entry.segmentName();
StringRef SectionName = Entry.sectionName();
uint64_t Address = Entry.address();
@@ -9910,7 +10212,7 @@ void llvm::printMachORebaseTable(object::MachOObjectFile *Obj) {
Address, Entry.typeName().str().c_str());
}
if (Err)
- report_error(Obj->getFileName(), std::move(Err));
+ report_error(std::move(Err), Obj->getFileName());
}
static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {
@@ -9938,12 +10240,12 @@ static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {
// bind table dumping
//===----------------------------------------------------------------------===//
-void llvm::printMachOBindTable(object::MachOObjectFile *Obj) {
+void printMachOBindTable(object::MachOObjectFile *Obj) {
// Build table of sections so names can used in final output.
outs() << "segment section address type "
"addend dylib symbol\n";
Error Err = Error::success();
- for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable(Err)) {
+ for (const object::MachOBindEntry &Entry : Obj->bindTable(Err)) {
StringRef SegmentName = Entry.segmentName();
StringRef SectionName = Entry.sectionName();
uint64_t Address = Entry.address();
@@ -9962,18 +10264,18 @@ void llvm::printMachOBindTable(object::MachOObjectFile *Obj) {
<< Entry.symbolName() << Attr << "\n";
}
if (Err)
- report_error(Obj->getFileName(), std::move(Err));
+ report_error(std::move(Err), Obj->getFileName());
}
//===----------------------------------------------------------------------===//
// lazy bind table dumping
//===----------------------------------------------------------------------===//
-void llvm::printMachOLazyBindTable(object::MachOObjectFile *Obj) {
+void printMachOLazyBindTable(object::MachOObjectFile *Obj) {
outs() << "segment section address "
"dylib symbol\n";
Error Err = Error::success();
- for (const llvm::object::MachOBindEntry &Entry : Obj->lazyBindTable(Err)) {
+ for (const object::MachOBindEntry &Entry : Obj->lazyBindTable(Err)) {
StringRef SegmentName = Entry.segmentName();
StringRef SectionName = Entry.sectionName();
uint64_t Address = Entry.address();
@@ -9987,18 +10289,18 @@ void llvm::printMachOLazyBindTable(object::MachOObjectFile *Obj) {
<< Entry.symbolName() << "\n";
}
if (Err)
- report_error(Obj->getFileName(), std::move(Err));
+ report_error(std::move(Err), Obj->getFileName());
}
//===----------------------------------------------------------------------===//
// weak bind table dumping
//===----------------------------------------------------------------------===//
-void llvm::printMachOWeakBindTable(object::MachOObjectFile *Obj) {
+void printMachOWeakBindTable(object::MachOObjectFile *Obj) {
outs() << "segment section address "
"type addend symbol\n";
Error Err = Error::success();
- for (const llvm::object::MachOBindEntry &Entry : Obj->weakBindTable(Err)) {
+ for (const object::MachOBindEntry &Entry : Obj->weakBindTable(Err)) {
// Strong symbols don't have a location to update.
if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
outs() << " strong "
@@ -10019,7 +10321,7 @@ void llvm::printMachOWeakBindTable(object::MachOObjectFile *Obj) {
<< "\n";
}
if (Err)
- report_error(Obj->getFileName(), std::move(Err));
+ report_error(std::move(Err), Obj->getFileName());
}
// get_dyld_bind_info_symbolname() is used for disassembly and passed an
@@ -10031,16 +10333,66 @@ static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
if (info->bindtable == nullptr) {
info->bindtable = llvm::make_unique<SymbolAddressMap>();
Error Err = Error::success();
- for (const llvm::object::MachOBindEntry &Entry : info->O->bindTable(Err)) {
+ for (const object::MachOBindEntry &Entry : info->O->bindTable(Err)) {
uint64_t Address = Entry.address();
StringRef name = Entry.symbolName();
if (!name.empty())
(*info->bindtable)[Address] = name;
}
if (Err)
- report_error(info->O->getFileName(), std::move(Err));
+ report_error(std::move(Err), info->O->getFileName());
}
auto name = info->bindtable->lookup(ReferenceValue);
return !name.empty() ? name.data() : nullptr;
}
+void printLazyBindTable(ObjectFile *o) {
+ outs() << "Lazy bind table:\n";
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ printMachOLazyBindTable(MachO);
+ else
+ WithColor::error()
+ << "This operation is only currently supported "
+ "for Mach-O executable files.\n";
+}
+
+void printWeakBindTable(ObjectFile *o) {
+ outs() << "Weak bind table:\n";
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ printMachOWeakBindTable(MachO);
+ else
+ WithColor::error()
+ << "This operation is only currently supported "
+ "for Mach-O executable files.\n";
+}
+
+void printExportsTrie(const ObjectFile *o) {
+ outs() << "Exports trie:\n";
+ if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ printMachOExportsTrie(MachO);
+ else
+ WithColor::error()
+ << "This operation is only currently supported "
+ "for Mach-O executable files.\n";
+}
+
+void printRebaseTable(ObjectFile *o) {
+ outs() << "Rebase table:\n";
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ printMachORebaseTable(MachO);
+ else
+ WithColor::error()
+ << "This operation is only currently supported "
+ "for Mach-O executable files.\n";
+}
+
+void printBindTable(ObjectFile *o) {
+ outs() << "Bind table:\n";
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ printMachOBindTable(MachO);
+ else
+ WithColor::error()
+ << "This operation is only currently supported "
+ "for Mach-O executable files.\n";
+}
+} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-objdump/WasmDump.cpp b/contrib/llvm/tools/llvm-objdump/WasmDump.cpp
index 045002cd4b34..da27a4acbb5f 100644
--- a/contrib/llvm/tools/llvm-objdump/WasmDump.cpp
+++ b/contrib/llvm/tools/llvm-objdump/WasmDump.cpp
@@ -1,9 +1,8 @@
//===-- WasmDump.cpp - wasm-specific dumper ---------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -15,14 +14,39 @@
#include "llvm-objdump.h"
#include "llvm/Object/Wasm.h"
-using namespace llvm;
-using namespace object;
+using namespace llvm::object;
-void llvm::printWasmFileHeader(const object::ObjectFile *Obj) {
- const WasmObjectFile *File = dyn_cast<const WasmObjectFile>(Obj);
+namespace llvm {
+void printWasmFileHeader(const object::ObjectFile *Obj) {
+ const auto *File = dyn_cast<const WasmObjectFile>(Obj);
outs() << "Program Header:\n";
outs() << "Version: 0x";
outs().write_hex(File->getHeader().Version);
outs() << "\n";
}
+
+Error getWasmRelocationValueString(const WasmObjectFile *Obj,
+ const RelocationRef &RelRef,
+ SmallVectorImpl<char> &Result) {
+ const wasm::WasmRelocation &Rel = Obj->getWasmRelocation(RelRef);
+ symbol_iterator SI = RelRef.getSymbol();
+ std::string FmtBuf;
+ raw_string_ostream Fmt(FmtBuf);
+ if (SI == Obj->symbol_end()) {
+ // Not all wasm relocations have symbols associated with them.
+ // In particular R_WASM_TYPE_INDEX_LEB.
+ Fmt << Rel.Index;
+ } else {
+ Expected<StringRef> SymNameOrErr = SI->getName();
+ if (!SymNameOrErr)
+ return SymNameOrErr.takeError();
+ StringRef SymName = *SymNameOrErr;
+ Result.append(SymName.begin(), SymName.end());
+ }
+ Fmt << (Rel.Addend < 0 ? "" : "+") << Rel.Addend;
+ Fmt.flush();
+ Result.append(FmtBuf.begin(), FmtBuf.end());
+ return Error::success();
+}
+} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp b/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 9bd4528ef7f7..58981203c59e 100644
--- a/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -1,9 +1,8 @@
//===-- llvm-objdump.cpp - Object file dumping utility for llvm -----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -19,6 +18,7 @@
#include "llvm-objdump.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Triple.h"
@@ -68,283 +68,298 @@
#include <unordered_map>
#include <utility>
-using namespace llvm;
-using namespace object;
+using namespace llvm::object;
+
+namespace llvm {
+
+cl::OptionCategory ObjdumpCat("llvm-objdump Options");
+
+// MachO specific
+extern cl::OptionCategory MachOCat;
+extern cl::opt<bool> Bind;
+extern cl::opt<bool> DataInCode;
+extern cl::opt<bool> DylibsUsed;
+extern cl::opt<bool> DylibId;
+extern cl::opt<bool> ExportsTrie;
+extern cl::opt<bool> FirstPrivateHeader;
+extern cl::opt<bool> IndirectSymbols;
+extern cl::opt<bool> InfoPlist;
+extern cl::opt<bool> LazyBind;
+extern cl::opt<bool> LinkOptHints;
+extern cl::opt<bool> ObjcMetaData;
+extern cl::opt<bool> Rebase;
+extern cl::opt<bool> UniversalHeaders;
+extern cl::opt<bool> WeakBind;
+
+static cl::opt<uint64_t> AdjustVMA(
+ "adjust-vma",
+ cl::desc("Increase the displayed address by the specified offset"),
+ cl::value_desc("offset"), cl::init(0), cl::cat(ObjdumpCat));
-cl::opt<bool>
- llvm::AllHeaders("all-headers",
- cl::desc("Display all available header information"));
+static cl::opt<bool>
+ AllHeaders("all-headers",
+ cl::desc("Display all available header information"),
+ cl::cat(ObjdumpCat));
static cl::alias AllHeadersShort("x", cl::desc("Alias for --all-headers"),
+ cl::NotHidden, cl::Grouping,
cl::aliasopt(AllHeaders));
-static cl::list<std::string>
-InputFilenames(cl::Positional, cl::desc("<input object files>"),cl::ZeroOrMore);
+static cl::opt<std::string>
+ ArchName("arch-name",
+ cl::desc("Target arch to disassemble for, "
+ "see -version for available targets"),
+ cl::cat(ObjdumpCat));
+
+cl::opt<bool> ArchiveHeaders("archive-headers",
+ cl::desc("Display archive header information"),
+ cl::cat(ObjdumpCat));
+static cl::alias ArchiveHeadersShort("a",
+ cl::desc("Alias for --archive-headers"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(ArchiveHeaders));
+
+cl::opt<bool> Demangle("demangle", cl::desc("Demangle symbols names"),
+ cl::init(false), cl::cat(ObjdumpCat));
+static cl::alias DemangleShort("C", cl::desc("Alias for --demangle"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(Demangle));
+
+cl::opt<bool> Disassemble(
+ "disassemble",
+ cl::desc("Display assembler mnemonics for the machine instructions"),
+ cl::cat(ObjdumpCat));
+static cl::alias DisassembleShort("d", cl::desc("Alias for --disassemble"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(Disassemble));
+
+cl::opt<bool> DisassembleAll(
+ "disassemble-all",
+ cl::desc("Display assembler mnemonics for the machine instructions"),
+ cl::cat(ObjdumpCat));
+static cl::alias DisassembleAllShort("D",
+ cl::desc("Alias for --disassemble-all"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(DisassembleAll));
-cl::opt<bool>
-llvm::Disassemble("disassemble",
- cl::desc("Display assembler mnemonics for the machine instructions"));
+static cl::list<std::string>
+ DisassembleFunctions("disassemble-functions", cl::CommaSeparated,
+ cl::desc("List of functions to disassemble. "
+ "Accept demangled names when --demangle is "
+ "specified, otherwise accept mangled names"),
+ cl::cat(ObjdumpCat));
+
+static cl::opt<bool> DisassembleZeroes(
+ "disassemble-zeroes",
+ cl::desc("Do not skip blocks of zeroes when disassembling"),
+ cl::cat(ObjdumpCat));
static cl::alias
-Disassembled("d", cl::desc("Alias for --disassemble"),
- cl::aliasopt(Disassemble));
+ DisassembleZeroesShort("z", cl::desc("Alias for --disassemble-zeroes"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(DisassembleZeroes));
-cl::opt<bool>
-llvm::DisassembleAll("disassemble-all",
- cl::desc("Display assembler mnemonics for the machine instructions"));
+static cl::list<std::string>
+ DisassemblerOptions("disassembler-options",
+ cl::desc("Pass target specific disassembler options"),
+ cl::value_desc("options"), cl::CommaSeparated,
+ cl::cat(ObjdumpCat));
static cl::alias
-DisassembleAlld("D", cl::desc("Alias for --disassemble-all"),
- cl::aliasopt(DisassembleAll));
-
-cl::opt<bool> llvm::Demangle("demangle", cl::desc("Demangle symbols names"),
- cl::init(false));
-
-static cl::alias DemangleShort("C", cl::desc("Alias for --demangle"),
- cl::aliasopt(llvm::Demangle));
+ DisassemblerOptionsShort("M", cl::desc("Alias for --disassembler-options"),
+ cl::NotHidden, cl::Grouping, cl::Prefix,
+ cl::CommaSeparated,
+ cl::aliasopt(DisassemblerOptions));
-static cl::list<std::string>
-DisassembleFunctions("df",
- cl::CommaSeparated,
- cl::desc("List of functions to disassemble"));
-static StringSet<> DisasmFuncsSet;
+cl::opt<DIDumpType> DwarfDumpType(
+ "dwarf", cl::init(DIDT_Null), cl::desc("Dump of dwarf debug sections:"),
+ cl::values(clEnumValN(DIDT_DebugFrame, "frames", ".debug_frame")),
+ cl::cat(ObjdumpCat));
+
+static cl::opt<bool> DynamicRelocations(
+ "dynamic-reloc",
+ cl::desc("Display the dynamic relocation entries in the file"),
+ cl::cat(ObjdumpCat));
+static cl::alias DynamicRelocationShort("R",
+ cl::desc("Alias for --dynamic-reloc"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(DynamicRelocations));
-cl::opt<bool>
-llvm::Relocations("reloc",
- cl::desc("Display the relocation entries in the file"));
-static cl::alias RelocationsShort("r", cl::desc("Alias for --reloc"),
- cl::NotHidden,
- cl::aliasopt(llvm::Relocations));
+static cl::opt<bool>
+ FaultMapSection("fault-map-section",
+ cl::desc("Display contents of faultmap section"),
+ cl::cat(ObjdumpCat));
-cl::opt<bool>
-llvm::DynamicRelocations("dynamic-reloc",
- cl::desc("Display the dynamic relocation entries in the file"));
-static cl::alias
-DynamicRelocationsd("R", cl::desc("Alias for --dynamic-reloc"),
- cl::aliasopt(DynamicRelocations));
+static cl::opt<bool>
+ FileHeaders("file-headers",
+ cl::desc("Display the contents of the overall file header"),
+ cl::cat(ObjdumpCat));
+static cl::alias FileHeadersShort("f", cl::desc("Alias for --file-headers"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(FileHeaders));
-cl::opt<bool>
- llvm::SectionContents("full-contents",
- cl::desc("Display the content of each section"));
+cl::opt<bool> SectionContents("full-contents",
+ cl::desc("Display the content of each section"),
+ cl::cat(ObjdumpCat));
static cl::alias SectionContentsShort("s",
cl::desc("Alias for --full-contents"),
+ cl::NotHidden, cl::Grouping,
cl::aliasopt(SectionContents));
-cl::opt<bool> llvm::SymbolTable("syms", cl::desc("Display the symbol table"));
-static cl::alias SymbolTableShort("t", cl::desc("Alias for --syms"),
- cl::NotHidden,
- cl::aliasopt(llvm::SymbolTable));
-
-cl::opt<bool>
-llvm::ExportsTrie("exports-trie", cl::desc("Display mach-o exported symbols"));
-
-cl::opt<bool>
-llvm::Rebase("rebase", cl::desc("Display mach-o rebasing info"));
-
-cl::opt<bool>
-llvm::Bind("bind", cl::desc("Display mach-o binding info"));
-
-cl::opt<bool>
-llvm::LazyBind("lazy-bind", cl::desc("Display mach-o lazy binding info"));
-
-cl::opt<bool>
-llvm::WeakBind("weak-bind", cl::desc("Display mach-o weak binding info"));
-
-cl::opt<bool>
-llvm::RawClangAST("raw-clang-ast",
- cl::desc("Dump the raw binary contents of the clang AST section"));
+static cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input object files>"),
+ cl::ZeroOrMore,
+ cl::cat(ObjdumpCat));
static cl::opt<bool>
-MachOOpt("macho", cl::desc("Use MachO specific object file parser"));
-static cl::alias
-MachOm("m", cl::desc("Alias for --macho"), cl::aliasopt(MachOOpt));
-
-cl::opt<std::string>
-llvm::TripleName("triple", cl::desc("Target triple to disassemble for, "
- "see -version for available targets"));
+ PrintLines("line-numbers",
+ cl::desc("Display source line numbers with "
+ "disassembly. Implies disassemble object"),
+ cl::cat(ObjdumpCat));
+static cl::alias PrintLinesShort("l", cl::desc("Alias for --line-numbers"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(PrintLines));
+
+static cl::opt<bool> MachOOpt("macho",
+ cl::desc("Use MachO specific object file parser"),
+ cl::cat(ObjdumpCat));
+static cl::alias MachOm("m", cl::desc("Alias for --macho"), cl::NotHidden,
+ cl::Grouping, cl::aliasopt(MachOOpt));
cl::opt<std::string>
-llvm::MCPU("mcpu",
- cl::desc("Target a specific cpu type (-mcpu=help for details)"),
- cl::value_desc("cpu-name"),
- cl::init(""));
-
-cl::opt<std::string>
-llvm::ArchName("arch-name", cl::desc("Target arch to disassemble for, "
- "see -version for available targets"));
-
-cl::opt<bool>
-llvm::SectionHeaders("section-headers", cl::desc("Display summaries of the "
- "headers for each section."));
-static cl::alias
-SectionHeadersShort("headers", cl::desc("Alias for --section-headers"),
- cl::aliasopt(SectionHeaders));
-static cl::alias
-SectionHeadersShorter("h", cl::desc("Alias for --section-headers"),
- cl::aliasopt(SectionHeaders));
-
-cl::list<std::string>
-llvm::FilterSections("section", cl::desc("Operate on the specified sections only. "
- "With -macho dump segment,section"));
-cl::alias
-static FilterSectionsj("j", cl::desc("Alias for --section"),
- cl::aliasopt(llvm::FilterSections));
-
-cl::list<std::string>
-llvm::MAttrs("mattr",
- cl::CommaSeparated,
- cl::desc("Target specific attributes"),
- cl::value_desc("a1,+a2,-a3,..."));
-
-cl::opt<bool>
-llvm::NoShowRawInsn("no-show-raw-insn", cl::desc("When disassembling "
- "instructions, do not print "
- "the instruction bytes."));
-cl::opt<bool>
-llvm::NoLeadingAddr("no-leading-addr", cl::desc("Print no leading address"));
-
-cl::opt<bool>
-llvm::UnwindInfo("unwind-info", cl::desc("Display unwind information"));
-
-static cl::alias
-UnwindInfoShort("u", cl::desc("Alias for --unwind-info"),
- cl::aliasopt(UnwindInfo));
+ MCPU("mcpu",
+ cl::desc("Target a specific cpu type (-mcpu=help for details)"),
+ cl::value_desc("cpu-name"), cl::init(""), cl::cat(ObjdumpCat));
+
+cl::list<std::string> MAttrs("mattr", cl::CommaSeparated,
+ cl::desc("Target specific attributes"),
+ cl::value_desc("a1,+a2,-a3,..."),
+ cl::cat(ObjdumpCat));
+
+cl::opt<bool> NoShowRawInsn("no-show-raw-insn",
+ cl::desc("When disassembling "
+ "instructions, do not print "
+ "the instruction bytes."),
+ cl::cat(ObjdumpCat));
+cl::opt<bool> NoLeadingAddr("no-leading-addr",
+ cl::desc("Print no leading address"),
+ cl::cat(ObjdumpCat));
+
+static cl::opt<bool> RawClangAST(
+ "raw-clang-ast",
+ cl::desc("Dump the raw binary contents of the clang AST section"),
+ cl::cat(ObjdumpCat));
cl::opt<bool>
-llvm::PrivateHeaders("private-headers",
- cl::desc("Display format specific file headers"));
-
-cl::opt<bool>
-llvm::FirstPrivateHeader("private-header",
- cl::desc("Display only the first format specific file "
- "header"));
-
-static cl::alias
-PrivateHeadersShort("p", cl::desc("Alias for --private-headers"),
- cl::aliasopt(PrivateHeaders));
-
-cl::opt<bool> llvm::FileHeaders(
- "file-headers",
- cl::desc("Display the contents of the overall file header"));
-
-static cl::alias FileHeadersShort("f", cl::desc("Alias for --file-headers"),
- cl::aliasopt(FileHeaders));
+ Relocations("reloc", cl::desc("Display the relocation entries in the file"),
+ cl::cat(ObjdumpCat));
+static cl::alias RelocationsShort("r", cl::desc("Alias for --reloc"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(Relocations));
-cl::opt<bool>
- llvm::ArchiveHeaders("archive-headers",
- cl::desc("Display archive header information"));
+cl::opt<bool> PrintImmHex("print-imm-hex",
+ cl::desc("Use hex format for immediate values"),
+ cl::cat(ObjdumpCat));
-cl::alias
-ArchiveHeadersShort("a", cl::desc("Alias for --archive-headers"),
- cl::aliasopt(ArchiveHeaders));
+cl::opt<bool> PrivateHeaders("private-headers",
+ cl::desc("Display format specific file headers"),
+ cl::cat(ObjdumpCat));
+static cl::alias PrivateHeadersShort("p",
+ cl::desc("Alias for --private-headers"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(PrivateHeaders));
-cl::opt<bool>
- llvm::PrintImmHex("print-imm-hex",
- cl::desc("Use hex format for immediate values"));
-
-cl::opt<bool> PrintFaultMaps("fault-map-section",
- cl::desc("Display contents of faultmap section"));
+cl::list<std::string>
+ FilterSections("section",
+ cl::desc("Operate on the specified sections only. "
+ "With -macho dump segment,section"),
+ cl::cat(ObjdumpCat));
+static cl::alias FilterSectionsj("j", cl::desc("Alias for --section"),
+ cl::NotHidden, cl::Grouping, cl::Prefix,
+ cl::aliasopt(FilterSections));
+
+cl::opt<bool> SectionHeaders("section-headers",
+ cl::desc("Display summaries of the "
+ "headers for each section."),
+ cl::cat(ObjdumpCat));
+static cl::alias SectionHeadersShort("headers",
+ cl::desc("Alias for --section-headers"),
+ cl::NotHidden,
+ cl::aliasopt(SectionHeaders));
+static cl::alias SectionHeadersShorter("h",
+ cl::desc("Alias for --section-headers"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(SectionHeaders));
-cl::opt<DIDumpType> llvm::DwarfDumpType(
- "dwarf", cl::init(DIDT_Null), cl::desc("Dump of dwarf debug sections:"),
- cl::values(clEnumValN(DIDT_DebugFrame, "frames", ".debug_frame")));
+static cl::opt<bool>
+ ShowLMA("show-lma",
+ cl::desc("Display LMA column when dumping ELF section headers"),
+ cl::cat(ObjdumpCat));
-cl::opt<bool> PrintSource(
+static cl::opt<bool> PrintSource(
"source",
cl::desc(
- "Display source inlined with disassembly. Implies disassemble object"));
-
-cl::alias PrintSourceShort("S", cl::desc("Alias for -source"),
- cl::aliasopt(PrintSource));
-
-cl::opt<bool> PrintLines("line-numbers",
- cl::desc("Display source line numbers with "
- "disassembly. Implies disassemble object"));
-
-cl::alias PrintLinesShort("l", cl::desc("Alias for -line-numbers"),
- cl::aliasopt(PrintLines));
+ "Display source inlined with disassembly. Implies disassemble object"),
+ cl::cat(ObjdumpCat));
+static cl::alias PrintSourceShort("S", cl::desc("Alias for -source"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(PrintSource));
-cl::opt<unsigned long long>
+static cl::opt<uint64_t>
StartAddress("start-address", cl::desc("Disassemble beginning at address"),
- cl::value_desc("address"), cl::init(0));
-cl::opt<unsigned long long>
- StopAddress("stop-address",
- cl::desc("Stop disassembly at address"),
- cl::value_desc("address"), cl::init(UINT64_MAX));
-
-cl::opt<bool> DisassembleZeroes(
- "disassemble-zeroes",
- cl::desc("Do not skip blocks of zeroes when disassembling"));
-cl::alias DisassembleZeroesShort("z",
- cl::desc("Alias for --disassemble-zeroes"),
- cl::aliasopt(DisassembleZeroes));
+ cl::value_desc("address"), cl::init(0), cl::cat(ObjdumpCat));
+static cl::opt<uint64_t> StopAddress("stop-address",
+ cl::desc("Stop disassembly at address"),
+ cl::value_desc("address"),
+ cl::init(UINT64_MAX), cl::cat(ObjdumpCat));
+
+cl::opt<bool> SymbolTable("syms", cl::desc("Display the symbol table"),
+ cl::cat(ObjdumpCat));
+static cl::alias SymbolTableShort("t", cl::desc("Alias for --syms"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(SymbolTable));
-static StringRef ToolName;
+cl::opt<std::string> TripleName("triple",
+ cl::desc("Target triple to disassemble for, "
+ "see -version for available targets"),
+ cl::cat(ObjdumpCat));
-typedef std::vector<std::tuple<uint64_t, StringRef, uint8_t>> SectionSymbolsTy;
+cl::opt<bool> UnwindInfo("unwind-info", cl::desc("Display unwind information"),
+ cl::cat(ObjdumpCat));
+static cl::alias UnwindInfoShort("u", cl::desc("Alias for --unwind-info"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(UnwindInfo));
-namespace {
-typedef std::function<bool(llvm::object::SectionRef const &)> FilterPredicate;
+static cl::opt<bool>
+ Wide("wide", cl::desc("Ignored for compatibility with GNU objdump"),
+ cl::cat(ObjdumpCat));
+static cl::alias WideShort("w", cl::Grouping, cl::aliasopt(Wide));
-class SectionFilterIterator {
-public:
- SectionFilterIterator(FilterPredicate P,
- llvm::object::section_iterator const &I,
- llvm::object::section_iterator const &E)
- : Predicate(std::move(P)), Iterator(I), End(E) {
- ScanPredicate();
- }
- const llvm::object::SectionRef &operator*() const { return *Iterator; }
- SectionFilterIterator &operator++() {
- ++Iterator;
- ScanPredicate();
- return *this;
- }
- bool operator!=(SectionFilterIterator const &Other) const {
- return Iterator != Other.Iterator;
- }
+static cl::extrahelp
+ HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
-private:
- void ScanPredicate() {
- while (Iterator != End && !Predicate(*Iterator)) {
- ++Iterator;
- }
- }
- FilterPredicate Predicate;
- llvm::object::section_iterator Iterator;
- llvm::object::section_iterator End;
-};
+static StringSet<> DisasmFuncsSet;
+static StringSet<> FoundSectionSet;
+static StringRef ToolName;
-class SectionFilter {
-public:
- SectionFilter(FilterPredicate P, llvm::object::ObjectFile const &O)
- : Predicate(std::move(P)), Object(O) {}
- SectionFilterIterator begin() {
- return SectionFilterIterator(Predicate, Object.section_begin(),
- Object.section_end());
- }
- SectionFilterIterator end() {
- return SectionFilterIterator(Predicate, Object.section_end(),
- Object.section_end());
- }
+typedef std::vector<std::tuple<uint64_t, StringRef, uint8_t>> SectionSymbolsTy;
-private:
- FilterPredicate Predicate;
- llvm::object::ObjectFile const &Object;
-};
-SectionFilter ToolSectionFilter(llvm::object::ObjectFile const &O) {
- return SectionFilter(
- [](llvm::object::SectionRef const &S) {
- if (FilterSections.empty())
- return true;
- llvm::StringRef String;
- std::error_code error = S.getName(String);
- if (error)
- return false;
- return is_contained(FilterSections, String);
- },
- O);
+static bool shouldKeep(object::SectionRef S) {
+ if (FilterSections.empty())
+ return true;
+ StringRef SecName;
+ std::error_code error = S.getName(SecName);
+ if (error)
+ return false;
+ // StringSet does not allow empty key so avoid adding sections with
+ // no name (such as the section with index 0) here.
+ if (!SecName.empty())
+ FoundSectionSet.insert(SecName);
+ return is_contained(FilterSections, SecName);
}
+
+SectionFilter ToolSectionFilter(object::ObjectFile const &O) {
+ return SectionFilter([](object::SectionRef S) { return shouldKeep(S); }, O);
}
-void llvm::error(std::error_code EC) {
+void error(std::error_code EC) {
if (!EC)
return;
WithColor::error(errs(), ToolName)
@@ -353,34 +368,39 @@ void llvm::error(std::error_code EC) {
exit(1);
}
-LLVM_ATTRIBUTE_NORETURN void llvm::error(Twine Message) {
+void error(Error E) {
+ if (!E)
+ return;
+ WithColor::error(errs(), ToolName) << toString(std::move(E));
+ exit(1);
+}
+
+LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
WithColor::error(errs(), ToolName) << Message << ".\n";
errs().flush();
exit(1);
}
-void llvm::warn(StringRef Message) {
+void warn(StringRef Message) {
WithColor::warning(errs(), ToolName) << Message << ".\n";
errs().flush();
}
-LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef File,
- Twine Message) {
- WithColor::error(errs(), ToolName)
- << "'" << File << "': " << Message << ".\n";
- exit(1);
+static void warn(Twine Message) {
+ // Output order between errs() and outs() matters especially for archive
+ // files where the output is per member object.
+ outs().flush();
+ WithColor::warning(errs(), ToolName) << Message << "\n";
+ errs().flush();
}
-LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef File,
- std::error_code EC) {
- assert(EC);
+LLVM_ATTRIBUTE_NORETURN void report_error(StringRef File, Twine Message) {
WithColor::error(errs(), ToolName)
- << "'" << File << "': " << EC.message() << ".\n";
+ << "'" << File << "': " << Message << ".\n";
exit(1);
}
-LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef File,
- llvm::Error E) {
+LLVM_ATTRIBUTE_NORETURN void report_error(Error E, StringRef File) {
assert(E);
std::string Buf;
raw_string_ostream OS(Buf);
@@ -390,10 +410,9 @@ LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef File,
exit(1);
}
-LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef ArchiveName,
- StringRef FileName,
- llvm::Error E,
- StringRef ArchitectureName) {
+LLVM_ATTRIBUTE_NORETURN void report_error(Error E, StringRef ArchiveName,
+ StringRef FileName,
+ StringRef ArchitectureName) {
assert(E);
WithColor::error(errs(), ToolName);
if (ArchiveName != "")
@@ -410,25 +429,39 @@ LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef ArchiveName,
exit(1);
}
-LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef ArchiveName,
- const object::Archive::Child &C,
- llvm::Error E,
- StringRef ArchitectureName) {
+LLVM_ATTRIBUTE_NORETURN void report_error(Error E, StringRef ArchiveName,
+ const object::Archive::Child &C,
+ StringRef ArchitectureName) {
Expected<StringRef> NameOrErr = C.getName();
// TODO: if we have a error getting the name then it would be nice to print
// the index of which archive member this is and or its offset in the
// archive instead of "???" as the name.
if (!NameOrErr) {
consumeError(NameOrErr.takeError());
- llvm::report_error(ArchiveName, "???", std::move(E), ArchitectureName);
+ report_error(std::move(E), ArchiveName, "???", ArchitectureName);
} else
- llvm::report_error(ArchiveName, NameOrErr.get(), std::move(E),
- ArchitectureName);
+ report_error(std::move(E), ArchiveName, NameOrErr.get(), ArchitectureName);
+}
+
+static void warnOnNoMatchForSections() {
+ SetVector<StringRef> MissingSections;
+ for (StringRef S : FilterSections) {
+ if (FoundSectionSet.count(S))
+ return;
+ // User may specify a unnamed section. Don't warn for it.
+ if (!S.empty())
+ MissingSections.insert(S);
+ }
+
+ // Warn only if no section in FilterSections is matched.
+ for (StringRef S : MissingSections)
+ warn("section '" + S + "' mentioned in a -j/--section option, but not "
+ "found in any input file");
}
static const Target *getTarget(const ObjectFile *Obj = nullptr) {
// Figure out the target triple.
- llvm::Triple TheTriple("unknown-unknown-unknown");
+ Triple TheTriple("unknown-unknown-unknown");
if (TripleName.empty()) {
if (Obj)
TheTriple = Obj->makeTriple();
@@ -459,423 +492,21 @@ static const Target *getTarget(const ObjectFile *Obj = nullptr) {
return TheTarget;
}
-bool llvm::isRelocAddressLess(RelocationRef A, RelocationRef B) {
+bool isRelocAddressLess(RelocationRef A, RelocationRef B) {
return A.getOffset() < B.getOffset();
}
-static std::string demangle(StringRef Name) {
- char *Demangled = nullptr;
- if (Name.startswith("_Z"))
- Demangled = itaniumDemangle(Name.data(), Demangled, nullptr, nullptr);
- else if (Name.startswith("?"))
- Demangled = microsoftDemangle(Name.data(), Demangled, nullptr, nullptr);
-
- if (!Demangled)
- return Name;
-
- std::string Ret = Demangled;
- free(Demangled);
- return Ret;
-}
-
-template <class ELFT>
-static std::error_code getRelocationValueString(const ELFObjectFile<ELFT> *Obj,
- const RelocationRef &RelRef,
- SmallVectorImpl<char> &Result) {
- typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename ELFObjectFile<ELFT>::Elf_Rela Elf_Rela;
-
- const ELFFile<ELFT> &EF = *Obj->getELFFile();
- DataRefImpl Rel = RelRef.getRawDataRefImpl();
- auto SecOrErr = EF.getSection(Rel.d.a);
- if (!SecOrErr)
- return errorToErrorCode(SecOrErr.takeError());
- const Elf_Shdr *Sec = *SecOrErr;
- auto SymTabOrErr = EF.getSection(Sec->sh_link);
- if (!SymTabOrErr)
- return errorToErrorCode(SymTabOrErr.takeError());
- const Elf_Shdr *SymTab = *SymTabOrErr;
- assert(SymTab->sh_type == ELF::SHT_SYMTAB ||
- SymTab->sh_type == ELF::SHT_DYNSYM);
- auto StrTabSec = EF.getSection(SymTab->sh_link);
- if (!StrTabSec)
- return errorToErrorCode(StrTabSec.takeError());
- auto StrTabOrErr = EF.getStringTable(*StrTabSec);
- if (!StrTabOrErr)
- return errorToErrorCode(StrTabOrErr.takeError());
- StringRef StrTab = *StrTabOrErr;
- int64_t Addend = 0;
- // If there is no Symbol associated with the relocation, we set the undef
- // boolean value to 'true'. This will prevent us from calling functions that
- // requires the relocation to be associated with a symbol.
- bool Undef = false;
- switch (Sec->sh_type) {
- default:
- return object_error::parse_failed;
- case ELF::SHT_REL: {
- // TODO: Read implicit addend from section data.
- break;
- }
- case ELF::SHT_RELA: {
- const Elf_Rela *ERela = Obj->getRela(Rel);
- Addend = ERela->r_addend;
- Undef = ERela->getSymbol(false) == 0;
- break;
- }
- }
- std::string Target;
- if (!Undef) {
- symbol_iterator SI = RelRef.getSymbol();
- const Elf_Sym *symb = Obj->getSymbol(SI->getRawDataRefImpl());
- if (symb->getType() == ELF::STT_SECTION) {
- Expected<section_iterator> SymSI = SI->getSection();
- if (!SymSI)
- return errorToErrorCode(SymSI.takeError());
- const Elf_Shdr *SymSec = Obj->getSection((*SymSI)->getRawDataRefImpl());
- auto SecName = EF.getSectionName(SymSec);
- if (!SecName)
- return errorToErrorCode(SecName.takeError());
- Target = *SecName;
- } else {
- Expected<StringRef> SymName = symb->getName(StrTab);
- if (!SymName)
- return errorToErrorCode(SymName.takeError());
- if (Demangle)
- Target = demangle(*SymName);
- else
- Target = *SymName;
- }
- } else
- Target = "*ABS*";
-
- // Default scheme is to print Target, as well as "+ <addend>" for nonzero
- // addend. Should be acceptable for all normal purposes.
- std::string FmtBuf;
- raw_string_ostream Fmt(FmtBuf);
- Fmt << Target;
- if (Addend != 0)
- Fmt << (Addend < 0 ? "" : "+") << Addend;
- Fmt.flush();
- Result.append(FmtBuf.begin(), FmtBuf.end());
- return std::error_code();
-}
-
-static std::error_code getRelocationValueString(const ELFObjectFileBase *Obj,
- const RelocationRef &Rel,
- SmallVectorImpl<char> &Result) {
- if (auto *ELF32LE = dyn_cast<ELF32LEObjectFile>(Obj))
- return getRelocationValueString(ELF32LE, Rel, Result);
- if (auto *ELF64LE = dyn_cast<ELF64LEObjectFile>(Obj))
- return getRelocationValueString(ELF64LE, Rel, Result);
- if (auto *ELF32BE = dyn_cast<ELF32BEObjectFile>(Obj))
- return getRelocationValueString(ELF32BE, Rel, Result);
- auto *ELF64BE = cast<ELF64BEObjectFile>(Obj);
- return getRelocationValueString(ELF64BE, Rel, Result);
-}
-
-static std::error_code getRelocationValueString(const COFFObjectFile *Obj,
- const RelocationRef &Rel,
- SmallVectorImpl<char> &Result) {
- symbol_iterator SymI = Rel.getSymbol();
- Expected<StringRef> SymNameOrErr = SymI->getName();
- if (!SymNameOrErr)
- return errorToErrorCode(SymNameOrErr.takeError());
- StringRef SymName = *SymNameOrErr;
- Result.append(SymName.begin(), SymName.end());
- return std::error_code();
-}
-
-static void printRelocationTargetName(const MachOObjectFile *O,
- const MachO::any_relocation_info &RE,
- raw_string_ostream &Fmt) {
- // Target of a scattered relocation is an address. In the interest of
- // generating pretty output, scan through the symbol table looking for a
- // symbol that aligns with that address. If we find one, print it.
- // Otherwise, we just print the hex address of the target.
- if (O->isRelocationScattered(RE)) {
- uint32_t Val = O->getPlainRelocationSymbolNum(RE);
-
- for (const SymbolRef &Symbol : O->symbols()) {
- Expected<uint64_t> Addr = Symbol.getAddress();
- if (!Addr)
- report_error(O->getFileName(), Addr.takeError());
- if (*Addr != Val)
- continue;
- Expected<StringRef> Name = Symbol.getName();
- if (!Name)
- report_error(O->getFileName(), Name.takeError());
- Fmt << *Name;
- return;
- }
-
- // If we couldn't find a symbol that this relocation refers to, try
- // to find a section beginning instead.
- for (const SectionRef &Section : ToolSectionFilter(*O)) {
- std::error_code ec;
-
- StringRef Name;
- uint64_t Addr = Section.getAddress();
- if (Addr != Val)
- continue;
- if ((ec = Section.getName(Name)))
- report_error(O->getFileName(), ec);
- Fmt << Name;
- return;
- }
-
- Fmt << format("0x%x", Val);
- return;
- }
-
- StringRef S;
- bool isExtern = O->getPlainRelocationExternal(RE);
- uint64_t Val = O->getPlainRelocationSymbolNum(RE);
-
- if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND) {
- Fmt << format("0x%0" PRIx64, Val);
- return;
- }
-
- if (isExtern) {
- symbol_iterator SI = O->symbol_begin();
- advance(SI, Val);
- Expected<StringRef> SOrErr = SI->getName();
- if (!SOrErr)
- report_error(O->getFileName(), SOrErr.takeError());
- S = *SOrErr;
- } else {
- section_iterator SI = O->section_begin();
- // Adjust for the fact that sections are 1-indexed.
- if (Val == 0) {
- Fmt << "0 (?,?)";
- return;
- }
- uint32_t I = Val - 1;
- while (I != 0 && SI != O->section_end()) {
- --I;
- advance(SI, 1);
- }
- if (SI == O->section_end())
- Fmt << Val << " (?,?)";
- else
- SI->getName(S);
- }
-
- Fmt << S;
-}
-
-static std::error_code getRelocationValueString(const WasmObjectFile *Obj,
- const RelocationRef &RelRef,
- SmallVectorImpl<char> &Result) {
- const wasm::WasmRelocation& Rel = Obj->getWasmRelocation(RelRef);
- symbol_iterator SI = RelRef.getSymbol();
- std::string FmtBuf;
- raw_string_ostream Fmt(FmtBuf);
- if (SI == Obj->symbol_end()) {
- // Not all wasm relocations have symbols associated with them.
- // In particular R_WEBASSEMBLY_TYPE_INDEX_LEB.
- Fmt << Rel.Index;
- } else {
- Expected<StringRef> SymNameOrErr = SI->getName();
- if (!SymNameOrErr)
- return errorToErrorCode(SymNameOrErr.takeError());
- StringRef SymName = *SymNameOrErr;
- Result.append(SymName.begin(), SymName.end());
- }
- Fmt << (Rel.Addend < 0 ? "" : "+") << Rel.Addend;
- Fmt.flush();
- Result.append(FmtBuf.begin(), FmtBuf.end());
- return std::error_code();
-}
-
-static std::error_code getRelocationValueString(const MachOObjectFile *Obj,
- const RelocationRef &RelRef,
- SmallVectorImpl<char> &Result) {
- DataRefImpl Rel = RelRef.getRawDataRefImpl();
- MachO::any_relocation_info RE = Obj->getRelocation(Rel);
-
- unsigned Arch = Obj->getArch();
-
- std::string FmtBuf;
- raw_string_ostream Fmt(FmtBuf);
- unsigned Type = Obj->getAnyRelocationType(RE);
- bool IsPCRel = Obj->getAnyRelocationPCRel(RE);
-
- // Determine any addends that should be displayed with the relocation.
- // These require decoding the relocation type, which is triple-specific.
-
- // X86_64 has entirely custom relocation types.
- if (Arch == Triple::x86_64) {
- switch (Type) {
- case MachO::X86_64_RELOC_GOT_LOAD:
- case MachO::X86_64_RELOC_GOT: {
- printRelocationTargetName(Obj, RE, Fmt);
- Fmt << "@GOT";
- if (IsPCRel)
- Fmt << "PCREL";
- break;
- }
- case MachO::X86_64_RELOC_SUBTRACTOR: {
- DataRefImpl RelNext = Rel;
- Obj->moveRelocationNext(RelNext);
- MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
-
- // X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type
- // X86_64_RELOC_UNSIGNED.
- // NOTE: Scattered relocations don't exist on x86_64.
- unsigned RType = Obj->getAnyRelocationType(RENext);
- if (RType != MachO::X86_64_RELOC_UNSIGNED)
- report_error(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after "
- "X86_64_RELOC_SUBTRACTOR.");
-
- // The X86_64_RELOC_UNSIGNED contains the minuend symbol;
- // X86_64_RELOC_SUBTRACTOR contains the subtrahend.
- printRelocationTargetName(Obj, RENext, Fmt);
- Fmt << "-";
- printRelocationTargetName(Obj, RE, Fmt);
- break;
- }
- case MachO::X86_64_RELOC_TLV:
- printRelocationTargetName(Obj, RE, Fmt);
- Fmt << "@TLV";
- if (IsPCRel)
- Fmt << "P";
- break;
- case MachO::X86_64_RELOC_SIGNED_1:
- printRelocationTargetName(Obj, RE, Fmt);
- Fmt << "-1";
- break;
- case MachO::X86_64_RELOC_SIGNED_2:
- printRelocationTargetName(Obj, RE, Fmt);
- Fmt << "-2";
- break;
- case MachO::X86_64_RELOC_SIGNED_4:
- printRelocationTargetName(Obj, RE, Fmt);
- Fmt << "-4";
- break;
- default:
- printRelocationTargetName(Obj, RE, Fmt);
- break;
- }
- // X86 and ARM share some relocation types in common.
- } else if (Arch == Triple::x86 || Arch == Triple::arm ||
- Arch == Triple::ppc) {
- // Generic relocation types...
- switch (Type) {
- case MachO::GENERIC_RELOC_PAIR: // prints no info
- return std::error_code();
- case MachO::GENERIC_RELOC_SECTDIFF: {
- DataRefImpl RelNext = Rel;
- Obj->moveRelocationNext(RelNext);
- MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
-
- // X86 sect diff's must be followed by a relocation of type
- // GENERIC_RELOC_PAIR.
- unsigned RType = Obj->getAnyRelocationType(RENext);
-
- if (RType != MachO::GENERIC_RELOC_PAIR)
- report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
- "GENERIC_RELOC_SECTDIFF.");
-
- printRelocationTargetName(Obj, RE, Fmt);
- Fmt << "-";
- printRelocationTargetName(Obj, RENext, Fmt);
- break;
- }
- }
-
- if (Arch == Triple::x86 || Arch == Triple::ppc) {
- switch (Type) {
- case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
- DataRefImpl RelNext = Rel;
- Obj->moveRelocationNext(RelNext);
- MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
-
- // X86 sect diff's must be followed by a relocation of type
- // GENERIC_RELOC_PAIR.
- unsigned RType = Obj->getAnyRelocationType(RENext);
- if (RType != MachO::GENERIC_RELOC_PAIR)
- report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
- "GENERIC_RELOC_LOCAL_SECTDIFF.");
-
- printRelocationTargetName(Obj, RE, Fmt);
- Fmt << "-";
- printRelocationTargetName(Obj, RENext, Fmt);
- break;
- }
- case MachO::GENERIC_RELOC_TLV: {
- printRelocationTargetName(Obj, RE, Fmt);
- Fmt << "@TLV";
- if (IsPCRel)
- Fmt << "P";
- break;
- }
- default:
- printRelocationTargetName(Obj, RE, Fmt);
- }
- } else { // ARM-specific relocations
- switch (Type) {
- case MachO::ARM_RELOC_HALF:
- case MachO::ARM_RELOC_HALF_SECTDIFF: {
- // Half relocations steal a bit from the length field to encode
- // whether this is an upper16 or a lower16 relocation.
- bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1;
-
- if (isUpper)
- Fmt << ":upper16:(";
- else
- Fmt << ":lower16:(";
- printRelocationTargetName(Obj, RE, Fmt);
-
- DataRefImpl RelNext = Rel;
- Obj->moveRelocationNext(RelNext);
- MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
-
- // ARM half relocs must be followed by a relocation of type
- // ARM_RELOC_PAIR.
- unsigned RType = Obj->getAnyRelocationType(RENext);
- if (RType != MachO::ARM_RELOC_PAIR)
- report_error(Obj->getFileName(), "Expected ARM_RELOC_PAIR after "
- "ARM_RELOC_HALF");
-
- // NOTE: The half of the target virtual address is stashed in the
- // address field of the secondary relocation, but we can't reverse
- // engineer the constant offset from it without decoding the movw/movt
- // instruction to find the other half in its immediate field.
-
- // ARM_RELOC_HALF_SECTDIFF encodes the second section in the
- // symbol/section pointer of the follow-on relocation.
- if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
- Fmt << "-";
- printRelocationTargetName(Obj, RENext, Fmt);
- }
-
- Fmt << ")";
- break;
- }
- default: { printRelocationTargetName(Obj, RE, Fmt); }
- }
- }
- } else
- printRelocationTargetName(Obj, RE, Fmt);
-
- Fmt.flush();
- Result.append(FmtBuf.begin(), FmtBuf.end());
- return std::error_code();
-}
-
-static std::error_code getRelocationValueString(const RelocationRef &Rel,
- SmallVectorImpl<char> &Result) {
+static Error getRelocationValueString(const RelocationRef &Rel,
+ SmallVectorImpl<char> &Result) {
const ObjectFile *Obj = Rel.getObject();
if (auto *ELF = dyn_cast<ELFObjectFileBase>(Obj))
- return getRelocationValueString(ELF, Rel, Result);
+ return getELFRelocationValueString(ELF, Rel, Result);
if (auto *COFF = dyn_cast<COFFObjectFile>(Obj))
- return getRelocationValueString(COFF, Rel, Result);
+ return getCOFFRelocationValueString(COFF, Rel, Result);
if (auto *Wasm = dyn_cast<WasmObjectFile>(Obj))
- return getRelocationValueString(Wasm, Rel, Result);
+ return getWasmRelocationValueString(Wasm, Rel, Result);
if (auto *MachO = dyn_cast<MachOObjectFile>(Obj))
- return getRelocationValueString(MachO, Rel, Result);
+ return getMachORelocationValueString(MachO, Rel, Result);
llvm_unreachable("unknown object file format");
}
@@ -928,13 +559,15 @@ private:
public:
SourcePrinter() = default;
SourcePrinter(const ObjectFile *Obj, StringRef DefaultArch) : Obj(Obj) {
- symbolize::LLVMSymbolizer::Options SymbolizerOpts(
- DILineInfoSpecifier::FunctionNameKind::None, true, false, false,
- DefaultArch);
+ symbolize::LLVMSymbolizer::Options SymbolizerOpts;
+ SymbolizerOpts.PrintFunctions = DILineInfoSpecifier::FunctionNameKind::None;
+ SymbolizerOpts.Demangle = false;
+ SymbolizerOpts.DefaultArch = DefaultArch;
Symbolizer.reset(new symbolize::LLVMSymbolizer(SymbolizerOpts));
}
virtual ~SourcePrinter() = default;
- virtual void printSourceLine(raw_ostream &OS, uint64_t Address,
+ virtual void printSourceLine(raw_ostream &OS,
+ object::SectionedAddress Address,
StringRef Delimiter = "; ");
};
@@ -949,35 +582,37 @@ bool SourcePrinter::cacheSource(const DILineInfo &LineInfo) {
Buffer = std::move(*BufferOrError);
}
// Chomp the file to get lines
- size_t BufferSize = Buffer->getBufferSize();
- const char *BufferStart = Buffer->getBufferStart();
- for (const char *Start = BufferStart, *End = BufferStart;
- End < BufferStart + BufferSize; End++)
- if (*End == '\n' || End == BufferStart + BufferSize - 1 ||
- (*End == '\r' && *(End + 1) == '\n')) {
- LineCache[LineInfo.FileName].push_back(StringRef(Start, End - Start));
- if (*End == '\r')
- End++;
- Start = End + 1;
+ const char *BufferStart = Buffer->getBufferStart(),
+ *BufferEnd = Buffer->getBufferEnd();
+ std::vector<StringRef> &Lines = LineCache[LineInfo.FileName];
+ const char *Start = BufferStart;
+ for (const char *I = BufferStart; I != BufferEnd; ++I)
+ if (*I == '\n') {
+ Lines.emplace_back(Start, I - Start - (BufferStart < I && I[-1] == '\r'));
+ Start = I + 1;
}
+ if (Start < BufferEnd)
+ Lines.emplace_back(Start, BufferEnd - Start);
SourceCache[LineInfo.FileName] = std::move(Buffer);
return true;
}
-void SourcePrinter::printSourceLine(raw_ostream &OS, uint64_t Address,
+void SourcePrinter::printSourceLine(raw_ostream &OS,
+ object::SectionedAddress Address,
StringRef Delimiter) {
if (!Symbolizer)
return;
+
DILineInfo LineInfo = DILineInfo();
- auto ExpectecLineInfo =
- Symbolizer->symbolizeCode(Obj->getFileName(), Address);
- if (!ExpectecLineInfo)
- consumeError(ExpectecLineInfo.takeError());
+ auto ExpectedLineInfo = Symbolizer->symbolizeCode(*Obj, Address);
+ if (!ExpectedLineInfo)
+ consumeError(ExpectedLineInfo.takeError());
else
- LineInfo = *ExpectecLineInfo;
+ LineInfo = *ExpectedLineInfo;
- if ((LineInfo.FileName == "<invalid>") || OldLineInfo.Line == LineInfo.Line ||
- LineInfo.Line == 0)
+ if ((LineInfo.FileName == "<invalid>") || LineInfo.Line == 0 ||
+ ((OldLineInfo.Line == LineInfo.Line) &&
+ (OldLineInfo.FileName == LineInfo.FileName)))
return;
if (PrintLines)
@@ -986,53 +621,79 @@ void SourcePrinter::printSourceLine(raw_ostream &OS, uint64_t Address,
if (SourceCache.find(LineInfo.FileName) == SourceCache.end())
if (!cacheSource(LineInfo))
return;
- auto FileBuffer = SourceCache.find(LineInfo.FileName);
- if (FileBuffer != SourceCache.end()) {
- auto LineBuffer = LineCache.find(LineInfo.FileName);
- if (LineBuffer != LineCache.end()) {
- if (LineInfo.Line > LineBuffer->second.size())
- return;
- // Vector begins at 0, line numbers are non-zero
- OS << Delimiter << LineBuffer->second[LineInfo.Line - 1].ltrim()
- << "\n";
- }
+ auto LineBuffer = LineCache.find(LineInfo.FileName);
+ if (LineBuffer != LineCache.end()) {
+ if (LineInfo.Line > LineBuffer->second.size())
+ return;
+ // Vector begins at 0, line numbers are non-zero
+ OS << Delimiter << LineBuffer->second[LineInfo.Line - 1] << '\n';
}
}
OldLineInfo = LineInfo;
}
+static bool isAArch64Elf(const ObjectFile *Obj) {
+ const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj);
+ return Elf && Elf->getEMachine() == ELF::EM_AARCH64;
+}
+
static bool isArmElf(const ObjectFile *Obj) {
- return (Obj->isELF() &&
- (Obj->getArch() == Triple::aarch64 ||
- Obj->getArch() == Triple::aarch64_be ||
- Obj->getArch() == Triple::arm || Obj->getArch() == Triple::armeb ||
- Obj->getArch() == Triple::thumb ||
- Obj->getArch() == Triple::thumbeb));
+ const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj);
+ return Elf && Elf->getEMachine() == ELF::EM_ARM;
+}
+
+static bool hasMappingSymbols(const ObjectFile *Obj) {
+ return isArmElf(Obj) || isAArch64Elf(Obj);
+}
+
+static void printRelocation(const RelocationRef &Rel, uint64_t Address,
+ bool Is64Bits) {
+ StringRef Fmt = Is64Bits ? "\t\t%016" PRIx64 ": " : "\t\t\t%08" PRIx64 ": ";
+ SmallString<16> Name;
+ SmallString<32> Val;
+ Rel.getTypeName(Name);
+ error(getRelocationValueString(Rel, Val));
+ outs() << format(Fmt.data(), Address) << Name << "\t" << Val << "\n";
}
class PrettyPrinter {
public:
virtual ~PrettyPrinter() = default;
virtual void printInst(MCInstPrinter &IP, const MCInst *MI,
- ArrayRef<uint8_t> Bytes, uint64_t Address,
- raw_ostream &OS, StringRef Annot,
- MCSubtargetInfo const &STI, SourcePrinter *SP,
+ ArrayRef<uint8_t> Bytes,
+ object::SectionedAddress Address, raw_ostream &OS,
+ StringRef Annot, MCSubtargetInfo const &STI,
+ SourcePrinter *SP,
std::vector<RelocationRef> *Rels = nullptr) {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address);
- if (!NoLeadingAddr)
- OS << format("%8" PRIx64 ":", Address);
- if (!NoShowRawInsn) {
- OS << "\t";
- dumpBytes(Bytes, OS);
+
+ {
+ formatted_raw_ostream FOS(OS);
+ if (!NoLeadingAddr)
+ FOS << format("%8" PRIx64 ":", Address.Address);
+ if (!NoShowRawInsn) {
+ FOS << ' ';
+ dumpBytes(Bytes, FOS);
+ }
+ FOS.flush();
+ // The output of printInst starts with a tab. Print some spaces so that
+ // the tab has 1 column and advances to the target tab stop.
+ unsigned TabStop = NoShowRawInsn ? 16 : 40;
+ unsigned Column = FOS.getColumn();
+ FOS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8);
+
+ // The dtor calls flush() to ensure the indent comes before printInst().
}
+
if (MI)
IP.printInst(MI, OS, "", STI);
else
- OS << " <unknown>";
+ OS << "\t<unknown>";
}
};
PrettyPrinter PrettyPrinterInst;
+
class HexagonPrettyPrinter : public PrettyPrinter {
public:
void printLead(ArrayRef<uint8_t> Bytes, uint64_t Address,
@@ -1044,17 +705,17 @@ public:
if (!NoShowRawInsn) {
OS << "\t";
dumpBytes(Bytes.slice(0, 4), OS);
- OS << format("%08" PRIx32, opcode);
+ OS << format("\t%08" PRIx32, opcode);
}
}
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
- uint64_t Address, raw_ostream &OS, StringRef Annot,
- MCSubtargetInfo const &STI, SourcePrinter *SP,
+ object::SectionedAddress Address, raw_ostream &OS,
+ StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
std::vector<RelocationRef> *Rels) override {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address, "");
if (!MI) {
- printLead(Bytes, Address, OS);
+ printLead(Bytes, Address.Address, OS);
OS << " <unknown>";
return;
}
@@ -1070,21 +731,15 @@ public:
auto HeadTail = PacketBundle.first.split('\n');
auto Preamble = " { ";
auto Separator = "";
- StringRef Fmt = "\t\t\t%08" PRIx64 ": ";
- std::vector<RelocationRef>::const_iterator RelCur = Rels->begin();
- std::vector<RelocationRef>::const_iterator RelEnd = Rels->end();
// Hexagon's packets require relocations to be inline rather than
// clustered at the end of the packet.
+ std::vector<RelocationRef>::const_iterator RelCur = Rels->begin();
+ std::vector<RelocationRef>::const_iterator RelEnd = Rels->end();
auto PrintReloc = [&]() -> void {
- while ((RelCur != RelEnd) && (RelCur->getOffset() <= Address)) {
- if (RelCur->getOffset() == Address) {
- SmallString<16> Name;
- SmallString<32> Val;
- RelCur->getTypeName(Name);
- error(getRelocationValueString(*RelCur, Val));
- OS << Separator << format(Fmt.data(), Address) << Name << "\t" << Val
- << "\n";
+ while ((RelCur != RelEnd) && (RelCur->getOffset() <= Address.Address)) {
+ if (RelCur->getOffset() == Address.Address) {
+ printRelocation(*RelCur, Address.Address, false);
return;
}
++RelCur;
@@ -1096,7 +751,7 @@ public:
Separator = "\n";
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address, "");
- printLead(Bytes, Address, OS);
+ printLead(Bytes, Address.Address, OS);
OS << Preamble;
Preamble = " ";
StringRef Inst;
@@ -1114,7 +769,7 @@ public:
OS << " } " << PacketBundle.second;
PrintReloc();
Bytes = Bytes.slice(4);
- Address += 4;
+ Address.Address += 4;
}
}
};
@@ -1123,14 +778,12 @@ HexagonPrettyPrinter HexagonPrettyPrinterInst;
class AMDGCNPrettyPrinter : public PrettyPrinter {
public:
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
- uint64_t Address, raw_ostream &OS, StringRef Annot,
- MCSubtargetInfo const &STI, SourcePrinter *SP,
+ object::SectionedAddress Address, raw_ostream &OS,
+ StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
std::vector<RelocationRef> *Rels) override {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address);
- typedef support::ulittle32_t U32;
-
if (MI) {
SmallString<40> InstStr;
raw_svector_ostream IS(InstStr);
@@ -1144,7 +797,7 @@ public:
// remaining
if (Bytes.size() >= 4) {
OS << format("\t.long 0x%08" PRIx32 " ",
- static_cast<uint32_t>(*reinterpret_cast<const U32*>(Bytes.data())));
+ support::endian::read32<support::little>(Bytes.data()));
OS.indent(42);
} else {
OS << format("\t.byte 0x%02" PRIx8, Bytes[0]);
@@ -1154,20 +807,21 @@ public:
}
}
- OS << format("// %012" PRIX64 ": ", Address);
- if (Bytes.size() >=4) {
- for (auto D : makeArrayRef(reinterpret_cast<const U32*>(Bytes.data()),
- Bytes.size() / sizeof(U32)))
- // D should be explicitly casted to uint32_t here as it is passed
- // by format to snprintf as vararg.
- OS << format("%08" PRIX32 " ", static_cast<uint32_t>(D));
+ OS << format("// %012" PRIX64 ":", Address.Address);
+ if (Bytes.size() >= 4) {
+ // D should be casted to uint32_t here as it is passed by format to
+ // snprintf as vararg.
+ for (uint32_t D : makeArrayRef(
+ reinterpret_cast<const support::little32_t *>(Bytes.data()),
+ Bytes.size() / 4))
+ OS << format(" %08" PRIX32, D);
} else {
- for (unsigned int i = 0; i < Bytes.size(); i++)
- OS << format("%02" PRIX8 " ", Bytes[i]);
+ for (unsigned char B : Bytes)
+ OS << format(" %02" PRIX8, B);
}
if (!Annot.empty())
- OS << "// " << Annot;
+ OS << " // " << Annot;
}
};
AMDGCNPrettyPrinter AMDGCNPrettyPrinterInst;
@@ -1175,13 +829,13 @@ AMDGCNPrettyPrinter AMDGCNPrettyPrinterInst;
class BPFPrettyPrinter : public PrettyPrinter {
public:
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
- uint64_t Address, raw_ostream &OS, StringRef Annot,
- MCSubtargetInfo const &STI, SourcePrinter *SP,
+ object::SectionedAddress Address, raw_ostream &OS,
+ StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
std::vector<RelocationRef> *Rels) override {
if (SP && (PrintSource || PrintLines))
SP->printSourceLine(OS, Address);
if (!NoLeadingAddr)
- OS << format("%8" PRId64 ":", Address / 8);
+ OS << format("%8" PRId64 ":", Address.Address / 8);
if (!NoShowRawInsn) {
OS << "\t";
dumpBytes(Bytes, OS);
@@ -1189,7 +843,7 @@ public:
if (MI)
IP.printInst(MI, OS, "", STI);
else
- OS << " <unknown>";
+ OS << "\t<unknown>";
}
};
BPFPrettyPrinter BPFPrettyPrinterInst;
@@ -1227,27 +881,25 @@ addDynamicElfSymbols(const ELFObjectFile<ELFT> *Obj,
std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
for (auto Symbol : Obj->getDynamicSymbolIterators()) {
uint8_t SymbolType = Symbol.getELFType();
- if (SymbolType != ELF::STT_FUNC || Symbol.getSize() == 0)
+ if (SymbolType == ELF::STT_SECTION)
continue;
- Expected<uint64_t> AddressOrErr = Symbol.getAddress();
- if (!AddressOrErr)
- report_error(Obj->getFileName(), AddressOrErr.takeError());
+ uint64_t Address = unwrapOrError(Symbol.getAddress(), Obj->getFileName());
+ // ELFSymbolRef::getAddress() returns size instead of value for common
+ // symbols which is not desirable for disassembly output. Overriding.
+ if (SymbolType == ELF::STT_COMMON)
+ Address = Obj->getSymbol(Symbol.getRawDataRefImpl())->st_value;
- Expected<StringRef> Name = Symbol.getName();
- if (!Name)
- report_error(Obj->getFileName(), Name.takeError());
- if (Name->empty())
+ StringRef Name = unwrapOrError(Symbol.getName(), Obj->getFileName());
+ if (Name.empty())
continue;
- Expected<section_iterator> SectionOrErr = Symbol.getSection();
- if (!SectionOrErr)
- report_error(Obj->getFileName(), SectionOrErr.takeError());
- section_iterator SecI = *SectionOrErr;
+ section_iterator SecI =
+ unwrapOrError(Symbol.getSection(), Obj->getFileName());
if (SecI == Obj->section_end())
continue;
- AllSymbols[*SecI].emplace_back(*AddressOrErr, *Name, SymbolType);
+ AllSymbols[*SecI].emplace_back(Address, Name, SymbolType);
}
}
@@ -1285,14 +937,10 @@ static void addPltEntries(const ObjectFile *Obj,
SymbolRef Symbol(PltEntry.first, ElfObj);
uint8_t SymbolType = getElfSymbolType(Obj, Symbol);
- Expected<StringRef> NameOrErr = Symbol.getName();
- if (!NameOrErr)
- report_error(Obj->getFileName(), NameOrErr.takeError());
- if (NameOrErr->empty())
- continue;
- StringRef Name = Saver.save((*NameOrErr + "@plt").str());
-
- AllSymbols[*Plt].emplace_back(PltEntry.second, Name, SymbolType);
+ StringRef Name = unwrapOrError(Symbol.getName(), Obj->getFileName());
+ if (!Name.empty())
+ AllSymbols[*Plt].emplace_back(
+ PltEntry.second, Saver.save((Name + "@plt").str()), SymbolType);
}
}
}
@@ -1301,10 +949,6 @@ static void addPltEntries(const ObjectFile *Obj,
// returns the number of zero bytes that can be skipped when dumping the
// disassembly of the instructions in Buf.
static size_t countSkippableZeroBytes(ArrayRef<uint8_t> Buf) {
- // When -z or --disassemble-zeroes are given we always dissasemble them.
- if (DisassembleZeroes)
- return 0;
-
// Find the number of leading zeroes.
size_t N = 0;
while (N < Buf.size() && !Buf[N])
@@ -1320,108 +964,160 @@ static size_t countSkippableZeroBytes(ArrayRef<uint8_t> Buf) {
return N & ~0x3;
}
-static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
- if (StartAddress > StopAddress)
- error("Start address should be less than stop address");
-
- const Target *TheTarget = getTarget(Obj);
-
- // Package up features to be passed to target/subtarget
- SubtargetFeatures Features = Obj->getFeatures();
- if (!MAttrs.empty())
- for (unsigned I = 0; I != MAttrs.size(); ++I)
- Features.AddFeature(MAttrs[I]);
-
- std::unique_ptr<const MCRegisterInfo> MRI(
- TheTarget->createMCRegInfo(TripleName));
- if (!MRI)
- report_error(Obj->getFileName(), "no register info for target " +
- TripleName);
-
- // Set up disassembler.
- std::unique_ptr<const MCAsmInfo> AsmInfo(
- TheTarget->createMCAsmInfo(*MRI, TripleName));
- if (!AsmInfo)
- report_error(Obj->getFileName(), "no assembly info for target " +
- TripleName);
- std::unique_ptr<const MCSubtargetInfo> STI(
- TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString()));
- if (!STI)
- report_error(Obj->getFileName(), "no subtarget info for target " +
- TripleName);
- std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
- if (!MII)
- report_error(Obj->getFileName(), "no instruction info for target " +
- TripleName);
- MCObjectFileInfo MOFI;
- MCContext Ctx(AsmInfo.get(), MRI.get(), &MOFI);
- // FIXME: for now initialize MCObjectFileInfo with default values
- MOFI.InitMCObjectFileInfo(Triple(TripleName), false, Ctx);
-
- std::unique_ptr<MCDisassembler> DisAsm(
- TheTarget->createMCDisassembler(*STI, Ctx));
- if (!DisAsm)
- report_error(Obj->getFileName(), "no disassembler for target " +
- TripleName);
+// Returns a map from sections to their relocations.
+static std::map<SectionRef, std::vector<RelocationRef>>
+getRelocsMap(object::ObjectFile const &Obj) {
+ std::map<SectionRef, std::vector<RelocationRef>> Ret;
+ for (SectionRef Sec : Obj.sections()) {
+ section_iterator Relocated = Sec.getRelocatedSection();
+ if (Relocated == Obj.section_end() || !shouldKeep(*Relocated))
+ continue;
+ std::vector<RelocationRef> &V = Ret[*Relocated];
+ for (const RelocationRef &R : Sec.relocations())
+ V.push_back(R);
+ // Sort relocations by address.
+ llvm::stable_sort(V, isRelocAddressLess);
+ }
+ return Ret;
+}
- std::unique_ptr<const MCInstrAnalysis> MIA(
- TheTarget->createMCInstrAnalysis(MII.get()));
+// Used for --adjust-vma to check if address should be adjusted by the
+// specified value for a given section.
+// For ELF we do not adjust non-allocatable sections like debug ones,
+// because they are not loadable.
+// TODO: implement for other file formats.
+static bool shouldAdjustVA(const SectionRef &Section) {
+ const ObjectFile *Obj = Section.getObject();
+ if (isa<object::ELFObjectFileBase>(Obj))
+ return ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC;
+ return false;
+}
- int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
- std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
- Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI));
- if (!IP)
- report_error(Obj->getFileName(), "no instruction printer for target " +
- TripleName);
- IP->setPrintImmHex(PrintImmHex);
- PrettyPrinter &PIP = selectPrettyPrinter(Triple(TripleName));
- StringRef Fmt = Obj->getBytesInAddress() > 4 ? "\t\t%016" PRIx64 ": " :
- "\t\t\t%08" PRIx64 ": ";
+typedef std::pair<uint64_t, char> MappingSymbolPair;
+static char getMappingSymbolKind(ArrayRef<MappingSymbolPair> MappingSymbols,
+ uint64_t Address) {
+ auto It =
+ partition_point(MappingSymbols, [Address](const MappingSymbolPair &Val) {
+ return Val.first <= Address;
+ });
+ // Return zero for any address before the first mapping symbol; this means
+ // we should use the default disassembly mode, depending on the target.
+ if (It == MappingSymbols.begin())
+ return '\x00';
+ return (It - 1)->second;
+}
- SourcePrinter SP(Obj, TheTarget->getName());
+static uint64_t
+dumpARMELFData(uint64_t SectionAddr, uint64_t Index, uint64_t End,
+ const ObjectFile *Obj, ArrayRef<uint8_t> Bytes,
+ ArrayRef<MappingSymbolPair> MappingSymbols) {
+ support::endianness Endian =
+ Obj->isLittleEndian() ? support::little : support::big;
+ while (Index < End) {
+ outs() << format("%8" PRIx64 ":", SectionAddr + Index);
+ outs() << "\t";
+ if (Index + 4 <= End) {
+ dumpBytes(Bytes.slice(Index, 4), outs());
+ outs() << "\t.word\t"
+ << format_hex(
+ support::endian::read32(Bytes.data() + Index, Endian), 10);
+ Index += 4;
+ } else if (Index + 2 <= End) {
+ dumpBytes(Bytes.slice(Index, 2), outs());
+ outs() << "\t\t.short\t"
+ << format_hex(
+ support::endian::read16(Bytes.data() + Index, Endian), 6);
+ Index += 2;
+ } else {
+ dumpBytes(Bytes.slice(Index, 1), outs());
+ outs() << "\t\t.byte\t" << format_hex(Bytes[0], 4);
+ ++Index;
+ }
+ outs() << "\n";
+ if (getMappingSymbolKind(MappingSymbols, Index) != 'd')
+ break;
+ }
+ return Index;
+}
- // Create a mapping, RelocSecs = SectionRelocMap[S], where sections
- // in RelocSecs contain the relocations for section S.
- std::error_code EC;
- std::map<SectionRef, SmallVector<SectionRef, 1>> SectionRelocMap;
- for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
- section_iterator Sec2 = Section.getRelocatedSection();
- if (Sec2 != Obj->section_end())
- SectionRelocMap[*Sec2].push_back(Section);
+static void dumpELFData(uint64_t SectionAddr, uint64_t Index, uint64_t End,
+ ArrayRef<uint8_t> Bytes) {
+ // print out data up to 8 bytes at a time in hex and ascii
+ uint8_t AsciiData[9] = {'\0'};
+ uint8_t Byte;
+ int NumBytes = 0;
+
+ for (; Index < End; ++Index) {
+ if (NumBytes == 0)
+ outs() << format("%8" PRIx64 ":", SectionAddr + Index);
+ Byte = Bytes.slice(Index)[0];
+ outs() << format(" %02x", Byte);
+ AsciiData[NumBytes] = isPrint(Byte) ? Byte : '.';
+
+ uint8_t IndentOffset = 0;
+ NumBytes++;
+ if (Index == End - 1 || NumBytes > 8) {
+ // Indent the space for less than 8 bytes data.
+ // 2 spaces for byte and one for space between bytes
+ IndentOffset = 3 * (8 - NumBytes);
+ for (int Excess = NumBytes; Excess < 8; Excess++)
+ AsciiData[Excess] = '\0';
+ NumBytes = 8;
+ }
+ if (NumBytes == 8) {
+ AsciiData[8] = '\0';
+ outs() << std::string(IndentOffset, ' ') << " ";
+ outs() << reinterpret_cast<char *>(AsciiData);
+ outs() << '\n';
+ NumBytes = 0;
+ }
}
+}
+
+static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
+ MCContext &Ctx, MCDisassembler *PrimaryDisAsm,
+ MCDisassembler *SecondaryDisAsm,
+ const MCInstrAnalysis *MIA, MCInstPrinter *IP,
+ const MCSubtargetInfo *PrimarySTI,
+ const MCSubtargetInfo *SecondarySTI,
+ PrettyPrinter &PIP,
+ SourcePrinter &SP, bool InlineRelocs) {
+ const MCSubtargetInfo *STI = PrimarySTI;
+ MCDisassembler *DisAsm = PrimaryDisAsm;
+ bool PrimaryIsThumb = false;
+ if (isArmElf(Obj))
+ PrimaryIsThumb = STI->checkFeatures("+thumb-mode");
+
+ std::map<SectionRef, std::vector<RelocationRef>> RelocMap;
+ if (InlineRelocs)
+ RelocMap = getRelocsMap(*Obj);
+ bool Is64Bits = Obj->getBytesInAddress() > 4;
// Create a mapping from virtual address to symbol name. This is used to
// pretty print the symbols while disassembling.
std::map<SectionRef, SectionSymbolsTy> AllSymbols;
SectionSymbolsTy AbsoluteSymbols;
+ const StringRef FileName = Obj->getFileName();
for (const SymbolRef &Symbol : Obj->symbols()) {
- Expected<uint64_t> AddressOrErr = Symbol.getAddress();
- if (!AddressOrErr)
- report_error(Obj->getFileName(), AddressOrErr.takeError());
- uint64_t Address = *AddressOrErr;
-
- Expected<StringRef> Name = Symbol.getName();
- if (!Name)
- report_error(Obj->getFileName(), Name.takeError());
- if (Name->empty())
- continue;
+ uint64_t Address = unwrapOrError(Symbol.getAddress(), FileName);
- Expected<section_iterator> SectionOrErr = Symbol.getSection();
- if (!SectionOrErr)
- report_error(Obj->getFileName(), SectionOrErr.takeError());
+ StringRef Name = unwrapOrError(Symbol.getName(), FileName);
+ if (Name.empty())
+ continue;
uint8_t SymbolType = ELF::STT_NOTYPE;
- if (Obj->isELF())
+ if (Obj->isELF()) {
SymbolType = getElfSymbolType(Obj, Symbol);
+ if (SymbolType == ELF::STT_SECTION)
+ continue;
+ }
- section_iterator SecI = *SectionOrErr;
+ section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName);
if (SecI != Obj->section_end())
- AllSymbols[*SecI].emplace_back(Address, *Name, SymbolType);
+ AllSymbols[*SecI].emplace_back(Address, Name, SymbolType);
else
- AbsoluteSymbols.emplace_back(Address, *Name, SymbolType);
-
-
+ AbsoluteSymbols.emplace_back(Address, Name, SymbolType);
}
if (AllSymbols.empty() && Obj->isELF())
addDynamicElfSymbols(Obj, AllSymbols);
@@ -1448,31 +1144,28 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
error(ExportEntry.getExportRVA(RVA));
uint64_t VA = COFFObj->getImageBase() + RVA;
- auto Sec = std::upper_bound(
- SectionAddresses.begin(), SectionAddresses.end(), VA,
- [](uint64_t LHS, const std::pair<uint64_t, SectionRef> &RHS) {
- return LHS < RHS.first;
+ auto Sec = partition_point(
+ SectionAddresses, [VA](const std::pair<uint64_t, SectionRef> &O) {
+ return O.first <= VA;
});
- if (Sec != SectionAddresses.begin())
+ if (Sec != SectionAddresses.begin()) {
--Sec;
- else
- Sec = SectionAddresses.end();
-
- if (Sec != SectionAddresses.end())
AllSymbols[Sec->second].emplace_back(VA, Name, ELF::STT_NOTYPE);
- else
+ } else
AbsoluteSymbols.emplace_back(VA, Name, ELF::STT_NOTYPE);
}
}
// Sort all the symbols, this allows us to use a simple binary search to find
// a symbol near an address.
+ StringSet<> FoundDisasmFuncsSet;
for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols)
array_pod_sort(SecSyms.second.begin(), SecSyms.second.end());
array_pod_sort(AbsoluteSymbols.begin(), AbsoluteSymbols.end());
for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
- if (!DisassembleAll && (!Section.isText() || Section.isVirtual()))
+ if (FilterSections.empty() && !DisassembleAll &&
+ (!Section.isText() || Section.isVirtual()))
continue;
uint64_t SectionAddr = Section.getAddress();
@@ -1482,25 +1175,23 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
// Get the list of all the symbols in this section.
SectionSymbolsTy &Symbols = AllSymbols[Section];
- std::vector<uint64_t> DataMappingSymsAddr;
- std::vector<uint64_t> TextMappingSymsAddr;
- if (isArmElf(Obj)) {
+ std::vector<MappingSymbolPair> MappingSymbols;
+ if (hasMappingSymbols(Obj)) {
for (const auto &Symb : Symbols) {
uint64_t Address = std::get<0>(Symb);
StringRef Name = std::get<1>(Symb);
if (Name.startswith("$d"))
- DataMappingSymsAddr.push_back(Address - SectionAddr);
+ MappingSymbols.emplace_back(Address - SectionAddr, 'd');
if (Name.startswith("$x"))
- TextMappingSymsAddr.push_back(Address - SectionAddr);
+ MappingSymbols.emplace_back(Address - SectionAddr, 'x');
if (Name.startswith("$a"))
- TextMappingSymsAddr.push_back(Address - SectionAddr);
+ MappingSymbols.emplace_back(Address - SectionAddr, 'a');
if (Name.startswith("$t"))
- TextMappingSymsAddr.push_back(Address - SectionAddr);
+ MappingSymbols.emplace_back(Address - SectionAddr, 't');
}
}
- llvm::sort(DataMappingSymsAddr);
- llvm::sort(TextMappingSymsAddr);
+ llvm::sort(MappingSymbols);
if (Obj->isELF() && Obj->getArch() == Triple::amdgcn) {
// AMDGPU disassembler uses symbolizer for printing labels
@@ -1514,19 +1205,6 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
}
}
- // Make a list of all the relocations for this section.
- std::vector<RelocationRef> Rels;
- if (InlineRelocs) {
- for (const SectionRef &RelocSec : SectionRelocMap[Section]) {
- for (const RelocationRef &Reloc : RelocSec.relocations()) {
- Rels.push_back(Reloc);
- }
- }
- }
-
- // Sort relocations by address.
- llvm::sort(Rels, isRelocAddressLess);
-
StringRef SegmentName = "";
if (const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj)) {
DataRefImpl DR = Section.getRawDataRefImpl();
@@ -1546,56 +1224,54 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
SmallString<40> Comments;
raw_svector_ostream CommentStream(Comments);
- StringRef BytesStr;
- error(Section.getContents(BytesStr));
- ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(BytesStr.data()),
- BytesStr.size());
+ ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(
+ unwrapOrError(Section.getContents(), Obj->getFileName()));
+
+ uint64_t VMAAdjustment = 0;
+ if (shouldAdjustVA(Section))
+ VMAAdjustment = AdjustVMA;
uint64_t Size;
uint64_t Index;
bool PrintedSection = false;
-
+ std::vector<RelocationRef> Rels = RelocMap[Section];
std::vector<RelocationRef>::const_iterator RelCur = Rels.begin();
std::vector<RelocationRef>::const_iterator RelEnd = Rels.end();
// Disassemble symbol by symbol.
for (unsigned SI = 0, SE = Symbols.size(); SI != SE; ++SI) {
- uint64_t Start = std::get<0>(Symbols[SI]) - SectionAddr;
- // The end is either the section end or the beginning of the next
- // symbol.
- uint64_t End = (SI == SE - 1)
- ? SectSize
- : std::get<0>(Symbols[SI + 1]) - SectionAddr;
- // Don't try to disassemble beyond the end of section contents.
- if (End > SectSize)
- End = SectSize;
- // If this symbol has the same address as the next symbol, then skip it.
- if (Start >= End)
- continue;
+ std::string SymbolName = std::get<1>(Symbols[SI]).str();
+ if (Demangle)
+ SymbolName = demangle(SymbolName);
- // Check if we need to skip symbol
- // Skip if the symbol's data is not between StartAddress and StopAddress
- if (End + SectionAddr < StartAddress ||
- Start + SectionAddr > StopAddress) {
+ // Skip if --disassemble-functions is not empty and the symbol is not in
+ // the list.
+ if (!DisasmFuncsSet.empty() && !DisasmFuncsSet.count(SymbolName))
continue;
- }
- /// Skip if user requested specific symbols and this is not in the list
- if (!DisasmFuncsSet.empty() &&
- !DisasmFuncsSet.count(std::get<1>(Symbols[SI])))
+ uint64_t Start = std::get<0>(Symbols[SI]);
+ if (Start < SectionAddr || StopAddress <= Start)
+ continue;
+ else
+ FoundDisasmFuncsSet.insert(SymbolName);
+
+ // The end is the section end, the beginning of the next symbol, or
+ // --stop-address.
+ uint64_t End = std::min<uint64_t>(SectionAddr + SectSize, StopAddress);
+ if (SI + 1 < SE)
+ End = std::min(End, std::get<0>(Symbols[SI + 1]));
+ if (Start >= End || End <= StartAddress)
continue;
+ Start -= SectionAddr;
+ End -= SectionAddr;
if (!PrintedSection) {
PrintedSection = true;
- outs() << "Disassembly of section ";
+ outs() << "\nDisassembly of section ";
if (!SegmentName.empty())
outs() << SegmentName << ",";
- outs() << SectionName << ':';
+ outs() << SectionName << ":\n";
}
- // Stop disassembly at the stop address specified
- if (End + SectionAddr > StopAddress)
- End = StopAddress - SectionAddr;
-
if (Obj->isELF() && Obj->getArch() == Triple::amdgcn) {
if (std::get<2>(Symbols[SI]) == ELF::STT_AMDGPU_HSA_KERNEL) {
// skip amd_kernel_code_t at the begining of kernel symbol (256 bytes)
@@ -1615,13 +1291,10 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
outs() << '\n';
if (!NoLeadingAddr)
- outs() << format("%016" PRIx64 " ", SectionAddr + Start);
+ outs() << format(Is64Bits ? "%016" PRIx64 " " : "%08" PRIx64 " ",
+ SectionAddr + Start + VMAAdjustment);
- StringRef SymbolName = std::get<1>(Symbols[SI]);
- if (Demangle)
- outs() << demangle(SymbolName) << ":\n";
- else
- outs() << SymbolName << ":\n";
+ outs() << SymbolName << ":\n";
// Don't print raw contents of a virtual section. A virtual section
// doesn't have any contents in the file.
@@ -1636,143 +1309,82 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
raw_ostream &DebugOut = nulls();
#endif
- for (Index = Start; Index < End; Index += Size) {
- MCInst Inst;
+ // Some targets (like WebAssembly) have a special prelude at the start
+ // of each symbol.
+ DisAsm->onSymbolStart(SymbolName, Size, Bytes.slice(Start, End - Start),
+ SectionAddr + Start, DebugOut, CommentStream);
+ Start += Size;
+
+ Index = Start;
+ if (SectionAddr < StartAddress)
+ Index = std::max<uint64_t>(Index, StartAddress - SectionAddr);
+
+ // If there is a data/common symbol inside an ELF text section and we are
+ // only disassembling text (applicable all architectures), we are in a
+ // situation where we must print the data and not disassemble it.
+ if (Obj->isELF() && !DisassembleAll && Section.isText()) {
+ uint8_t SymTy = std::get<2>(Symbols[SI]);
+ if (SymTy == ELF::STT_OBJECT || SymTy == ELF::STT_COMMON) {
+ dumpELFData(SectionAddr, Index, End, Bytes);
+ Index = End;
+ }
+ }
- if (Index + SectionAddr < StartAddress ||
- Index + SectionAddr > StopAddress) {
- // skip byte by byte till StartAddress is reached
- Size = 1;
+ bool CheckARMELFData = hasMappingSymbols(Obj) &&
+ std::get<2>(Symbols[SI]) != ELF::STT_OBJECT &&
+ !DisassembleAll;
+ while (Index < End) {
+ // ARM and AArch64 ELF binaries can interleave data and text in the
+ // same section. We rely on the markers introduced to understand what
+ // we need to dump. If the data marker is within a function, it is
+ // denoted as a word/short etc.
+ if (CheckARMELFData &&
+ getMappingSymbolKind(MappingSymbols, Index) == 'd') {
+ Index = dumpARMELFData(SectionAddr, Index, End, Obj, Bytes,
+ MappingSymbols);
continue;
}
- // AArch64 ELF binaries can interleave data and text in the
- // same section. We rely on the markers introduced to
- // understand what we need to dump. If the data marker is within a
- // function, it is denoted as a word/short etc
- if (isArmElf(Obj) && std::get<2>(Symbols[SI]) != ELF::STT_OBJECT &&
- !DisassembleAll) {
- uint64_t Stride = 0;
-
- auto DAI = std::lower_bound(DataMappingSymsAddr.begin(),
- DataMappingSymsAddr.end(), Index);
- if (DAI != DataMappingSymsAddr.end() && *DAI == Index) {
- // Switch to data.
- while (Index < End) {
- outs() << format("%8" PRIx64 ":", SectionAddr + Index);
- outs() << "\t";
- if (Index + 4 <= End) {
- Stride = 4;
- dumpBytes(Bytes.slice(Index, 4), outs());
- outs() << "\t.word\t";
- uint32_t Data = 0;
- if (Obj->isLittleEndian()) {
- const auto Word =
- reinterpret_cast<const support::ulittle32_t *>(
- Bytes.data() + Index);
- Data = *Word;
- } else {
- const auto Word = reinterpret_cast<const support::ubig32_t *>(
- Bytes.data() + Index);
- Data = *Word;
- }
- outs() << "0x" << format("%08" PRIx32, Data);
- } else if (Index + 2 <= End) {
- Stride = 2;
- dumpBytes(Bytes.slice(Index, 2), outs());
- outs() << "\t\t.short\t";
- uint16_t Data = 0;
- if (Obj->isLittleEndian()) {
- const auto Short =
- reinterpret_cast<const support::ulittle16_t *>(
- Bytes.data() + Index);
- Data = *Short;
- } else {
- const auto Short =
- reinterpret_cast<const support::ubig16_t *>(Bytes.data() +
- Index);
- Data = *Short;
- }
- outs() << "0x" << format("%04" PRIx16, Data);
- } else {
- Stride = 1;
- dumpBytes(Bytes.slice(Index, 1), outs());
- outs() << "\t\t.byte\t";
- outs() << "0x" << format("%02" PRIx8, Bytes.slice(Index, 1)[0]);
- }
- Index += Stride;
- outs() << "\n";
- auto TAI = std::lower_bound(TextMappingSymsAddr.begin(),
- TextMappingSymsAddr.end(), Index);
- if (TAI != TextMappingSymsAddr.end() && *TAI == Index)
- break;
- }
+
+ // When -z or --disassemble-zeroes are given we always dissasemble
+ // them. Otherwise we might want to skip zero bytes we see.
+ if (!DisassembleZeroes) {
+ uint64_t MaxOffset = End - Index;
+ // For -reloc: print zero blocks patched by relocations, so that
+ // relocations can be shown in the dump.
+ if (RelCur != RelEnd)
+ MaxOffset = RelCur->getOffset() - Index;
+
+ if (size_t N =
+ countSkippableZeroBytes(Bytes.slice(Index, MaxOffset))) {
+ outs() << "\t\t..." << '\n';
+ Index += N;
+ continue;
}
}
- // If there is a data symbol inside an ELF text section and we are only
- // disassembling text (applicable all architectures),
- // we are in a situation where we must print the data and not
- // disassemble it.
- if (Obj->isELF() && std::get<2>(Symbols[SI]) == ELF::STT_OBJECT &&
- !DisassembleAll && Section.isText()) {
- // print out data up to 8 bytes at a time in hex and ascii
- uint8_t AsciiData[9] = {'\0'};
- uint8_t Byte;
- int NumBytes = 0;
-
- for (Index = Start; Index < End; Index += 1) {
- if (((SectionAddr + Index) < StartAddress) ||
- ((SectionAddr + Index) > StopAddress))
- continue;
- if (NumBytes == 0) {
- outs() << format("%8" PRIx64 ":", SectionAddr + Index);
- outs() << "\t";
- }
- Byte = Bytes.slice(Index)[0];
- outs() << format(" %02x", Byte);
- AsciiData[NumBytes] = isPrint(Byte) ? Byte : '.';
-
- uint8_t IndentOffset = 0;
- NumBytes++;
- if (Index == End - 1 || NumBytes > 8) {
- // Indent the space for less than 8 bytes data.
- // 2 spaces for byte and one for space between bytes
- IndentOffset = 3 * (8 - NumBytes);
- for (int Excess = 8 - NumBytes; Excess < 8; Excess++)
- AsciiData[Excess] = '\0';
- NumBytes = 8;
- }
- if (NumBytes == 8) {
- AsciiData[8] = '\0';
- outs() << std::string(IndentOffset, ' ') << " ";
- outs() << reinterpret_cast<char *>(AsciiData);
- outs() << '\n';
- NumBytes = 0;
- }
+ if (SecondarySTI) {
+ if (getMappingSymbolKind(MappingSymbols, Index) == 'a') {
+ STI = PrimaryIsThumb ? SecondarySTI : PrimarySTI;
+ DisAsm = PrimaryIsThumb ? SecondaryDisAsm : PrimaryDisAsm;
+ } else if (getMappingSymbolKind(MappingSymbols, Index) == 't') {
+ STI = PrimaryIsThumb ? PrimarySTI : SecondarySTI;
+ DisAsm = PrimaryIsThumb ? PrimaryDisAsm : SecondaryDisAsm;
}
}
- if (Index >= End)
- break;
-
- if (size_t N =
- countSkippableZeroBytes(Bytes.slice(Index, End - Index))) {
- outs() << "\t\t..." << '\n';
- Index += N;
- if (Index >= End)
- break;
- }
// Disassemble a real instruction or a data when disassemble all is
// provided
- bool Disassembled = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
- SectionAddr + Index, DebugOut,
- CommentStream);
+ MCInst Inst;
+ bool Disassembled = DisAsm->getInstruction(
+ Inst, Size, Bytes.slice(Index), SectionAddr + Index, DebugOut,
+ CommentStream);
if (Size == 0)
Size = 1;
- PIP.printInst(*IP, Disassembled ? &Inst : nullptr,
- Bytes.slice(Index, Size), SectionAddr + Index, outs(), "",
- *STI, &SP, &Rels);
+ PIP.printInst(
+ *IP, Disassembled ? &Inst : nullptr, Bytes.slice(Index, Size),
+ {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, outs(),
+ "", *STI, &SP, &Rels);
outs() << CommentStream.str();
Comments.clear();
@@ -1791,37 +1403,34 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
// N.B. We don't walk the relocations in the relocatable case yet.
auto *TargetSectionSymbols = &Symbols;
if (!Obj->isRelocatableObject()) {
- auto SectionAddress = std::upper_bound(
- SectionAddresses.begin(), SectionAddresses.end(), Target,
- [](uint64_t LHS,
- const std::pair<uint64_t, SectionRef> &RHS) {
- return LHS < RHS.first;
+ auto It = partition_point(
+ SectionAddresses,
+ [=](const std::pair<uint64_t, SectionRef> &O) {
+ return O.first <= Target;
});
- if (SectionAddress != SectionAddresses.begin()) {
- --SectionAddress;
- TargetSectionSymbols = &AllSymbols[SectionAddress->second];
+ if (It != SectionAddresses.begin()) {
+ --It;
+ TargetSectionSymbols = &AllSymbols[It->second];
} else {
TargetSectionSymbols = &AbsoluteSymbols;
}
}
- // Find the first symbol in the section whose offset is less than
+ // Find the last symbol in the section whose offset is less than
// or equal to the target. If there isn't a section that contains
// the target, find the nearest preceding absolute symbol.
- auto TargetSym = std::upper_bound(
- TargetSectionSymbols->begin(), TargetSectionSymbols->end(),
- Target, [](uint64_t LHS,
- const std::tuple<uint64_t, StringRef, uint8_t> &RHS) {
- return LHS < std::get<0>(RHS);
+ auto TargetSym = partition_point(
+ *TargetSectionSymbols,
+ [=](const std::tuple<uint64_t, StringRef, uint8_t> &O) {
+ return std::get<0>(O) <= Target;
});
if (TargetSym == TargetSectionSymbols->begin()) {
TargetSectionSymbols = &AbsoluteSymbols;
- TargetSym = std::upper_bound(
- AbsoluteSymbols.begin(), AbsoluteSymbols.end(),
- Target, [](uint64_t LHS,
- const std::tuple<uint64_t, StringRef, uint8_t> &RHS) {
- return LHS < std::get<0>(RHS);
- });
+ TargetSym = partition_point(
+ AbsoluteSymbols,
+ [=](const std::tuple<uint64_t, StringRef, uint8_t> &O) {
+ return std::get<0>(O) <= Target;
+ });
}
if (TargetSym != TargetSectionSymbols->begin()) {
--TargetSym;
@@ -1838,34 +1447,125 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
outs() << "\n";
// Hexagon does this in pretty printer
- if (Obj->getArch() != Triple::hexagon)
+ if (Obj->getArch() != Triple::hexagon) {
// Print relocation for instruction.
while (RelCur != RelEnd) {
- uint64_t Addr = RelCur->getOffset();
- SmallString<16> Name;
- SmallString<32> Val;
-
+ uint64_t Offset = RelCur->getOffset();
// If this relocation is hidden, skip it.
- if (getHidden(*RelCur) || ((SectionAddr + Addr) < StartAddress)) {
+ if (getHidden(*RelCur) || SectionAddr + Offset < StartAddress) {
++RelCur;
continue;
}
- // Stop when rel_cur's address is past the current instruction.
- if (Addr >= Index + Size)
+ // Stop when RelCur's offset is past the current instruction.
+ if (Offset >= Index + Size)
break;
- RelCur->getTypeName(Name);
- error(getRelocationValueString(*RelCur, Val));
- outs() << format(Fmt.data(), SectionAddr + Addr) << Name << "\t"
- << Val << "\n";
+
+ // When --adjust-vma is used, update the address printed.
+ if (RelCur->getSymbol() != Obj->symbol_end()) {
+ Expected<section_iterator> SymSI =
+ RelCur->getSymbol()->getSection();
+ if (SymSI && *SymSI != Obj->section_end() &&
+ shouldAdjustVA(**SymSI))
+ Offset += AdjustVMA;
+ }
+
+ printRelocation(*RelCur, SectionAddr + Offset, Is64Bits);
++RelCur;
}
+ }
+
+ Index += Size;
}
}
}
+ StringSet<> MissingDisasmFuncsSet =
+ set_difference(DisasmFuncsSet, FoundDisasmFuncsSet);
+ for (StringRef MissingDisasmFunc : MissingDisasmFuncsSet.keys())
+ warn("failed to disassemble missing function " + MissingDisasmFunc);
+}
+
+static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
+ const Target *TheTarget = getTarget(Obj);
+
+ // Package up features to be passed to target/subtarget
+ SubtargetFeatures Features = Obj->getFeatures();
+ if (!MAttrs.empty())
+ for (unsigned I = 0; I != MAttrs.size(); ++I)
+ Features.AddFeature(MAttrs[I]);
+
+ std::unique_ptr<const MCRegisterInfo> MRI(
+ TheTarget->createMCRegInfo(TripleName));
+ if (!MRI)
+ report_error(Obj->getFileName(),
+ "no register info for target " + TripleName);
+
+ // Set up disassembler.
+ std::unique_ptr<const MCAsmInfo> AsmInfo(
+ TheTarget->createMCAsmInfo(*MRI, TripleName));
+ if (!AsmInfo)
+ report_error(Obj->getFileName(),
+ "no assembly info for target " + TripleName);
+ std::unique_ptr<const MCSubtargetInfo> STI(
+ TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString()));
+ if (!STI)
+ report_error(Obj->getFileName(),
+ "no subtarget info for target " + TripleName);
+ std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
+ if (!MII)
+ report_error(Obj->getFileName(),
+ "no instruction info for target " + TripleName);
+ MCObjectFileInfo MOFI;
+ MCContext Ctx(AsmInfo.get(), MRI.get(), &MOFI);
+ // FIXME: for now initialize MCObjectFileInfo with default values
+ MOFI.InitMCObjectFileInfo(Triple(TripleName), false, Ctx);
+
+ std::unique_ptr<MCDisassembler> DisAsm(
+ TheTarget->createMCDisassembler(*STI, Ctx));
+ if (!DisAsm)
+ report_error(Obj->getFileName(),
+ "no disassembler for target " + TripleName);
+
+ // If we have an ARM object file, we need a second disassembler, because
+ // ARM CPUs have two different instruction sets: ARM mode, and Thumb mode.
+ // We use mapping symbols to switch between the two assemblers, where
+ // appropriate.
+ std::unique_ptr<MCDisassembler> SecondaryDisAsm;
+ std::unique_ptr<const MCSubtargetInfo> SecondarySTI;
+ if (isArmElf(Obj) && !STI->checkFeatures("+mclass")) {
+ if (STI->checkFeatures("+thumb-mode"))
+ Features.AddFeature("-thumb-mode");
+ else
+ Features.AddFeature("+thumb-mode");
+ SecondarySTI.reset(TheTarget->createMCSubtargetInfo(TripleName, MCPU,
+ Features.getString()));
+ SecondaryDisAsm.reset(TheTarget->createMCDisassembler(*SecondarySTI, Ctx));
+ }
+
+ std::unique_ptr<const MCInstrAnalysis> MIA(
+ TheTarget->createMCInstrAnalysis(MII.get()));
+
+ int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
+ std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
+ Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI));
+ if (!IP)
+ report_error(Obj->getFileName(),
+ "no instruction printer for target " + TripleName);
+ IP->setPrintImmHex(PrintImmHex);
+
+ PrettyPrinter &PIP = selectPrettyPrinter(Triple(TripleName));
+ SourcePrinter SP(Obj, TheTarget->getName());
+
+ for (StringRef Opt : DisassemblerOptions)
+ if (!IP->applyTargetSpecificCLOption(Opt))
+ error("Unrecognized disassembler option: " + Opt);
+
+ disassembleObject(TheTarget, Obj, Ctx, DisAsm.get(), SecondaryDisAsm.get(),
+ MIA.get(), IP.get(), STI.get(), SecondarySTI.get(), PIP,
+ SP, InlineRelocs);
}
-void llvm::printRelocations(const ObjectFile *Obj) {
+void printRelocations(const ObjectFile *Obj) {
StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 :
"%08" PRIx64;
// Regular objdump doesn't print relocations in non-relocatable object
@@ -1873,28 +1573,40 @@ void llvm::printRelocations(const ObjectFile *Obj) {
if (!Obj->isRelocatableObject())
return;
+ // Build a mapping from relocation target to a vector of relocation
+ // sections. Usually, there is an only one relocation section for
+ // each relocated section.
+ MapVector<SectionRef, std::vector<SectionRef>> SecToRelSec;
for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
if (Section.relocation_begin() == Section.relocation_end())
continue;
+ const SectionRef TargetSec = *Section.getRelocatedSection();
+ SecToRelSec[TargetSec].push_back(Section);
+ }
+
+ for (std::pair<SectionRef, std::vector<SectionRef>> &P : SecToRelSec) {
StringRef SecName;
- error(Section.getName(SecName));
+ error(P.first.getName(SecName));
outs() << "RELOCATION RECORDS FOR [" << SecName << "]:\n";
- for (const RelocationRef &Reloc : Section.relocations()) {
- uint64_t Address = Reloc.getOffset();
- SmallString<32> RelocName;
- SmallString<32> ValueStr;
- if (Address < StartAddress || Address > StopAddress || getHidden(Reloc))
- continue;
- Reloc.getTypeName(RelocName);
- error(getRelocationValueString(Reloc, ValueStr));
- outs() << format(Fmt.data(), Address) << " " << RelocName << " "
- << ValueStr << "\n";
+
+ for (SectionRef Section : P.second) {
+ for (const RelocationRef &Reloc : Section.relocations()) {
+ uint64_t Address = Reloc.getOffset();
+ SmallString<32> RelocName;
+ SmallString<32> ValueStr;
+ if (Address < StartAddress || Address > StopAddress || getHidden(Reloc))
+ continue;
+ Reloc.getTypeName(RelocName);
+ error(getRelocationValueString(Reloc, ValueStr));
+ outs() << format(Fmt.data(), Address) << " " << RelocName << " "
+ << ValueStr << "\n";
+ }
}
outs() << "\n";
}
}
-void llvm::printDynamicRelocations(const ObjectFile *Obj) {
+void printDynamicRelocations(const ObjectFile *Obj) {
// For the moment, this option is for ELF only
if (!Obj->isELF())
return;
@@ -1911,9 +1623,7 @@ void llvm::printDynamicRelocations(const ObjectFile *Obj) {
outs() << "DYNAMIC RELOCATION RECORDS\n";
StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64;
- for (const SectionRef &Section : DynRelSec) {
- if (Section.relocation_begin() == Section.relocation_end())
- continue;
+ for (const SectionRef &Section : DynRelSec)
for (const RelocationRef &Reloc : Section.relocations()) {
uint64_t Address = Reloc.getOffset();
SmallString<32> RelocName;
@@ -1923,34 +1633,60 @@ void llvm::printDynamicRelocations(const ObjectFile *Obj) {
outs() << format(Fmt.data(), Address) << " " << RelocName << " "
<< ValueStr << "\n";
}
- }
}
-void llvm::printSectionHeaders(const ObjectFile *Obj) {
- outs() << "Sections:\n"
- "Idx Name Size Address Type\n";
+// Returns true if we need to show LMA column when dumping section headers. We
+// show it only when the platform is ELF and either we have at least one section
+// whose VMA and LMA are different and/or when --show-lma flag is used.
+static bool shouldDisplayLMA(const ObjectFile *Obj) {
+ if (!Obj->isELF())
+ return false;
+ for (const SectionRef &S : ToolSectionFilter(*Obj))
+ if (S.getAddress() != getELFSectionLMA(S))
+ return true;
+ return ShowLMA;
+}
+
+void printSectionHeaders(const ObjectFile *Obj) {
+ bool HasLMAColumn = shouldDisplayLMA(Obj);
+ if (HasLMAColumn)
+ outs() << "Sections:\n"
+ "Idx Name Size VMA LMA "
+ "Type\n";
+ else
+ outs() << "Sections:\n"
+ "Idx Name Size VMA Type\n";
+
for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
StringRef Name;
error(Section.getName(Name));
- uint64_t Address = Section.getAddress();
+ uint64_t VMA = Section.getAddress();
+ if (shouldAdjustVA(Section))
+ VMA += AdjustVMA;
+
uint64_t Size = Section.getSize();
bool Text = Section.isText();
bool Data = Section.isData();
bool BSS = Section.isBSS();
std::string Type = (std::string(Text ? "TEXT " : "") +
(Data ? "DATA " : "") + (BSS ? "BSS" : ""));
- outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %s\n",
- (unsigned)Section.getIndex(), Name.str().c_str(), Size,
- Address, Type.c_str());
+
+ if (HasLMAColumn)
+ outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %016" PRIx64
+ " %s\n",
+ (unsigned)Section.getIndex(), Name.str().c_str(), Size,
+ VMA, getELFSectionLMA(Section), Type.c_str());
+ else
+ outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %s\n",
+ (unsigned)Section.getIndex(), Name.str().c_str(), Size,
+ VMA, Type.c_str());
}
outs() << "\n";
}
-void llvm::printSectionContents(const ObjectFile *Obj) {
- std::error_code EC;
+void printSectionContents(const ObjectFile *Obj) {
for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
StringRef Name;
- StringRef Contents;
error(Section.getName(Name));
uint64_t BaseAddr = Section.getAddress();
uint64_t Size = Section.getSize();
@@ -1965,7 +1701,7 @@ void llvm::printSectionContents(const ObjectFile *Obj) {
continue;
}
- error(Section.getContents(Contents));
+ StringRef Contents = unwrapOrError(Section.getContents(), Obj->getFileName());
// Dump out the content as hex and printable ascii characters.
for (std::size_t Addr = 0, End = Contents.size(); Addr < End; Addr += 16) {
@@ -1993,8 +1729,8 @@ void llvm::printSectionContents(const ObjectFile *Obj) {
}
}
-void llvm::printSymbolTable(const ObjectFile *O, StringRef ArchiveName,
- StringRef ArchitectureName) {
+void printSymbolTable(const ObjectFile *O, StringRef ArchiveName,
+ StringRef ArchitectureName) {
outs() << "SYMBOL TABLE:\n";
if (const COFFObjectFile *Coff = dyn_cast<const COFFObjectFile>(O)) {
@@ -2002,41 +1738,24 @@ void llvm::printSymbolTable(const ObjectFile *O, StringRef ArchiveName,
return;
}
+ const StringRef FileName = O->getFileName();
for (auto I = O->symbol_begin(), E = O->symbol_end(); I != E; ++I) {
- // Skip printing the special zero symbol when dumping an ELF file.
- // This makes the output consistent with the GNU objdump.
- if (I == O->symbol_begin() && isa<ELFObjectFileBase>(O))
- continue;
-
const SymbolRef &Symbol = *I;
- Expected<uint64_t> AddressOrError = Symbol.getAddress();
- if (!AddressOrError)
- report_error(ArchiveName, O->getFileName(), AddressOrError.takeError(),
- ArchitectureName);
- uint64_t Address = *AddressOrError;
+ uint64_t Address = unwrapOrError(Symbol.getAddress(), ArchiveName, FileName,
+ ArchitectureName);
if ((Address < StartAddress) || (Address > StopAddress))
continue;
- Expected<SymbolRef::Type> TypeOrError = Symbol.getType();
- if (!TypeOrError)
- report_error(ArchiveName, O->getFileName(), TypeOrError.takeError(),
- ArchitectureName);
- SymbolRef::Type Type = *TypeOrError;
+ SymbolRef::Type Type = unwrapOrError(Symbol.getType(), ArchiveName,
+ FileName, ArchitectureName);
uint32_t Flags = Symbol.getFlags();
- Expected<section_iterator> SectionOrErr = Symbol.getSection();
- if (!SectionOrErr)
- report_error(ArchiveName, O->getFileName(), SectionOrErr.takeError(),
- ArchitectureName);
- section_iterator Section = *SectionOrErr;
+ section_iterator Section = unwrapOrError(Symbol.getSection(), ArchiveName,
+ FileName, ArchitectureName);
StringRef Name;
- if (Type == SymbolRef::ST_Debug && Section != O->section_end()) {
+ if (Type == SymbolRef::ST_Debug && Section != O->section_end())
Section->getName(Name);
- } else {
- Expected<StringRef> NameOrErr = Symbol.getName();
- if (!NameOrErr)
- report_error(ArchiveName, O->getFileName(), NameOrErr.takeError(),
- ArchitectureName);
- Name = *NameOrErr;
- }
+ else
+ Name = unwrapOrError(Symbol.getName(), ArchiveName, FileName,
+ ArchitectureName);
bool Global = Flags & SymbolRef::SF_Global;
bool Weak = Flags & SymbolRef::SF_Weak;
@@ -2136,59 +1855,9 @@ static void printUnwindInfo(const ObjectFile *O) {
"for COFF and MachO object files.\n";
}
-void llvm::printExportsTrie(const ObjectFile *o) {
- outs() << "Exports trie:\n";
- if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
- printMachOExportsTrie(MachO);
- else
- WithColor::error(errs(), ToolName)
- << "This operation is only currently supported "
- "for Mach-O executable files.\n";
-}
-
-void llvm::printRebaseTable(ObjectFile *o) {
- outs() << "Rebase table:\n";
- if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
- printMachORebaseTable(MachO);
- else
- WithColor::error(errs(), ToolName)
- << "This operation is only currently supported "
- "for Mach-O executable files.\n";
-}
-
-void llvm::printBindTable(ObjectFile *o) {
- outs() << "Bind table:\n";
- if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
- printMachOBindTable(MachO);
- else
- WithColor::error(errs(), ToolName)
- << "This operation is only currently supported "
- "for Mach-O executable files.\n";
-}
-
-void llvm::printLazyBindTable(ObjectFile *o) {
- outs() << "Lazy bind table:\n";
- if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
- printMachOLazyBindTable(MachO);
- else
- WithColor::error(errs(), ToolName)
- << "This operation is only currently supported "
- "for Mach-O executable files.\n";
-}
-
-void llvm::printWeakBindTable(ObjectFile *o) {
- outs() << "Weak bind table:\n";
- if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
- printMachOWeakBindTable(MachO);
- else
- WithColor::error(errs(), ToolName)
- << "This operation is only currently supported "
- "for Mach-O executable files.\n";
-}
-
/// Dump the raw contents of the __clangast section so the output can be piped
/// into llvm-bcanalyzer.
-void llvm::printRawClangAST(const ObjectFile *Obj) {
+void printRawClangAST(const ObjectFile *Obj) {
if (outs().is_displayed()) {
WithColor::error(errs(), ToolName)
<< "The -raw-clang-ast option will dump the raw binary contents of "
@@ -2215,8 +1884,8 @@ void llvm::printRawClangAST(const ObjectFile *Obj) {
if (!ClangASTSection)
return;
- StringRef ClangASTContents;
- error(ClangASTSection.getValue().getContents(ClangASTContents));
+ StringRef ClangASTContents = unwrapOrError(
+ ClangASTSection.getValue().getContents(), Obj->getFileName());
outs().write(ClangASTContents.data(), ClangASTContents.size());
}
@@ -2252,9 +1921,8 @@ static void printFaultMaps(const ObjectFile *Obj) {
return;
}
- StringRef FaultMapContents;
- error(FaultMapSection.getValue().getContents(FaultMapContents));
-
+ StringRef FaultMapContents =
+ unwrapOrError(FaultMapSection.getValue().getContents(), Obj->getFileName());
FaultMapParser FMP(FaultMapContents.bytes_begin(),
FaultMapContents.bytes_end());
@@ -2264,7 +1932,9 @@ static void printFaultMaps(const ObjectFile *Obj) {
static void printPrivateFileHeaders(const ObjectFile *O, bool OnlyFirst) {
if (O->isELF()) {
printELFFileHeader(O);
- return printELFDynamicSection(O);
+ printELFDynamicSection(O);
+ printELFSymbolVersionInfo(O);
+ return;
}
if (O->isCOFF())
return printCOFFFileHeader(O);
@@ -2285,12 +1955,9 @@ static void printFileHeaders(const ObjectFile *O) {
Triple::ArchType AT = O->getArch();
outs() << "architecture: " << Triple::getArchTypeName(AT) << "\n";
- Expected<uint64_t> StartAddrOrErr = O->getStartAddress();
- if (!StartAddrOrErr)
- report_error(O->getFileName(), StartAddrOrErr.takeError());
+ uint64_t Address = unwrapOrError(O->getStartAddress(), O->getFileName());
StringRef Fmt = O->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64;
- uint64_t Address = StartAddrOrErr.get();
outs() << "start address: "
<< "0x" << format(Fmt.data(), Address) << "\n\n";
}
@@ -2315,22 +1982,9 @@ static void printArchiveChild(StringRef Filename, const Archive::Child &C) {
outs() << " ";
- Expected<unsigned> UIDOrErr = C.getUID();
- if (!UIDOrErr)
- report_error(Filename, UIDOrErr.takeError());
- unsigned UID = UIDOrErr.get();
- outs() << format("%d/", UID);
-
- Expected<unsigned> GIDOrErr = C.getGID();
- if (!GIDOrErr)
- report_error(Filename, GIDOrErr.takeError());
- unsigned GID = GIDOrErr.get();
- outs() << format("%-d ", GID);
-
- Expected<uint64_t> Size = C.getRawSize();
- if (!Size)
- report_error(Filename, Size.takeError());
- outs() << format("%6" PRId64, Size.get()) << " ";
+ outs() << format("%d/%d %6" PRId64 " ", unwrapOrError(C.getUID(), Filename),
+ unwrapOrError(C.getGID(), Filename),
+ unwrapOrError(C.getRawSize(), Filename));
StringRef RawLastModified = C.getRawLastModified();
unsigned Seconds;
@@ -2349,10 +2003,7 @@ static void printArchiveChild(StringRef Filename, const Archive::Child &C) {
Expected<StringRef> NameOrErr = C.getName();
if (!NameOrErr) {
consumeError(NameOrErr.takeError());
- Expected<StringRef> RawNameOrErr = C.getRawName();
- if (!RawNameOrErr)
- report_error(Filename, NameOrErr.takeError());
- Name = RawNameOrErr.get();
+ Name = unwrapOrError(C.getRawName(), Filename);
} else {
Name = NameOrErr.get();
}
@@ -2404,7 +2055,7 @@ static void dumpObject(ObjectFile *O, const Archive *A = nullptr,
printWeakBindTable(O);
if (RawClangAST)
printRawClangAST(O);
- if (PrintFaultMaps)
+ if (FaultMapSection)
printFaultMaps(O);
if (DwarfDumpType != DIDT_Null) {
std::unique_ptr<DIContext> DICtx = DWARFContext::create(*O);
@@ -2439,7 +2090,7 @@ static void dumpArchive(const Archive *A) {
Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
if (!ChildOrErr) {
if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
- report_error(A->getFileName(), C, std::move(E));
+ report_error(std::move(E), A->getFileName(), C);
continue;
}
if (ObjectFile *O = dyn_cast<ObjectFile>(&*ChildOrErr.get()))
@@ -2447,10 +2098,11 @@ static void dumpArchive(const Archive *A) {
else if (COFFImportFile *I = dyn_cast<COFFImportFile>(&*ChildOrErr.get()))
dumpObject(I, A, &C);
else
- report_error(A->getFileName(), object_error::invalid_file_type);
+ report_error(errorCodeToError(object_error::invalid_file_type),
+ A->getFileName());
}
if (Err)
- report_error(A->getFileName(), std::move(Err));
+ report_error(std::move(Err), A->getFileName());
}
/// Open file and figure out how to dump it.
@@ -2464,10 +2116,8 @@ static void dumpInput(StringRef file) {
}
// Attempt to open the binary.
- Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
- if (!BinaryOrErr)
- report_error(file, BinaryOrErr.takeError());
- Binary &Binary = *BinaryOrErr.get().getBinary();
+ OwningBinary<Binary> OBinary = unwrapOrError(createBinary(file), file);
+ Binary &Binary = *OBinary.getBinary();
if (Archive *A = dyn_cast<Archive>(&Binary))
dumpArchive(A);
@@ -2476,22 +2126,29 @@ static void dumpInput(StringRef file) {
else if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Binary))
parseInputMachO(UB);
else
- report_error(file, object_error::invalid_file_type);
+ report_error(errorCodeToError(object_error::invalid_file_type), file);
}
+} // namespace llvm
int main(int argc, char **argv) {
+ using namespace llvm;
InitLLVM X(argc, argv);
+ const cl::OptionCategory *OptionFilters[] = {&ObjdumpCat, &MachOCat};
+ cl::HideUnrelatedOptions(OptionFilters);
// Initialize targets and assembly printers/parsers.
- llvm::InitializeAllTargetInfos();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllDisassemblers();
+ InitializeAllTargetInfos();
+ InitializeAllTargetMCs();
+ InitializeAllDisassemblers();
// Register the target printer for --version.
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
cl::ParseCommandLineOptions(argc, argv, "llvm object file dumper\n");
+ if (StartAddress >= StopAddress)
+ error("start address should be less than stop address");
+
ToolName = argv[0];
// Defaults to a.out if no filenames specified.
@@ -2499,40 +2156,22 @@ int main(int argc, char **argv) {
InputFilenames.push_back("a.out");
if (AllHeaders)
- FileHeaders = PrivateHeaders = Relocations = SectionHeaders = SymbolTable =
- true;
+ ArchiveHeaders = FileHeaders = PrivateHeaders = Relocations =
+ SectionHeaders = SymbolTable = true;
- if (DisassembleAll || PrintSource || PrintLines)
+ if (DisassembleAll || PrintSource || PrintLines ||
+ (!DisassembleFunctions.empty()))
Disassemble = true;
- if (!Disassemble
- && !Relocations
- && !DynamicRelocations
- && !SectionHeaders
- && !SectionContents
- && !SymbolTable
- && !UnwindInfo
- && !PrivateHeaders
- && !FileHeaders
- && !FirstPrivateHeader
- && !ExportsTrie
- && !Rebase
- && !Bind
- && !LazyBind
- && !WeakBind
- && !RawClangAST
- && !(UniversalHeaders && MachOOpt)
- && !ArchiveHeaders
- && !(IndirectSymbols && MachOOpt)
- && !(DataInCode && MachOOpt)
- && !(LinkOptHints && MachOOpt)
- && !(InfoPlist && MachOOpt)
- && !(DylibsUsed && MachOOpt)
- && !(DylibId && MachOOpt)
- && !(ObjcMetaData && MachOOpt)
- && !(!FilterSections.empty() && MachOOpt)
- && !PrintFaultMaps
- && DwarfDumpType == DIDT_Null) {
+ if (!ArchiveHeaders && !Disassemble && DwarfDumpType == DIDT_Null &&
+ !DynamicRelocations && !FileHeaders && !PrivateHeaders && !RawClangAST &&
+ !Relocations && !SectionHeaders && !SectionContents && !SymbolTable &&
+ !UnwindInfo && !FaultMapSection &&
+ !(MachOOpt &&
+ (Bind || DataInCode || DylibId || DylibsUsed || ExportsTrie ||
+ FirstPrivateHeader || IndirectSymbols || InfoPlist || LazyBind ||
+ LinkOptHints || ObjcMetaData || Rebase || UniversalHeaders ||
+ WeakBind || !FilterSections.empty()))) {
cl::PrintHelpMessage();
return 2;
}
@@ -2542,5 +2181,7 @@ int main(int argc, char **argv) {
llvm::for_each(InputFilenames, dumpInput);
+ warnOnNoMatchForSections();
+
return EXIT_SUCCESS;
}
diff --git a/contrib/llvm/tools/llvm-objdump/llvm-objdump.h b/contrib/llvm/tools/llvm-objdump/llvm-objdump.h
index fe2cb05fe227..e58d4a05c2e6 100644
--- a/contrib/llvm/tools/llvm-objdump/llvm-objdump.h
+++ b/contrib/llvm/tools/llvm-objdump/llvm-objdump.h
@@ -1,8 +1,7 @@
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -19,57 +18,86 @@ namespace llvm {
class StringRef;
namespace object {
- class COFFObjectFile;
- class COFFImportFile;
- class MachOObjectFile;
- class MachOUniversalBinary;
- class ObjectFile;
- class Archive;
- class RelocationRef;
+class COFFObjectFile;
+class COFFImportFile;
+class ELFObjectFileBase;
+class ELFSectionRef;
+class MachOObjectFile;
+class MachOUniversalBinary;
+class RelocationRef;
}
-extern cl::opt<std::string> TripleName;
-extern cl::opt<std::string> ArchName;
-extern cl::opt<std::string> MCPU;
-extern cl::list<std::string> MAttrs;
-extern cl::list<std::string> FilterSections;
-extern cl::opt<bool> AllHeaders;
extern cl::opt<bool> Demangle;
-extern cl::opt<bool> Disassemble;
-extern cl::opt<bool> DisassembleAll;
-extern cl::opt<bool> NoShowRawInsn;
-extern cl::opt<bool> NoLeadingAddr;
-extern cl::opt<bool> PrivateHeaders;
-extern cl::opt<bool> FileHeaders;
-extern cl::opt<bool> FirstPrivateHeader;
-extern cl::opt<bool> ExportsTrie;
-extern cl::opt<bool> Rebase;
-extern cl::opt<bool> Bind;
-extern cl::opt<bool> LazyBind;
-extern cl::opt<bool> WeakBind;
-extern cl::opt<bool> RawClangAST;
-extern cl::opt<bool> UniversalHeaders;
-extern cl::opt<bool> ArchiveHeaders;
-extern cl::opt<bool> IndirectSymbols;
-extern cl::opt<bool> DataInCode;
-extern cl::opt<bool> LinkOptHints;
-extern cl::opt<bool> InfoPlist;
-extern cl::opt<bool> DylibsUsed;
-extern cl::opt<bool> DylibId;
-extern cl::opt<bool> ObjcMetaData;
-extern cl::opt<std::string> DisSymName;
-extern cl::opt<bool> NonVerbose;
-extern cl::opt<bool> Relocations;
-extern cl::opt<bool> DynamicRelocations;
-extern cl::opt<bool> SectionHeaders;
-extern cl::opt<bool> SectionContents;
-extern cl::opt<bool> SymbolTable;
-extern cl::opt<bool> UnwindInfo;
-extern cl::opt<bool> PrintImmHex;
-extern cl::opt<DIDumpType> DwarfDumpType;
+
+typedef std::function<bool(llvm::object::SectionRef const &)> FilterPredicate;
+
+class SectionFilterIterator {
+public:
+ SectionFilterIterator(FilterPredicate P,
+ llvm::object::section_iterator const &I,
+ llvm::object::section_iterator const &E)
+ : Predicate(std::move(P)), Iterator(I), End(E) {
+ ScanPredicate();
+ }
+ const llvm::object::SectionRef &operator*() const { return *Iterator; }
+ SectionFilterIterator &operator++() {
+ ++Iterator;
+ ScanPredicate();
+ return *this;
+ }
+ bool operator!=(SectionFilterIterator const &Other) const {
+ return Iterator != Other.Iterator;
+ }
+
+private:
+ void ScanPredicate() {
+ while (Iterator != End && !Predicate(*Iterator)) {
+ ++Iterator;
+ }
+ }
+ FilterPredicate Predicate;
+ llvm::object::section_iterator Iterator;
+ llvm::object::section_iterator End;
+};
+
+class SectionFilter {
+public:
+ SectionFilter(FilterPredicate P, llvm::object::ObjectFile const &O)
+ : Predicate(std::move(P)), Object(O) {}
+ SectionFilterIterator begin() {
+ return SectionFilterIterator(Predicate, Object.section_begin(),
+ Object.section_end());
+ }
+ SectionFilterIterator end() {
+ return SectionFilterIterator(Predicate, Object.section_end(),
+ Object.section_end());
+ }
+
+private:
+ FilterPredicate Predicate;
+ llvm::object::ObjectFile const &Object;
+};
// Various helper functions.
+SectionFilter ToolSectionFilter(llvm::object::ObjectFile const &O);
+
+Error getELFRelocationValueString(const object::ELFObjectFileBase *Obj,
+ const object::RelocationRef &Rel,
+ llvm::SmallVectorImpl<char> &Result);
+Error getCOFFRelocationValueString(const object::COFFObjectFile *Obj,
+ const object::RelocationRef &Rel,
+ llvm::SmallVectorImpl<char> &Result);
+Error getWasmRelocationValueString(const object::WasmObjectFile *Obj,
+ const object::RelocationRef &RelRef,
+ llvm::SmallVectorImpl<char> &Result);
+Error getMachORelocationValueString(const object::MachOObjectFile *Obj,
+ const object::RelocationRef &RelRef,
+ llvm::SmallVectorImpl<char> &Result);
+
+uint64_t getELFSectionLMA(const object::ELFSectionRef& Sec);
+
void error(std::error_code ec);
+void error(Error E);
bool isRelocAddressLess(object::RelocationRef A, object::RelocationRef B);
void parseInputMachO(StringRef Filename);
void parseInputMachO(object::MachOUniversalBinary *UB);
@@ -82,6 +110,7 @@ void printMachOLazyBindTable(object::MachOObjectFile *O);
void printMachOWeakBindTable(object::MachOObjectFile *O);
void printELFFileHeader(const object::ObjectFile *O);
void printELFDynamicSection(const object::ObjectFile *Obj);
+void printELFSymbolVersionInfo(const object::ObjectFile *Obj);
void printCOFFFileHeader(const object::ObjectFile *O);
void printCOFFSymbolTable(const object::COFFImportFile *I);
void printCOFFSymbolTable(const object::COFFObjectFile *O);
@@ -103,18 +132,20 @@ void printSymbolTable(const object::ObjectFile *O, StringRef ArchiveName,
void warn(StringRef Message);
LLVM_ATTRIBUTE_NORETURN void error(Twine Message);
LLVM_ATTRIBUTE_NORETURN void report_error(StringRef File, Twine Message);
-LLVM_ATTRIBUTE_NORETURN void report_error(StringRef File, std::error_code EC);
-LLVM_ATTRIBUTE_NORETURN void report_error(StringRef File, llvm::Error E);
-LLVM_ATTRIBUTE_NORETURN void report_error(StringRef FileName,
- StringRef ArchiveName,
- llvm::Error E,
- StringRef ArchitectureName
- = StringRef());
-LLVM_ATTRIBUTE_NORETURN void report_error(StringRef ArchiveName,
- const object::Archive::Child &C,
- llvm::Error E,
- StringRef ArchitectureName
- = StringRef());
+LLVM_ATTRIBUTE_NORETURN void report_error(Error E, StringRef File);
+LLVM_ATTRIBUTE_NORETURN void
+report_error(Error E, StringRef FileName, StringRef ArchiveName,
+ StringRef ArchitectureName = StringRef());
+LLVM_ATTRIBUTE_NORETURN void
+report_error(Error E, StringRef ArchiveName, const object::Archive::Child &C,
+ StringRef ArchitectureName = StringRef());
+
+template <typename T, typename... Ts>
+T unwrapOrError(Expected<T> EO, Ts &&... Args) {
+ if (EO)
+ return std::move(*EO);
+ report_error(EO.takeError(), std::forward<Ts>(Args)...);
+}
} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp
index 2b96c8f986aa..162d12c120b4 100644
--- a/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp
@@ -1,9 +1,8 @@
//===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -341,9 +340,7 @@ static void iterateOneModule(PDBFile &File, LinePrinter &P,
if (ModiStream == kInvalidStreamIndex)
return;
- auto ModStreamData = MappedBlockStream::createIndexedStream(
- File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
- File.getAllocator());
+ auto ModStreamData = File.createIndexedStream(ModiStream);
ModuleDebugStreamRef ModStream(Modi, std::move(ModStreamData));
if (auto EC = ModStream.reload()) {
P.formatLine("Could not parse debug information.");
diff --git a/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h
index aa5342998e56..d3aceb47679e 100644
--- a/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h
+++ b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h
@@ -1,9 +1,8 @@
//===- BytesOutputStyle.h ------------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
index e4f6aa7f6ec5..962d4cf88a8a 100644
--- a/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
@@ -1,9 +1,8 @@
//===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -14,6 +13,7 @@
#include "MinimalSymbolDumper.h"
#include "MinimalTypeDumper.h"
#include "StreamUtil.h"
+#include "TypeReferenceTracker.h"
#include "llvm-pdbutil.h"
#include "llvm/ADT/STLExtras.h"
@@ -61,7 +61,12 @@ using namespace llvm::msf;
using namespace llvm::pdb;
DumpOutputStyle::DumpOutputStyle(InputFile &File)
- : File(File), P(2, false, outs()) {}
+ : File(File), P(2, false, outs()) {
+ if (opts::dump::DumpTypeRefStats)
+ RefTracker.reset(new TypeReferenceTracker(File));
+}
+
+DumpOutputStyle::~DumpOutputStyle() {}
PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); }
object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); }
@@ -77,6 +82,10 @@ void DumpOutputStyle::printStreamNotPresent(StringRef StreamName) {
}
Error DumpOutputStyle::dump() {
+ // Walk symbols & globals if we are supposed to mark types referenced.
+ if (opts::dump::DumpTypeRefStats)
+ RefTracker->mark();
+
if (opts::dump::DumpSummary) {
if (auto EC = dumpFileSummary())
return EC;
@@ -101,6 +110,12 @@ Error DumpOutputStyle::dump() {
P.NewLine();
}
+ if (opts::dump::DumpTypeStats) {
+ if (auto EC = dumpTypeStats())
+ return EC;
+ P.NewLine();
+ }
+
if (opts::dump::DumpNamedStreams) {
if (auto EC = dumpNamedStreams())
return EC;
@@ -188,6 +203,11 @@ Error DumpOutputStyle::dump() {
return EC;
}
+ if (opts::dump::DumpTypeRefStats) {
+ if (auto EC = dumpTypeRefStats())
+ return EC;
+ }
+
if (opts::dump::DumpSectionHeaders) {
if (auto EC = dumpSectionHeaders())
return EC;
@@ -203,6 +223,8 @@ Error DumpOutputStyle::dump() {
return EC;
}
+ P.NewLine();
+
return Error::success();
}
@@ -293,18 +315,30 @@ static inline std::string formatModuleDetailKind(SymbolKind K) {
return formatSymbolKind(K);
}
+// Get the stats sorted by size, descending.
+std::vector<StatCollection::KindAndStat>
+StatCollection::getStatsSortedBySize() const {
+ std::vector<KindAndStat> SortedStats(Individual.begin(), Individual.end());
+ llvm::stable_sort(SortedStats,
+ [](const KindAndStat &LHS, const KindAndStat &RHS) {
+ return LHS.second.Size > RHS.second.Size;
+ });
+ return SortedStats;
+}
+
template <typename Kind>
static void printModuleDetailStats(LinePrinter &P, StringRef Label,
const StatCollection &Stats) {
P.NewLine();
P.formatLine(" {0}", Label);
AutoIndent Indent(P);
- P.formatLine("{0,40}: {1,7} entries ({2,8} bytes)", "Total",
+ P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", "Total",
Stats.Totals.Count, Stats.Totals.Size);
P.formatLine("{0}", fmt_repeat('-', 74));
- for (const auto &K : Stats.Individual) {
+
+ for (const auto &K : Stats.getStatsSortedBySize()) {
std::string KindName = formatModuleDetailKind(Kind(K.first));
- P.formatLine("{0,40}: {1,7} entries ({2,8} bytes)", KindName,
+ P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", KindName,
K.second.Count, K.second.Size);
}
}
@@ -662,6 +696,35 @@ Error DumpOutputStyle::dumpSymbolStats() {
return Error::success();
}
+Error DumpOutputStyle::dumpTypeStats() {
+ printHeader(P, "Type Record Stats");
+
+ // Iterate the types, categorize by kind, accumulate size stats.
+ StatCollection TypeStats;
+ LazyRandomTypeCollection &Types = File.types();
+ for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) {
+ CVType Type = Types.getType(*TI);
+ TypeStats.update(uint32_t(Type.kind()), Type.length());
+ }
+
+ P.NewLine();
+ P.formatLine(" Types");
+ AutoIndent Indent(P);
+ P.formatLine("{0,14}: {1,7} entries ({2,12:N} bytes, {3,7} avg)", "Total",
+ TypeStats.Totals.Count, TypeStats.Totals.Size,
+ (double)TypeStats.Totals.Size / TypeStats.Totals.Count);
+ P.formatLine("{0}", fmt_repeat('-', 74));
+
+ for (const auto &K : TypeStats.getStatsSortedBySize()) {
+ P.formatLine("{0,14}: {1,7} entries ({2,12:N} bytes, {3,7} avg)",
+ formatTypeLeafKind(TypeLeafKind(K.first)), K.second.Count,
+ K.second.Size, (double)K.second.Size / K.second.Count);
+ }
+
+
+ return Error::success();
+}
+
static bool isValidNamespaceIdentifier(StringRef S) {
if (S.empty())
return false;
@@ -806,7 +869,7 @@ Error DumpOutputStyle::dumpUdtStats() {
fmt_align(SizeHeader, AlignStyle::Right, SD));
P.formatLine("{0}", fmt_repeat('-', TableWidth));
- for (const auto &Stat : UdtTargetStats.Individual) {
+ for (const auto &Stat : UdtTargetStats.getStatsSortedBySize()) {
StringRef Label = getUdtStatLabel(Stat.first);
P.formatLine("{0} | {1:N} {2:N}",
fmt_align(Label, AlignStyle::Right, FieldWidth),
@@ -819,12 +882,25 @@ Error DumpOutputStyle::dumpUdtStats() {
fmt_align(UdtStats.Totals.Count, AlignStyle::Right, CD),
fmt_align(UdtStats.Totals.Size, AlignStyle::Right, SD));
P.formatLine("{0}", fmt_repeat('-', TableWidth));
- for (const auto &Stat : NamespacedStats) {
- std::string Label = formatv("namespace '{0}'", Stat.getKey());
+ struct StrAndStat {
+ StringRef Key;
+ StatCollection::Stat Stat;
+ };
+
+ // Print namespace stats in descending order of size.
+ std::vector<StrAndStat> NamespacedStatsSorted;
+ for (const auto &Stat : NamespacedStats)
+ NamespacedStatsSorted.push_back({Stat.getKey(), Stat.second});
+ llvm::stable_sort(NamespacedStatsSorted,
+ [](const StrAndStat &L, const StrAndStat &R) {
+ return L.Stat.Size > R.Stat.Size;
+ });
+ for (const auto &Stat : NamespacedStatsSorted) {
+ std::string Label = formatv("namespace '{0}'", Stat.Key);
P.formatLine("{0} | {1:N} {2:N}",
fmt_align(Label, AlignStyle::Right, FieldWidth),
- fmt_align(Stat.second.Count, AlignStyle::Right, CD),
- fmt_align(Stat.second.Size, AlignStyle::Right, SD));
+ fmt_align(Stat.Stat.Count, AlignStyle::Right, CD),
+ fmt_align(Stat.Stat.Size, AlignStyle::Right, SD));
}
return Error::success();
}
@@ -921,6 +997,10 @@ Error DumpOutputStyle::dumpInlineeLines() {
P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
fmtle(Entry.Header->SourceLineNum));
Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
+ for (const auto &ExtraFileID : Entry.ExtraFiles) {
+ P.formatLine(" ");
+ Strings.formatFromChecksumsOffset(P, ExtraFileID, true);
+ }
}
P.NewLine();
});
@@ -1011,17 +1091,12 @@ Error DumpOutputStyle::dumpOldFpo(PDBFile &File) {
ExitOnError Err("Error dumping old fpo data:");
auto &Dbi = Err(File.getPDBDbiStream());
- uint32_t Index = Dbi.getDebugStreamIndex(DbgHeaderType::FPO);
- if (Index == kInvalidStreamIndex) {
+ if (!Dbi.hasOldFpoRecords()) {
printStreamNotPresent("FPO");
return Error::success();
}
- std::unique_ptr<MappedBlockStream> OldFpo = File.createIndexedStream(Index);
- BinaryStreamReader Reader(*OldFpo);
- FixedStreamArray<object::FpoData> Records;
- Err(Reader.readArray(Records,
- Reader.bytesRemaining() / sizeof(object::FpoData)));
+ const FixedStreamArray<object::FpoData>& Records = Dbi.getOldFpoRecords();
P.printLine(" RVA | Code | Locals | Params | Prolog | Saved Regs | Use "
"BP | Has SEH | Frame Type");
@@ -1043,18 +1118,12 @@ Error DumpOutputStyle::dumpNewFpo(PDBFile &File) {
ExitOnError Err("Error dumping new fpo data:");
auto &Dbi = Err(File.getPDBDbiStream());
- uint32_t Index = Dbi.getDebugStreamIndex(DbgHeaderType::NewFPO);
- if (Index == kInvalidStreamIndex) {
+ if (!Dbi.hasNewFpoRecords()) {
printStreamNotPresent("New FPO");
return Error::success();
}
- std::unique_ptr<MappedBlockStream> NewFpo = File.createIndexedStream(Index);
-
- DebugFrameDataSubsectionRef FDS;
- if (auto EC = FDS.initialize(*NewFpo))
- return make_error<RawError>(raw_error_code::corrupt_file,
- "Invalid new fpo stream");
+ const DebugFrameDataSubsectionRef& FDS = Dbi.getNewFpoRecords();
P.printLine(" RVA | Code | Locals | Params | Stack | Prolog | Saved Regs "
"| Has SEH | Has C++EH | Start | Program");
@@ -1239,14 +1308,15 @@ static void buildDepSet(LazyRandomTypeCollection &Types,
static void
dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
- uint32_t NumTypeRecords, uint32_t NumHashBuckets,
+ TypeReferenceTracker *RefTracker, uint32_t NumTypeRecords,
+ uint32_t NumHashBuckets,
FixedStreamArray<support::ulittle32_t> HashValues,
TpiStream *Stream, bool Bytes, bool Extras) {
Printer.formatLine("Showing {0:N} records", NumTypeRecords);
uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords);
- MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
+ MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker,
NumHashBuckets, HashValues, Stream);
if (auto EC = codeview::visitTypeStream(Types, V)) {
@@ -1257,12 +1327,13 @@ dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
static void dumpPartialTypeStream(LinePrinter &Printer,
LazyRandomTypeCollection &Types,
+ TypeReferenceTracker *RefTracker,
TpiStream &Stream, ArrayRef<TypeIndex> TiList,
bool Bytes, bool Extras, bool Deps) {
uint32_t Width =
NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
- MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
+ MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker,
Stream.getNumHashBuckets(), Stream.getHashValues(),
&Stream);
@@ -1311,12 +1382,12 @@ Error DumpOutputStyle::dumpTypesFromObjectFile() {
else
continue;
- StringRef Contents;
- if (auto EC = S.getContents(Contents))
- return errorCodeToError(EC);
+ Expected<StringRef> ContentsOrErr = S.getContents();
+ if (!ContentsOrErr)
+ return ContentsOrErr.takeError();
uint32_t Magic;
- BinaryStreamReader Reader(Contents, llvm::support::little);
+ BinaryStreamReader Reader(*ContentsOrErr, llvm::support::little);
if (auto EC = Reader.readInteger(Magic))
return EC;
if (Magic != COFF::DEBUG_SECTION_MAGIC)
@@ -1326,8 +1397,8 @@ Error DumpOutputStyle::dumpTypesFromObjectFile() {
Types.reset(Reader, 100);
if (opts::dump::DumpTypes) {
- dumpFullTypeStream(P, Types, 0, 0, {}, nullptr, opts::dump::DumpTypeData,
- false);
+ dumpFullTypeStream(P, Types, RefTracker.get(), 0, 0, {}, nullptr,
+ opts::dump::DumpTypeData, false);
} else if (opts::dump::DumpTypeExtras) {
auto LocalHashes = LocallyHashedType::hashTypeCollection(Types);
auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types);
@@ -1396,23 +1467,36 @@ Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids();
+ // Only emit notes about referenced/unreferenced for types.
+ TypeReferenceTracker *MaybeTracker =
+ (StreamIdx == StreamTPI) ? RefTracker.get() : nullptr;
+
// Enable resolving forward decls.
Stream.buildHashMap();
if (DumpTypes || !Indices.empty()) {
if (Indices.empty())
- dumpFullTypeStream(P, Types, Stream.getNumTypeRecords(),
+ dumpFullTypeStream(P, Types, MaybeTracker, Stream.getNumTypeRecords(),
Stream.getNumHashBuckets(), Stream.getHashValues(),
&Stream, DumpBytes, DumpExtras);
else {
std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
- dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
- opts::dump::DumpTypeDependents);
+ dumpPartialTypeStream(P, Types, MaybeTracker, Stream, TiList, DumpBytes,
+ DumpExtras, opts::dump::DumpTypeDependents);
}
}
if (DumpExtras) {
P.NewLine();
+
+ P.formatLine("Header Version: {0}",
+ static_cast<uint32_t>(Stream.getTpiVersion()));
+ P.formatLine("Hash Stream Index: {0}", Stream.getTypeHashStreamIndex());
+ P.formatLine("Aux Hash Stream Index: {0}",
+ Stream.getTypeHashStreamAuxIndex());
+ P.formatLine("Hash Key Size: {0}", Stream.getHashKeySize());
+ P.formatLine("Num Hash Buckets: {0}", Stream.getNumHashBuckets());
+
auto IndexOffsets = Stream.getTypeIndexOffsets();
P.formatLine("Type Index Offsets:");
for (const auto &IO : IndexOffsets) {
@@ -1523,6 +1607,34 @@ Error DumpOutputStyle::dumpModuleSymsForPdb() {
return Error::success();
}
+Error DumpOutputStyle::dumpTypeRefStats() {
+ printHeader(P, "Type Reference Statistics");
+ AutoIndent Indent(P);
+
+ // Sum the byte size of all type records, and the size and count of all
+ // referenced records.
+ size_t TotalRecs = File.types().size();
+ size_t RefRecs = 0;
+ size_t TotalBytes = 0;
+ size_t RefBytes = 0;
+ auto &Types = File.types();
+ for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) {
+ CVType Type = File.types().getType(*TI);
+ TotalBytes += Type.length();
+ if (RefTracker->isTypeReferenced(*TI)) {
+ ++RefRecs;
+ RefBytes += Type.length();
+ }
+ }
+
+ P.formatLine("Records referenced: {0:N} / {1:N} {2:P}", RefRecs, TotalRecs,
+ (double)RefRecs / TotalRecs);
+ P.formatLine("Bytes referenced: {0:N} / {1:N} {2:P}", RefBytes, TotalBytes,
+ (double)RefBytes / TotalBytes);
+
+ return Error::success();
+}
+
Error DumpOutputStyle::dumpGSIRecords() {
printHeader(P, "GSI Records");
diff --git a/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
index 9b3a85587bde..796cd7a10c36 100644
--- a/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
+++ b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h
@@ -1,9 +1,8 @@
//===- DumpOutputStyle.h -------------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -35,6 +34,7 @@ class COFFObjectFile;
namespace pdb {
class GSIHashTable;
class InputFile;
+class TypeReferenceTracker;
struct StatCollection {
struct Stat {
@@ -49,6 +49,8 @@ struct StatCollection {
}
};
+ using KindAndStat = std::pair<uint32_t, Stat>;
+
void update(uint32_t Kind, uint32_t RecordSize) {
Totals.update(RecordSize);
auto Iter = Individual.try_emplace(Kind, 1, RecordSize);
@@ -57,12 +59,15 @@ struct StatCollection {
}
Stat Totals;
DenseMap<uint32_t, Stat> Individual;
+
+ std::vector<KindAndStat> getStatsSortedBySize() const;
};
class DumpOutputStyle : public OutputStyle {
public:
DumpOutputStyle(InputFile &File);
+ ~DumpOutputStyle() override;
Error dump() override;
@@ -77,6 +82,7 @@ private:
Error dumpStreamSummary();
Error dumpSymbolStats();
Error dumpUdtStats();
+ Error dumpTypeStats();
Error dumpNamedStreams();
Error dumpStringTable();
Error dumpStringTableFromPdb();
@@ -90,6 +96,7 @@ private:
Error dumpNewFpo(PDBFile &File);
Error dumpTpiStream(uint32_t StreamIdx);
Error dumpTypesFromObjectFile();
+ Error dumpTypeRefStats();
Error dumpModules();
Error dumpModuleFiles();
Error dumpModuleSymsForPdb();
@@ -105,6 +112,7 @@ private:
void dumpSectionHeaders(StringRef Label, DbgHeaderType Type);
InputFile &File;
+ std::unique_ptr<TypeReferenceTracker> RefTracker;
LinePrinter P;
SmallVector<StreamInfo, 32> StreamPurposes;
};
diff --git a/contrib/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp
index d16bfa480e1d..94faa0463981 100644
--- a/contrib/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp
@@ -1,9 +1,8 @@
//===- ExplainOutputStyle.cpp --------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h
index 9a497accb812..f405cf615e92 100644
--- a/contrib/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h
+++ b/contrib/llvm/tools/llvm-pdbutil/ExplainOutputStyle.h
@@ -1,9 +1,8 @@
//===- ExplainOutputStyle.h ----------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/FormatUtil.cpp b/contrib/llvm/tools/llvm-pdbutil/FormatUtil.cpp
index f55d478127d6..1a13f383e53c 100644
--- a/contrib/llvm/tools/llvm-pdbutil/FormatUtil.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/FormatUtil.cpp
@@ -1,9 +1,8 @@
//===- FormatUtil.cpp ----------------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/FormatUtil.h b/contrib/llvm/tools/llvm-pdbutil/FormatUtil.h
index 9a003c9285c9..19ce248f9a6f 100644
--- a/contrib/llvm/tools/llvm-pdbutil/FormatUtil.h
+++ b/contrib/llvm/tools/llvm-pdbutil/FormatUtil.h
@@ -1,9 +1,8 @@
//===- FormatUtil.h ------------------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/InputFile.cpp b/contrib/llvm/tools/llvm-pdbutil/InputFile.cpp
index 8eb116cf0d80..bd23bfdbe31a 100644
--- a/contrib/llvm/tools/llvm-pdbutil/InputFile.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/InputFile.cpp
@@ -1,9 +1,8 @@
//===- InputFile.cpp ------------------------------------------ *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -67,17 +66,20 @@ getModuleDebugStream(PDBFile &File, StringRef &ModuleName, uint32_t Index) {
static inline bool isCodeViewDebugSubsection(object::SectionRef Section,
StringRef Name,
BinaryStreamReader &Reader) {
- StringRef SectionName, Contents;
+ StringRef SectionName;
if (Section.getName(SectionName))
return false;
if (SectionName != Name)
return false;
- if (Section.getContents(Contents))
+ Expected<StringRef> ContentsOrErr = Section.getContents();
+ if (!ContentsOrErr) {
+ consumeError(ContentsOrErr.takeError());
return false;
+ }
- Reader = BinaryStreamReader(Contents, support::little);
+ Reader = BinaryStreamReader(*ContentsOrErr, support::little);
uint32_t Magic;
if (Reader.bytesRemaining() < sizeof(uint32_t))
return false;
diff --git a/contrib/llvm/tools/llvm-pdbutil/InputFile.h b/contrib/llvm/tools/llvm-pdbutil/InputFile.h
index ee4e651c1e99..f25390c971d0 100644
--- a/contrib/llvm/tools/llvm-pdbutil/InputFile.h
+++ b/contrib/llvm/tools/llvm-pdbutil/InputFile.h
@@ -1,9 +1,8 @@
//===- InputFile.h -------------------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp
index e80a1762450b..280c000bd65f 100644
--- a/contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp
@@ -1,9 +1,8 @@
//===- LinePrinter.cpp ------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -187,8 +186,7 @@ void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
return;
}
- auto S = MappedBlockStream::createIndexedStream(
- File.getMsfLayout(), File.getMsfBuffer(), StreamIdx, File.getAllocator());
+ auto S = File.createIndexedStream(StreamIdx);
if (!S) {
NewLine();
formatLine("Stream {0}: Not present", StreamIdx);
diff --git a/contrib/llvm/tools/llvm-pdbutil/LinePrinter.h b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.h
index 09bde28f516a..7ecfae17354f 100644
--- a/contrib/llvm/tools/llvm-pdbutil/LinePrinter.h
+++ b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.h
@@ -1,9 +1,8 @@
//===- LinePrinter.h ------------------------------------------ *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -133,8 +132,7 @@ struct AutoIndent {
template <class T>
inline raw_ostream &operator<<(LinePrinter &Printer, const T &Item) {
- Printer.getStream() << Item;
- return Printer.getStream();
+ return Printer.getStream() << Item;
}
enum class PDB_ColorItem {
diff --git a/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
index 2c7b213b0a9f..e5ae47050678 100644
--- a/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp
@@ -1,9 +1,8 @@
//===- MinimalSymbolDumper.cpp -------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -207,6 +206,7 @@ static std::string formatSourceLanguage(SourceLanguage Lang) {
RETURN_CASE(SourceLanguage, MSIL, "msil");
RETURN_CASE(SourceLanguage, HLSL, "hlsl");
RETURN_CASE(SourceLanguage, D, "d");
+ RETURN_CASE(SourceLanguage, Swift, "swift");
}
return formatUnknownEnum(Lang);
}
@@ -287,21 +287,39 @@ static std::string formatCookieKind(FrameCookieKind Kind) {
return formatUnknownEnum(Kind);
}
-static std::string formatRegisterId(RegisterId Id) {
- switch (Id) {
+static std::string formatRegisterId(RegisterId Id, CPUType Cpu) {
+ if (Cpu == CPUType::ARM64) {
+ switch (Id) {
+#define CV_REGISTERS_ARM64
+#define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name)
+#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
+#undef CV_REGISTER
+#undef CV_REGISTERS_ARM64
+
+ default:
+ break;
+ }
+ } else {
+ switch (Id) {
+#define CV_REGISTERS_X86
#define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name)
#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
#undef CV_REGISTER
+#undef CV_REGISTERS_X86
+
+ default:
+ break;
+ }
}
return formatUnknownEnum(Id);
}
-static std::string formatRegisterId(uint16_t Reg16) {
- return formatRegisterId(RegisterId(Reg16));
+static std::string formatRegisterId(uint16_t Reg16, CPUType Cpu) {
+ return formatRegisterId(RegisterId(Reg16), Cpu);
}
-static std::string formatRegisterId(ulittle16_t &Reg16) {
- return formatRegisterId(uint16_t(Reg16));
+static std::string formatRegisterId(ulittle16_t &Reg16, CPUType Cpu) {
+ return formatRegisterId(uint16_t(Reg16), Cpu);
}
static std::string formatRange(LocalVariableAddrRange Range) {
@@ -331,7 +349,7 @@ Error MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol &Record,
// append to the existing line.
P.formatLine("{0} | {1} [size = {2}]",
fmt_align(Offset, AlignStyle::Right, 6),
- formatSymbolKind(Record.Type), Record.length());
+ formatSymbolKind(Record.kind()), Record.length());
P.Indent();
return Error::success();
}
@@ -562,7 +580,7 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
AutoIndent Indent(P, 7);
P.formatLine("register = {0}, offset = {1}, offset in parent = {2}, has "
"spilled udt = {3}",
- formatRegisterId(Def.Hdr.Register),
+ formatRegisterId(Def.Hdr.Register, CompilationCPU),
int32_t(Def.Hdr.BasePointerOffset), Def.offsetInParent(),
Def.hasSpilledUDTMember());
P.formatLine("range = {0}, gaps = {1}", formatRange(Def.Range),
@@ -575,7 +593,7 @@ Error MinimalSymbolDumper::visitKnownRecord(
AutoIndent Indent(P, 7);
P.formatLine("register = {0}, may have no name = {1}, range start = "
"{2}, length = {3}",
- formatRegisterId(DefRangeRegister.Hdr.Register),
+ formatRegisterId(DefRangeRegister.Hdr.Register, CompilationCPU),
bool(DefRangeRegister.Hdr.MayHaveNoName),
formatSegmentOffset(DefRangeRegister.Range.ISectStart,
DefRangeRegister.Range.OffsetStart),
@@ -590,7 +608,7 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
AutoIndent Indent(P, 7);
bool NoName = !!(Def.Hdr.MayHaveNoName == 0);
P.formatLine("register = {0}, may have no name = {1}, offset in parent = {2}",
- formatRegisterId(Def.Hdr.Register), NoName,
+ formatRegisterId(Def.Hdr.Register, CompilationCPU), NoName,
uint32_t(Def.Hdr.OffsetInParent));
P.formatLine("range = {0}, gaps = {1}", formatRange(Def.Range),
formatGaps(P.getIndentLevel() + 9, Def.Gaps));
@@ -617,7 +635,7 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, DefRangeSym &Def) {
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FrameCookieSym &FC) {
AutoIndent Indent(P, 7);
P.formatLine("code offset = {0}, Register = {1}, kind = {2}, flags = {3}",
- FC.CodeOffset, formatRegisterId(FC.Register),
+ FC.CodeOffset, formatRegisterId(FC.Register, CompilationCPU),
formatCookieKind(FC.CookieKind), FC.Flags);
return Error::success();
}
@@ -631,9 +649,10 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FrameProcSym &FP) {
FP.BytesOfCalleeSavedRegisters,
formatSegmentOffset(FP.SectionIdOfExceptionHandler,
FP.OffsetOfExceptionHandler));
- P.formatLine("local fp reg = {0}, param fp reg = {1}",
- formatRegisterId(FP.getLocalFramePtrReg(CompilationCPU)),
- formatRegisterId(FP.getParamFramePtrReg(CompilationCPU)));
+ P.formatLine(
+ "local fp reg = {0}, param fp reg = {1}",
+ formatRegisterId(FP.getLocalFramePtrReg(CompilationCPU), CompilationCPU),
+ formatRegisterId(FP.getParamFramePtrReg(CompilationCPU), CompilationCPU));
P.formatLine("flags = {0}",
formatFrameProcedureOptions(P.getIndentLevel() + 9, FP.Flags));
return Error::success();
@@ -650,13 +669,89 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, InlineSiteSym &IS) {
AutoIndent Indent(P, 7);
- auto Bytes = makeArrayRef(IS.AnnotationData);
- StringRef Annotations(reinterpret_cast<const char *>(Bytes.begin()),
- Bytes.size());
-
P.formatLine("inlinee = {0}, parent = {1}, end = {2}", idIndex(IS.Inlinee),
IS.Parent, IS.End);
- P.formatLine("annotations = {0}", toHex(Annotations));
+
+ // Break down the annotation byte code and calculate code and line offsets.
+ // FIXME: It would be helpful if we could look up the initial file and inlinee
+ // lines offset using the inlinee index above.
+ uint32_t CodeOffset = 0;
+ int32_t LineOffset = 0;
+ for (auto &Annot : IS.annotations()) {
+ P.formatLine(" {0}", fmt_align(toHex(Annot.Bytes), AlignStyle::Left, 9));
+
+ auto formatCodeOffset = [&](uint32_t Delta) {
+ CodeOffset += Delta;
+ P.format(" code 0x{0} (+0x{1})", utohexstr(CodeOffset), utohexstr(Delta));
+ };
+ auto formatCodeLength = [&](uint32_t Length) {
+ // Notably, changing the code length does not affect the code offset.
+ P.format(" code end 0x{0} (+0x{1})", utohexstr(CodeOffset + Length),
+ utohexstr(Length));
+ };
+ auto formatLineOffset = [&](int32_t Delta) {
+ LineOffset += Delta;
+ char Sign = Delta > 0 ? '+' : '-';
+ P.format(" line {0} ({1}{2})", LineOffset, Sign, std::abs(Delta));
+ };
+
+ // Use the opcode to interpret the integer values.
+ switch (Annot.OpCode) {
+ case BinaryAnnotationsOpCode::Invalid:
+ break;
+ case BinaryAnnotationsOpCode::CodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffset:
+ formatCodeOffset(Annot.U1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeLineOffset:
+ formatLineOffset(Annot.S1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeLength:
+ formatCodeLength(Annot.U1);
+ // Apparently this annotation updates the code offset. It's hard to make
+ // MSVC produce this opcode, but clang uses it, and debuggers seem to use
+ // this interpretation.
+ CodeOffset += Annot.U1;
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
+ formatCodeOffset(Annot.U1);
+ formatLineOffset(Annot.S1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
+ formatCodeOffset(Annot.U2);
+ formatCodeLength(Annot.U1);
+ break;
+
+ case BinaryAnnotationsOpCode::ChangeFile: {
+ uint32_t FileOffset = Annot.U1;
+ StringRef Filename = "<unknown>";
+ if (SymGroup) {
+ if (Expected<StringRef> MaybeFile =
+ SymGroup->getNameFromStringTable(FileOffset))
+ Filename = *MaybeFile;
+ else
+ return MaybeFile.takeError();
+ }
+ P.format(" setfile {0} 0x{1}", utohexstr(FileOffset));
+ break;
+ }
+
+ // The rest of these are hard to convince MSVC to emit, so they are not as
+ // well understood.
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
+ formatCodeOffset(Annot.U1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeLineEndDelta:
+ case BinaryAnnotationsOpCode::ChangeRangeKind:
+ case BinaryAnnotationsOpCode::ChangeColumnStart:
+ case BinaryAnnotationsOpCode::ChangeColumnEnd:
+ P.format(" {0} {1}", Annot.Name, Annot.U1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeColumnEndDelta:
+ P.format(" {0} {1}", Annot.Name, Annot.S1);
+ break;
+ }
+ }
return Error::success();
}
@@ -665,7 +760,8 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
P.format(" `{0}`", Register.Name);
AutoIndent Indent(P, 7);
P.formatLine("register = {0}, type = {1}",
- formatRegisterId(Register.Register), typeIndex(Register.Index));
+ formatRegisterId(Register.Register, CompilationCPU),
+ typeIndex(Register.Index));
return Error::success();
}
@@ -753,9 +849,9 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
RegRelativeSym &RegRel) {
P.format(" `{0}`", RegRel.Name);
AutoIndent Indent(P, 7);
- P.formatLine("type = {0}, register = {1}, offset = {2}",
- typeIndex(RegRel.Type), formatRegisterId(RegRel.Register),
- RegRel.Offset);
+ P.formatLine(
+ "type = {0}, register = {1}, offset = {2}", typeIndex(RegRel.Type),
+ formatRegisterId(RegRel.Register, CompilationCPU), RegRel.Offset);
return Error::success();
}
@@ -780,3 +876,12 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
P.format(" `{0}`", UN.Name);
return Error::success();
}
+
+Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
+ AnnotationSym &Annot) {
+ AutoIndent Indent(P, 7);
+ P.formatLine("addr = {0}", formatSegmentOffset(Annot.Segment, Annot.CodeOffset));
+ P.formatLine("strings = {0}", typesetStringList(P.getIndentLevel() + 9 + 2,
+ Annot.Strings));
+ return Error::success();
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h b/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h
index 033e193cee6c..cdc75c1cfba0 100644
--- a/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h
@@ -1,9 +1,8 @@
//===- MinimalSymbolDumper.h ---------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
index 3f10e8ab8a1e..3fdef085f19e 100644
--- a/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
@@ -1,9 +1,8 @@
//===- MinimalTypeDumper.cpp ---------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -11,6 +10,7 @@
#include "FormatUtil.h"
#include "LinePrinter.h"
+#include "TypeReferenceTracker.h"
#include "llvm-pdbutil.h"
#include "llvm/DebugInfo/CodeView/CVRecord.h"
@@ -222,11 +222,10 @@ Error MinimalTypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
// formatLine puts the newline at the beginning, so we use formatLine here
// to start a new line, and then individual visit methods use format to
// append to the existing line.
- if (!Hashes) {
- P.formatLine("{0} | {1} [size = {2}]",
- fmt_align(Index, AlignStyle::Right, Width),
- formatTypeLeafKind(Record.Type), Record.length());
- } else {
+ P.formatLine("{0} | {1} [size = {2}",
+ fmt_align(Index, AlignStyle::Right, Width),
+ formatTypeLeafKind(Record.kind()), Record.length());
+ if (Hashes) {
std::string H;
if (Index.toArrayIndex() >= HashValues.size()) {
H = "(not present)";
@@ -242,13 +241,19 @@ Error MinimalTypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
else
H = "0x" + utohexstr(Hash) + ", our hash = 0x" + utohexstr(OurHash);
}
- P.formatLine("{0} | {1} [size = {2}, hash = {3}]",
- fmt_align(Index, AlignStyle::Right, Width),
- formatTypeLeafKind(Record.Type), Record.length(), H);
+ P.format(", hash = {0}", H);
}
+ if (RefTracker) {
+ if (RefTracker->isTypeReferenced(Index))
+ P.format(", referenced");
+ else
+ P.format(", unreferenced");
+ }
+ P.format("]");
P.Indent(Width + 3);
return Error::success();
}
+
Error MinimalTypeDumpVisitor::visitTypeEnd(CVType &Record) {
P.Unindent(Width + 3);
if (RecordBytes) {
diff --git a/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h b/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h
index 8f6bdc6110ae..6bc456d47ac4 100644
--- a/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/MinimalTypeDumper.h
@@ -1,9 +1,8 @@
//===- MinimalTypeDumper.h ------------------------------------ *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -21,17 +20,19 @@ class LazyRandomTypeCollection;
namespace pdb {
class LinePrinter;
class TpiStream;
+class TypeReferenceTracker;
class MinimalTypeDumpVisitor : public codeview::TypeVisitorCallbacks {
public:
MinimalTypeDumpVisitor(LinePrinter &P, uint32_t Width, bool RecordBytes,
bool Hashes, codeview::LazyRandomTypeCollection &Types,
+ TypeReferenceTracker *RefTracker,
uint32_t NumHashBuckets,
FixedStreamArray<support::ulittle32_t> HashValues,
pdb::TpiStream *Stream)
: P(P), Width(Width), RecordBytes(RecordBytes), Hashes(Hashes),
- Types(Types), NumHashBuckets(NumHashBuckets), HashValues(HashValues),
- Stream(Stream) {}
+ Types(Types), RefTracker(RefTracker), NumHashBuckets(NumHashBuckets),
+ HashValues(HashValues), Stream(Stream) {}
Error visitTypeBegin(codeview::CVType &Record,
codeview::TypeIndex Index) override;
@@ -57,6 +58,7 @@ private:
bool RecordBytes = false;
bool Hashes = false;
codeview::LazyRandomTypeCollection &Types;
+ pdb::TypeReferenceTracker *RefTracker = nullptr;
uint32_t NumHashBuckets;
codeview::TypeIndex CurrentTypeIndex;
FixedStreamArray<support::ulittle32_t> HashValues;
diff --git a/contrib/llvm/tools/llvm-pdbutil/OutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/OutputStyle.h
index dfefc25a215e..40b0de8bdf72 100644
--- a/contrib/llvm/tools/llvm-pdbutil/OutputStyle.h
+++ b/contrib/llvm/tools/llvm-pdbutil/OutputStyle.h
@@ -1,9 +1,8 @@
//===- OutputStyle.h ------------------------------------------ *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PdbYaml.cpp b/contrib/llvm/tools/llvm-pdbutil/PdbYaml.cpp
index 3ea333608314..a26241967b5a 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PdbYaml.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PdbYaml.cpp
@@ -1,9 +1,8 @@
-//===- PdbYAML.cpp -------------------------------------------- *- C++ --*-===//
+//===-- PdbYaml.cpp ------------------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -51,6 +50,7 @@ template <> struct ScalarEnumerationTraits<llvm::pdb::PDB_Machine> {
io.enumCase(Value, "SH3DSP", PDB_Machine::SH3DSP);
io.enumCase(Value, "Thumb", PDB_Machine::Thumb);
io.enumCase(Value, "WceMipsV2", PDB_Machine::WceMipsV2);
+ io.enumCase(Value, "Arm64", PDB_Machine::Arm64);
}
};
diff --git a/contrib/llvm/tools/llvm-pdbutil/PdbYaml.h b/contrib/llvm/tools/llvm-pdbutil/PdbYaml.h
index 97ba87266cc6..ed6346c2c4db 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PdbYaml.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PdbYaml.h
@@ -1,9 +1,8 @@
//===- PdbYAML.h ---------------------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp
index bcdecca81aec..cd01a4004819 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp
@@ -1,9 +1,8 @@
//===- PrettyBuiltinDumper.cpp ---------------------------------- *- C++ *-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.h
index fb6b0b172e6e..3bdef34c48f8 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.h
@@ -1,9 +1,8 @@
//===- PrettyBuiltinDumper.h ---------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp
index f009f53a3932..b7eccac5988c 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp
@@ -1,9 +1,8 @@
//===- PrettyClassDefinitionDumper.cpp --------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h
index 6569a1d304f6..f43c5c11bdfd 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h
@@ -1,9 +1,8 @@
//===- PrettyClassDefinitionDumper.h ----------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp
index a572522c8cd7..a522935e34f1 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp
@@ -1,9 +1,8 @@
//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h
index f83f1a6c1b34..8f78b3b503d0 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h
@@ -1,9 +1,8 @@
//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp
index 94a0b2d5e780..cf769ff66472 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp
@@ -1,9 +1,8 @@
//===- PrettyCompilandDumper.cpp - llvm-pdbutil compiland dumper -*- C++ *-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.h
index 1a840e49607c..c83a58672d1a 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyCompilandDumper.h
@@ -1,9 +1,8 @@
//===- PrettyCompilandDumper.h - llvm-pdbutil compiland dumper -*- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp
index f4cbd3f8fa14..9ed5893f252e 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp
@@ -1,9 +1,8 @@
//===- PrettyEnumDumper.cpp -------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.h
index c6e65a6d1772..e7c5c1aeb018 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyEnumDumper.h
@@ -1,9 +1,8 @@
//===- PrettyEnumDumper.h ---------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp
index 1270223b1c78..fede031ec0c0 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp
@@ -1,9 +1,8 @@
//===- PrettyExternalSymbolDumper.cpp -------------------------- *- C++ *-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h
index 6a009862ddd4..58fafe943315 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h
@@ -1,9 +1,8 @@
//===- PrettyExternalSymbolDumper.h --------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.cpp
index 836ede41054e..b820ca333965 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.cpp
@@ -1,9 +1,8 @@
//===- PrettyFunctionDumper.cpp --------------------------------- *- C++ *-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -139,7 +138,8 @@ void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer) {
if (Symbol.hasFramePointer()) {
WithColor(Printer, PDB_ColorItem::Register).get()
- << Symbol.getLocalBasePointerRegisterId();
+ << CPURegister{Symbol.getRawSymbol().getPlatform(),
+ Symbol.getLocalBasePointerRegisterId()};
} else {
WithColor(Printer, PDB_ColorItem::Register).get() << "FPO";
}
@@ -229,9 +229,9 @@ void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) {
uint32_t TypeId = Symbol.getTypeId();
auto Type = Symbol.getSession().getSymbolById(TypeId);
if (Type)
- Printer << "<unknown-type>";
- else
Type->dump(*this);
+ else
+ Printer << "<unknown-type>";
}
void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.h
index 1a6f5430ec5a..df62604ac881 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyFunctionDumper.h
@@ -1,9 +1,8 @@
//===- PrettyFunctionDumper.h --------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp
index daf3cd45b327..e8f8e5aa62c9 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp
@@ -1,9 +1,8 @@
//===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.h
index 36e586fea7e3..b6539d95bf31 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyTypeDumper.h
@@ -1,9 +1,8 @@
//===- PrettyTypeDumper.h - PDBSymDumper implementation for types *- C++ *-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.cpp
index 2b3f3691ed98..ef73a8cdf9c4 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.cpp
@@ -1,9 +1,8 @@
//===- PrettyTypedefDumper.cpp - PDBSymDumper impl for typedefs -- * C++ *-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.h
index 133bbfb7db0e..ad8b3f37dcfd 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyTypedefDumper.h
@@ -1,9 +1,8 @@
//===- PrettyTypedefDumper.h - llvm-pdbutil typedef dumper ---*- C++ ----*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp
index ddac8cf0da4a..6dd7cc384cc9 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp
@@ -1,9 +1,8 @@
//===- PrettyVariableDumper.cpp ---------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.h b/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.h
index cacf1ce9577b..65cf5cd2cf55 100644
--- a/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.h
+++ b/contrib/llvm/tools/llvm-pdbutil/PrettyVariableDumper.h
@@ -1,9 +1,8 @@
//===- PrettyVariableDumper.h - PDBSymDumper variable dumper ----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/StreamUtil.cpp b/contrib/llvm/tools/llvm-pdbutil/StreamUtil.cpp
index 367d947d25ee..7dfc2beefe78 100644
--- a/contrib/llvm/tools/llvm-pdbutil/StreamUtil.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/StreamUtil.cpp
@@ -1,9 +1,8 @@
//===- StreamUtil.cpp - PDB stream utilities --------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/StreamUtil.h b/contrib/llvm/tools/llvm-pdbutil/StreamUtil.h
index 0e2e80707361..f810f7dc15b4 100644
--- a/contrib/llvm/tools/llvm-pdbutil/StreamUtil.h
+++ b/contrib/llvm/tools/llvm-pdbutil/StreamUtil.h
@@ -1,9 +1,8 @@
//===- Streamutil.h - PDB stream utilities ----------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp b/contrib/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp
new file mode 100644
index 000000000000..f184f02e01ee
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/TypeReferenceTracker.cpp
@@ -0,0 +1,160 @@
+//===- TypeReferenceTracker.cpp ------------------------------- *- C++ --*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TypeReferenceTracker.h"
+
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+using namespace llvm::codeview;
+
+// LazyRandomTypeCollection doesn't appear to expose the number of records, so
+// just iterate up front to find out.
+static uint32_t getNumRecordsInCollection(LazyRandomTypeCollection &Types) {
+ uint32_t NumTypes = 0;
+ for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI))
+ ++NumTypes;
+ return NumTypes;
+}
+
+TypeReferenceTracker::TypeReferenceTracker(InputFile &File)
+ : File(File), Types(File.types()),
+ Ids(File.isPdb() ? &File.ids() : nullptr) {
+ NumTypeRecords = getNumRecordsInCollection(Types);
+ TypeReferenced.resize(NumTypeRecords, false);
+
+ // If this is a PDB, ids are stored separately, so make a separate bit vector.
+ if (Ids) {
+ NumIdRecords = getNumRecordsInCollection(*Ids);
+ IdReferenced.resize(NumIdRecords, false);
+ }
+
+ // Get the TpiStream pointer for forward decl resolution if this is a pdb.
+ // Build the hash map to enable resolving forward decls.
+ if (File.isPdb()) {
+ Tpi = &cantFail(File.pdb().getPDBTpiStream());
+ Tpi->buildHashMap();
+ }
+}
+
+void TypeReferenceTracker::mark() {
+ // Walk type roots:
+ // - globals
+ // - modi symbols
+ // - LF_UDT_MOD_SRC_LINE? VC always links these in.
+ for (SymbolGroup SG : File.symbol_groups()) {
+ if (File.isObj()) {
+ for (const auto &SS : SG.getDebugSubsections()) {
+ // FIXME: Are there other type-referencing subsections? Inlinees?
+ // Probably for IDs.
+ if (SS.kind() != DebugSubsectionKind::Symbols)
+ continue;
+
+ CVSymbolArray Symbols;
+ BinaryStreamReader Reader(SS.getRecordData());
+ cantFail(Reader.readArray(Symbols, Reader.getLength()));
+ for (const CVSymbol &S : Symbols)
+ addTypeRefsFromSymbol(S);
+ }
+ } else if (SG.hasDebugStream()) {
+ for (const CVSymbol &S : SG.getPdbModuleStream().getSymbolArray())
+ addTypeRefsFromSymbol(S);
+ }
+ }
+
+ // Walk globals and mark types referenced from globals.
+ if (File.isPdb() && File.pdb().hasPDBGlobalsStream()) {
+ SymbolStream &SymStream = cantFail(File.pdb().getPDBSymbolStream());
+ GlobalsStream &GS = cantFail(File.pdb().getPDBGlobalsStream());
+ for (uint32_t PubSymOff : GS.getGlobalsTable()) {
+ CVSymbol Sym = SymStream.readRecord(PubSymOff);
+ addTypeRefsFromSymbol(Sym);
+ }
+ }
+
+ // FIXME: Should we walk Ids?
+}
+
+void TypeReferenceTracker::addOneTypeRef(TiRefKind RefKind, TypeIndex RefTI) {
+ // If it's simple or already seen, no need to add to work list.
+ BitVector &TypeOrIdReferenced =
+ (Ids && RefKind == TiRefKind::IndexRef) ? IdReferenced : TypeReferenced;
+ if (RefTI.isSimple() || TypeOrIdReferenced.test(RefTI.toArrayIndex()))
+ return;
+
+ // Otherwise, mark it seen and add it to the work list.
+ TypeOrIdReferenced.set(RefTI.toArrayIndex());
+ RefWorklist.push_back({RefKind, RefTI});
+}
+
+void TypeReferenceTracker::addTypeRefsFromSymbol(const CVSymbol &Sym) {
+ SmallVector<TiReference, 4> DepList;
+ // FIXME: Check for failure.
+ discoverTypeIndicesInSymbol(Sym, DepList);
+ addReferencedTypes(Sym.content(), DepList);
+ markReferencedTypes();
+}
+
+void TypeReferenceTracker::addReferencedTypes(ArrayRef<uint8_t> RecData,
+ ArrayRef<TiReference> DepList) {
+ for (const auto &Ref : DepList) {
+ // FIXME: Report OOB slice instead of truncating.
+ ArrayRef<uint8_t> ByteSlice =
+ RecData.drop_front(Ref.Offset).take_front(4 * Ref.Count);
+ ArrayRef<TypeIndex> TIs(
+ reinterpret_cast<const TypeIndex *>(ByteSlice.data()),
+ ByteSlice.size() / 4);
+
+ // If this is a PDB and this is an item reference, track it in the IPI
+ // bitvector. Otherwise, it's a type ref, or there is only one stream.
+ for (TypeIndex RefTI : TIs)
+ addOneTypeRef(Ref.Kind, RefTI);
+ }
+}
+
+void TypeReferenceTracker::markReferencedTypes() {
+ while (!RefWorklist.empty()) {
+ TiRefKind RefKind;
+ TypeIndex RefTI;
+ std::tie(RefKind, RefTI) = RefWorklist.pop_back_val();
+ Optional<CVType> Rec = (Ids && RefKind == TiRefKind::IndexRef)
+ ? Ids->tryGetType(RefTI)
+ : Types.tryGetType(RefTI);
+ if (!Rec)
+ continue; // FIXME: Report a reference to a non-existant type.
+
+ SmallVector<TiReference, 4> DepList;
+ // FIXME: Check for failure.
+ discoverTypeIndices(*Rec, DepList);
+ addReferencedTypes(Rec->content(), DepList);
+
+ // If this is a tag kind and this is a PDB input, mark the complete type as
+ // referenced.
+ // FIXME: This limitation makes this feature somewhat useless on object file
+ // inputs.
+ if (Tpi) {
+ switch (Rec->kind()) {
+ default:
+ break;
+ case LF_CLASS:
+ case LF_INTERFACE:
+ case LF_STRUCTURE:
+ case LF_UNION:
+ case LF_ENUM:
+ addOneTypeRef(TiRefKind::TypeRef,
+ cantFail(Tpi->findFullDeclForForwardRef(RefTI)));
+ break;
+ }
+ }
+ }
+}
diff --git a/contrib/llvm/tools/llvm-pdbutil/TypeReferenceTracker.h b/contrib/llvm/tools/llvm-pdbutil/TypeReferenceTracker.h
new file mode 100644
index 000000000000..8861731ab6ee
--- /dev/null
+++ b/contrib/llvm/tools/llvm-pdbutil/TypeReferenceTracker.h
@@ -0,0 +1,69 @@
+//===- TypeReferenceTracker.h --------------------------------- *- C++ --*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_TYPEREFERENCETRACKER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_TYPEREFERENCETRACKER_H
+
+#include "InputFile.h"
+
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace pdb {
+
+class TpiStream;
+
+/// Maintains bitvector to track whether a type was referenced by a symbol
+/// record.
+class TypeReferenceTracker {
+public:
+ TypeReferenceTracker(InputFile &File);
+
+ // Do the work of marking referenced types.
+ void mark();
+
+ // Return true if a symbol record transitively references this type.
+ bool isTypeReferenced(codeview::TypeIndex TI) {
+ return TI.toArrayIndex() <= NumTypeRecords &&
+ TypeReferenced.test(TI.toArrayIndex());
+ }
+
+private:
+ void addTypeRefsFromSymbol(const codeview::CVSymbol &Sym);
+
+ // Mark types on this list as referenced.
+ void addReferencedTypes(ArrayRef<uint8_t> RecData,
+ ArrayRef<codeview::TiReference> Refs);
+
+ // Consume all types on the worklist.
+ void markReferencedTypes();
+
+ void addOneTypeRef(codeview::TiRefKind RefKind, codeview::TypeIndex RefTI);
+
+ InputFile &File;
+ codeview::LazyRandomTypeCollection &Types;
+ codeview::LazyRandomTypeCollection *Ids = nullptr;
+ TpiStream *Tpi = nullptr;
+ BitVector TypeReferenced;
+ BitVector IdReferenced;
+ SmallVector<std::pair<codeview::TiRefKind, codeview::TypeIndex>, 10>
+ RefWorklist;
+ uint32_t NumTypeRecords = 0;
+ uint32_t NumIdRecords = 0;
+};
+
+} // namespace pdb
+} // namespace llvm
+
+#endif // LLVM_TOOLS_LLVMPDBDUMP_TYPEREFERENCETRACKER_H
diff --git a/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp
index 62b5c428d410..80b76657facc 100644
--- a/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp
@@ -1,9 +1,8 @@
//===- YAMLOutputStyle.cpp ------------------------------------ *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -232,10 +231,7 @@ Error YAMLOutputStyle::dumpDbiStream() {
if (ModiStream == kInvalidStreamIndex)
continue;
- auto ModStreamData = msf::MappedBlockStream::createIndexedStream(
- File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
- File.getAllocator());
-
+ auto ModStreamData = File.createIndexedStream(ModiStream);
pdb::ModuleDebugStreamRef ModS(MI, std::move(ModStreamData));
if (auto EC = ModS.reload())
return EC;
diff --git a/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.h
index a5ad3355d2ab..7a50af1abe3f 100644
--- a/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.h
+++ b/contrib/llvm/tools/llvm-pdbutil/YAMLOutputStyle.h
@@ -1,9 +1,8 @@
//===- YAMLOutputStyle.h -------------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
index 76f61a2a95a7..785a98086791 100644
--- a/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
+++ b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
@@ -1,9 +1,8 @@
//===- llvm-pdbutil.cpp - Dump debug info from a PDB file -------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -463,7 +462,10 @@ cl::opt<bool> DumpSymbolStats(
"sym-stats",
cl::desc("Dump a detailed breakdown of symbol usage/size for each module"),
cl::cat(MsfOptions), cl::sub(DumpSubcommand));
-
+cl::opt<bool> DumpTypeStats(
+ "type-stats",
+ cl::desc("Dump a detailed breakdown of type usage/size"),
+ cl::cat(MsfOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpUdtStats(
"udt-stats",
cl::desc("Dump a detailed breakdown of S_UDT record usage / stats"),
@@ -477,6 +479,11 @@ cl::opt<bool> DumpTypeData(
"type-data",
cl::desc("dump CodeView type record raw bytes from TPI stream"),
cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+cl::opt<bool>
+ DumpTypeRefStats("type-ref-stats",
+ cl::desc("dump statistics on the number and size of types "
+ "transitively referenced by symbol records"),
+ cl::cat(TypeOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpTypeExtras("type-extras",
cl::desc("dump type hashes and index offsets"),
@@ -927,7 +934,7 @@ static std::string stringOr(std::string Str, std::string IfEmpty) {
static void dumpInjectedSources(LinePrinter &Printer, IPDBSession &Session) {
auto Sources = Session.getInjectedSources();
- if (0 == Sources->getChildCount()) {
+ if (!Sources || !Sources->getChildCount()) {
Printer.printLine("There are no injected sources.");
return;
}
@@ -940,9 +947,6 @@ static void dumpInjectedSources(LinePrinter &Printer, IPDBSession &Session) {
std::string VFName = stringOr(IS->getVirtualFileName(), "<null>");
uint32_t CRC = IS->getCrc32();
- std::string CompressionStr;
- llvm::raw_string_ostream Stream(CompressionStr);
- Stream << IS->getCompression();
WithColor(Printer, PDB_ColorItem::Path).get() << File;
Printer << " (";
WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Size;
@@ -961,7 +965,9 @@ static void dumpInjectedSources(LinePrinter &Printer, IPDBSession &Session) {
Printer << ", ";
WithColor(Printer, PDB_ColorItem::Keyword).get() << "compression";
Printer << "=";
- WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Stream.str();
+ dumpPDBSourceCompression(
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get(),
+ IS->getCompression());
if (!opts::pretty::ShowInjectedSourceContent)
continue;
@@ -970,7 +976,12 @@ static void dumpInjectedSources(LinePrinter &Printer, IPDBSession &Session) {
int Indent = Printer.getIndentLevel();
Printer.Unindent(Indent);
- Printer.printLine(IS->getCode());
+ if (IS->getCompression() == PDB_SourceCompression::None)
+ Printer.printLine(IS->getCode());
+ else
+ Printer.formatBinary("Compressed data",
+ arrayRefFromStringRef(IS->getCode()),
+ /*StartOffset=*/0);
// Re-indent back to the original level.
Printer.Indent(Indent);
@@ -1272,12 +1283,7 @@ static void dumpPretty(StringRef Path) {
WithColor(Printer, PDB_ColorItem::SectionHeader).get()
<< "---INJECTED SOURCES---";
AutoIndent Indent1(Printer);
-
- if (ReaderType == PDB_ReaderType::Native)
- Printer.printLine(
- "Injected sources are not supported with the native reader.");
- else
- dumpInjectedSources(Printer, *Session);
+ dumpInjectedSources(Printer, *Session);
}
Printer.NewLine();
@@ -1377,8 +1383,7 @@ static void exportStream() {
<< "' (index " << Index << ") to file " << OutFileName << ".\n";
}
- SourceStream = MappedBlockStream::createIndexedStream(
- File.getMsfLayout(), File.getMsfBuffer(), Index, File.getAllocator());
+ SourceStream = File.createIndexedStream(Index);
auto OutFile = ExitOnErr(
FileOutputBuffer::create(OutFileName, SourceStream->getLength()));
FileBufferByteStream DestStream(std::move(OutFile), llvm::support::little);
diff --git a/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
index a57cc51d7fd7..321f41bba7f1 100644
--- a/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
+++ b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h
@@ -1,9 +1,8 @@
//===- llvm-pdbutil.h ----------------------------------------- *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -141,6 +140,7 @@ extern llvm::cl::opt<bool> DumpSummary;
extern llvm::cl::opt<bool> DumpFpm;
extern llvm::cl::opt<bool> DumpStreams;
extern llvm::cl::opt<bool> DumpSymbolStats;
+extern llvm::cl::opt<bool> DumpTypeStats;
extern llvm::cl::opt<bool> DumpUdtStats;
extern llvm::cl::opt<bool> DumpStreamBlocks;
@@ -156,6 +156,7 @@ extern llvm::cl::opt<bool> DumpTypeData;
extern llvm::cl::opt<bool> DumpTypeExtras;
extern llvm::cl::list<uint32_t> DumpTypeIndex;
extern llvm::cl::opt<bool> DumpTypeDependents;
+extern llvm::cl::opt<bool> DumpTypeRefStats;
extern llvm::cl::opt<bool> DumpSectionHeaders;
extern llvm::cl::opt<bool> DumpIds;
diff --git a/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp b/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp
index c25cbc2b64df..16d3ebe3fcbc 100644
--- a/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -1,9 +1,8 @@
//===- llvm-profdata.cpp - LLVM profile data tool -------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -27,8 +26,8 @@
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/WithColor.h"
#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -201,6 +200,32 @@ static bool isFatalError(instrprof_error IPE) {
}
}
+/// Computer the overlap b/w profile BaseFilename and TestFileName,
+/// and store the program level result to Overlap.
+static void overlapInput(const std::string &BaseFilename,
+ const std::string &TestFilename, WriterContext *WC,
+ OverlapStats &Overlap,
+ const OverlapFuncFilters &FuncFilter,
+ raw_fd_ostream &OS, bool IsCS) {
+ auto ReaderOrErr = InstrProfReader::create(TestFilename);
+ if (Error E = ReaderOrErr.takeError()) {
+ // Skip the empty profiles by returning sliently.
+ instrprof_error IPE = InstrProfError::take(std::move(E));
+ if (IPE != instrprof_error::empty_raw_profile)
+ WC->Err = make_error<InstrProfError>(IPE);
+ return;
+ }
+
+ auto Reader = std::move(ReaderOrErr.get());
+ for (auto &I : *Reader) {
+ OverlapStats FuncOverlap(OverlapStats::FunctionLevel);
+ FuncOverlap.setFuncInfo(I.Name, I.Hash);
+
+ WC->Writer.overlapRecord(std::move(I), Overlap, FuncOverlap, FuncFilter);
+ FuncOverlap.dump(OS);
+ }
+}
+
/// Load an input into a writer context.
static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
WriterContext *WC) {
@@ -226,7 +251,8 @@ static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
auto Reader = std::move(ReaderOrErr.get());
bool IsIRProfile = Reader->isIRLevelProfile();
- if (WC->Writer.setIsIRLevelProfile(IsIRProfile)) {
+ bool HasCSIRProfile = Reader->hasCSIRLevelProfile();
+ if (WC->Writer.setIsIRLevelProfile(IsIRProfile, HasCSIRProfile)) {
WC->Err = make_error<StringError>(
"Merge IR generated profile with Clang generated profile.",
std::error_code());
@@ -291,11 +317,6 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
OutputFormat != PF_Text)
exitWithError("Unknown format is specified.");
- std::error_code EC;
- raw_fd_ostream Output(OutputFilename.data(), EC, sys::fs::F_None);
- if (EC)
- exitWithErrorCode(EC, OutputFilename);
-
std::mutex ErrorLock;
SmallSet<instrprof_error, 4> WriterErrorCodes;
@@ -358,6 +379,11 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
WC->ErrWhence);
}
+ std::error_code EC;
+ raw_fd_ostream Output(OutputFilename.data(), EC, sys::fs::F_None);
+ if (EC)
+ exitWithErrorCode(EC, OutputFilename);
+
InstrProfWriter &Writer = Contexts[0]->Writer;
if (OutputFormat == PF_Text) {
if (Error E = Writer.writeText(Output))
@@ -407,12 +433,6 @@ static void mergeSampleProfile(const WeightedFileVector &Inputs,
StringRef OutputFilename,
ProfileFormat OutputFormat) {
using namespace sampleprof;
- auto WriterOrErr =
- SampleProfileWriter::create(OutputFilename, FormatMap[OutputFormat]);
- if (std::error_code EC = WriterOrErr.getError())
- exitWithErrorCode(EC, OutputFilename);
-
- auto Writer = std::move(WriterOrErr.get());
StringMap<FunctionSamples> ProfileMap;
SmallVector<std::unique_ptr<sampleprof::SampleProfileReader>, 5> Readers;
LLVMContext Context;
@@ -447,6 +467,12 @@ static void mergeSampleProfile(const WeightedFileVector &Inputs,
}
}
}
+ auto WriterOrErr =
+ SampleProfileWriter::create(OutputFilename, FormatMap[OutputFormat]);
+ if (std::error_code EC = WriterOrErr.getError())
+ exitWithErrorCode(EC, OutputFilename);
+
+ auto Writer = std::move(WriterOrErr.get());
Writer->write(ProfileMap);
}
@@ -608,6 +634,65 @@ static int merge_main(int argc, const char *argv[]) {
return 0;
}
+/// Computer the overlap b/w profile BaseFilename and profile TestFilename.
+static void overlapInstrProfile(const std::string &BaseFilename,
+ const std::string &TestFilename,
+ const OverlapFuncFilters &FuncFilter,
+ raw_fd_ostream &OS, bool IsCS) {
+ std::mutex ErrorLock;
+ SmallSet<instrprof_error, 4> WriterErrorCodes;
+ WriterContext Context(false, ErrorLock, WriterErrorCodes);
+ WeightedFile WeightedInput{BaseFilename, 1};
+ OverlapStats Overlap;
+ Error E = Overlap.accumuateCounts(BaseFilename, TestFilename, IsCS);
+ if (E)
+ exitWithError(std::move(E), "Error in getting profile count sums");
+ if (Overlap.Base.CountSum < 1.0f) {
+ OS << "Sum of edge counts for profile " << BaseFilename << " is 0.\n";
+ exit(0);
+ }
+ if (Overlap.Test.CountSum < 1.0f) {
+ OS << "Sum of edge counts for profile " << TestFilename << " is 0.\n";
+ exit(0);
+ }
+ loadInput(WeightedInput, nullptr, &Context);
+ overlapInput(BaseFilename, TestFilename, &Context, Overlap, FuncFilter, OS,
+ IsCS);
+ Overlap.dump(OS);
+}
+
+static int overlap_main(int argc, const char *argv[]) {
+ cl::opt<std::string> BaseFilename(cl::Positional, cl::Required,
+ cl::desc("<base profile file>"));
+ cl::opt<std::string> TestFilename(cl::Positional, cl::Required,
+ cl::desc("<test profile file>"));
+ cl::opt<std::string> Output("output", cl::value_desc("output"), cl::init("-"),
+ cl::desc("Output file"));
+ cl::alias OutputA("o", cl::desc("Alias for --output"), cl::aliasopt(Output));
+ cl::opt<bool> IsCS("cs", cl::init(false),
+ cl::desc("For context sensitive counts"));
+ cl::opt<unsigned long long> ValueCutoff(
+ "value-cutoff", cl::init(-1),
+ cl::desc(
+ "Function level overlap information for every function in test "
+ "profile with max count value greater then the parameter value"));
+ cl::opt<std::string> FuncNameFilter(
+ "function",
+ cl::desc("Function level overlap information for matching functions"));
+ cl::ParseCommandLineOptions(argc, argv, "LLVM profile data overlap tool\n");
+
+ std::error_code EC;
+ raw_fd_ostream OS(Output.data(), EC, sys::fs::F_Text);
+ if (EC)
+ exitWithErrorCode(EC, Output);
+
+ overlapInstrProfile(BaseFilename, TestFilename,
+ OverlapFuncFilters{ValueCutoff, FuncNameFilter}, OS,
+ IsCS);
+
+ return 0;
+}
+
typedef struct ValueSitesStats {
ValueSitesStats()
: TotalNumValueSites(0), TotalNumValueSitesWithValueProfile(0),
@@ -643,7 +728,7 @@ static void traverseAllValueSites(const InstrProfRecord &Func, uint32_t VK,
for (uint32_t V = 0; V < NV; V++) {
OS << "\t[ " << format("%2u", I) << ", ";
if (Symtab == nullptr)
- OS << format("%4u", VD[V].Value);
+ OS << format("%4" PRIu64, VD[V].Value);
else
OS << Symtab->getFuncName(VD[V].Value);
OS << ", " << format("%10" PRId64, VD[V].Count) << " ] ("
@@ -670,9 +755,10 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
uint32_t TopN, bool ShowIndirectCallTargets,
bool ShowMemOPSizes, bool ShowDetailedSummary,
std::vector<uint32_t> DetailedSummaryCutoffs,
- bool ShowAllFunctions, uint64_t ValueCutoff,
- bool OnlyListBelow, const std::string &ShowFunction,
- bool TextFormat, raw_fd_ostream &OS) {
+ bool ShowAllFunctions, bool ShowCS,
+ uint64_t ValueCutoff, bool OnlyListBelow,
+ const std::string &ShowFunction, bool TextFormat,
+ raw_fd_ostream &OS) {
auto ReaderOrErr = InstrProfReader::create(Filename);
std::vector<uint32_t> Cutoffs = std::move(DetailedSummaryCutoffs);
if (ShowDetailedSummary && Cutoffs.empty()) {
@@ -709,6 +795,11 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
OS << ":ir\n";
for (const auto &Func : *Reader) {
+ if (Reader->isIRLevelProfile()) {
+ bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
+ if (FuncIsCS != ShowCS)
+ continue;
+ }
bool Show =
ShowAllFunctions || (!ShowFunction.empty() &&
Func.Name.find(ShowFunction) != Func.Name.npos);
@@ -900,6 +991,8 @@ static int show_main(int argc, const char *argv[]) {
cl::value_desc("800000,901000,999999"));
cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
cl::desc("Details for every function"));
+ cl::opt<bool> ShowCS("showcs", cl::init(false),
+ cl::desc("Show context sensitive counts"));
cl::opt<std::string> ShowFunction("function",
cl::desc("Details for matching functions"));
@@ -927,6 +1020,12 @@ static int show_main(int argc, const char *argv[]) {
if (OutputFilename.empty())
OutputFilename = "-";
+ if (!Filename.compare(OutputFilename)) {
+ errs() << sys::path::filename(argv[0])
+ << ": Input file name cannot be the same as the output file name!\n";
+ return 1;
+ }
+
std::error_code EC;
raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text);
if (EC)
@@ -935,14 +1034,12 @@ static int show_main(int argc, const char *argv[]) {
if (ShowAllFunctions && !ShowFunction.empty())
WithColor::warning() << "-function argument ignored: showing all functions\n";
- std::vector<uint32_t> Cutoffs(DetailedSummaryCutoffs.begin(),
- DetailedSummaryCutoffs.end());
if (ProfileKind == instr)
return showInstrProfile(Filename, ShowCounts, TopNFunctions,
ShowIndirectCallTargets, ShowMemOPSizes,
ShowDetailedSummary, DetailedSummaryCutoffs,
- ShowAllFunctions, ValueCutoff, OnlyListBelow,
- ShowFunction, TextFormat, OS);
+ ShowAllFunctions, ShowCS, ValueCutoff,
+ OnlyListBelow, ShowFunction, TextFormat, OS);
else
return showSampleProfile(Filename, ShowCounts, ShowAllFunctions,
ShowFunction, OS);
@@ -959,6 +1056,8 @@ int main(int argc, const char *argv[]) {
func = merge_main;
else if (strcmp(argv[1], "show") == 0)
func = show_main;
+ else if (strcmp(argv[1], "overlap") == 0)
+ func = overlap_main;
if (func) {
std::string Invocation(ProgName.str() + " " + argv[1]);
@@ -973,7 +1072,7 @@ int main(int argc, const char *argv[]) {
<< "USAGE: " << ProgName << " <command> [args...]\n"
<< "USAGE: " << ProgName << " <command> -help\n\n"
<< "See each individual command --help for more details.\n"
- << "Available commands: merge, show\n";
+ << "Available commands: merge, show, overlap\n";
return 0;
}
}
@@ -983,6 +1082,6 @@ int main(int argc, const char *argv[]) {
else
errs() << ProgName << ": Unknown command!\n";
- errs() << "USAGE: " << ProgName << " <merge|show> [args...]\n";
+ errs() << "USAGE: " << ProgName << " <merge|show|overlap> [args...]\n";
return 1;
}
diff --git a/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h b/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h
index 51128f113c4c..11f9d6166a59 100644
--- a/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h
+++ b/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h
@@ -1,9 +1,8 @@
//===--- ARMEHABIPrinter.h - ARM EHABI Unwind Information Printer ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -366,6 +365,8 @@ template <typename ET>
ErrorOr<StringRef>
PrinterContext<ET>::FunctionAtAddress(unsigned Section,
uint64_t Address) const {
+ if (!Symtab)
+ return readobj_error::unknown_symbol;
auto StrTableOrErr = ELF->getStringTableForSymtab(*Symtab);
if (!StrTableOrErr)
error(StrTableOrErr.takeError());
@@ -551,13 +552,15 @@ void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex,
const Elf_Shdr *EHT =
FindExceptionTable(SectionIndex, Entry * IndexTableEntrySize + 4);
- if (auto Name = ELF->getSectionName(EHT))
- SW.printString("ExceptionHandlingTable", *Name);
+ if (EHT)
+ if (auto Name = ELF->getSectionName(EHT))
+ SW.printString("ExceptionHandlingTable", *Name);
uint64_t TableEntryOffset = PREL31(Word1, IT->sh_addr);
SW.printHex("TableEntryOffset", TableEntryOffset);
- PrintExceptionTable(IT, EHT, TableEntryOffset);
+ if (EHT)
+ PrintExceptionTable(IT, EHT, TableEntryOffset);
}
}
}
diff --git a/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
index 4b823b816c35..4de14e2e78d5 100644
--- a/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
+++ b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
@@ -1,9 +1,8 @@
//===-- ARMWinEHPrinter.cpp - Windows on ARM EH Data Printer ----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -1095,17 +1094,17 @@ void Decoder::dumpProcedureData(const COFFObjectFile &COFF,
break;
}
-std::error_code Decoder::dumpProcedureData(const COFFObjectFile &COFF) {
+Error Decoder::dumpProcedureData(const COFFObjectFile &COFF) {
for (const auto &Section : COFF.sections()) {
- StringRef SectionName;
- if (std::error_code EC =
- COFF.getSectionName(COFF.getCOFFSection(Section), SectionName))
- return EC;
+ Expected<StringRef> NameOrErr =
+ COFF.getSectionName(COFF.getCOFFSection(Section));
+ if (!NameOrErr)
+ return NameOrErr.takeError();
- if (SectionName.startswith(".pdata"))
+ if (NameOrErr->startswith(".pdata"))
dumpProcedureData(COFF, Section);
}
- return std::error_code();
+ return Error::success();
}
}
}
diff --git a/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.h b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.h
index e271a1e6fe77..5de7062cb1d7 100644
--- a/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.h
+++ b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.h
@@ -1,9 +1,8 @@
//===--- ARMWinEHPrinter.h - Windows on ARM Unwind Information Printer ----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -157,7 +156,7 @@ public:
Decoder(ScopedPrinter &SW, bool isAArch64) : SW(SW),
OS(SW.getOStream()),
isAArch64(isAArch64) {}
- std::error_code dumpProcedureData(const object::COFFObjectFile &COFF);
+ Error dumpProcedureData(const object::COFFObjectFile &COFF);
};
}
}
diff --git a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp
index 3e2626dad118..4c2e39dfa3cc 100644
--- a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -1,9 +1,8 @@
//===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -44,13 +43,14 @@
#include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/WindowsResource.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/LEB128.h"
+#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/Win64EH.h"
#include "llvm/Support/raw_ostream.h"
@@ -81,8 +81,6 @@ public:
void printFileHeaders() override;
void printSectionHeaders() override;
void printRelocations() override;
- void printSymbols() override;
- void printDynamicSymbols() override;
void printUnwindInfo() override;
void printNeededLibraries() override;
@@ -95,12 +93,16 @@ public:
void printCOFFResources() override;
void printCOFFLoadConfig() override;
void printCodeViewDebugInfo() override;
- void
- mergeCodeViewTypes(llvm::codeview::MergingTypeTableBuilder &CVIDs,
- llvm::codeview::MergingTypeTableBuilder &CVTypes) override;
+ void mergeCodeViewTypes(llvm::codeview::MergingTypeTableBuilder &CVIDs,
+ llvm::codeview::MergingTypeTableBuilder &CVTypes,
+ llvm::codeview::GlobalTypeTableBuilder &GlobalCVIDs,
+ llvm::codeview::GlobalTypeTableBuilder &GlobalCVTypes,
+ bool GHash) override;
void printStackMap() const override;
void printAddrsig() override;
private:
+ void printSymbols() override;
+ void printDynamicSymbols() override;
void printSymbol(const SymbolRef &Sym);
void printRelocation(const SectionRef &Section, const RelocationRef &Reloc,
uint64_t Bias = 0);
@@ -568,29 +570,6 @@ static const EnumEntry<uint8_t> FileChecksumKindNames[] = {
LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, SHA256),
};
-static const EnumEntry<COFF::ResourceTypeID> ResourceTypeNames[]{
- {"kRT_CURSOR (ID 1)", COFF::RID_Cursor},
- {"kRT_BITMAP (ID 2)", COFF::RID_Bitmap},
- {"kRT_ICON (ID 3)", COFF::RID_Icon},
- {"kRT_MENU (ID 4)", COFF::RID_Menu},
- {"kRT_DIALOG (ID 5)", COFF::RID_Dialog},
- {"kRT_STRING (ID 6)", COFF::RID_String},
- {"kRT_FONTDIR (ID 7)", COFF::RID_FontDir},
- {"kRT_FONT (ID 8)", COFF::RID_Font},
- {"kRT_ACCELERATOR (ID 9)", COFF::RID_Accelerator},
- {"kRT_RCDATA (ID 10)", COFF::RID_RCData},
- {"kRT_MESSAGETABLE (ID 11)", COFF::RID_MessageTable},
- {"kRT_GROUP_CURSOR (ID 12)", COFF::RID_Group_Cursor},
- {"kRT_GROUP_ICON (ID 14)", COFF::RID_Group_Icon},
- {"kRT_VERSION (ID 16)", COFF::RID_Version},
- {"kRT_DLGINCLUDE (ID 17)", COFF::RID_DLGInclude},
- {"kRT_PLUGPLAY (ID 19)", COFF::RID_PlugPlay},
- {"kRT_VXD (ID 20)", COFF::RID_VXD},
- {"kRT_ANICURSOR (ID 21)", COFF::RID_AniCursor},
- {"kRT_ANIICON (ID 22)", COFF::RID_AniIcon},
- {"kRT_HTML (ID 23)", COFF::RID_HTML},
- {"kRT_MANIFEST (ID 24)", COFF::RID_Manifest}};
-
template <typename T>
static std::error_code getSymbolAuxData(const COFFObjectFile *Obj,
COFFSymbolRef Symbol,
@@ -613,11 +592,14 @@ void COFFDumper::cacheRelocations() {
RelocMap[Section].push_back(Reloc);
// Sort relocations by address.
- llvm::sort(RelocMap[Section], relocAddressLess);
+ llvm::sort(RelocMap[Section], [](RelocationRef L, RelocationRef R) {
+ return L.getOffset() < R.getOffset();
+ });
}
}
-void COFFDumper::printDataDirectory(uint32_t Index, const std::string &FieldName) {
+void COFFDumper::printDataDirectory(uint32_t Index,
+ const std::string &FieldName) {
const data_directory *Data;
if (Obj->getDataDirectory(Index, Data))
return;
@@ -951,8 +933,7 @@ void COFFDumper::initializeFileAndStringTables(BinaryStreamReader &Reader) {
void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
const SectionRef &Section) {
- StringRef SectionContents;
- error(Section.getContents(SectionContents));
+ StringRef SectionContents = unwrapOrError(Section.getContents());
StringRef Data = SectionContents;
SmallVector<StringRef, 10> FunctionNames;
@@ -980,6 +961,11 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
error(consume(Data, SubSectionSize));
ListScope S(W, "Subsection");
+ // Dump the subsection as normal even if the ignore bit is set.
+ if (SubType & SubsectionIgnoreFlag) {
+ W.printHex("IgnoredSubsectionKind", SubType);
+ SubType &= ~SubsectionIgnoreFlag;
+ }
W.printEnum("SubSectionType", SubType, makeArrayRef(SubSectionTypes));
W.printHex("SubSectionSize", SubSectionSize);
@@ -1228,13 +1214,15 @@ void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) {
}
void COFFDumper::mergeCodeViewTypes(MergingTypeTableBuilder &CVIDs,
- MergingTypeTableBuilder &CVTypes) {
+ MergingTypeTableBuilder &CVTypes,
+ GlobalTypeTableBuilder &GlobalCVIDs,
+ GlobalTypeTableBuilder &GlobalCVTypes,
+ bool GHash) {
for (const SectionRef &S : Obj->sections()) {
StringRef SectionName;
error(S.getName(SectionName));
if (SectionName == ".debug$T") {
- StringRef Data;
- error(S.getContents(Data));
+ StringRef Data = unwrapOrError(S.getContents());
uint32_t Magic;
error(consume(Data, Magic));
if (Magic != 4)
@@ -1249,9 +1237,18 @@ void COFFDumper::mergeCodeViewTypes(MergingTypeTableBuilder &CVIDs,
}
SmallVector<TypeIndex, 128> SourceToDest;
Optional<uint32_t> PCHSignature;
- if (auto EC = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, Types,
- PCHSignature))
- return error(std::move(EC));
+ if (GHash) {
+ std::vector<GloballyHashedType> Hashes =
+ GloballyHashedType::hashTypes(Types);
+ if (auto EC =
+ mergeTypeAndIdRecords(GlobalCVIDs, GlobalCVTypes, SourceToDest,
+ Types, Hashes, PCHSignature))
+ return error(std::move(EC));
+ } else {
+ if (auto EC = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, Types,
+ PCHSignature))
+ return error(std::move(EC));
+ }
}
}
}
@@ -1261,8 +1258,7 @@ void COFFDumper::printCodeViewTypeSection(StringRef SectionName,
ListScope D(W, "CodeViewTypes");
W.printNumber("Section", SectionName, Obj->getSectionID(Section));
- StringRef Data;
- error(Section.getContents(Data));
+ StringRef Data = unwrapOrError(Section.getContents());
if (opts::CodeViewSubsectionBytes)
W.printBinaryBlock("Data", Data);
@@ -1322,9 +1318,7 @@ void COFFDumper::printSectionHeaders() {
if (opts::SectionData &&
!(Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)) {
- StringRef Data;
- error(Sec.getContents(Data));
-
+ StringRef Data = unwrapOrError(Sec.getContents());
W.printBinaryBlock("SectionData", Data);
}
}
@@ -1398,15 +1392,11 @@ void COFFDumper::printSymbols() {
void COFFDumper::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); }
-static ErrorOr<StringRef>
+static Expected<StringRef>
getSectionName(const llvm::object::COFFObjectFile *Obj, int32_t SectionNumber,
const coff_section *Section) {
- if (Section) {
- StringRef SectionName;
- if (std::error_code EC = Obj->getSectionName(Section, SectionName))
- return EC;
- return SectionName;
- }
+ if (Section)
+ return Obj->getSectionName(Section);
if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
return StringRef("IMAGE_SYM_DEBUG");
if (SectionNumber == llvm::COFF::IMAGE_SYM_ABSOLUTE)
@@ -1431,11 +1421,10 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
if (Obj->getSymbolName(Symbol, SymbolName))
SymbolName = "";
- StringRef SectionName = "";
- ErrorOr<StringRef> Res =
- getSectionName(Obj, Symbol.getSectionNumber(), Section);
- if (Res)
- SectionName = *Res;
+ StringRef SectionName;
+ if (Expected<StringRef> NameOrErr =
+ getSectionName(Obj, Symbol.getSectionNumber(), Section))
+ SectionName = *NameOrErr;
W.printString("Name", SymbolName);
W.printNumber("Value", Symbol.getValue());
@@ -1503,16 +1492,12 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
&& Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
const coff_section *Assoc;
StringRef AssocName = "";
- std::error_code EC = Obj->getSection(AuxNumber, Assoc);
- ErrorOr<StringRef> Res = getSectionName(Obj, AuxNumber, Assoc);
- if (Res)
- AssocName = *Res;
- if (!EC)
- EC = Res.getError();
- if (EC) {
- AssocName = "";
+ if (std::error_code EC = Obj->getSection(AuxNumber, Assoc))
error(EC);
- }
+ Expected<StringRef> Res = getSectionName(Obj, AuxNumber, Assoc);
+ if (!Res)
+ error(Res.takeError());
+ AssocName = *Res;
W.printNumber("AssocSection", AssocName, AuxNumber);
}
@@ -1559,7 +1544,8 @@ void COFFDumper::printUnwindInfo() {
case COFF::IMAGE_FILE_MACHINE_ARMNT: {
ARM::WinEH::Decoder Decoder(W, Obj->getMachine() ==
COFF::IMAGE_FILE_MACHINE_ARM64);
- Decoder.dumpProcedureData(*Obj);
+ // TODO Propagate the error.
+ consumeError(Decoder.dumpProcedureData(*Obj));
break;
}
default:
@@ -1581,10 +1567,10 @@ void COFFDumper::printNeededLibraries() {
Libs.push_back(Name);
}
- std::stable_sort(Libs.begin(), Libs.end());
+ llvm::stable_sort(Libs);
for (const auto &L : Libs) {
- outs() << " " << L << "\n";
+ W.startLine() << L << "\n";
}
}
@@ -1674,15 +1660,13 @@ void COFFDumper::printCOFFExports() {
void COFFDumper::printCOFFDirectives() {
for (const SectionRef &Section : Obj->sections()) {
- StringRef Contents;
StringRef Name;
error(Section.getName(Name));
if (Name != ".drectve")
continue;
- error(Section.getContents(Contents));
-
+ StringRef Contents = unwrapOrError(Section.getContents());
W.printString("Directive(s)", Contents);
}
}
@@ -1721,8 +1705,7 @@ void COFFDumper::printCOFFResources() {
if (!Name.startswith(".rsrc"))
continue;
- StringRef Ref;
- error(S.getContents(Ref));
+ StringRef Ref = unwrapOrError(S.getContents());
if ((Name == ".rsrc") || (Name == ".rsrc$01")) {
ResourceSectionRef RSF(Ref);
@@ -1777,7 +1760,8 @@ void COFFDumper::printResourceDirectoryTable(
SmallString<20> IDStr;
raw_svector_ostream OS(IDStr);
if (i < Table.NumberOfNameEntries) {
- ArrayRef<UTF16> RawEntryNameString = unwrapOrError(RSF.getEntryNameString(Entry));
+ ArrayRef<UTF16> RawEntryNameString =
+ unwrapOrError(RSF.getEntryNameString(Entry));
std::vector<UTF16> EndianCorrectedNameString;
if (llvm::sys::IsBigEndianHost) {
EndianCorrectedNameString.resize(RawEntryNameString.size() + 1);
@@ -1793,9 +1777,8 @@ void COFFDumper::printResourceDirectoryTable(
OS << EntryNameString;
} else {
if (Level == "Type") {
- ScopedPrinter Printer(OS);
- Printer.printEnum("", Entry.Identifier.ID,
- makeArrayRef(ResourceTypeNames));
+ OS << ": ";
+ printResourceTypeName(Entry.Identifier.ID, OS);
IDStr = IDStr.slice(0, IDStr.find_first_of(")", 0) + 1);
} else {
OS << ": (ID " << Entry.Identifier.ID << ")";
@@ -1848,18 +1831,16 @@ void COFFDumper::printStackMap() const {
if (StackMapSection == object::SectionRef())
return;
- StringRef StackMapContents;
- StackMapSection.getContents(StackMapContents);
- ArrayRef<uint8_t> StackMapContentsArray(
- reinterpret_cast<const uint8_t*>(StackMapContents.data()),
- StackMapContents.size());
+ StringRef StackMapContents = unwrapOrError(StackMapSection.getContents());
+ ArrayRef<uint8_t> StackMapContentsArray =
+ arrayRefFromStringRef(StackMapContents);
if (Obj->isLittleEndian())
prettyPrintStackMap(
- W, StackMapV2Parser<support::little>(StackMapContentsArray));
+ W, StackMapParser<support::little>(StackMapContentsArray));
else
- prettyPrintStackMap(W,
- StackMapV2Parser<support::big>(StackMapContentsArray));
+ prettyPrintStackMap(
+ W, StackMapParser<support::big>(StackMapContentsArray));
}
void COFFDumper::printAddrsig() {
@@ -1876,15 +1857,13 @@ void COFFDumper::printAddrsig() {
if (AddrsigSection == object::SectionRef())
return;
- StringRef AddrsigContents;
- AddrsigSection.getContents(AddrsigContents);
- ArrayRef<uint8_t> AddrsigContentsArray(
- reinterpret_cast<const uint8_t*>(AddrsigContents.data()),
- AddrsigContents.size());
+ StringRef AddrsigContents = unwrapOrError(AddrsigSection.getContents());
+ ArrayRef<uint8_t> AddrsigContentsArray(AddrsigContents.bytes_begin(),
+ AddrsigContents.size());
ListScope L(W, "Addrsig");
- auto *Cur = reinterpret_cast<const uint8_t *>(AddrsigContents.begin());
- auto *End = reinterpret_cast<const uint8_t *>(AddrsigContents.end());
+ const uint8_t *Cur = AddrsigContents.bytes_begin();
+ const uint8_t *End = AddrsigContents.bytes_end();
while (Cur != End) {
unsigned Size;
const char *Err;
@@ -1905,16 +1884,10 @@ void COFFDumper::printAddrsig() {
}
}
-void llvm::dumpCodeViewMergedTypes(
- ScopedPrinter &Writer, llvm::codeview::MergingTypeTableBuilder &IDTable,
- llvm::codeview::MergingTypeTableBuilder &CVTypes) {
- // Flatten it first, then run our dumper on it.
- SmallString<0> TypeBuf;
- CVTypes.ForEachRecord([&](TypeIndex TI, const CVType &Record) {
- TypeBuf.append(Record.RecordData.begin(), Record.RecordData.end());
- });
-
- TypeTableCollection TpiTypes(CVTypes.records());
+void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
+ ArrayRef<ArrayRef<uint8_t>> IpiRecords,
+ ArrayRef<ArrayRef<uint8_t>> TpiRecords) {
+ TypeTableCollection TpiTypes(TpiRecords);
{
ListScope S(Writer, "MergedTypeStream");
TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
@@ -1924,7 +1897,7 @@ void llvm::dumpCodeViewMergedTypes(
// Flatten the id stream and print it next. The ID stream refers to names from
// the type stream.
- TypeTableCollection IpiTypes(IDTable.records());
+ TypeTableCollection IpiTypes(IpiRecords);
{
ListScope S(Writer, "MergedIDStream");
TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
diff --git a/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp
index 18010c34f0f3..c9d5e82263db 100644
--- a/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp
+++ b/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp
@@ -1,9 +1,8 @@
//===-- COFFImportDumper.cpp - COFF import library dumper -------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -51,7 +50,7 @@ void dumpCOFFImportFile(const COFFImportFile *File, ScopedPrinter &Writer) {
for (const object::BasicSymbolRef &Sym : File->symbols()) {
raw_ostream &OS = Writer.startLine();
OS << "Symbol: ";
- Sym.printName(OS);
+ cantFail(Sym.printName(OS));
OS << "\n";
}
}
diff --git a/contrib/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h b/contrib/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
index d91d764c4d0a..7055510ef2f2 100644
--- a/contrib/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
+++ b/contrib/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
@@ -1,9 +1,8 @@
//===--- DwarfCFIEHPrinter.h - DWARF-based Unwind Information Printer -----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp
index 93254717e921..4e1cb7d544e7 100644
--- a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -1,9 +1,8 @@
//===- ELFDumper.cpp - ELF-specific dumper --------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -20,6 +19,7 @@
#include "llvm-readobj.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/STLExtras.h"
@@ -30,6 +30,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h"
#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Demangle/Demangle.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ELFTypes.h"
@@ -66,13 +67,14 @@ using namespace llvm;
using namespace llvm::object;
using namespace ELF;
-#define LLVM_READOBJ_ENUM_CASE(ns, enum) \
- case ns::enum: return #enum;
+#define LLVM_READOBJ_ENUM_CASE(ns, enum) \
+ case ns::enum: \
+ return #enum;
-#define ENUM_ENT(enum, altName) \
+#define ENUM_ENT(enum, altName) \
{ #enum, altName, ELF::enum }
-#define ENUM_ENT_1(enum) \
+#define ENUM_ENT_1(enum) \
{ #enum, #enum, ELF::enum }
#define LLVM_READOBJ_PHDR_ENUM(ns, enum) \
@@ -132,14 +134,17 @@ struct DynRegionInfo {
const Type *Start = reinterpret_cast<const Type *>(Addr);
if (!Start)
return {Start, Start};
- if (EntSize != sizeof(Type) || Size % EntSize)
- reportError("Invalid entity size");
+ if (EntSize != sizeof(Type) || Size % EntSize) {
+ // TODO: Add a section index to this warning.
+ reportWarning("invalid section size (" + Twine(Size) +
+ ") or entity size (" + Twine(EntSize) + ")");
+ return {Start, Start};
+ }
return {Start, Start + (Size / EntSize)};
}
};
-template<typename ELFT>
-class ELFDumper : public ObjDumper {
+template <typename ELFT> class ELFDumper : public ObjDumper {
public:
ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, ScopedPrinter &Writer);
@@ -147,13 +152,14 @@ public:
void printSectionHeaders() override;
void printRelocations() override;
void printDynamicRelocations() override;
- void printSymbols() override;
- void printDynamicSymbols() override;
+ void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override;
+ void printHashSymbols() override;
void printUnwindInfo() override;
void printDynamicTable() override;
void printNeededLibraries() override;
- void printProgramHeaders() override;
+ void printProgramHeaders(bool PrintProgramHeaders,
+ cl::boolOrDefault PrintSectionMapping) override;
void printHashTable() override;
void printGnuHashTable() override;
void printLoadName() override;
@@ -177,6 +183,8 @@ public:
void printELFLinkerOptions() override;
+ const object::ELFObjectFile<ELFT> *getElfObject() const { return ObjF; };
+
private:
std::unique_ptr<DumpStyle<ELFT>> ELFDumperStyle;
@@ -185,24 +193,25 @@ private:
DynRegionInfo checkDRI(DynRegionInfo DRI) {
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
if (DRI.Addr < Obj->base() ||
- (const uint8_t *)DRI.Addr + DRI.Size > Obj->base() + Obj->getBufSize())
+ reinterpret_cast<const uint8_t *>(DRI.Addr) + DRI.Size >
+ Obj->base() + Obj->getBufSize())
error(llvm::object::object_error::parse_failed);
return DRI;
}
DynRegionInfo createDRIFrom(const Elf_Phdr *P, uintX_t EntSize) {
- return checkDRI({ObjF->getELFFile()->base() + P->p_offset, P->p_filesz, EntSize});
+ return checkDRI(
+ {ObjF->getELFFile()->base() + P->p_offset, P->p_filesz, EntSize});
}
DynRegionInfo createDRIFrom(const Elf_Shdr *S) {
- return checkDRI({ObjF->getELFFile()->base() + S->sh_offset, S->sh_size, S->sh_entsize});
+ return checkDRI(
+ {ObjF->getELFFile()->base() + S->sh_offset, S->sh_size, S->sh_entsize});
}
- void parseDynamicTable(ArrayRef<const Elf_Phdr *> LoadSegments);
+ void loadDynamicTable(const ELFFile<ELFT> *Obj);
+ void parseDynamicTable();
- void printValue(uint64_t Type, uint64_t Value);
-
- StringRef getDynamicString(uint64_t Offset) const;
StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb,
bool &IsDefault) const;
void LoadVersionMap() const;
@@ -217,7 +226,7 @@ private:
DynRegionInfo DynSymRegion;
DynRegionInfo DynamicTable;
StringRef DynamicStringTable;
- StringRef SOName;
+ StringRef SOName = "<Not found>";
const Elf_Hash *HashTable = nullptr;
const Elf_GnuHash *GnuHashTable = nullptr;
const Elf_Shdr *DotSymtabSec = nullptr;
@@ -226,9 +235,9 @@ private:
StringRef DynSymtabName;
ArrayRef<Elf_Word> ShndxTable;
- const Elf_Shdr *dot_gnu_version_sec = nullptr; // .gnu.version
- const Elf_Shdr *dot_gnu_version_r_sec = nullptr; // .gnu.version_r
- const Elf_Shdr *dot_gnu_version_d_sec = nullptr; // .gnu.version_d
+ const Elf_Shdr *SymbolVersionSection = nullptr; // .gnu.version
+ const Elf_Shdr *SymbolVersionNeedSection = nullptr; // .gnu.version_r
+ const Elf_Shdr *SymbolVersionDefSection = nullptr; // .gnu.version_d
// Records for each version index the corresponding Verdef or Vernaux entry.
// This is filled the first time LoadVersionMap() is called.
@@ -256,7 +265,18 @@ private:
public:
Elf_Dyn_Range dynamic_table() const {
- return DynamicTable.getAsArrayRef<Elf_Dyn>();
+ // A valid .dynamic section contains an array of entries terminated
+ // with a DT_NULL entry. However, sometimes the section content may
+ // continue past the DT_NULL entry, so to dump the section correctly,
+ // we first find the end of the entries by iterating over them.
+ Elf_Dyn_Range Table = DynamicTable.getAsArrayRef<Elf_Dyn>();
+
+ size_t Size = 0;
+ while (Size < Table.size())
+ if (Table[Size++].getTag() == DT_NULL)
+ break;
+
+ return Table.slice(0, Size);
}
Elf_Sym_Range dynamic_symbols() const {
@@ -271,9 +291,14 @@ public:
void getSectionNameIndex(const Elf_Sym *Symbol, const Elf_Sym *FirstSym,
StringRef &SectionName,
unsigned &SectionIndex) const;
- StringRef getStaticSymbolName(uint32_t Index) const;
+ std::string getStaticSymbolName(uint32_t Index) const;
+ StringRef getSymbolVersionByIndex(StringRef StrTab,
+ uint32_t VersionSymbolIndex,
+ bool &IsDefault) const;
void printSymbolsHelper(bool IsDynamic) const;
+ void printDynamicEntry(raw_ostream &OS, uint64_t Type, uint64_t Value) const;
+
const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; }
const Elf_Shdr *getDotCGProfileSec() const { return DotCGProfileSec; }
const Elf_Shdr *getDotAddrsigSec() const { return DotAddrsigSec; }
@@ -283,6 +308,7 @@ public:
const DynRegionInfo &getDynRelaRegion() const { return DynRelaRegion; }
const DynRegionInfo &getDynRelrRegion() const { return DynRelrRegion; }
const DynRegionInfo &getDynPLTRelRegion() const { return DynPLTRelRegion; }
+ const DynRegionInfo &getDynamicTableRegion() const { return DynamicTable; }
const Elf_Hash *getHashTable() const { return HashTable; }
const Elf_GnuHash *getGnuHashTable() const { return GnuHashTable; }
};
@@ -328,15 +354,25 @@ public:
virtual void printGroupSections(const ELFFile<ELFT> *Obj) = 0;
virtual void printRelocations(const ELFFile<ELFT> *Obj) = 0;
virtual void printSectionHeaders(const ELFFile<ELFT> *Obj) = 0;
- virtual void printSymbols(const ELFFile<ELFT> *Obj) = 0;
- virtual void printDynamicSymbols(const ELFFile<ELFT> *Obj) = 0;
+ virtual void printSymbols(const ELFFile<ELFT> *Obj, bool PrintSymbols,
+ bool PrintDynamicSymbols) = 0;
+ virtual void printHashSymbols(const ELFFile<ELFT> *Obj) {}
+ virtual void printDynamic(const ELFFile<ELFT> *Obj) {}
virtual void printDynamicRelocations(const ELFFile<ELFT> *Obj) = 0;
- virtual void printSymtabMessage(const ELFFile<ELFT> *obj, StringRef Name,
+ virtual void printSymtabMessage(const ELFFile<ELFT> *Obj, StringRef Name,
size_t Offset) {}
virtual void printSymbol(const ELFFile<ELFT> *Obj, const Elf_Sym *Symbol,
const Elf_Sym *FirstSym, StringRef StrTable,
bool IsDynamic) = 0;
- virtual void printProgramHeaders(const ELFFile<ELFT> *Obj) = 0;
+ virtual void printProgramHeaders(const ELFFile<ELFT> *Obj,
+ bool PrintProgramHeaders,
+ cl::boolOrDefault PrintSectionMapping) = 0;
+ virtual void printVersionSymbolSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) = 0;
+ virtual void printVersionDefinitionSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) = 0;
+ virtual void printVersionDependencySection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) = 0;
virtual void printHashHistogram(const ELFFile<ELFT> *Obj) = 0;
virtual void printCGProfile(const ELFFile<ELFT> *Obj) = 0;
virtual void printAddrsig(const ELFFile<ELFT> *Obj) = 0;
@@ -351,24 +387,36 @@ private:
};
template <typename ELFT> class GNUStyle : public DumpStyle<ELFT> {
- formatted_raw_ostream OS;
+ formatted_raw_ostream &OS;
public:
TYPEDEF_ELF_TYPES(ELFT)
GNUStyle(ScopedPrinter &W, ELFDumper<ELFT> *Dumper)
- : DumpStyle<ELFT>(Dumper), OS(W.getOStream()) {}
+ : DumpStyle<ELFT>(Dumper),
+ OS(static_cast<formatted_raw_ostream&>(W.getOStream())) {
+ assert (&W.getOStream() == &llvm::fouts());
+ }
void printFileHeaders(const ELFO *Obj) override;
void printGroupSections(const ELFFile<ELFT> *Obj) override;
void printRelocations(const ELFO *Obj) override;
void printSectionHeaders(const ELFO *Obj) override;
- void printSymbols(const ELFO *Obj) override;
- void printDynamicSymbols(const ELFO *Obj) override;
+ void printSymbols(const ELFO *Obj, bool PrintSymbols,
+ bool PrintDynamicSymbols) override;
+ void printHashSymbols(const ELFO *Obj) override;
+ void printDynamic(const ELFFile<ELFT> *Obj) override;
void printDynamicRelocations(const ELFO *Obj) override;
void printSymtabMessage(const ELFO *Obj, StringRef Name,
size_t Offset) override;
- void printProgramHeaders(const ELFO *Obj) override;
+ void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders,
+ cl::boolOrDefault PrintSectionMapping) override;
+ void printVersionSymbolSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) override;
+ void printVersionDefinitionSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) override;
+ void printVersionDependencySection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) override;
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
void printCGProfile(const ELFFile<ELFT> *Obj) override;
void printAddrsig(const ELFFile<ELFT> *Obj) override;
@@ -379,11 +427,11 @@ public:
private:
struct Field {
- StringRef Str;
+ std::string Str;
unsigned Column;
Field(StringRef S, unsigned Col) : Str(S), Column(Col) {}
- Field(unsigned Col) : Str(""), Column(Col) {}
+ Field(unsigned Col) : Column(Col) {}
};
template <typename T, typename TEnum>
@@ -433,6 +481,8 @@ private:
void printRelocHeader(unsigned SType);
void printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab,
const Elf_Rela &R, bool IsRela);
+ void printRelocation(const ELFO *Obj, const Elf_Sym *Sym,
+ StringRef SymbolName, const Elf_Rela &R, bool IsRela);
void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
StringRef StrTable, bool IsDynamic) override;
std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol,
@@ -442,6 +492,8 @@ private:
bool checkoffsets(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
bool checkVMA(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
bool checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
+ void printProgramHeaders(const ELFO *Obj);
+ void printSectionMapping(const ELFO *Obj);
};
template <typename ELFT> class LLVMStyle : public DumpStyle<ELFT> {
@@ -456,10 +508,18 @@ public:
void printRelocations(const ELFO *Obj) override;
void printRelocations(const Elf_Shdr *Sec, const ELFO *Obj);
void printSectionHeaders(const ELFO *Obj) override;
- void printSymbols(const ELFO *Obj) override;
- void printDynamicSymbols(const ELFO *Obj) override;
+ void printSymbols(const ELFO *Obj, bool PrintSymbols,
+ bool PrintDynamicSymbols) override;
+ void printDynamic(const ELFFile<ELFT> *Obj) override;
void printDynamicRelocations(const ELFO *Obj) override;
- void printProgramHeaders(const ELFO *Obj) override;
+ void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders,
+ cl::boolOrDefault PrintSectionMapping) override;
+ void printVersionSymbolSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) override;
+ void printVersionDefinitionSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) override;
+ void printVersionDependencySection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) override;
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
void printCGProfile(const ELFFile<ELFT> *Obj) override;
void printAddrsig(const ELFFile<ELFT> *Obj) override;
@@ -471,8 +531,12 @@ public:
private:
void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab);
void printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel);
+ void printSymbols(const ELFO *Obj);
+ void printDynamicSymbols(const ELFO *Obj);
void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
StringRef StrTable, bool IsDynamic) override;
+ void printProgramHeaders(const ELFO *Obj);
+ void printSectionMapping(const ELFO *Obj) {}
ScopedPrinter &W;
};
@@ -516,65 +580,71 @@ std::error_code createELFDumper(const object::ObjectFile *Obj,
// Iterate through the versions needed section, and place each Elf_Vernaux
// in the VersionMap according to its index.
template <class ELFT>
-void ELFDumper<ELFT>::LoadVersionNeeds(const Elf_Shdr *sec) const {
- unsigned vn_size = sec->sh_size; // Size of section in bytes
- unsigned vn_count = sec->sh_info; // Number of Verneed entries
- const char *sec_start = (const char *)ObjF->getELFFile()->base() + sec->sh_offset;
- const char *sec_end = sec_start + vn_size;
+void ELFDumper<ELFT>::LoadVersionNeeds(const Elf_Shdr *Sec) const {
+ unsigned VerneedSize = Sec->sh_size; // Size of section in bytes
+ unsigned VerneedEntries = Sec->sh_info; // Number of Verneed entries
+ const uint8_t *VerneedStart = reinterpret_cast<const uint8_t *>(
+ ObjF->getELFFile()->base() + Sec->sh_offset);
+ const uint8_t *VerneedEnd = VerneedStart + VerneedSize;
// The first Verneed entry is at the start of the section.
- const char *p = sec_start;
- for (unsigned i = 0; i < vn_count; i++) {
- if (p + sizeof(Elf_Verneed) > sec_end)
+ const uint8_t *VerneedBuf = VerneedStart;
+ for (unsigned VerneedIndex = 0; VerneedIndex < VerneedEntries;
+ ++VerneedIndex) {
+ if (VerneedBuf + sizeof(Elf_Verneed) > VerneedEnd)
report_fatal_error("Section ended unexpectedly while scanning "
"version needed records.");
- const Elf_Verneed *vn = reinterpret_cast<const Elf_Verneed *>(p);
- if (vn->vn_version != ELF::VER_NEED_CURRENT)
+ const Elf_Verneed *Verneed =
+ reinterpret_cast<const Elf_Verneed *>(VerneedBuf);
+ if (Verneed->vn_version != ELF::VER_NEED_CURRENT)
report_fatal_error("Unexpected verneed version");
// Iterate through the Vernaux entries
- const char *paux = p + vn->vn_aux;
- for (unsigned j = 0; j < vn->vn_cnt; j++) {
- if (paux + sizeof(Elf_Vernaux) > sec_end)
+ const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
+ for (unsigned VernauxIndex = 0; VernauxIndex < Verneed->vn_cnt;
+ ++VernauxIndex) {
+ if (VernauxBuf + sizeof(Elf_Vernaux) > VerneedEnd)
report_fatal_error("Section ended unexpected while scanning auxiliary "
"version needed records.");
- const Elf_Vernaux *vna = reinterpret_cast<const Elf_Vernaux *>(paux);
- size_t index = vna->vna_other & ELF::VERSYM_VERSION;
- if (index >= VersionMap.size())
- VersionMap.resize(index + 1);
- VersionMap[index] = VersionMapEntry(vna);
- paux += vna->vna_next;
+ const Elf_Vernaux *Vernaux =
+ reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
+ size_t Index = Vernaux->vna_other & ELF::VERSYM_VERSION;
+ if (Index >= VersionMap.size())
+ VersionMap.resize(Index + 1);
+ VersionMap[Index] = VersionMapEntry(Vernaux);
+ VernauxBuf += Vernaux->vna_next;
}
- p += vn->vn_next;
+ VerneedBuf += Verneed->vn_next;
}
}
// Iterate through the version definitions, and place each Elf_Verdef
// in the VersionMap according to its index.
template <class ELFT>
-void ELFDumper<ELFT>::LoadVersionDefs(const Elf_Shdr *sec) const {
- unsigned vd_size = sec->sh_size; // Size of section in bytes
- unsigned vd_count = sec->sh_info; // Number of Verdef entries
- const char *sec_start = (const char *)ObjF->getELFFile()->base() + sec->sh_offset;
- const char *sec_end = sec_start + vd_size;
+void ELFDumper<ELFT>::LoadVersionDefs(const Elf_Shdr *Sec) const {
+ unsigned VerdefSize = Sec->sh_size; // Size of section in bytes
+ unsigned VerdefEntries = Sec->sh_info; // Number of Verdef entries
+ const uint8_t *VerdefStart = reinterpret_cast<const uint8_t *>(
+ ObjF->getELFFile()->base() + Sec->sh_offset);
+ const uint8_t *VerdefEnd = VerdefStart + VerdefSize;
// The first Verdef entry is at the start of the section.
- const char *p = sec_start;
- for (unsigned i = 0; i < vd_count; i++) {
- if (p + sizeof(Elf_Verdef) > sec_end)
+ const uint8_t *VerdefBuf = VerdefStart;
+ for (unsigned VerdefIndex = 0; VerdefIndex < VerdefEntries; ++VerdefIndex) {
+ if (VerdefBuf + sizeof(Elf_Verdef) > VerdefEnd)
report_fatal_error("Section ended unexpectedly while scanning "
"version definitions.");
- const Elf_Verdef *vd = reinterpret_cast<const Elf_Verdef *>(p);
- if (vd->vd_version != ELF::VER_DEF_CURRENT)
+ const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf);
+ if (Verdef->vd_version != ELF::VER_DEF_CURRENT)
report_fatal_error("Unexpected verdef version");
- size_t index = vd->vd_ndx & ELF::VERSYM_VERSION;
- if (index >= VersionMap.size())
- VersionMap.resize(index + 1);
- VersionMap[index] = VersionMapEntry(vd);
- p += vd->vd_next;
+ size_t Index = Verdef->vd_ndx & ELF::VERSYM_VERSION;
+ if (Index >= VersionMap.size())
+ VersionMap.resize(Index + 1);
+ VersionMap[Index] = VersionMapEntry(Verdef);
+ VerdefBuf += Verdef->vd_next;
}
}
template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() const {
// If there is no dynamic symtab or version table, there is nothing to do.
- if (!DynSymRegion.Addr || !dot_gnu_version_sec)
+ if (!DynSymRegion.Addr || !SymbolVersionSection)
return;
// Has the VersionMap already been loaded?
@@ -586,243 +656,111 @@ template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() const {
VersionMap.push_back(VersionMapEntry());
VersionMap.push_back(VersionMapEntry());
- if (dot_gnu_version_d_sec)
- LoadVersionDefs(dot_gnu_version_d_sec);
-
- if (dot_gnu_version_r_sec)
- LoadVersionNeeds(dot_gnu_version_r_sec);
-}
-
-template <typename ELFO, class ELFT>
-static void printVersionSymbolSection(ELFDumper<ELFT> *Dumper, const ELFO *Obj,
- const typename ELFO::Elf_Shdr *Sec,
- ScopedPrinter &W) {
- DictScope SS(W, "Version symbols");
- if (!Sec)
- return;
- StringRef Name = unwrapOrError(Obj->getSectionName(Sec));
- W.printNumber("Section Name", Name, Sec->sh_name);
- W.printHex("Address", Sec->sh_addr);
- W.printHex("Offset", Sec->sh_offset);
- W.printNumber("Link", Sec->sh_link);
-
- const uint8_t *P = (const uint8_t *)Obj->base() + Sec->sh_offset;
- StringRef StrTable = Dumper->getDynamicStringTable();
-
- // Same number of entries in the dynamic symbol table (DT_SYMTAB).
- ListScope Syms(W, "Symbols");
- for (const typename ELFO::Elf_Sym &Sym : Dumper->dynamic_symbols()) {
- DictScope S(W, "Symbol");
- std::string FullSymbolName =
- Dumper->getFullSymbolName(&Sym, StrTable, true /* IsDynamic */);
- W.printNumber("Version", *P);
- W.printString("Name", FullSymbolName);
- P += sizeof(typename ELFO::Elf_Half);
- }
-}
-
-static const EnumEntry<unsigned> SymVersionFlags[] = {
- {"Base", "BASE", VER_FLG_BASE},
- {"Weak", "WEAK", VER_FLG_WEAK},
- {"Info", "INFO", VER_FLG_INFO}};
-
-template <typename ELFO, class ELFT>
-static void printVersionDefinitionSection(ELFDumper<ELFT> *Dumper,
- const ELFO *Obj,
- const typename ELFO::Elf_Shdr *Sec,
- ScopedPrinter &W) {
- using VerDef = typename ELFO::Elf_Verdef;
- using VerdAux = typename ELFO::Elf_Verdaux;
-
- DictScope SD(W, "SHT_GNU_verdef");
- if (!Sec)
- return;
-
- // The number of entries in the section SHT_GNU_verdef
- // is determined by DT_VERDEFNUM tag.
- unsigned VerDefsNum = 0;
- for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) {
- if (Dyn.d_tag == DT_VERDEFNUM) {
- VerDefsNum = Dyn.d_un.d_val;
- break;
- }
- }
-
- const uint8_t *SecStartAddress =
- (const uint8_t *)Obj->base() + Sec->sh_offset;
- const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size;
- const uint8_t *P = SecStartAddress;
- const typename ELFO::Elf_Shdr *StrTab =
- unwrapOrError(Obj->getSection(Sec->sh_link));
-
- while (VerDefsNum--) {
- if (P + sizeof(VerDef) > SecEndAddress)
- report_fatal_error("invalid offset in the section");
-
- auto *VD = reinterpret_cast<const VerDef *>(P);
- DictScope Def(W, "Definition");
- W.printNumber("Version", VD->vd_version);
- W.printEnum("Flags", VD->vd_flags, makeArrayRef(SymVersionFlags));
- W.printNumber("Index", VD->vd_ndx);
- W.printNumber("Hash", VD->vd_hash);
- W.printString("Name",
- StringRef((const char *)(Obj->base() + StrTab->sh_offset +
- VD->getAux()->vda_name)));
- if (!VD->vd_cnt)
- report_fatal_error("at least one definition string must exist");
- if (VD->vd_cnt > 2)
- report_fatal_error("more than one predecessor is not expected");
-
- if (VD->vd_cnt == 2) {
- const uint8_t *PAux = P + VD->vd_aux + VD->getAux()->vda_next;
- const VerdAux *Aux = reinterpret_cast<const VerdAux *>(PAux);
- W.printString("Predecessor",
- StringRef((const char *)(Obj->base() + StrTab->sh_offset +
- Aux->vda_name)));
- }
-
- P += VD->vd_next;
- }
-}
-
-template <typename ELFO, class ELFT>
-static void printVersionDependencySection(ELFDumper<ELFT> *Dumper,
- const ELFO *Obj,
- const typename ELFO::Elf_Shdr *Sec,
- ScopedPrinter &W) {
- using VerNeed = typename ELFO::Elf_Verneed;
- using VernAux = typename ELFO::Elf_Vernaux;
-
- DictScope SD(W, "SHT_GNU_verneed");
- if (!Sec)
- return;
-
- unsigned VerNeedNum = 0;
- for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) {
- if (Dyn.d_tag == DT_VERNEEDNUM) {
- VerNeedNum = Dyn.d_un.d_val;
- break;
- }
- }
-
- const uint8_t *SecData = (const uint8_t *)Obj->base() + Sec->sh_offset;
- const typename ELFO::Elf_Shdr *StrTab =
- unwrapOrError(Obj->getSection(Sec->sh_link));
-
- const uint8_t *P = SecData;
- for (unsigned I = 0; I < VerNeedNum; ++I) {
- const VerNeed *Need = reinterpret_cast<const VerNeed *>(P);
- DictScope Entry(W, "Dependency");
- W.printNumber("Version", Need->vn_version);
- W.printNumber("Count", Need->vn_cnt);
- W.printString("FileName",
- StringRef((const char *)(Obj->base() + StrTab->sh_offset +
- Need->vn_file)));
-
- const uint8_t *PAux = P + Need->vn_aux;
- for (unsigned J = 0; J < Need->vn_cnt; ++J) {
- const VernAux *Aux = reinterpret_cast<const VernAux *>(PAux);
- DictScope Entry(W, "Entry");
- W.printNumber("Hash", Aux->vna_hash);
- W.printEnum("Flags", Aux->vna_flags, makeArrayRef(SymVersionFlags));
- W.printNumber("Index", Aux->vna_other);
- W.printString("Name",
- StringRef((const char *)(Obj->base() + StrTab->sh_offset +
- Aux->vna_name)));
- PAux += Aux->vna_next;
- }
- P += Need->vn_next;
- }
-}
-
-template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() {
- // Dump version symbol section.
- printVersionSymbolSection(this, ObjF->getELFFile(), dot_gnu_version_sec, W);
-
- // Dump version definition section.
- printVersionDefinitionSection(this, ObjF->getELFFile(), dot_gnu_version_d_sec, W);
+ if (SymbolVersionDefSection)
+ LoadVersionDefs(SymbolVersionDefSection);
- // Dump version dependency section.
- printVersionDependencySection(this, ObjF->getELFFile(), dot_gnu_version_r_sec, W);
+ if (SymbolVersionNeedSection)
+ LoadVersionNeeds(SymbolVersionNeedSection);
}
template <typename ELFT>
StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab,
- const Elf_Sym *symb,
+ const Elf_Sym *Sym,
bool &IsDefault) const {
// This is a dynamic symbol. Look in the GNU symbol version table.
- if (!dot_gnu_version_sec) {
+ if (!SymbolVersionSection) {
// No version table.
IsDefault = false;
- return StringRef("");
+ return "";
}
// Determine the position in the symbol table of this entry.
- size_t entry_index = (reinterpret_cast<uintptr_t>(symb) -
+ size_t EntryIndex = (reinterpret_cast<uintptr_t>(Sym) -
reinterpret_cast<uintptr_t>(DynSymRegion.Addr)) /
sizeof(Elf_Sym);
- // Get the corresponding version index entry
- const Elf_Versym *vs = unwrapOrError(
- ObjF->getELFFile()->template getEntry<Elf_Versym>(dot_gnu_version_sec, entry_index));
- size_t version_index = vs->vs_index & ELF::VERSYM_VERSION;
+ // Get the corresponding version index entry.
+ const Elf_Versym *Versym =
+ unwrapOrError(ObjF->getELFFile()->template getEntry<Elf_Versym>(
+ SymbolVersionSection, EntryIndex));
+ return this->getSymbolVersionByIndex(StrTab, Versym->vs_index, IsDefault);
+}
+
+static std::string maybeDemangle(StringRef Name) {
+ return opts::Demangle ? demangle(Name) : Name.str();
+}
+
+template <typename ELFT>
+std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
+ const ELFFile<ELFT> *Obj = ObjF->getELFFile();
+ StringRef StrTable =
+ unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec));
+ Elf_Sym_Range Syms = unwrapOrError(Obj->symbols(DotSymtabSec));
+ if (Index >= Syms.size())
+ reportError("Invalid symbol index");
+ const Elf_Sym *Sym = &Syms[Index];
+ return maybeDemangle(unwrapOrError(Sym->getName(StrTable)));
+}
+
+template <typename ELFT>
+StringRef ELFDumper<ELFT>::getSymbolVersionByIndex(StringRef StrTab,
+ uint32_t SymbolVersionIndex,
+ bool &IsDefault) const {
+ size_t VersionIndex = SymbolVersionIndex & VERSYM_VERSION;
// Special markers for unversioned symbols.
- if (version_index == ELF::VER_NDX_LOCAL ||
- version_index == ELF::VER_NDX_GLOBAL) {
+ if (VersionIndex == VER_NDX_LOCAL || VersionIndex == VER_NDX_GLOBAL) {
IsDefault = false;
- return StringRef("");
+ return "";
}
- // Lookup this symbol in the version table
+ // Lookup this symbol in the version table.
LoadVersionMap();
- if (version_index >= VersionMap.size() || VersionMap[version_index].isNull())
+ if (VersionIndex >= VersionMap.size() || VersionMap[VersionIndex].isNull())
reportError("Invalid version entry");
- const VersionMapEntry &entry = VersionMap[version_index];
+ const VersionMapEntry &Entry = VersionMap[VersionIndex];
- // Get the version name string
- size_t name_offset;
- if (entry.isVerdef()) {
+ // Get the version name string.
+ size_t NameOffset;
+ if (Entry.isVerdef()) {
// The first Verdaux entry holds the name.
- name_offset = entry.getVerdef()->getAux()->vda_name;
- IsDefault = !(vs->vs_index & ELF::VERSYM_HIDDEN);
+ NameOffset = Entry.getVerdef()->getAux()->vda_name;
+ IsDefault = !(SymbolVersionIndex & VERSYM_HIDDEN);
} else {
- name_offset = entry.getVernaux()->vna_name;
+ NameOffset = Entry.getVernaux()->vna_name;
IsDefault = false;
}
- if (name_offset >= StrTab.size())
+ if (NameOffset >= StrTab.size())
reportError("Invalid string offset");
- return StringRef(StrTab.data() + name_offset);
-}
-
-template <typename ELFT>
-StringRef ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
- const ELFFile<ELFT> *Obj = ObjF->getELFFile();
- StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec));
- Elf_Sym_Range Syms = unwrapOrError(Obj->symbols(DotSymtabSec));
- if (Index >= Syms.size())
- reportError("Invalid symbol index");
- const Elf_Sym *Sym = &Syms[Index];
- return unwrapOrError(Sym->getName(StrTable));
+ return StrTab.data() + NameOffset;
}
template <typename ELFT>
std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol,
StringRef StrTable,
bool IsDynamic) const {
- StringRef SymbolName = unwrapOrError(Symbol->getName(StrTable));
+ std::string SymbolName =
+ maybeDemangle(unwrapOrError(Symbol->getName(StrTable)));
+
+ if (SymbolName.empty() && Symbol->getType() == ELF::STT_SECTION) {
+ unsigned SectionIndex;
+ StringRef SectionName;
+ Elf_Sym_Range Syms =
+ unwrapOrError(ObjF->getELFFile()->symbols(DotSymtabSec));
+ getSectionNameIndex(Symbol, Syms.begin(), SectionName, SectionIndex);
+ return SectionName;
+ }
+
if (!IsDynamic)
return SymbolName;
- std::string FullSymbolName(SymbolName);
-
bool IsDefault;
StringRef Version = getSymbolVersion(StrTable, &*Symbol, IsDefault);
if (!Version.empty()) {
- FullSymbolName += (IsDefault ? "@@" : "@");
- FullSymbolName += Version;
+ SymbolName += (IsDefault ? "@@" : "@");
+ SymbolName += Version;
}
- return FullSymbolName;
+ return SymbolName;
}
template <typename ELFT>
@@ -914,6 +852,11 @@ static const EnumEntry<unsigned> ElfOSABI[] = {
{"Standalone", "Standalone App", ELF::ELFOSABI_STANDALONE}
};
+static const EnumEntry<unsigned> SymVersionFlags[] = {
+ {"Base", "BASE", VER_FLG_BASE},
+ {"Weak", "WEAK", VER_FLG_WEAK},
+ {"Info", "INFO", VER_FLG_INFO}};
+
static const EnumEntry<unsigned> AMDGPUElfOSABI[] = {
{"AMDGPU_HSA", "AMDGPU - HSA", ELF::ELFOSABI_AMDGPU_HSA},
{"AMDGPU_PAL", "AMDGPU - PAL", ELF::ELFOSABI_AMDGPU_PAL},
@@ -1103,16 +1046,6 @@ static const EnumEntry<unsigned> ElfSymbolVisibilities[] = {
{"HIDDEN", "HIDDEN", ELF::STV_HIDDEN},
{"PROTECTED", "PROTECTED", ELF::STV_PROTECTED}};
-static const EnumEntry<unsigned> ElfSymbolTypes[] = {
- {"None", "NOTYPE", ELF::STT_NOTYPE},
- {"Object", "OBJECT", ELF::STT_OBJECT},
- {"Function", "FUNC", ELF::STT_FUNC},
- {"Section", "SECTION", ELF::STT_SECTION},
- {"File", "FILE", ELF::STT_FILE},
- {"Common", "COMMON", ELF::STT_COMMON},
- {"TLS", "TLS", ELF::STT_TLS},
- {"GNU_IFunc", "IFUNC", ELF::STT_GNU_IFUNC}};
-
static const EnumEntry<unsigned> AMDGPUSymbolTypes[] = {
{ "AMDGPU_HSA_KERNEL", ELF::STT_AMDGPU_HSA_KERNEL }
};
@@ -1205,14 +1138,12 @@ static const char *getElfSegmentType(unsigned Arch, unsigned Type) {
// program header type.
switch (Arch) {
case ELF::EM_ARM:
- switch (Type) {
- LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX);
- }
+ switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX); }
break;
case ELF::EM_MIPS:
case ELF::EM_MIPS_RS3_LE:
switch (Type) {
- LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_REGINFO);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_REGINFO);
LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_RTPROC);
LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_OPTIONS);
LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_ABIFLAGS);
@@ -1233,14 +1164,15 @@ static const char *getElfSegmentType(unsigned Arch, unsigned Type) {
LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_EH_FRAME);
LLVM_READOBJ_ENUM_CASE(ELF, PT_SUNW_UNWIND);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_STACK);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_RELRO);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_STACK);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_RELRO);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_RANDOMIZE);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_WXNEEDED);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_BOOTDATA);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_RANDOMIZE);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_WXNEEDED);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_BOOTDATA);
- default: return "";
+ default:
+ return "";
}
}
@@ -1368,7 +1300,11 @@ static const EnumEntry<unsigned> ElfHeaderAMDGPUFlags[] = {
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX902),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX904),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX906),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX908),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX909),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1010),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1011),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1012),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_XNACK),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_SRAM_ECC)
};
@@ -1420,68 +1356,118 @@ static const char *getElfMipsOptionsOdkType(unsigned Odk) {
}
template <typename ELFT>
-ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
- ScopedPrinter &Writer)
- : ObjDumper(Writer), ObjF(ObjF) {
- SmallVector<const Elf_Phdr *, 4> LoadSegments;
- const ELFFile<ELFT> *Obj = ObjF->getELFFile();
+void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) {
+ // Try to locate the PT_DYNAMIC header.
+ const Elf_Phdr *DynamicPhdr = nullptr;
for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) {
- if (Phdr.p_type == ELF::PT_DYNAMIC) {
- DynamicTable = createDRIFrom(&Phdr, sizeof(Elf_Dyn));
+ if (Phdr.p_type != ELF::PT_DYNAMIC)
continue;
- }
- if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0)
+ DynamicPhdr = &Phdr;
+ break;
+ }
+
+ // Try to locate the .dynamic section in the sections header table.
+ const Elf_Shdr *DynamicSec = nullptr;
+ for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
+ if (Sec.sh_type != ELF::SHT_DYNAMIC)
continue;
- LoadSegments.push_back(&Phdr);
+ DynamicSec = &Sec;
+ break;
+ }
+
+ // Information in the section header has priority over the information
+ // in a PT_DYNAMIC header.
+ // Ignore sh_entsize and use the expected value for entry size explicitly.
+ // This allows us to dump the dynamic sections with a broken sh_entsize
+ // field.
+ if (DynamicSec) {
+ DynamicTable = checkDRI({ObjF->getELFFile()->base() + DynamicSec->sh_offset,
+ DynamicSec->sh_size, sizeof(Elf_Dyn)});
+ parseDynamicTable();
+ }
+
+ // If we have a PT_DYNAMIC header, we will either check the found dynamic
+ // section or take the dynamic table data directly from the header.
+ if (!DynamicPhdr)
+ return;
+
+ if (DynamicPhdr->p_offset + DynamicPhdr->p_filesz >
+ ObjF->getMemoryBufferRef().getBufferSize())
+ reportError(
+ "PT_DYNAMIC segment offset + size exceeds the size of the file");
+
+ if (!DynamicSec) {
+ DynamicTable = createDRIFrom(DynamicPhdr, sizeof(Elf_Dyn));
+ parseDynamicTable();
+ return;
}
+ StringRef Name = unwrapOrError(Obj->getSectionName(DynamicSec));
+ if (DynamicSec->sh_addr + DynamicSec->sh_size >
+ DynamicPhdr->p_vaddr + DynamicPhdr->p_memsz ||
+ DynamicSec->sh_addr < DynamicPhdr->p_vaddr)
+ reportWarning("The SHT_DYNAMIC section '" + Name +
+ "' is not contained within the "
+ "PT_DYNAMIC segment");
+
+ if (DynamicSec->sh_addr != DynamicPhdr->p_vaddr)
+ reportWarning("The SHT_DYNAMIC section '" + Name +
+ "' is not at the start of "
+ "PT_DYNAMIC segment");
+}
+
+template <typename ELFT>
+ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
+ ScopedPrinter &Writer)
+ : ObjDumper(Writer), ObjF(ObjF) {
+ const ELFFile<ELFT> *Obj = ObjF->getELFFile();
+
for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
switch (Sec.sh_type) {
case ELF::SHT_SYMTAB:
- if (DotSymtabSec != nullptr)
- reportError("Multiple SHT_SYMTAB");
- DotSymtabSec = &Sec;
+ if (!DotSymtabSec)
+ DotSymtabSec = &Sec;
break;
case ELF::SHT_DYNSYM:
- if (DynSymRegion.Size)
- reportError("Multiple SHT_DYNSYM");
- DynSymRegion = createDRIFrom(&Sec);
- // This is only used (if Elf_Shdr present)for naming section in GNU style
- DynSymtabName = unwrapOrError(Obj->getSectionName(&Sec));
- DynamicStringTable = unwrapOrError(Obj->getStringTableForSymtab(Sec));
+ if (!DynSymRegion.Size) {
+ DynSymRegion = createDRIFrom(&Sec);
+ // This is only used (if Elf_Shdr present)for naming section in GNU
+ // style
+ DynSymtabName = unwrapOrError(Obj->getSectionName(&Sec));
+
+ if (Expected<StringRef> E = Obj->getStringTableForSymtab(Sec))
+ DynamicStringTable = *E;
+ else
+ warn(E.takeError());
+ }
break;
case ELF::SHT_SYMTAB_SHNDX:
ShndxTable = unwrapOrError(Obj->getSHNDXTable(Sec));
break;
case ELF::SHT_GNU_versym:
- if (dot_gnu_version_sec != nullptr)
- reportError("Multiple SHT_GNU_versym");
- dot_gnu_version_sec = &Sec;
+ if (!SymbolVersionSection)
+ SymbolVersionSection = &Sec;
break;
case ELF::SHT_GNU_verdef:
- if (dot_gnu_version_d_sec != nullptr)
- reportError("Multiple SHT_GNU_verdef");
- dot_gnu_version_d_sec = &Sec;
+ if (!SymbolVersionDefSection)
+ SymbolVersionDefSection = &Sec;
break;
case ELF::SHT_GNU_verneed:
- if (dot_gnu_version_r_sec != nullptr)
- reportError("Multiple SHT_GNU_verneed");
- dot_gnu_version_r_sec = &Sec;
+ if (!SymbolVersionNeedSection)
+ SymbolVersionNeedSection = &Sec;
break;
case ELF::SHT_LLVM_CALL_GRAPH_PROFILE:
- if (DotCGProfileSec != nullptr)
- reportError("Multiple .llvm.call-graph-profile");
- DotCGProfileSec = &Sec;
+ if (!DotCGProfileSec)
+ DotCGProfileSec = &Sec;
break;
case ELF::SHT_LLVM_ADDRSIG:
- if (DotAddrsigSec != nullptr)
- reportError("Multiple .llvm_addrsig");
- DotAddrsigSec = &Sec;
+ if (!DotAddrsigSec)
+ DotAddrsigSec = &Sec;
break;
}
}
- parseDynamicTable(LoadSegments);
+ loadDynamicTable(Obj);
if (opts::Output == opts::GNU)
ELFDumperStyle.reset(new GNUStyle<ELFT>(Writer, this));
@@ -1489,13 +1475,84 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
ELFDumperStyle.reset(new LLVMStyle<ELFT>(Writer, this));
}
-template <typename ELFT>
-void ELFDumper<ELFT>::parseDynamicTable(
- ArrayRef<const Elf_Phdr *> LoadSegments) {
- auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * {
+static const char *getTypeString(unsigned Arch, uint64_t Type) {
+#define DYNAMIC_TAG(n, v)
+ switch (Arch) {
+
+ case EM_AARCH64:
+ switch (Type) {
+#define AARCH64_DYNAMIC_TAG(name, value) \
+ case DT_##name: \
+ return #name;
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef AARCH64_DYNAMIC_TAG
+ }
+ break;
+
+ case EM_HEXAGON:
+ switch (Type) {
+#define HEXAGON_DYNAMIC_TAG(name, value) \
+ case DT_##name: \
+ return #name;
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef HEXAGON_DYNAMIC_TAG
+ }
+ break;
+
+ case EM_MIPS:
+ switch (Type) {
+#define MIPS_DYNAMIC_TAG(name, value) \
+ case DT_##name: \
+ return #name;
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef MIPS_DYNAMIC_TAG
+ }
+ break;
+
+ case EM_PPC64:
+ switch (Type) {
+#define PPC64_DYNAMIC_TAG(name, value) \
+ case DT_##name: \
+ return #name;
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef PPC64_DYNAMIC_TAG
+ }
+ break;
+ }
+#undef DYNAMIC_TAG
+ switch (Type) {
+// Now handle all dynamic tags except the architecture specific ones
+#define AARCH64_DYNAMIC_TAG(name, value)
+#define MIPS_DYNAMIC_TAG(name, value)
+#define HEXAGON_DYNAMIC_TAG(name, value)
+#define PPC64_DYNAMIC_TAG(name, value)
+// Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc.
+#define DYNAMIC_TAG_MARKER(name, value)
+#define DYNAMIC_TAG(name, value) \
+ case DT_##name: \
+ return #name;
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef DYNAMIC_TAG
+#undef AARCH64_DYNAMIC_TAG
+#undef MIPS_DYNAMIC_TAG
+#undef HEXAGON_DYNAMIC_TAG
+#undef PPC64_DYNAMIC_TAG
+#undef DYNAMIC_TAG_MARKER
+ default:
+ return "unknown";
+ }
+}
+
+template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() {
+ auto toMappedAddr = [&](uint64_t Tag, uint64_t VAddr) -> const uint8_t * {
auto MappedAddrOrError = ObjF->getELFFile()->toMappedAddr(VAddr);
- if (!MappedAddrOrError)
- report_fatal_error(MappedAddrOrError.takeError());
+ if (!MappedAddrOrError) {
+ reportWarning("Unable to parse DT_" +
+ Twine(getTypeString(
+ ObjF->getELFFile()->getHeader()->e_machine, Tag)) +
+ ": " + llvm::toString(MappedAddrOrError.takeError()));
+ return nullptr;
+ }
return MappedAddrOrError.get();
};
@@ -1505,25 +1562,26 @@ void ELFDumper<ELFT>::parseDynamicTable(
for (const Elf_Dyn &Dyn : dynamic_table()) {
switch (Dyn.d_tag) {
case ELF::DT_HASH:
- HashTable =
- reinterpret_cast<const Elf_Hash *>(toMappedAddr(Dyn.getPtr()));
+ HashTable = reinterpret_cast<const Elf_Hash *>(
+ toMappedAddr(Dyn.getTag(), Dyn.getPtr()));
break;
case ELF::DT_GNU_HASH:
- GnuHashTable =
- reinterpret_cast<const Elf_GnuHash *>(toMappedAddr(Dyn.getPtr()));
+ GnuHashTable = reinterpret_cast<const Elf_GnuHash *>(
+ toMappedAddr(Dyn.getTag(), Dyn.getPtr()));
break;
case ELF::DT_STRTAB:
- StringTableBegin = (const char *)toMappedAddr(Dyn.getPtr());
+ StringTableBegin = reinterpret_cast<const char *>(
+ toMappedAddr(Dyn.getTag(), Dyn.getPtr()));
break;
case ELF::DT_STRSZ:
StringTableSize = Dyn.getVal();
break;
case ELF::DT_SYMTAB:
- DynSymRegion.Addr = toMappedAddr(Dyn.getPtr());
+ DynSymRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
DynSymRegion.EntSize = sizeof(Elf_Sym);
break;
case ELF::DT_RELA:
- DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr());
+ DynRelaRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
break;
case ELF::DT_RELASZ:
DynRelaRegion.Size = Dyn.getVal();
@@ -1535,7 +1593,7 @@ void ELFDumper<ELFT>::parseDynamicTable(
SONameOffset = Dyn.getVal();
break;
case ELF::DT_REL:
- DynRelRegion.Addr = toMappedAddr(Dyn.getPtr());
+ DynRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
break;
case ELF::DT_RELSZ:
DynRelRegion.Size = Dyn.getVal();
@@ -1545,7 +1603,7 @@ void ELFDumper<ELFT>::parseDynamicTable(
break;
case ELF::DT_RELR:
case ELF::DT_ANDROID_RELR:
- DynRelrRegion.Addr = toMappedAddr(Dyn.getPtr());
+ DynRelrRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
break;
case ELF::DT_RELRSZ:
case ELF::DT_ANDROID_RELRSZ:
@@ -1565,7 +1623,7 @@ void ELFDumper<ELFT>::parseDynamicTable(
Twine((uint64_t)Dyn.getVal()));
break;
case ELF::DT_JMPREL:
- DynPLTRelRegion.Addr = toMappedAddr(Dyn.getPtr());
+ DynPLTRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
break;
case ELF::DT_PLTRELSZ:
DynPLTRelRegion.Size = Dyn.getVal();
@@ -1574,8 +1632,8 @@ void ELFDumper<ELFT>::parseDynamicTable(
}
if (StringTableBegin)
DynamicStringTable = StringRef(StringTableBegin, StringTableSize);
- if (SONameOffset)
- SOName = getDynamicString(SONameOffset);
+ if (SONameOffset && SONameOffset < DynamicStringTable.size())
+ SOName = DynamicStringTable.data() + SONameOffset;
}
template <typename ELFT>
@@ -1593,37 +1651,52 @@ typename ELFDumper<ELFT>::Elf_Relr_Range ELFDumper<ELFT>::dyn_relrs() const {
return DynRelrRegion.getAsArrayRef<Elf_Relr>();
}
-template<class ELFT>
-void ELFDumper<ELFT>::printFileHeaders() {
+template <class ELFT> void ELFDumper<ELFT>::printFileHeaders() {
ELFDumperStyle->printFileHeaders(ObjF->getELFFile());
}
-template<class ELFT>
-void ELFDumper<ELFT>::printSectionHeaders() {
+template <class ELFT> void ELFDumper<ELFT>::printSectionHeaders() {
ELFDumperStyle->printSectionHeaders(ObjF->getELFFile());
}
-template<class ELFT>
-void ELFDumper<ELFT>::printRelocations() {
+template <class ELFT> void ELFDumper<ELFT>::printRelocations() {
ELFDumperStyle->printRelocations(ObjF->getELFFile());
}
-template <class ELFT> void ELFDumper<ELFT>::printProgramHeaders() {
- ELFDumperStyle->printProgramHeaders(ObjF->getELFFile());
+template <class ELFT>
+void ELFDumper<ELFT>::printProgramHeaders(
+ bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) {
+ ELFDumperStyle->printProgramHeaders(ObjF->getELFFile(), PrintProgramHeaders,
+ PrintSectionMapping);
+}
+
+template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() {
+ // Dump version symbol section.
+ ELFDumperStyle->printVersionSymbolSection(ObjF->getELFFile(),
+ SymbolVersionSection);
+
+ // Dump version definition section.
+ ELFDumperStyle->printVersionDefinitionSection(ObjF->getELFFile(),
+ SymbolVersionDefSection);
+
+ // Dump version dependency section.
+ ELFDumperStyle->printVersionDependencySection(ObjF->getELFFile(),
+ SymbolVersionNeedSection);
}
template <class ELFT> void ELFDumper<ELFT>::printDynamicRelocations() {
ELFDumperStyle->printDynamicRelocations(ObjF->getELFFile());
}
-template<class ELFT>
-void ELFDumper<ELFT>::printSymbols() {
- ELFDumperStyle->printSymbols(ObjF->getELFFile());
+template <class ELFT>
+void ELFDumper<ELFT>::printSymbols(bool PrintSymbols,
+ bool PrintDynamicSymbols) {
+ ELFDumperStyle->printSymbols(ObjF->getELFFile(), PrintSymbols,
+ PrintDynamicSymbols);
}
-template<class ELFT>
-void ELFDumper<ELFT>::printDynamicSymbols() {
- ELFDumperStyle->printDynamicSymbols(ObjF->getELFFile());
+template <class ELFT> void ELFDumper<ELFT>::printHashSymbols() {
+ ELFDumperStyle->printHashSymbols(ObjF->getELFFile());
}
template <class ELFT> void ELFDumper<ELFT>::printHashHistogram() {
@@ -1642,61 +1715,7 @@ template <class ELFT> void ELFDumper<ELFT>::printELFLinkerOptions() {
ELFDumperStyle->printELFLinkerOptions(ObjF->getELFFile());
}
-static const char *getTypeString(unsigned Arch, uint64_t Type) {
-#define DYNAMIC_TAG(n, v)
- switch (Arch) {
- case EM_HEXAGON:
- switch (Type) {
-#define HEXAGON_DYNAMIC_TAG(name, value) \
- case DT_##name: \
- return #name;
-#include "llvm/BinaryFormat/DynamicTags.def"
-#undef HEXAGON_DYNAMIC_TAG
- }
- break;
-
- case EM_MIPS:
- switch (Type) {
-#define MIPS_DYNAMIC_TAG(name, value) \
- case DT_##name: \
- return #name;
-#include "llvm/BinaryFormat/DynamicTags.def"
-#undef MIPS_DYNAMIC_TAG
- }
- break;
-
- case EM_PPC64:
- switch(Type) {
-#define PPC64_DYNAMIC_TAG(name, value) \
- case DT_##name: \
- return #name;
-#include "llvm/BinaryFormat/DynamicTags.def"
-#undef PPC64_DYNAMIC_TAG
- }
- break;
- }
-#undef DYNAMIC_TAG
- switch (Type) {
-// Now handle all dynamic tags except the architecture specific ones
-#define MIPS_DYNAMIC_TAG(name, value)
-#define HEXAGON_DYNAMIC_TAG(name, value)
-#define PPC64_DYNAMIC_TAG(name, value)
-// Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc.
-#define DYNAMIC_TAG_MARKER(name, value)
-#define DYNAMIC_TAG(name, value) \
- case DT_##name: \
- return #name;
-#include "llvm/BinaryFormat/DynamicTags.def"
-#undef DYNAMIC_TAG
-#undef MIPS_DYNAMIC_TAG
-#undef HEXAGON_DYNAMIC_TAG
-#undef PPC64_DYNAMIC_TAG
-#undef DYNAMIC_TAG_MARKER
- default: return "unknown";
- }
-}
-
-#define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \
+#define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \
{ #enum, prefix##_##enum }
static const EnumEntry<unsigned> ElfDynamicDTFlags[] = {
@@ -1724,6 +1743,7 @@ static const EnumEntry<unsigned> ElfDynamicDTFlags1[] = {
LLVM_READOBJ_DT_FLAG_ENT(DF_1, CONFALT),
LLVM_READOBJ_DT_FLAG_ENT(DF_1, ENDFILTEE),
LLVM_READOBJ_DT_FLAG_ENT(DF_1, DISPRELDNE),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, DISPRELPND),
LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODIRECT),
LLVM_READOBJ_DT_FLAG_ENT(DF_1, IGNMULDEF),
LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOKSYMS),
@@ -1776,20 +1796,97 @@ void printFlags(T Value, ArrayRef<EnumEntry<TFlag>> Flags, raw_ostream &OS) {
}
template <class ELFT>
-StringRef ELFDumper<ELFT>::getDynamicString(uint64_t Value) const {
- if (Value >= DynamicStringTable.size())
- reportError("Invalid dynamic string table reference");
- return StringRef(DynamicStringTable.data() + Value);
-}
-
-static void printLibrary(raw_ostream &OS, const Twine &Tag, const Twine &Name) {
- OS << Tag << ": [" << Name << "]";
-}
+void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
+ uint64_t Value) const {
+ const char *ConvChar =
+ (opts::Output == opts::GNU) ? "0x%" PRIx64 : "0x%" PRIX64;
+
+ // Handle custom printing of architecture specific tags
+ switch (ObjF->getELFFile()->getHeader()->e_machine) {
+ case EM_AARCH64:
+ switch (Type) {
+ case DT_AARCH64_BTI_PLT:
+ case DT_AARCH64_PAC_PLT:
+ OS << Value;
+ return;
+ default:
+ break;
+ }
+ break;
+ case EM_HEXAGON:
+ switch (Type) {
+ case DT_HEXAGON_VER:
+ OS << Value;
+ return;
+ case DT_HEXAGON_SYMSZ:
+ case DT_HEXAGON_PLT:
+ OS << format(ConvChar, Value);
+ return;
+ default:
+ break;
+ }
+ break;
+ case EM_MIPS:
+ switch (Type) {
+ case DT_MIPS_RLD_VERSION:
+ case DT_MIPS_LOCAL_GOTNO:
+ case DT_MIPS_SYMTABNO:
+ case DT_MIPS_UNREFEXTNO:
+ OS << Value;
+ return;
+ case DT_MIPS_TIME_STAMP:
+ case DT_MIPS_ICHECKSUM:
+ case DT_MIPS_IVERSION:
+ case DT_MIPS_BASE_ADDRESS:
+ case DT_MIPS_MSYM:
+ case DT_MIPS_CONFLICT:
+ case DT_MIPS_LIBLIST:
+ case DT_MIPS_CONFLICTNO:
+ case DT_MIPS_LIBLISTNO:
+ case DT_MIPS_GOTSYM:
+ case DT_MIPS_HIPAGENO:
+ case DT_MIPS_RLD_MAP:
+ case DT_MIPS_DELTA_CLASS:
+ case DT_MIPS_DELTA_CLASS_NO:
+ case DT_MIPS_DELTA_INSTANCE:
+ case DT_MIPS_DELTA_RELOC:
+ case DT_MIPS_DELTA_RELOC_NO:
+ case DT_MIPS_DELTA_SYM:
+ case DT_MIPS_DELTA_SYM_NO:
+ case DT_MIPS_DELTA_CLASSSYM:
+ case DT_MIPS_DELTA_CLASSSYM_NO:
+ case DT_MIPS_CXX_FLAGS:
+ case DT_MIPS_PIXIE_INIT:
+ case DT_MIPS_SYMBOL_LIB:
+ case DT_MIPS_LOCALPAGE_GOTIDX:
+ case DT_MIPS_LOCAL_GOTIDX:
+ case DT_MIPS_HIDDEN_GOTIDX:
+ case DT_MIPS_PROTECTED_GOTIDX:
+ case DT_MIPS_OPTIONS:
+ case DT_MIPS_INTERFACE:
+ case DT_MIPS_DYNSTR_ALIGN:
+ case DT_MIPS_INTERFACE_SIZE:
+ case DT_MIPS_RLD_TEXT_RESOLVE_ADDR:
+ case DT_MIPS_PERF_SUFFIX:
+ case DT_MIPS_COMPACT_SIZE:
+ case DT_MIPS_GP_VALUE:
+ case DT_MIPS_AUX_DYNAMIC:
+ case DT_MIPS_PLTGOT:
+ case DT_MIPS_RWPLT:
+ case DT_MIPS_RLD_MAP_REL:
+ OS << format(ConvChar, Value);
+ return;
+ case DT_MIPS_FLAGS:
+ printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS);
+ return;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
-template <class ELFT>
-void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) {
- raw_ostream &OS = W.getOStream();
- const char* ConvChar = (opts::Output == opts::GNU) ? "0x%" PRIx64 : "0x%" PRIX64;
switch (Type) {
case DT_PLTREL:
if (Value == DT_REL) {
@@ -1818,22 +1915,12 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) {
case DT_VERSYM:
case DT_GNU_HASH:
case DT_NULL:
- case DT_MIPS_BASE_ADDRESS:
- case DT_MIPS_GOTSYM:
- case DT_MIPS_RLD_MAP:
- case DT_MIPS_RLD_MAP_REL:
- case DT_MIPS_PLTGOT:
- case DT_MIPS_OPTIONS:
OS << format(ConvChar, Value);
break;
case DT_RELACOUNT:
case DT_RELCOUNT:
case DT_VERDEFNUM:
case DT_VERNEEDNUM:
- case DT_MIPS_RLD_VERSION:
- case DT_MIPS_LOCAL_GOTNO:
- case DT_MIPS_SYMTABNO:
- case DT_MIPS_UNREFEXTNO:
OS << Value;
break;
case DT_PLTRELSZ:
@@ -1851,24 +1938,30 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) {
OS << Value << " (bytes)";
break;
case DT_NEEDED:
- printLibrary(OS, "Shared library", getDynamicString(Value));
- break;
case DT_SONAME:
- printLibrary(OS, "Library soname", getDynamicString(Value));
- break;
case DT_AUXILIARY:
- printLibrary(OS, "Auxiliary library", getDynamicString(Value));
- break;
+ case DT_USED:
case DT_FILTER:
- printLibrary(OS, "Filter library", getDynamicString(Value));
- break;
case DT_RPATH:
- case DT_RUNPATH:
- OS << getDynamicString(Value);
- break;
- case DT_MIPS_FLAGS:
- printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS);
+ case DT_RUNPATH: {
+ const std::map<uint64_t, const char*> TagNames = {
+ {DT_NEEDED, "Shared library"},
+ {DT_SONAME, "Library soname"},
+ {DT_AUXILIARY, "Auxiliary library"},
+ {DT_USED, "Not needed object"},
+ {DT_FILTER, "Filter library"},
+ {DT_RPATH, "Library rpath"},
+ {DT_RUNPATH, "Library runpath"},
+ };
+ OS << TagNames.at(Type) << ": ";
+ if (DynamicStringTable.empty())
+ OS << "<String table is empty or was not found> ";
+ else if (Value < DynamicStringTable.size())
+ OS << "[" << StringRef(DynamicStringTable.data() + Value) << "]";
+ else
+ OS << "<Invalid offset 0x" << utohexstr(Value) << ">";
break;
+ }
case DT_FLAGS:
printFlags(Value, makeArrayRef(ElfDynamicDTFlags), OS);
break;
@@ -1881,14 +1974,9 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) {
}
}
-template<class ELFT>
-void ELFDumper<ELFT>::printUnwindInfo() {
- const unsigned Machine = ObjF->getELFFile()->getHeader()->e_machine;
- if (Machine == EM_386 || Machine == EM_X86_64) {
- DwarfCFIEH::PrinterContext<ELFT> Ctx(W, ObjF);
- return Ctx.printUnwindInformation();
- }
- W.startLine() << "UnwindInfo not implemented.\n";
+template <class ELFT> void ELFDumper<ELFT>::printUnwindInfo() {
+ DwarfCFIEH::PrinterContext<ELFT> Ctx(W, ObjF);
+ Ctx.printUnwindInformation();
}
namespace {
@@ -1898,73 +1986,40 @@ template <> void ELFDumper<ELF32LE>::printUnwindInfo() {
const unsigned Machine = Obj->getHeader()->e_machine;
if (Machine == EM_ARM) {
ARM::EHABI::PrinterContext<ELF32LE> Ctx(W, Obj, DotSymtabSec);
- return Ctx.PrintUnwindInformation();
+ Ctx.PrintUnwindInformation();
}
- W.startLine() << "UnwindInfo not implemented.\n";
+ DwarfCFIEH::PrinterContext<ELF32LE> Ctx(W, ObjF);
+ Ctx.printUnwindInformation();
}
} // end anonymous namespace
-template<class ELFT>
-void ELFDumper<ELFT>::printDynamicTable() {
- auto I = dynamic_table().begin();
- auto E = dynamic_table().end();
-
- if (I == E)
- return;
-
- --E;
- while (I != E && E->getTag() == ELF::DT_NULL)
- --E;
- if (E->getTag() != ELF::DT_NULL)
- ++E;
- ++E;
-
- ptrdiff_t Total = std::distance(I, E);
- if (Total == 0)
- return;
-
- raw_ostream &OS = W.getOStream();
- W.startLine() << "DynamicSection [ (" << Total << " entries)\n";
-
- bool Is64 = ELFT::Is64Bits;
-
- W.startLine()
- << " Tag" << (Is64 ? " " : " ") << "Type"
- << " " << "Name/Value\n";
- while (I != E) {
- const Elf_Dyn &Entry = *I;
- uintX_t Tag = Entry.getTag();
- ++I;
- W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, opts::Output != opts::GNU) << " "
- << format("%-21s", getTypeString(ObjF->getELFFile()->getHeader()->e_machine, Tag));
- printValue(Tag, Entry.getVal());
- OS << "\n";
- }
-
- W.startLine() << "]\n";
+template <class ELFT> void ELFDumper<ELFT>::printDynamicTable() {
+ ELFDumperStyle->printDynamic(ObjF->getELFFile());
}
-template<class ELFT>
-void ELFDumper<ELFT>::printNeededLibraries() {
+template <class ELFT> void ELFDumper<ELFT>::printNeededLibraries() {
ListScope D(W, "NeededLibraries");
using LibsTy = std::vector<StringRef>;
LibsTy Libs;
for (const auto &Entry : dynamic_table())
- if (Entry.d_tag == ELF::DT_NEEDED)
- Libs.push_back(getDynamicString(Entry.d_un.d_val));
+ if (Entry.d_tag == ELF::DT_NEEDED) {
+ uint64_t Value = Entry.d_un.d_val;
+ if (Value < DynamicStringTable.size())
+ Libs.push_back(StringRef(DynamicStringTable.data() + Value));
+ else
+ Libs.push_back("<Library name index out of range>");
+ }
- std::stable_sort(Libs.begin(), Libs.end());
+ llvm::stable_sort(Libs);
for (const auto &L : Libs)
- W.startLine() << L << "\n";
+ W.startLine() << L << "\n";
}
-
-template <typename ELFT>
-void ELFDumper<ELFT>::printHashTable() {
+template <typename ELFT> void ELFDumper<ELFT>::printHashTable() {
DictScope D(W, "HashTable");
if (!HashTable)
return;
@@ -1974,8 +2029,7 @@ void ELFDumper<ELFT>::printHashTable() {
W.printList("Chains", HashTable->chains());
}
-template <typename ELFT>
-void ELFDumper<ELFT>::printGnuHashTable() {
+template <typename ELFT> void ELFDumper<ELFT>::printGnuHashTable() {
DictScope D(W, "GnuHashTable");
if (!GnuHashTable)
return;
@@ -1996,8 +2050,7 @@ template <typename ELFT> void ELFDumper<ELFT>::printLoadName() {
W.printString("LoadName", SOName);
}
-template <class ELFT>
-void ELFDumper<ELFT>::printAttributes() {
+template <class ELFT> void ELFDumper<ELFT>::printAttributes() {
W.startLine() << "Attributes not implemented.\n";
}
@@ -2486,7 +2539,7 @@ template <class ELFT> void ELFDumper<ELFT>::printStackMap() const {
unwrapOrError(Obj->getSectionContents(StackMapSection));
prettyPrintStackMap(
- W, StackMapV2Parser<ELFT::TargetEndianness>(StackMapContentsArray));
+ W, StackMapParser<ELFT::TargetEndianness>(StackMapContentsArray));
}
template <class ELFT> void ELFDumper<ELFT>::printGroupSections() {
@@ -2527,7 +2580,8 @@ static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> *Obj) {
ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(Obj->sections());
if (Arr.empty())
return "65535 (corrupt: out of range)";
- return to_string(ElfHeader->e_shstrndx) + " (" + to_string(Arr[0].sh_link) + ")";
+ return to_string(ElfHeader->e_shstrndx) + " (" + to_string(Arr[0].sh_link) +
+ ")";
}
template <class ELFT> void GNUStyle<ELFT>::printFileHeaders(const ELFO *Obj) {
@@ -2599,7 +2653,7 @@ struct GroupMember {
struct GroupSection {
StringRef Name;
- StringRef Signature;
+ std::string Signature;
uint64_t ShName;
uint64_t Index;
uint32_t Link;
@@ -2630,13 +2684,13 @@ std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj) {
StringRef Name = unwrapOrError(Obj->getSectionName(&Sec));
StringRef Signature = StrTable.data() + Sym->st_name;
- Ret.push_back({Name,
- Signature,
- Sec.sh_name,
+ Ret.push_back({Name,
+ maybeDemangle(Signature),
+ Sec.sh_name,
I - 1,
Sec.sh_link,
Sec.sh_info,
- Data[0],
+ Data[0],
{}});
std::vector<GroupMember> &GM = Ret.back().Members;
@@ -2691,53 +2745,57 @@ template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) {
template <class ELFT>
void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab,
const Elf_Rela &R, bool IsRela) {
- std::string Offset, Info, Addend, Value;
- SmallString<32> RelocName;
- StringRef TargetName;
- const Elf_Sym *Sym = nullptr;
- unsigned Width = ELFT::Is64Bits ? 16 : 8;
- unsigned Bias = ELFT::Is64Bits ? 8 : 0;
-
- // First two fields are bit width dependent. The rest of them are after are
- // fixed width.
- Field Fields[5] = {0, 10 + Bias, 19 + 2 * Bias, 42 + 2 * Bias, 53 + 2 * Bias};
- Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName);
- Sym = unwrapOrError(Obj->getRelocationSymbol(&R, SymTab));
+ const Elf_Sym *Sym = unwrapOrError(Obj->getRelocationSymbol(&R, SymTab));
+ std::string TargetName;
if (Sym && Sym->getType() == ELF::STT_SECTION) {
const Elf_Shdr *Sec = unwrapOrError(
Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable()));
TargetName = unwrapOrError(Obj->getSectionName(Sec));
} else if (Sym) {
StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab));
- TargetName = unwrapOrError(Sym->getName(StrTable));
+ TargetName = this->dumper()->getFullSymbolName(
+ Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */);
}
+ printRelocation(Obj, Sym, TargetName, R, IsRela);
+}
- if (Sym && IsRela) {
- if (R.r_addend < 0)
- Addend = " - ";
- else
- Addend = " + ";
- }
+template <class ELFT>
+void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Sym *Sym,
+ StringRef SymbolName, const Elf_Rela &R,
+ bool IsRela) {
+ // First two fields are bit width dependent. The rest of them are fixed width.
+ unsigned Bias = ELFT::Is64Bits ? 8 : 0;
+ Field Fields[5] = {0, 10 + Bias, 19 + 2 * Bias, 42 + 2 * Bias, 53 + 2 * Bias};
+ unsigned Width = ELFT::Is64Bits ? 16 : 8;
- Offset = to_string(format_hex_no_prefix(R.r_offset, Width));
- Info = to_string(format_hex_no_prefix(R.r_info, Width));
+ Fields[0].Str = to_string(format_hex_no_prefix(R.r_offset, Width));
+ Fields[1].Str = to_string(format_hex_no_prefix(R.r_info, Width));
- int64_t RelAddend = R.r_addend;
- if (IsRela)
- Addend += to_hexString(std::abs(RelAddend), false);
-
- if (Sym)
- Value = to_string(format_hex_no_prefix(Sym->getValue(), Width));
-
- Fields[0].Str = Offset;
- Fields[1].Str = Info;
- Fields[2].Str = RelocName;
- Fields[3].Str = Value;
- Fields[4].Str = TargetName;
- for (auto &field : Fields)
- printField(field);
- OS << Addend;
- OS << "\n";
+ SmallString<32> RelocName;
+ Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName);
+ Fields[2].Str = RelocName.c_str();
+
+ if (Sym && (!SymbolName.empty() || Sym->getValue() != 0))
+ Fields[3].Str = to_string(format_hex_no_prefix(Sym->getValue(), Width));
+
+ Fields[4].Str = SymbolName;
+ for (const Field &F : Fields)
+ printField(F);
+
+ std::string Addend;
+ if (IsRela) {
+ int64_t RelAddend = R.r_addend;
+ if (!SymbolName.empty()) {
+ if (R.r_addend < 0) {
+ Addend = " - ";
+ RelAddend = std::abs(RelAddend);
+ } else
+ Addend = " + ";
+ }
+
+ Addend += to_hexString(RelAddend, false);
+ }
+ OS << Addend << "\n";
}
template <class ELFT> void GNUStyle<ELFT>::printRelocHeader(unsigned SType) {
@@ -2764,10 +2822,8 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocHeader(unsigned SType) {
template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {
bool HasRelocSections = false;
for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
- if (Sec.sh_type != ELF::SHT_REL &&
- Sec.sh_type != ELF::SHT_RELA &&
- Sec.sh_type != ELF::SHT_RELR &&
- Sec.sh_type != ELF::SHT_ANDROID_REL &&
+ if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA &&
+ Sec.sh_type != ELF::SHT_RELR && Sec.sh_type != ELF::SHT_ANDROID_REL &&
Sec.sh_type != ELF::SHT_ANDROID_RELA &&
Sec.sh_type != ELF::SHT_ANDROID_RELR)
continue;
@@ -2832,7 +2888,21 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {
OS << "\nThere are no relocations in this file.\n";
}
-std::string getSectionTypeString(unsigned Arch, unsigned Type) {
+// Print the offset of a particular section from anyone of the ranges:
+// [SHT_LOOS, SHT_HIOS], [SHT_LOPROC, SHT_HIPROC], [SHT_LOUSER, SHT_HIUSER].
+// If 'Type' does not fall within any of those ranges, then a string is
+// returned as '<unknown>' followed by the type value.
+static std::string getSectionTypeOffsetString(unsigned Type) {
+ if (Type >= SHT_LOOS && Type <= SHT_HIOS)
+ return "LOOS+0x" + to_hexString(Type - SHT_LOOS);
+ else if (Type >= SHT_LOPROC && Type <= SHT_HIPROC)
+ return "LOPROC+0x" + to_hexString(Type - SHT_LOPROC);
+ else if (Type >= SHT_LOUSER && Type <= SHT_HIUSER)
+ return "LOUSER+0x" + to_hexString(Type - SHT_LOUSER);
+ return "0x" + to_hexString(Type) + ": <unknown>";
+}
+
+static std::string getSectionTypeString(unsigned Arch, unsigned Type) {
using namespace ELF;
switch (Arch) {
@@ -2863,10 +2933,10 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) {
return "MIPS_REGINFO";
case SHT_MIPS_OPTIONS:
return "MIPS_OPTIONS";
+ case SHT_MIPS_DWARF:
+ return "MIPS_DWARF";
case SHT_MIPS_ABIFLAGS:
return "MIPS_ABIFLAGS";
- case SHT_MIPS_DWARF:
- return "SHT_MIPS_DWARF";
}
break;
}
@@ -2905,6 +2975,10 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) {
return "GROUP";
case SHT_SYMTAB_SHNDX:
return "SYMTAB SECTION INDICES";
+ case SHT_ANDROID_REL:
+ return "ANDROID_REL";
+ case SHT_ANDROID_RELA:
+ return "ANDROID_RELA";
case SHT_RELR:
case SHT_ANDROID_RELR:
return "RELR";
@@ -2916,6 +2990,8 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) {
return "LLVM_CALL_GRAPH_PROFILE";
case SHT_LLVM_ADDRSIG:
return "LLVM_ADDRSIG";
+ case SHT_LLVM_DEPENDENT_LIBRARIES:
+ return "LLVM_DEPENDENT_LIBRARIES";
// FIXME: Parse processor specific GNU attributes
case SHT_GNU_ATTRIBUTES:
return "ATTRIBUTES";
@@ -2928,69 +3004,65 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) {
case SHT_GNU_versym:
return "VERSYM";
default:
- return "";
+ return getSectionTypeOffsetString(Type);
}
return "";
}
template <class ELFT>
-void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
- size_t SectionIndex = 0;
- std::string Number, Type, Size, Address, Offset, Flags, Link, Info, EntrySize,
- Alignment;
- unsigned Bias;
- unsigned Width;
-
- if (ELFT::Is64Bits) {
- Bias = 0;
- Width = 16;
- } else {
- Bias = 8;
- Width = 8;
- }
+static StringRef getSectionName(const typename ELFT::Shdr &Sec,
+ const ELFObjectFile<ELFT> &ElfObj,
+ ArrayRef<typename ELFT::Shdr> Sections) {
+ const ELFFile<ELFT> &Obj = *ElfObj.getELFFile();
+ uint32_t Index = Obj.getHeader()->e_shstrndx;
+ if (Index == ELF::SHN_XINDEX)
+ Index = Sections[0].sh_link;
+ if (!Index) // no section string table.
+ return "";
+ // TODO: Test a case when the sh_link of the section with index 0 is broken.
+ if (Index >= Sections.size())
+ reportError(ElfObj.getFileName(),
+ createError("section header string table index " +
+ Twine(Index) + " does not exist"));
+ StringRef Data = toStringRef(unwrapOrError(
+ Obj.template getSectionContentsAsArray<uint8_t>(&Sections[Index])));
+ return unwrapOrError(Obj.getSectionName(&Sec, Data));
+}
+template <class ELFT>
+void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
+ unsigned Bias = ELFT::Is64Bits ? 0 : 8;
ArrayRef<Elf_Shdr> Sections = unwrapOrError(Obj->sections());
OS << "There are " << to_string(Sections.size())
<< " section headers, starting at offset "
<< "0x" << to_hexString(Obj->getHeader()->e_shoff, false) << ":\n\n";
OS << "Section Headers:\n";
- Field Fields[11] = {{"[Nr]", 2},
- {"Name", 7},
- {"Type", 25},
- {"Address", 41},
- {"Off", 58 - Bias},
- {"Size", 65 - Bias},
- {"ES", 72 - Bias},
- {"Flg", 75 - Bias},
- {"Lk", 79 - Bias},
- {"Inf", 82 - Bias},
- {"Al", 86 - Bias}};
- for (auto &f : Fields)
- printField(f);
+ Field Fields[11] = {
+ {"[Nr]", 2}, {"Name", 7}, {"Type", 25},
+ {"Address", 41}, {"Off", 58 - Bias}, {"Size", 65 - Bias},
+ {"ES", 72 - Bias}, {"Flg", 75 - Bias}, {"Lk", 79 - Bias},
+ {"Inf", 82 - Bias}, {"Al", 86 - Bias}};
+ for (auto &F : Fields)
+ printField(F);
OS << "\n";
+ const ELFObjectFile<ELFT> *ElfObj = this->dumper()->getElfObject();
+ size_t SectionIndex = 0;
for (const Elf_Shdr &Sec : Sections) {
- Number = to_string(SectionIndex);
- Fields[0].Str = Number;
- Fields[1].Str = unwrapOrError(Obj->getSectionName(&Sec));
- Type = getSectionTypeString(Obj->getHeader()->e_machine, Sec.sh_type);
- Fields[2].Str = Type;
- Address = to_string(format_hex_no_prefix(Sec.sh_addr, Width));
- Fields[3].Str = Address;
- Offset = to_string(format_hex_no_prefix(Sec.sh_offset, 6));
- Fields[4].Str = Offset;
- Size = to_string(format_hex_no_prefix(Sec.sh_size, 6));
- Fields[5].Str = Size;
- EntrySize = to_string(format_hex_no_prefix(Sec.sh_entsize, 2));
- Fields[6].Str = EntrySize;
- Flags = getGNUFlags(Sec.sh_flags);
- Fields[7].Str = Flags;
- Link = to_string(Sec.sh_link);
- Fields[8].Str = Link;
- Info = to_string(Sec.sh_info);
- Fields[9].Str = Info;
- Alignment = to_string(Sec.sh_addralign);
- Fields[10].Str = Alignment;
+ Fields[0].Str = to_string(SectionIndex);
+ Fields[1].Str = getSectionName(Sec, *ElfObj, Sections);
+ Fields[2].Str =
+ getSectionTypeString(Obj->getHeader()->e_machine, Sec.sh_type);
+ Fields[3].Str =
+ to_string(format_hex_no_prefix(Sec.sh_addr, ELFT::Is64Bits ? 16 : 8));
+ Fields[4].Str = to_string(format_hex_no_prefix(Sec.sh_offset, 6));
+ Fields[5].Str = to_string(format_hex_no_prefix(Sec.sh_size, 6));
+ Fields[6].Str = to_string(format_hex_no_prefix(Sec.sh_entsize, 2));
+ Fields[7].Str = getGNUFlags(Sec.sh_flags);
+ Fields[8].Str = to_string(Sec.sh_link);
+ Fields[9].Str = to_string(Sec.sh_info);
+ Fields[10].Str = to_string(Sec.sh_addralign);
+
OS.PadToColumn(Fields[0].Column);
OS << "[" << right_justify(Fields[0].Str, 2) << "]";
for (int i = 1; i < 7; i++)
@@ -3043,9 +3115,10 @@ std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj,
case ELF::SHN_COMMON:
return "COM";
case ELF::SHN_XINDEX:
- SectionIndex = unwrapOrError(object::getExtendedSymbolTableIndex<ELFT>(
- Symbol, FirstSym, this->dumper()->getShndxTable()));
- LLVM_FALLTHROUGH;
+ return to_string(
+ format_decimal(unwrapOrError(object::getExtendedSymbolTableIndex<ELFT>(
+ Symbol, FirstSym, this->dumper()->getShndxTable())),
+ 3));
default:
// Find if:
// Processor specific
@@ -3072,7 +3145,6 @@ void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
bool IsDynamic) {
static int Idx = 0;
static bool Dynamic = true;
- size_t Width;
// If this function was called with a different value from IsDynamic
// from last call, happens when we move from dynamic to static symbol
@@ -3081,111 +3153,87 @@ void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
Idx = 0;
Dynamic = false;
}
- std::string Num, Name, Value, Size, Binding, Type, Visibility, Section;
- unsigned Bias = 0;
- if (ELFT::Is64Bits) {
- Bias = 8;
- Width = 16;
- } else {
- Bias = 0;
- Width = 8;
- }
+
+ unsigned Bias = ELFT::Is64Bits ? 8 : 0;
Field Fields[8] = {0, 8, 17 + Bias, 23 + Bias,
31 + Bias, 38 + Bias, 47 + Bias, 51 + Bias};
- Num = to_string(format_decimal(Idx++, 6)) + ":";
- Value = to_string(format_hex_no_prefix(Symbol->st_value, Width));
- Size = to_string(format_decimal(Symbol->st_size, 5));
+ Fields[0].Str = to_string(format_decimal(Idx++, 6)) + ":";
+ Fields[1].Str = to_string(
+ format_hex_no_prefix(Symbol->st_value, ELFT::Is64Bits ? 16 : 8));
+ Fields[2].Str = to_string(format_decimal(Symbol->st_size, 5));
+
unsigned char SymbolType = Symbol->getType();
if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU &&
SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS)
- Type = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes));
+ Fields[3].Str = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes));
else
- Type = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes));
- unsigned Vis = Symbol->getVisibility();
- Binding = printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
- Visibility = printEnum(Vis, makeArrayRef(ElfSymbolVisibilities));
- Section = getSymbolSectionNdx(Obj, Symbol, FirstSym);
- Name = this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic);
- Fields[0].Str = Num;
- Fields[1].Str = Value;
- Fields[2].Str = Size;
- Fields[3].Str = Type;
- Fields[4].Str = Binding;
- Fields[5].Str = Visibility;
- Fields[6].Str = Section;
- Fields[7].Str = Name;
+ Fields[3].Str = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes));
+
+ Fields[4].Str =
+ printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
+ Fields[5].Str =
+ printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities));
+ Fields[6].Str = getSymbolSectionNdx(Obj, Symbol, FirstSym);
+ Fields[7].Str =
+ this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic);
for (auto &Entry : Fields)
printField(Entry);
OS << "\n";
}
+
template <class ELFT>
void GNUStyle<ELFT>::printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym,
uint32_t Sym, StringRef StrTable,
uint32_t Bucket) {
- std::string Num, Buc, Name, Value, Size, Binding, Type, Visibility, Section;
- unsigned Width, Bias = 0;
- if (ELFT::Is64Bits) {
- Bias = 8;
- Width = 16;
- } else {
- Bias = 0;
- Width = 8;
- }
+ unsigned Bias = ELFT::Is64Bits ? 8 : 0;
Field Fields[9] = {0, 6, 11, 20 + Bias, 25 + Bias,
34 + Bias, 41 + Bias, 49 + Bias, 53 + Bias};
- Num = to_string(format_decimal(Sym, 5));
- Buc = to_string(format_decimal(Bucket, 3)) + ":";
+ Fields[0].Str = to_string(format_decimal(Sym, 5));
+ Fields[1].Str = to_string(format_decimal(Bucket, 3)) + ":";
const auto Symbol = FirstSym + Sym;
- Value = to_string(format_hex_no_prefix(Symbol->st_value, Width));
- Size = to_string(format_decimal(Symbol->st_size, 5));
+ Fields[2].Str = to_string(
+ format_hex_no_prefix(Symbol->st_value, ELFT::Is64Bits ? 18 : 8));
+ Fields[3].Str = to_string(format_decimal(Symbol->st_size, 5));
+
unsigned char SymbolType = Symbol->getType();
if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU &&
SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS)
- Type = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes));
+ Fields[4].Str = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes));
else
- Type = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes));
- unsigned Vis = Symbol->getVisibility();
- Binding = printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
- Visibility = printEnum(Vis, makeArrayRef(ElfSymbolVisibilities));
- Section = getSymbolSectionNdx(Obj, Symbol, FirstSym);
- Name = this->dumper()->getFullSymbolName(Symbol, StrTable, true);
- Fields[0].Str = Num;
- Fields[1].Str = Buc;
- Fields[2].Str = Value;
- Fields[3].Str = Size;
- Fields[4].Str = Type;
- Fields[5].Str = Binding;
- Fields[6].Str = Visibility;
- Fields[7].Str = Section;
- Fields[8].Str = Name;
+ Fields[4].Str = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes));
+
+ Fields[5].Str =
+ printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
+ Fields[6].Str =
+ printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities));
+ Fields[7].Str = getSymbolSectionNdx(Obj, Symbol, FirstSym);
+ Fields[8].Str = this->dumper()->getFullSymbolName(Symbol, StrTable, true);
+
for (auto &Entry : Fields)
printField(Entry);
OS << "\n";
}
-template <class ELFT> void GNUStyle<ELFT>::printSymbols(const ELFO *Obj) {
- if (opts::DynamicSymbols)
+template <class ELFT>
+void GNUStyle<ELFT>::printSymbols(const ELFO *Obj, bool PrintSymbols,
+ bool PrintDynamicSymbols) {
+ if (!PrintSymbols && !PrintDynamicSymbols)
return;
+ // GNU readelf prints both the .dynsym and .symtab with --symbols.
this->dumper()->printSymbolsHelper(true);
- this->dumper()->printSymbolsHelper(false);
+ if (PrintSymbols)
+ this->dumper()->printSymbolsHelper(false);
}
-template <class ELFT>
-void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
+template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) {
if (this->dumper()->getDynamicStringTable().empty())
return;
auto StringTable = this->dumper()->getDynamicStringTable();
auto DynSyms = this->dumper()->dynamic_symbols();
- auto GnuHash = this->dumper()->getGnuHashTable();
- auto SysVHash = this->dumper()->getHashTable();
-
- // If no hash or .gnu.hash found, try using symbol table
- if (GnuHash == nullptr && SysVHash == nullptr)
- this->dumper()->printSymbolsHelper(true);
// Try printing .hash
- if (this->dumper()->getHashTable()) {
+ if (auto SysVHash = this->dumper()->getHashTable()) {
OS << "\n Symbol table of .hash for image:\n";
if (ELFT::Is64Bits)
OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
@@ -3193,14 +3241,12 @@ void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
OS << "\n";
- uint32_t NBuckets = SysVHash->nbucket;
- uint32_t NChains = SysVHash->nchain;
auto Buckets = SysVHash->buckets();
auto Chains = SysVHash->chains();
- for (uint32_t Buc = 0; Buc < NBuckets; Buc++) {
+ for (uint32_t Buc = 0; Buc < SysVHash->nbucket; Buc++) {
if (Buckets[Buc] == ELF::STN_UNDEF)
continue;
- for (uint32_t Ch = Buckets[Buc]; Ch < NChains; Ch = Chains[Ch]) {
+ for (uint32_t Ch = Buckets[Buc]; Ch < SysVHash->nchain; Ch = Chains[Ch]) {
if (Ch == ELF::STN_UNDEF)
break;
printHashedSymbol(Obj, &DynSyms[0], Ch, StringTable, Buc);
@@ -3209,16 +3255,15 @@ void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
}
// Try printing .gnu.hash
- if (GnuHash) {
+ if (auto GnuHash = this->dumper()->getGnuHashTable()) {
OS << "\n Symbol table of .gnu.hash for image:\n";
if (ELFT::Is64Bits)
OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
else
OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
OS << "\n";
- uint32_t NBuckets = GnuHash->nbuckets;
auto Buckets = GnuHash->buckets();
- for (uint32_t Buc = 0; Buc < NBuckets; Buc++) {
+ for (uint32_t Buc = 0; Buc < GnuHash->nbuckets; Buc++) {
if (Buckets[Buc] == ELF::STN_UNDEF)
continue;
uint32_t Index = Buckets[Buc];
@@ -3266,8 +3311,8 @@ bool GNUStyle<ELFT>::checkoffsets(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) {
(IsSpecial && Phdr.p_type != ELF::PT_TLS) ? 0 : Sec.sh_size;
if (Sec.sh_offset >= Phdr.p_offset)
return ((Sec.sh_offset + SectionSize <= Phdr.p_filesz + Phdr.p_offset)
- /*only non-zero sized sections at end*/ &&
- (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz));
+ /*only non-zero sized sections at end*/
+ && (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz));
return false;
}
@@ -3302,12 +3347,21 @@ bool GNUStyle<ELFT>::checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) {
}
template <class ELFT>
+void GNUStyle<ELFT>::printProgramHeaders(
+ const ELFO *Obj, bool PrintProgramHeaders,
+ cl::boolOrDefault PrintSectionMapping) {
+ if (PrintProgramHeaders)
+ printProgramHeaders(Obj);
+
+ // Display the section mapping along with the program headers, unless
+ // -section-mapping is explicitly set to false.
+ if (PrintSectionMapping != cl::BOU_FALSE)
+ printSectionMapping(Obj);
+}
+
+template <class ELFT>
void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
unsigned Bias = ELFT::Is64Bits ? 8 : 0;
- unsigned Width = ELFT::Is64Bits ? 18 : 10;
- unsigned SizeWidth = ELFT::Is64Bits ? 8 : 7;
- std::string Type, Offset, VMA, LMA, FileSz, MemSz, Flag, Align;
-
const Elf_Ehdr *Header = Obj->getHeader();
Field Fields[8] = {2, 17, 26, 37 + Bias,
48 + Bias, 56 + Bias, 64 + Bias, 68 + Bias};
@@ -3323,23 +3377,18 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
else
OS << " Type Offset VirtAddr PhysAddr FileSiz "
<< "MemSiz Flg Align\n";
+
+ unsigned Width = ELFT::Is64Bits ? 18 : 10;
+ unsigned SizeWidth = ELFT::Is64Bits ? 8 : 7;
for (const auto &Phdr : unwrapOrError(Obj->program_headers())) {
- Type = getElfPtType(Header->e_machine, Phdr.p_type);
- Offset = to_string(format_hex(Phdr.p_offset, 8));
- VMA = to_string(format_hex(Phdr.p_vaddr, Width));
- LMA = to_string(format_hex(Phdr.p_paddr, Width));
- FileSz = to_string(format_hex(Phdr.p_filesz, SizeWidth));
- MemSz = to_string(format_hex(Phdr.p_memsz, SizeWidth));
- Flag = printPhdrFlags(Phdr.p_flags);
- Align = to_string(format_hex(Phdr.p_align, 1));
- Fields[0].Str = Type;
- Fields[1].Str = Offset;
- Fields[2].Str = VMA;
- Fields[3].Str = LMA;
- Fields[4].Str = FileSz;
- Fields[5].Str = MemSz;
- Fields[6].Str = Flag;
- Fields[7].Str = Align;
+ Fields[0].Str = getElfPtType(Header->e_machine, Phdr.p_type);
+ Fields[1].Str = to_string(format_hex(Phdr.p_offset, 8));
+ Fields[2].Str = to_string(format_hex(Phdr.p_vaddr, Width));
+ Fields[3].Str = to_string(format_hex(Phdr.p_paddr, Width));
+ Fields[4].Str = to_string(format_hex(Phdr.p_filesz, SizeWidth));
+ Fields[5].Str = to_string(format_hex(Phdr.p_memsz, SizeWidth));
+ Fields[6].Str = printPhdrFlags(Phdr.p_flags);
+ Fields[7].Str = to_string(format_hex(Phdr.p_align, 1));
for (auto Field : Fields)
printField(Field);
if (Phdr.p_type == ELF::PT_INTERP) {
@@ -3348,7 +3397,12 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
}
OS << "\n";
}
+}
+
+template <class ELFT>
+void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) {
OS << "\n Section to Segment mapping:\n Segment Sections...\n";
+ DenseSet<const Elf_Shdr *> BelongsToSegment;
int Phnum = 0;
for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) {
std::string Sections;
@@ -3363,58 +3417,66 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
Phdr.p_type != ELF::PT_TLS;
if (!TbssInNonTLS && checkTLSSections(Phdr, Sec) &&
checkoffsets(Phdr, Sec) && checkVMA(Phdr, Sec) &&
- checkPTDynamic(Phdr, Sec) && (Sec.sh_type != ELF::SHT_NULL))
+ checkPTDynamic(Phdr, Sec) && (Sec.sh_type != ELF::SHT_NULL)) {
Sections += unwrapOrError(Obj->getSectionName(&Sec)).str() + " ";
+ BelongsToSegment.insert(&Sec);
+ }
}
OS << Sections << "\n";
OS.flush();
}
+
+ // Display sections that do not belong to a segment.
+ std::string Sections;
+ for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
+ if (BelongsToSegment.find(&Sec) == BelongsToSegment.end())
+ Sections += unwrapOrError(Obj->getSectionName(&Sec)).str() + ' ';
+ }
+ if (!Sections.empty()) {
+ OS << " None " << Sections << '\n';
+ OS.flush();
+ }
}
template <class ELFT>
void GNUStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela R,
bool IsRela) {
- SmallString<32> RelocName;
- StringRef SymbolName;
- unsigned Width = ELFT::Is64Bits ? 16 : 8;
- unsigned Bias = ELFT::Is64Bits ? 8 : 0;
- // First two fields are bit width dependent. The rest of them are after are
- // fixed width.
- Field Fields[5] = {0, 10 + Bias, 19 + 2 * Bias, 42 + 2 * Bias, 53 + 2 * Bias};
-
uint32_t SymIndex = R.getSymbol(Obj->isMips64EL());
const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex;
- Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName);
- SymbolName =
- unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()));
- std::string Addend, Info, Offset, Value;
- Offset = to_string(format_hex_no_prefix(R.r_offset, Width));
- Info = to_string(format_hex_no_prefix(R.r_info, Width));
- Value = to_string(format_hex_no_prefix(Sym->getValue(), Width));
- int64_t RelAddend = R.r_addend;
- if (!SymbolName.empty() && IsRela) {
- if (R.r_addend < 0)
- Addend = " - ";
- else
- Addend = " + ";
- }
+ std::string SymbolName = maybeDemangle(
+ unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable())));
+ printRelocation(Obj, Sym, SymbolName, R, IsRela);
+}
- if (SymbolName.empty() && Sym->getValue() == 0)
- Value = "";
+template <class ELFT> void GNUStyle<ELFT>::printDynamic(const ELFO *Obj) {
+ Elf_Dyn_Range Table = this->dumper()->dynamic_table();
+ if (Table.empty())
+ return;
- if (IsRela)
- Addend += to_string(format_hex_no_prefix(std::abs(RelAddend), 1));
+ const DynRegionInfo &DynamicTableRegion =
+ this->dumper()->getDynamicTableRegion();
+ OS << "Dynamic section at offset "
+ << format_hex(reinterpret_cast<const uint8_t *>(DynamicTableRegion.Addr) -
+ Obj->base(),
+ 1)
+ << " contains " << Table.size() << " entries:\n";
- Fields[0].Str = Offset;
- Fields[1].Str = Info;
- Fields[2].Str = RelocName.c_str();
- Fields[3].Str = Value;
- Fields[4].Str = SymbolName;
- for (auto &Field : Fields)
- printField(Field);
- OS << Addend;
- OS << "\n";
+ bool Is64 = ELFT::Is64Bits;
+ if (Is64)
+ OS << " Tag Type Name/Value\n";
+ else
+ OS << " Tag Type Name/Value\n";
+ for (auto Entry : Table) {
+ uintX_t Tag = Entry.getTag();
+ std::string TypeString = std::string("(") +
+ getTypeString(Obj->getHeader()->e_machine, Tag) +
+ ")";
+ OS << " " << format_hex(Tag, Is64 ? 18 : 10)
+ << format(" %-20s ", TypeString.c_str());
+ this->dumper()->printDynamicEntry(OS, Tag, Entry.getVal());
+ OS << "\n";
+ }
}
template <class ELFT>
@@ -3427,7 +3489,8 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
OS << "\n'RELA' relocation section at offset "
<< format_hex(reinterpret_cast<const uint8_t *>(DynRelaRegion.Addr) -
Obj->base(),
- 1) << " contains " << DynRelaRegion.Size << " bytes:\n";
+ 1)
+ << " contains " << DynRelaRegion.Size << " bytes:\n";
printRelocHeader(ELF::SHT_RELA);
for (const Elf_Rela &Rela : this->dumper()->dyn_relas())
printDynamicRelocation(Obj, Rela, true);
@@ -3436,7 +3499,8 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
OS << "\n'REL' relocation section at offset "
<< format_hex(reinterpret_cast<const uint8_t *>(DynRelRegion.Addr) -
Obj->base(),
- 1) << " contains " << DynRelRegion.Size << " bytes:\n";
+ 1)
+ << " contains " << DynRelRegion.Size << " bytes:\n";
printRelocHeader(ELF::SHT_REL);
for (const Elf_Rel &Rel : this->dumper()->dyn_rels()) {
Elf_Rela Rela;
@@ -3450,7 +3514,8 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
OS << "\n'RELR' relocation section at offset "
<< format_hex(reinterpret_cast<const uint8_t *>(DynRelrRegion.Addr) -
Obj->base(),
- 1) << " contains " << DynRelrRegion.Size << " bytes:\n";
+ 1)
+ << " contains " << DynRelrRegion.Size << " bytes:\n";
printRelocHeader(ELF::SHT_REL);
Elf_Relr_Range Relrs = this->dumper()->dyn_relrs();
std::vector<Elf_Rela> RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs));
@@ -3462,7 +3527,8 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
OS << "\n'PLT' relocation section at offset "
<< format_hex(reinterpret_cast<const uint8_t *>(DynPLTRelRegion.Addr) -
Obj->base(),
- 1) << " contains " << DynPLTRelRegion.Size << " bytes:\n";
+ 1)
+ << " contains " << DynPLTRelRegion.Size << " bytes:\n";
}
if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) {
printRelocHeader(ELF::SHT_RELA);
@@ -3480,18 +3546,189 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
}
}
+template <class ELFT>
+static void printGNUVersionSectionProlog(formatted_raw_ostream &OS,
+ const Twine &Name, unsigned EntriesNum,
+ const ELFFile<ELFT> *Obj,
+ const typename ELFT::Shdr *Sec) {
+ StringRef SecName = unwrapOrError(Obj->getSectionName(Sec));
+ OS << Name << " section '" << SecName << "' "
+ << "contains " << EntriesNum << " entries:\n";
+
+ const typename ELFT::Shdr *SymTab =
+ unwrapOrError(Obj->getSection(Sec->sh_link));
+ StringRef SymTabName = unwrapOrError(Obj->getSectionName(SymTab));
+ OS << " Addr: " << format_hex_no_prefix(Sec->sh_addr, 16)
+ << " Offset: " << format_hex(Sec->sh_offset, 8)
+ << " Link: " << Sec->sh_link << " (" << SymTabName << ")\n";
+}
+
+template <class ELFT>
+void GNUStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) {
+ if (!Sec)
+ return;
+
+ unsigned Entries = Sec->sh_size / sizeof(Elf_Versym);
+ printGNUVersionSectionProlog(OS, "Version symbols", Entries, Obj, Sec);
+
+ const uint8_t *VersymBuf =
+ reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset);
+ const ELFDumper<ELFT> *Dumper = this->dumper();
+ StringRef StrTable = Dumper->getDynamicStringTable();
+
+ // readelf prints 4 entries per line.
+ for (uint64_t VersymRow = 0; VersymRow < Entries; VersymRow += 4) {
+ OS << " " << format_hex_no_prefix(VersymRow, 3) << ":";
+
+ for (uint64_t VersymIndex = 0;
+ (VersymIndex < 4) && (VersymIndex + VersymRow) < Entries;
+ ++VersymIndex) {
+ const Elf_Versym *Versym =
+ reinterpret_cast<const Elf_Versym *>(VersymBuf);
+ switch (Versym->vs_index) {
+ case 0:
+ OS << " 0 (*local*) ";
+ break;
+ case 1:
+ OS << " 1 (*global*) ";
+ break;
+ default:
+ OS << format("%4x%c", Versym->vs_index & VERSYM_VERSION,
+ Versym->vs_index & VERSYM_HIDDEN ? 'h' : ' ');
+
+ bool IsDefault = true;
+ std::string VersionName = Dumper->getSymbolVersionByIndex(
+ StrTable, Versym->vs_index, IsDefault);
+
+ if (!VersionName.empty())
+ VersionName = "(" + VersionName + ")";
+ else
+ VersionName = "(*invalid*)";
+ OS << left_justify(VersionName, 13);
+ }
+ VersymBuf += sizeof(Elf_Versym);
+ }
+ OS << '\n';
+ }
+ OS << '\n';
+}
+
+static std::string versionFlagToString(unsigned Flags) {
+ if (Flags == 0)
+ return "none";
+
+ std::string Ret;
+ auto AddFlag = [&Ret, &Flags](unsigned Flag, StringRef Name) {
+ if (!(Flags & Flag))
+ return;
+ if (!Ret.empty())
+ Ret += " | ";
+ Ret += Name;
+ Flags &= ~Flag;
+ };
+
+ AddFlag(VER_FLG_BASE, "BASE");
+ AddFlag(VER_FLG_WEAK, "WEAK");
+ AddFlag(VER_FLG_INFO, "INFO");
+ AddFlag(~0, "<unknown>");
+ return Ret;
+}
+
+template <class ELFT>
+void GNUStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) {
+ if (!Sec)
+ return;
+
+ unsigned VerDefsNum = Sec->sh_info;
+ printGNUVersionSectionProlog(OS, "Version definition", VerDefsNum, Obj, Sec);
+
+ const Elf_Shdr *StrTabSec = unwrapOrError(Obj->getSection(Sec->sh_link));
+ StringRef StringTable(
+ reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset),
+ (size_t)StrTabSec->sh_size);
+
+ const uint8_t *VerdefBuf = unwrapOrError(Obj->getSectionContents(Sec)).data();
+ const uint8_t *Begin = VerdefBuf;
+
+ while (VerDefsNum--) {
+ const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf);
+ OS << format(" 0x%04x: Rev: %u Flags: %s Index: %u Cnt: %u",
+ VerdefBuf - Begin, (unsigned)Verdef->vd_version,
+ versionFlagToString(Verdef->vd_flags).c_str(),
+ (unsigned)Verdef->vd_ndx, (unsigned)Verdef->vd_cnt);
+
+ const uint8_t *VerdauxBuf = VerdefBuf + Verdef->vd_aux;
+ const Elf_Verdaux *Verdaux =
+ reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf);
+ OS << format(" Name: %s\n",
+ StringTable.drop_front(Verdaux->vda_name).data());
+
+ for (unsigned I = 1; I < Verdef->vd_cnt; ++I) {
+ VerdauxBuf += Verdaux->vda_next;
+ Verdaux = reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf);
+ OS << format(" 0x%04x: Parent %u: %s\n", VerdauxBuf - Begin, I,
+ StringTable.drop_front(Verdaux->vda_name).data());
+ }
+
+ VerdefBuf += Verdef->vd_next;
+ }
+ OS << '\n';
+}
+
+template <class ELFT>
+void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) {
+ if (!Sec)
+ return;
+
+ unsigned VerneedNum = Sec->sh_info;
+ printGNUVersionSectionProlog(OS, "Version needs", VerneedNum, Obj, Sec);
+
+ ArrayRef<uint8_t> SecData = unwrapOrError(Obj->getSectionContents(Sec));
+
+ const Elf_Shdr *StrTabSec = unwrapOrError(Obj->getSection(Sec->sh_link));
+ StringRef StringTable = {
+ reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset),
+ (size_t)StrTabSec->sh_size};
+
+ const uint8_t *VerneedBuf = SecData.data();
+ for (unsigned I = 0; I < VerneedNum; ++I) {
+ const Elf_Verneed *Verneed =
+ reinterpret_cast<const Elf_Verneed *>(VerneedBuf);
+
+ OS << format(" 0x%04x: Version: %u File: %s Cnt: %u\n",
+ reinterpret_cast<const uint8_t *>(Verneed) - SecData.begin(),
+ (unsigned)Verneed->vn_version,
+ StringTable.drop_front(Verneed->vn_file).data(),
+ (unsigned)Verneed->vn_cnt);
+
+ const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
+ for (unsigned J = 0; J < Verneed->vn_cnt; ++J) {
+ const Elf_Vernaux *Vernaux =
+ reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
+
+ OS << format(" 0x%04x: Name: %s Flags: %s Version: %u\n",
+ reinterpret_cast<const uint8_t *>(Vernaux) - SecData.begin(),
+ StringTable.drop_front(Vernaux->vna_name).data(),
+ versionFlagToString(Vernaux->vna_flags).c_str(),
+ (unsigned)Vernaux->vna_other);
+ VernauxBuf += Vernaux->vna_next;
+ }
+ VerneedBuf += Verneed->vn_next;
+ }
+ OS << '\n';
+}
+
// Hash histogram shows statistics of how efficient the hash was for the
// dynamic symbol table. The table shows number of hash buckets for different
// lengths of chains as absolute number and percentage of the total buckets.
// Additionally cumulative coverage of symbols for each set of buckets.
template <class ELFT>
void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
-
- const Elf_Hash *HashTable = this->dumper()->getHashTable();
- const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable();
-
// Print histogram for .hash section
- if (HashTable) {
+ if (const Elf_Hash *HashTable = this->dumper()->getHashTable()) {
size_t NBucket = HashTable->nbucket;
size_t NChain = HashTable->nchain;
ArrayRef<Elf_Word> Buckets = HashTable->buckets();
@@ -3535,7 +3772,7 @@ void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
}
// Print histogram for .gnu.hash section
- if (GnuHashTable) {
+ if (const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable()) {
size_t NBucket = GnuHashTable->nbuckets;
ArrayRef<Elf_Word> Buckets = GnuHashTable->buckets();
unsigned NumSyms = this->dumper()->dynamic_symbols().size();
@@ -3595,6 +3832,24 @@ void GNUStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) {
OS << "GNUStyle::printAddrsig not implemented\n";
}
+static StringRef getGenericNoteTypeName(const uint32_t NT) {
+ static const struct {
+ uint32_t ID;
+ const char *Name;
+ } Notes[] = {
+ {ELF::NT_VERSION, "NT_VERSION (version)"},
+ {ELF::NT_ARCH, "NT_ARCH (architecture)"},
+ {ELF::NT_GNU_BUILD_ATTRIBUTE_OPEN, "OPEN"},
+ {ELF::NT_GNU_BUILD_ATTRIBUTE_FUNC, "func"},
+ };
+
+ for (const auto &Note : Notes)
+ if (Note.ID == NT)
+ return Note.Name;
+
+ return "";
+}
+
static std::string getGNUNoteTypeName(const uint32_t NT) {
static const struct {
uint32_t ID;
@@ -3649,14 +3904,11 @@ static std::string getAMDNoteTypeName(const uint32_t NT) {
static const struct {
uint32_t ID;
const char *Name;
- } Notes[] = {
- {ELF::NT_AMD_AMDGPU_HSA_METADATA,
- "NT_AMD_AMDGPU_HSA_METADATA (HSA Metadata)"},
- {ELF::NT_AMD_AMDGPU_ISA,
- "NT_AMD_AMDGPU_ISA (ISA Version)"},
- {ELF::NT_AMD_AMDGPU_PAL_METADATA,
- "NT_AMD_AMDGPU_PAL_METADATA (PAL Metadata)"}
- };
+ } Notes[] = {{ELF::NT_AMD_AMDGPU_HSA_METADATA,
+ "NT_AMD_AMDGPU_HSA_METADATA (HSA Metadata)"},
+ {ELF::NT_AMD_AMDGPU_ISA, "NT_AMD_AMDGPU_ISA (ISA Version)"},
+ {ELF::NT_AMD_AMDGPU_PAL_METADATA,
+ "NT_AMD_AMDGPU_PAL_METADATA (PAL Metadata)"}};
for (const auto &Note : Notes)
if (Note.ID == NT)
@@ -3683,6 +3935,16 @@ static std::string getGNUProperty(uint32_t Type, uint32_t DataSize,
ArrayRef<uint8_t> Data) {
std::string str;
raw_string_ostream OS(str);
+ uint32_t PrData;
+ auto DumpBit = [&](uint32_t Flag, StringRef Name) {
+ if (PrData & Flag) {
+ PrData &= ~Flag;
+ OS << Name;
+ if (PrData)
+ OS << ", ";
+ }
+ };
+
switch (Type) {
default:
OS << format("<application-specific type 0x%x>", Type);
@@ -3701,41 +3963,101 @@ static std::string getGNUProperty(uint32_t Type, uint32_t DataSize,
if (DataSize)
OS << format(" <corrupt length: 0x%x>", DataSize);
return OS.str();
+ case GNU_PROPERTY_AARCH64_FEATURE_1_AND:
case GNU_PROPERTY_X86_FEATURE_1_AND:
- OS << "X86 features: ";
- if (DataSize != 4 && DataSize != 8) {
+ OS << ((Type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) ? "aarch64 feature: "
+ : "x86 feature: ");
+ if (DataSize != 4) {
OS << format("<corrupt length: 0x%x>", DataSize);
return OS.str();
}
- uint64_t CFProtection =
- (DataSize == 4)
- ? support::endian::read32<ELFT::TargetEndianness>(Data.data())
- : support::endian::read64<ELFT::TargetEndianness>(Data.data());
- if (CFProtection == 0) {
- OS << "none";
+ PrData = support::endian::read32<ELFT::TargetEndianness>(Data.data());
+ if (PrData == 0) {
+ OS << "<None>";
return OS.str();
}
- if (CFProtection & GNU_PROPERTY_X86_FEATURE_1_IBT) {
- OS << "IBT";
- CFProtection &= ~GNU_PROPERTY_X86_FEATURE_1_IBT;
- if (CFProtection)
- OS << ", ";
+ if (Type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
+ DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_BTI, "BTI");
+ DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_PAC, "PAC");
+ } else {
+ DumpBit(GNU_PROPERTY_X86_FEATURE_1_IBT, "IBT");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_1_SHSTK, "SHSTK");
}
- if (CFProtection & GNU_PROPERTY_X86_FEATURE_1_SHSTK) {
- OS << "SHSTK";
- CFProtection &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK;
- if (CFProtection)
- OS << ", ";
+ if (PrData)
+ OS << format("<unknown flags: 0x%x>", PrData);
+ return OS.str();
+ case GNU_PROPERTY_X86_ISA_1_NEEDED:
+ case GNU_PROPERTY_X86_ISA_1_USED:
+ OS << "x86 ISA "
+ << (Type == GNU_PROPERTY_X86_ISA_1_NEEDED ? "needed: " : "used: ");
+ if (DataSize != 4) {
+ OS << format("<corrupt length: 0x%x>", DataSize);
+ return OS.str();
}
- if (CFProtection)
- OS << format("<unknown flags: 0x%llx>", CFProtection);
+ PrData = support::endian::read32<ELFT::TargetEndianness>(Data.data());
+ if (PrData == 0) {
+ OS << "<None>";
+ return OS.str();
+ }
+ DumpBit(GNU_PROPERTY_X86_ISA_1_CMOV, "CMOV");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_SSE, "SSE");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_SSE2, "SSE2");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_SSE3, "SSE3");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_SSSE3, "SSSE3");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_SSE4_1, "SSE4_1");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_SSE4_2, "SSE4_2");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX, "AVX");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX2, "AVX2");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_FMA, "FMA");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512F, "AVX512F");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512CD, "AVX512CD");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512ER, "AVX512ER");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512PF, "AVX512PF");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512VL, "AVX512VL");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512DQ, "AVX512DQ");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512BW, "AVX512BW");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_4FMAPS, "AVX512_4FMAPS");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_4VNNIW, "AVX512_4VNNIW");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_BITALG, "AVX512_BITALG");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_IFMA, "AVX512_IFMA");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_VBMI, "AVX512_VBMI");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_VBMI2, "AVX512_VBMI2");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_VNNI, "AVX512_VNNI");
+ if (PrData)
+ OS << format("<unknown flags: 0x%x>", PrData);
+ return OS.str();
+ break;
+ case GNU_PROPERTY_X86_FEATURE_2_NEEDED:
+ case GNU_PROPERTY_X86_FEATURE_2_USED:
+ OS << "x86 feature "
+ << (Type == GNU_PROPERTY_X86_FEATURE_2_NEEDED ? "needed: " : "used: ");
+ if (DataSize != 4) {
+ OS << format("<corrupt length: 0x%x>", DataSize);
+ return OS.str();
+ }
+ PrData = support::endian::read32<ELFT::TargetEndianness>(Data.data());
+ if (PrData == 0) {
+ OS << "<None>";
+ return OS.str();
+ }
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_X86, "x86");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_X87, "x87");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_MMX, "MMX");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_XMM, "XMM");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_YMM, "YMM");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_ZMM, "ZMM");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_FXSR, "FXSR");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_XSAVE, "XSAVE");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_XSAVEOPT, "XSAVEOPT");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_XSAVEC, "XSAVEC");
+ if (PrData)
+ OS << format("<unknown flags: 0x%x>", PrData);
return OS.str();
}
}
template <typename ELFT>
-static SmallVector<std::string, 4>
-getGNUPropertyList(ArrayRef<uint8_t> Arr) {
+static SmallVector<std::string, 4> getGNUPropertyList(ArrayRef<uint8_t> Arr) {
using Elf_Word = typename ELFT::Word;
SmallVector<std::string, 4> Properties;
@@ -3770,12 +4092,11 @@ struct GNUAbiTag {
bool IsValid;
};
-template <typename ELFT>
-static GNUAbiTag getGNUAbiTag(ArrayRef<uint8_t> Desc) {
+template <typename ELFT> static GNUAbiTag getGNUAbiTag(ArrayRef<uint8_t> Desc) {
typedef typename ELFT::Word Elf_Word;
- ArrayRef<Elf_Word> Words(reinterpret_cast<const Elf_Word*>(Desc.begin()),
- reinterpret_cast<const Elf_Word*>(Desc.end()));
+ ArrayRef<Elf_Word> Words(reinterpret_cast<const Elf_Word *>(Desc.begin()),
+ reinterpret_cast<const Elf_Word *>(Desc.end()));
if (Words.size() < 4)
return {"", "", /*IsValid=*/false};
@@ -3846,24 +4167,13 @@ static AMDNote getAMDNote(uint32_t NoteType, ArrayRef<uint8_t> Desc) {
default:
return {"", ""};
case ELF::NT_AMD_AMDGPU_HSA_METADATA:
- return {"HSA Metadata",
- std::string(reinterpret_cast<const char *>(Desc.data()),
- Desc.size())};
+ return {
+ "HSA Metadata",
+ std::string(reinterpret_cast<const char *>(Desc.data()), Desc.size())};
case ELF::NT_AMD_AMDGPU_ISA:
- return {"ISA Version",
- std::string(reinterpret_cast<const char *>(Desc.data()),
- Desc.size())};
- case ELF::NT_AMD_AMDGPU_PAL_METADATA:
- const uint32_t *PALMetadataBegin =
- reinterpret_cast<const uint32_t *>(Desc.data());
- const uint32_t *PALMetadataEnd = PALMetadataBegin + Desc.size();
- std::vector<uint32_t> PALMetadata(PALMetadataBegin, PALMetadataEnd);
- std::string PALMetadataString;
- auto Error = AMDGPU::PALMD::toString(PALMetadata, PALMetadataString);
- if (Error) {
- return {"PAL Metadata", "Invalid"};
- }
- return {"PAL Metadata", PALMetadataString};
+ return {
+ "ISA Version",
+ std::string(reinterpret_cast<const char *>(Desc.data()), Desc.size())};
}
}
@@ -3877,36 +4187,28 @@ static AMDGPUNote getAMDGPUNote(uint32_t NoteType, ArrayRef<uint8_t> Desc) {
switch (NoteType) {
default:
return {"", ""};
- case ELF::NT_AMDGPU_METADATA:
+ case ELF::NT_AMDGPU_METADATA: {
auto MsgPackString =
StringRef(reinterpret_cast<const char *>(Desc.data()), Desc.size());
- msgpack::Reader MsgPackReader(MsgPackString);
- auto OptMsgPackNodeOrErr = msgpack::Node::read(MsgPackReader);
- if (errorToBool(OptMsgPackNodeOrErr.takeError()))
- return {"AMDGPU Metadata", "Invalid AMDGPU Metadata"};
- auto &OptMsgPackNode = *OptMsgPackNodeOrErr;
- if (!OptMsgPackNode)
+ msgpack::Document MsgPackDoc;
+ if (!MsgPackDoc.readFromBlob(MsgPackString, /*Multi=*/false))
return {"AMDGPU Metadata", "Invalid AMDGPU Metadata"};
- auto &MsgPackNode = *OptMsgPackNode;
AMDGPU::HSAMD::V3::MetadataVerifier Verifier(true);
- if (!Verifier.verify(*MsgPackNode))
+ if (!Verifier.verify(MsgPackDoc.getRoot()))
return {"AMDGPU Metadata", "Invalid AMDGPU Metadata"};
std::string HSAMetadataString;
raw_string_ostream StrOS(HSAMetadataString);
- yaml::Output YOut(StrOS);
- YOut << MsgPackNode;
+ MsgPackDoc.toYAML(StrOS);
return {"AMDGPU Metadata", StrOS.str()};
}
+ }
}
template <class ELFT>
void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
- const Elf_Ehdr *e = Obj->getHeader();
- bool IsCore = e->e_type == ELF::ET_CORE;
-
auto PrintHeader = [&](const typename ELFT::Off Offset,
const typename ELFT::Addr Size) {
OS << "Displaying notes found at file offset " << format_hex(Offset, 10)
@@ -3938,12 +4240,16 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
if (!N.Type.empty())
OS << " " << N.Type << ":\n " << N.Value << '\n';
} else {
- OS << "Unknown note type: (" << format_hex(Type, 10) << ')';
+ StringRef NoteType = getGenericNoteTypeName(Type);
+ if (!NoteType.empty())
+ OS << NoteType;
+ else
+ OS << "Unknown note type: (" << format_hex(Type, 10) << ')';
}
OS << '\n';
};
- if (IsCore) {
+ if (Obj->getHeader()->e_type == ELF::ET_CORE) {
for (const auto &P : unwrapOrError(Obj->program_headers())) {
if (P.p_type != PT_NOTE)
continue;
@@ -3992,7 +4298,10 @@ void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
<< format_hex_no_prefix(Parser.getGp(), 8 + Bias) << "\n\n";
OS << " Reserved entries:\n";
- OS << " Address Access Initial Purpose\n";
+ if (ELFT::Is64Bits)
+ OS << " Address Access Initial Purpose\n";
+ else
+ OS << " Address Access Initial Purpose\n";
PrintEntry(Parser.getGotLazyResolver(), "Lazy resolver");
if (Parser.getGotModulePointer())
PrintEntry(Parser.getGotModulePointer(), "Module pointer (GNU extension)");
@@ -4000,7 +4309,10 @@ void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
if (!Parser.getLocalEntries().empty()) {
OS << "\n";
OS << " Local entries:\n";
- OS << " Address Access Initial\n";
+ if (ELFT::Is64Bits)
+ OS << " Address Access Initial\n";
+ else
+ OS << " Address Access Initial\n";
for (auto &E : Parser.getLocalEntries())
PrintEntry(&E, "");
}
@@ -4011,7 +4323,11 @@ void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
if (!Parser.getGlobalEntries().empty()) {
OS << "\n";
OS << " Global entries:\n";
- OS << " Address Access Initial Sym.Val. Type Ndx Name\n";
+ if (ELFT::Is64Bits)
+ OS << " Address Access Initial Sym.Val."
+ << " Type Ndx Name\n";
+ else
+ OS << " Address Access Initial Sym.Val. Type Ndx Name\n";
for (auto &E : Parser.getGlobalEntries()) {
const Elf_Sym *Sym = Parser.getGotSym(&E);
std::string SymName = this->dumper()->getFullSymbolName(
@@ -4045,7 +4361,7 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
size_t Bias = ELFT::Is64Bits ? 8 : 0;
auto PrintEntry = [&](const Elf_Addr *E, StringRef Purpose) {
OS.PadToColumn(2);
- OS << format_hex_no_prefix(Parser.getGotAddress(E), 8 + Bias);
+ OS << format_hex_no_prefix(Parser.getPltAddress(E), 8 + Bias);
OS.PadToColumn(11 + Bias);
OS << format_hex_no_prefix(*E, 8 + Bias);
OS.PadToColumn(20 + 2 * Bias);
@@ -4058,7 +4374,7 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
OS << " Address Initial Purpose\n";
PrintEntry(Parser.getPltLazyResolver(), "PLT lazy resolver");
if (Parser.getPltModulePointer())
- PrintEntry(Parser.getGotModulePointer(), "Module pointer");
+ PrintEntry(Parser.getPltModulePointer(), "Module pointer");
if (!Parser.getPltEntries().empty()) {
OS << "\n";
@@ -4070,7 +4386,7 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
Sym, this->dumper()->getDynamicStringTable(), false);
OS.PadToColumn(2);
- OS << to_string(format_hex_no_prefix(Parser.getGotAddress(&E), 8 + Bias));
+ OS << to_string(format_hex_no_prefix(Parser.getPltAddress(&E), 8 + Bias));
OS.PadToColumn(11 + Bias);
OS << to_string(format_hex_no_prefix(E, 8 + Bias));
OS.PadToColumn(20 + 2 * Bias);
@@ -4087,21 +4403,21 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
}
template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) {
- const Elf_Ehdr *e = Obj->getHeader();
+ const Elf_Ehdr *E = Obj->getHeader();
{
DictScope D(W, "ElfHeader");
{
DictScope D(W, "Ident");
- W.printBinary("Magic", makeArrayRef(e->e_ident).slice(ELF::EI_MAG0, 4));
- W.printEnum("Class", e->e_ident[ELF::EI_CLASS], makeArrayRef(ElfClass));
- W.printEnum("DataEncoding", e->e_ident[ELF::EI_DATA],
+ W.printBinary("Magic", makeArrayRef(E->e_ident).slice(ELF::EI_MAG0, 4));
+ W.printEnum("Class", E->e_ident[ELF::EI_CLASS], makeArrayRef(ElfClass));
+ W.printEnum("DataEncoding", E->e_ident[ELF::EI_DATA],
makeArrayRef(ElfDataEncoding));
- W.printNumber("FileVersion", e->e_ident[ELF::EI_VERSION]);
+ W.printNumber("FileVersion", E->e_ident[ELF::EI_VERSION]);
auto OSABI = makeArrayRef(ElfOSABI);
- if (e->e_ident[ELF::EI_OSABI] >= ELF::ELFOSABI_FIRST_ARCH &&
- e->e_ident[ELF::EI_OSABI] <= ELF::ELFOSABI_LAST_ARCH) {
- switch (e->e_machine) {
+ if (E->e_ident[ELF::EI_OSABI] >= ELF::ELFOSABI_FIRST_ARCH &&
+ E->e_ident[ELF::EI_OSABI] <= ELF::ELFOSABI_LAST_ARCH) {
+ switch (E->e_machine) {
case ELF::EM_AMDGPU:
OSABI = makeArrayRef(AMDGPUElfOSABI);
break;
@@ -4113,34 +4429,35 @@ template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) {
break;
}
}
- W.printEnum("OS/ABI", e->e_ident[ELF::EI_OSABI], OSABI);
- W.printNumber("ABIVersion", e->e_ident[ELF::EI_ABIVERSION]);
- W.printBinary("Unused", makeArrayRef(e->e_ident).slice(ELF::EI_PAD));
+ W.printEnum("OS/ABI", E->e_ident[ELF::EI_OSABI], OSABI);
+ W.printNumber("ABIVersion", E->e_ident[ELF::EI_ABIVERSION]);
+ W.printBinary("Unused", makeArrayRef(E->e_ident).slice(ELF::EI_PAD));
}
- W.printEnum("Type", e->e_type, makeArrayRef(ElfObjectFileType));
- W.printEnum("Machine", e->e_machine, makeArrayRef(ElfMachineType));
- W.printNumber("Version", e->e_version);
- W.printHex("Entry", e->e_entry);
- W.printHex("ProgramHeaderOffset", e->e_phoff);
- W.printHex("SectionHeaderOffset", e->e_shoff);
- if (e->e_machine == EM_MIPS)
- W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderMipsFlags),
+ W.printEnum("Type", E->e_type, makeArrayRef(ElfObjectFileType));
+ W.printEnum("Machine", E->e_machine, makeArrayRef(ElfMachineType));
+ W.printNumber("Version", E->e_version);
+ W.printHex("Entry", E->e_entry);
+ W.printHex("ProgramHeaderOffset", E->e_phoff);
+ W.printHex("SectionHeaderOffset", E->e_shoff);
+ if (E->e_machine == EM_MIPS)
+ W.printFlags("Flags", E->e_flags, makeArrayRef(ElfHeaderMipsFlags),
unsigned(ELF::EF_MIPS_ARCH), unsigned(ELF::EF_MIPS_ABI),
unsigned(ELF::EF_MIPS_MACH));
- else if (e->e_machine == EM_AMDGPU)
- W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderAMDGPUFlags),
+ else if (E->e_machine == EM_AMDGPU)
+ W.printFlags("Flags", E->e_flags, makeArrayRef(ElfHeaderAMDGPUFlags),
unsigned(ELF::EF_AMDGPU_MACH));
- else if (e->e_machine == EM_RISCV)
- W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderRISCVFlags));
+ else if (E->e_machine == EM_RISCV)
+ W.printFlags("Flags", E->e_flags, makeArrayRef(ElfHeaderRISCVFlags));
else
- W.printFlags("Flags", e->e_flags);
- W.printNumber("HeaderSize", e->e_ehsize);
- W.printNumber("ProgramHeaderEntrySize", e->e_phentsize);
- W.printNumber("ProgramHeaderCount", e->e_phnum);
- W.printNumber("SectionHeaderEntrySize", e->e_shentsize);
+ W.printFlags("Flags", E->e_flags);
+ W.printNumber("HeaderSize", E->e_ehsize);
+ W.printNumber("ProgramHeaderEntrySize", E->e_phentsize);
+ W.printNumber("ProgramHeaderCount", E->e_phnum);
+ W.printNumber("SectionHeaderEntrySize", E->e_shentsize);
W.printString("SectionHeaderCount", getSectionHeadersNumString(Obj));
- W.printString("StringTableSectionIndex", getSectionHeaderTableIndexString(Obj));
+ W.printString("StringTableSectionIndex",
+ getSectionHeaderTableIndexString(Obj));
}
}
@@ -4185,10 +4502,8 @@ template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const ELFO *Obj) {
for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
++SectionNumber;
- if (Sec.sh_type != ELF::SHT_REL &&
- Sec.sh_type != ELF::SHT_RELA &&
- Sec.sh_type != ELF::SHT_RELR &&
- Sec.sh_type != ELF::SHT_ANDROID_REL &&
+ if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA &&
+ Sec.sh_type != ELF::SHT_RELR && Sec.sh_type != ELF::SHT_ANDROID_REL &&
Sec.sh_type != ELF::SHT_ANDROID_RELA &&
Sec.sh_type != ELF::SHT_ANDROID_RELR)
continue;
@@ -4249,7 +4564,7 @@ void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, Elf_Rela Rel,
const Elf_Shdr *SymTab) {
SmallString<32> RelocName;
Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);
- StringRef TargetName;
+ std::string TargetName;
const Elf_Sym *Sym = unwrapOrError(Obj->getRelocationSymbol(&Rel, SymTab));
if (Sym && Sym->getType() == ELF::STT_SECTION) {
const Elf_Shdr *Sec = unwrapOrError(
@@ -4257,7 +4572,8 @@ void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, Elf_Rela Rel,
TargetName = unwrapOrError(Obj->getSectionName(Sec));
} else if (Sym) {
StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab));
- TargetName = unwrapOrError(Sym->getName(StrTable));
+ TargetName = this->dumper()->getFullSymbolName(
+ Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */);
}
if (opts::ExpandRelocs) {
@@ -4270,8 +4586,8 @@ void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, Elf_Rela Rel,
} else {
raw_ostream &OS = W.startLine();
OS << W.hex(Rel.r_offset) << " " << RelocName << " "
- << (!TargetName.empty() ? TargetName : "-") << " "
- << W.hex(Rel.r_addend) << "\n";
+ << (!TargetName.empty() ? TargetName : "-") << " " << W.hex(Rel.r_addend)
+ << "\n";
}
}
@@ -4280,13 +4596,12 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
ListScope SectionsD(W, "Sections");
int SectionIndex = -1;
- for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
- ++SectionIndex;
-
- StringRef Name = unwrapOrError(Obj->getSectionName(&Sec));
-
+ ArrayRef<Elf_Shdr> Sections = unwrapOrError(Obj->sections());
+ const ELFObjectFile<ELFT> *ElfObj = this->dumper()->getElfObject();
+ for (const Elf_Shdr &Sec : Sections) {
+ StringRef Name = getSectionName(Sec, *ElfObj, Sections);
DictScope SectionD(W, "Section");
- W.printNumber("Index", SectionIndex);
+ W.printNumber("Index", ++SectionIndex);
W.printNumber("Name", Name, Sec.sh_name);
W.printHex(
"Type",
@@ -4350,8 +4665,9 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
if (opts::SectionData && Sec.sh_type != ELF::SHT_NOBITS) {
ArrayRef<uint8_t> Data = unwrapOrError(Obj->getSectionContents(&Sec));
- W.printBinaryBlock("SectionData",
- StringRef((const char *)Data.data(), Data.size()));
+ W.printBinaryBlock(
+ "SectionData",
+ StringRef(reinterpret_cast<const char *>(Data.data()), Data.size()));
}
}
}
@@ -4402,6 +4718,15 @@ void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
W.printHex("Section", SectionName, SectionIndex);
}
+template <class ELFT>
+void LLVMStyle<ELFT>::printSymbols(const ELFO *Obj, bool PrintSymbols,
+ bool PrintDynamicSymbols) {
+ if (PrintSymbols)
+ printSymbols(Obj);
+ if (PrintDynamicSymbols)
+ printDynamicSymbols(Obj);
+}
+
template <class ELFT> void LLVMStyle<ELFT>::printSymbols(const ELFO *Obj) {
ListScope Group(W, "Symbols");
this->dumper()->printSymbolsHelper(false);
@@ -4413,6 +4738,31 @@ void LLVMStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
this->dumper()->printSymbolsHelper(true);
}
+template <class ELFT> void LLVMStyle<ELFT>::printDynamic(const ELFFile<ELFT> *Obj) {
+ Elf_Dyn_Range Table = this->dumper()->dynamic_table();
+ if (Table.empty())
+ return;
+
+ raw_ostream &OS = W.getOStream();
+ W.startLine() << "DynamicSection [ (" << Table.size() << " entries)\n";
+
+ bool Is64 = ELFT::Is64Bits;
+ if (Is64)
+ W.startLine() << " Tag Type Name/Value\n";
+ else
+ W.startLine() << " Tag Type Name/Value\n";
+ for (auto Entry : Table) {
+ uintX_t Tag = Entry.getTag();
+ W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, true) << " "
+ << format("%-21s",
+ getTypeString(Obj->getHeader()->e_machine, Tag));
+ this->dumper()->printDynamicEntry(OS, Tag, Entry.getVal());
+ OS << "\n";
+ }
+
+ W.startLine() << "]\n";
+}
+
template <class ELFT>
void LLVMStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
const DynRegionInfo &DynRelRegion = this->dumper()->getDynRelRegion();
@@ -4459,11 +4809,11 @@ template <class ELFT>
void LLVMStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel) {
SmallString<32> RelocName;
Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);
- StringRef SymbolName;
+ std::string SymbolName;
uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL());
const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex;
- SymbolName =
- unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()));
+ SymbolName = maybeDemangle(
+ unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable())));
if (opts::ExpandRelocs) {
DictScope Group(W, "Relocation");
W.printHex("Offset", Rel.r_offset);
@@ -4473,12 +4823,22 @@ void LLVMStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel) {
} else {
raw_ostream &OS = W.startLine();
OS << W.hex(Rel.r_offset) << " " << RelocName << " "
- << (!SymbolName.empty() ? SymbolName : "-") << " "
- << W.hex(Rel.r_addend) << "\n";
+ << (!SymbolName.empty() ? SymbolName : "-") << " " << W.hex(Rel.r_addend)
+ << "\n";
}
}
template <class ELFT>
+void LLVMStyle<ELFT>::printProgramHeaders(
+ const ELFO *Obj, bool PrintProgramHeaders,
+ cl::boolOrDefault PrintSectionMapping) {
+ if (PrintProgramHeaders)
+ printProgramHeaders(Obj);
+ if (PrintSectionMapping == cl::BOU_TRUE)
+ printSectionMapping(Obj);
+}
+
+template <class ELFT>
void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
ListScope L(W, "ProgramHeaders");
@@ -4498,6 +4858,125 @@ void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
}
template <class ELFT>
+void LLVMStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) {
+ DictScope SS(W, "Version symbols");
+ if (!Sec)
+ return;
+
+ StringRef SecName = unwrapOrError(Obj->getSectionName(Sec));
+ W.printNumber("Section Name", SecName, Sec->sh_name);
+ W.printHex("Address", Sec->sh_addr);
+ W.printHex("Offset", Sec->sh_offset);
+ W.printNumber("Link", Sec->sh_link);
+
+ const uint8_t *VersymBuf =
+ reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset);
+ const ELFDumper<ELFT> *Dumper = this->dumper();
+ StringRef StrTable = Dumper->getDynamicStringTable();
+
+ // Same number of entries in the dynamic symbol table (DT_SYMTAB).
+ ListScope Syms(W, "Symbols");
+ for (const Elf_Sym &Sym : Dumper->dynamic_symbols()) {
+ DictScope S(W, "Symbol");
+ const Elf_Versym *Versym = reinterpret_cast<const Elf_Versym *>(VersymBuf);
+ std::string FullSymbolName =
+ Dumper->getFullSymbolName(&Sym, StrTable, true /* IsDynamic */);
+ W.printNumber("Version", Versym->vs_index & VERSYM_VERSION);
+ W.printString("Name", FullSymbolName);
+ VersymBuf += sizeof(Elf_Versym);
+ }
+}
+
+template <class ELFT>
+void LLVMStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) {
+ DictScope SD(W, "SHT_GNU_verdef");
+ if (!Sec)
+ return;
+
+ const uint8_t *SecStartAddress =
+ reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset);
+ const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size;
+ const uint8_t *VerdefBuf = SecStartAddress;
+ const Elf_Shdr *StrTab = unwrapOrError(Obj->getSection(Sec->sh_link));
+
+ unsigned VerDefsNum = Sec->sh_info;
+ while (VerDefsNum--) {
+ if (VerdefBuf + sizeof(Elf_Verdef) > SecEndAddress)
+ // FIXME: report_fatal_error is not a good way to report error. We should
+ // emit a parsing error here and below.
+ report_fatal_error("invalid offset in the section");
+
+ const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf);
+ DictScope Def(W, "Definition");
+ W.printNumber("Version", Verdef->vd_version);
+ W.printEnum("Flags", Verdef->vd_flags, makeArrayRef(SymVersionFlags));
+ W.printNumber("Index", Verdef->vd_ndx);
+ W.printNumber("Hash", Verdef->vd_hash);
+ W.printString("Name", StringRef(reinterpret_cast<const char *>(
+ Obj->base() + StrTab->sh_offset +
+ Verdef->getAux()->vda_name)));
+ if (!Verdef->vd_cnt)
+ report_fatal_error("at least one definition string must exist");
+ if (Verdef->vd_cnt > 2)
+ report_fatal_error("more than one predecessor is not expected");
+
+ if (Verdef->vd_cnt == 2) {
+ const uint8_t *VerdauxBuf =
+ VerdefBuf + Verdef->vd_aux + Verdef->getAux()->vda_next;
+ const Elf_Verdaux *Verdaux =
+ reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf);
+ W.printString("Predecessor",
+ StringRef(reinterpret_cast<const char *>(
+ Obj->base() + StrTab->sh_offset + Verdaux->vda_name)));
+ }
+ VerdefBuf += Verdef->vd_next;
+ }
+}
+
+template <class ELFT>
+void LLVMStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) {
+ DictScope SD(W, "SHT_GNU_verneed");
+ if (!Sec)
+ return;
+
+ const uint8_t *SecData =
+ reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset);
+ const Elf_Shdr *StrTab = unwrapOrError(Obj->getSection(Sec->sh_link));
+
+ const uint8_t *VerneedBuf = SecData;
+ unsigned VerneedNum = Sec->sh_info;
+ for (unsigned I = 0; I < VerneedNum; ++I) {
+ const Elf_Verneed *Verneed =
+ reinterpret_cast<const Elf_Verneed *>(VerneedBuf);
+ DictScope Entry(W, "Dependency");
+ W.printNumber("Version", Verneed->vn_version);
+ W.printNumber("Count", Verneed->vn_cnt);
+ W.printString("FileName",
+ StringRef(reinterpret_cast<const char *>(
+ Obj->base() + StrTab->sh_offset + Verneed->vn_file)));
+
+ const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
+ ListScope L(W, "Entries");
+ for (unsigned J = 0; J < Verneed->vn_cnt; ++J) {
+ const Elf_Vernaux *Vernaux =
+ reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
+ DictScope Entry(W, "Entry");
+ W.printNumber("Hash", Vernaux->vna_hash);
+ W.printEnum("Flags", Vernaux->vna_flags, makeArrayRef(SymVersionFlags));
+ W.printNumber("Index", Vernaux->vna_other);
+ W.printString("Name",
+ StringRef(reinterpret_cast<const char *>(
+ Obj->base() + StrTab->sh_offset + Vernaux->vna_name)));
+ VernauxBuf += Vernaux->vna_next;
+ }
+ VerneedBuf += Verneed->vn_next;
+ }
+}
+
+template <class ELFT>
void LLVMStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
W.startLine() << "Hash Histogram not implemented!\n";
}
@@ -4542,8 +5021,7 @@ void LLVMStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) {
}
template <typename ELFT>
-static void printGNUNoteLLVMStyle(uint32_t NoteType,
- ArrayRef<uint8_t> Desc,
+static void printGNUNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc,
ScopedPrinter &W) {
switch (NoteType) {
default:
@@ -4576,8 +5054,6 @@ static void printGNUNoteLLVMStyle(uint32_t NoteType,
template <class ELFT>
void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
ListScope L(W, "Notes");
- const Elf_Ehdr *e = Obj->getHeader();
- bool IsCore = e->e_type == ELF::ET_CORE;
auto PrintHeader = [&](const typename ELFT::Off Offset,
const typename ELFT::Addr Size) {
@@ -4609,11 +5085,16 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
if (!N.Type.empty())
W.printString(N.Type, N.Value);
} else {
- W.getOStream() << "Unknown note type: (" << format_hex(Type, 10) << ')';
+ StringRef NoteType = getGenericNoteTypeName(Type);
+ if (!NoteType.empty())
+ W.printString("Type", NoteType);
+ else
+ W.printString("Type",
+ "Unknown (" + to_string(format_hex(Type, 10)) + ")");
}
};
- if (IsCore) {
+ if (Obj->getHeader()->e_type == ELF::ET_CORE) {
for (const auto &P : unwrapOrError(Obj->program_headers())) {
if (P.p_type != PT_NOTE)
continue;
diff --git a/contrib/llvm/tools/llvm-readobj/Error.cpp b/contrib/llvm/tools/llvm-readobj/Error.cpp
index 03d349440e6b..1010f18a58c8 100644
--- a/contrib/llvm/tools/llvm-readobj/Error.cpp
+++ b/contrib/llvm/tools/llvm-readobj/Error.cpp
@@ -1,9 +1,8 @@
//===- Error.cpp - system_error extensions for llvm-readobj -----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-readobj/Error.h b/contrib/llvm/tools/llvm-readobj/Error.h
index f3e24bbe5dbf..f390e1b96f8a 100644
--- a/contrib/llvm/tools/llvm-readobj/Error.h
+++ b/contrib/llvm/tools/llvm-readobj/Error.h
@@ -1,9 +1,8 @@
//===- Error.h - system_error extensions for llvm-readobj -------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-readobj/MachODumper.cpp b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp
index 35e4cfcb6b10..32a3866eb2f2 100644
--- a/contrib/llvm/tools/llvm-readobj/MachODumper.cpp
+++ b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp
@@ -1,9 +1,8 @@
-//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//
+//===- MachODumper.cpp - Object file dumping utility for llvm -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -34,8 +33,6 @@ public:
void printFileHeaders() override;
void printSectionHeaders() override;
void printRelocations() override;
- void printSymbols() override;
- void printDynamicSymbols() override;
void printUnwindInfo() override;
void printStackMap() const override;
@@ -53,6 +50,8 @@ private:
template<class MachHeader>
void printFileHeaders(const MachHeader &Header);
+ void printSymbols() override;
+ void printDynamicSymbols() override;
void printSymbol(const SymbolRef &Symbol);
void printRelocation(const RelocationRef &Reloc);
@@ -163,6 +162,7 @@ static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesARM[] = {
static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesARM64[] = {
LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64_ALL),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64E),
};
static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesSPARC[] = {
@@ -483,15 +483,8 @@ void MachODumper::printSectionHeaders(const MachOObjectFile *Obj) {
}
}
- if (opts::SectionData) {
- bool IsBSS = Section.isBSS();
- if (!IsBSS) {
- StringRef Data;
- error(Section.getContents(Data));
-
- W.printBinaryBlock("SectionData", Data);
- }
- }
+ if (opts::SectionData && !Section.isBSS())
+ W.printBinaryBlock("SectionData", unwrapOrError(Section.getContents()));
}
}
@@ -660,18 +653,16 @@ void MachODumper::printStackMap() const {
if (StackMapSection == object::SectionRef())
return;
- StringRef StackMapContents;
- StackMapSection.getContents(StackMapContents);
- ArrayRef<uint8_t> StackMapContentsArray(
- reinterpret_cast<const uint8_t*>(StackMapContents.data()),
- StackMapContents.size());
+ StringRef StackMapContents = unwrapOrError(StackMapSection.getContents());
+ ArrayRef<uint8_t> StackMapContentsArray =
+ arrayRefFromStringRef(StackMapContents);
if (Obj->isLittleEndian())
prettyPrintStackMap(
- W, StackMapV2Parser<support::little>(StackMapContentsArray));
+ W, StackMapParser<support::little>(StackMapContentsArray));
else
- prettyPrintStackMap(W,
- StackMapV2Parser<support::big>(StackMapContentsArray));
+ prettyPrintStackMap(
+ W, StackMapParser<support::big>(StackMapContentsArray));
}
void MachODumper::printNeededLibraries() {
@@ -695,10 +686,10 @@ void MachODumper::printNeededLibraries() {
}
}
- std::stable_sort(Libs.begin(), Libs.end());
+ llvm::stable_sort(Libs);
for (const auto &L : Libs) {
- outs() << " " << L << "\n";
+ W.startLine() << L << "\n";
}
}
diff --git a/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp b/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp
index a725140c9d33..0a9e22c8a71c 100644
--- a/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp
+++ b/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp
@@ -1,9 +1,8 @@
//===-- ObjDumper.cpp - Base dumper class -----------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -17,8 +16,10 @@
#include "llvm-readobj.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
+#include <map>
namespace llvm {
@@ -32,116 +33,127 @@ static void printAsPrintable(raw_ostream &W, const uint8_t *Start, size_t Len) {
W << (isPrint(Start[i]) ? static_cast<char>(Start[i]) : '.');
}
-static Expected<object::SectionRef>
-getSecNameOrIndexAsSecRef(const object::ObjectFile *Obj, StringRef SecName) {
- char *StrPtr;
- long SectionIndex = strtol(SecName.data(), &StrPtr, 10);
- object::SectionRef Section;
- long SecIndex;
- if (Obj->isELF())
- SecIndex = 0;
- else
- SecIndex = 1;
- for (object::SectionRef SecRef : Obj->sections()) {
- if (*StrPtr) {
- StringRef SectionName;
-
- if (std::error_code E = SecRef.getName(SectionName))
- return errorCodeToError(E);
-
- if (SectionName == SecName)
- return SecRef;
- } else if (SecIndex == SectionIndex)
- return SecRef;
+static std::vector<object::SectionRef>
+getSectionRefsByNameOrIndex(const object::ObjectFile *Obj,
+ ArrayRef<std::string> Sections) {
+ std::vector<object::SectionRef> Ret;
+ std::map<std::string, bool> SecNames;
+ std::map<unsigned, bool> SecIndices;
+ unsigned SecIndex;
+ for (StringRef Section : Sections) {
+ if (!Section.getAsInteger(0, SecIndex))
+ SecIndices.emplace(SecIndex, false);
+ else
+ SecNames.emplace(Section, false);
+ }
+ SecIndex = Obj->isELF() ? 0 : 1;
+ for (object::SectionRef SecRef : Obj->sections()) {
+ StringRef SecName;
+ error(SecRef.getName(SecName));
+ auto NameIt = SecNames.find(SecName);
+ if (NameIt != SecNames.end())
+ NameIt->second = true;
+ auto IndexIt = SecIndices.find(SecIndex);
+ if (IndexIt != SecIndices.end())
+ IndexIt->second = true;
+ if (NameIt != SecNames.end() || IndexIt != SecIndices.end())
+ Ret.push_back(SecRef);
SecIndex++;
}
- return make_error<StringError>("invalid section reference",
- object::object_error::parse_failed);
+
+ for (const std::pair<std::string, bool> &S : SecNames)
+ if (!S.second)
+ reportWarning(formatv("could not find section '{0}'", S.first).str());
+ for (std::pair<unsigned, bool> S : SecIndices)
+ if (!S.second)
+ reportWarning(formatv("could not find section {0}", S.first).str());
+
+ return Ret;
}
-void ObjDumper::printSectionAsString(const object::ObjectFile *Obj,
- StringRef SecName) {
- Expected<object::SectionRef> SectionRefOrError =
- getSecNameOrIndexAsSecRef(Obj, SecName);
- if (!SectionRefOrError)
- error(std::move(SectionRefOrError));
- object::SectionRef Section = *SectionRefOrError;
- StringRef SectionName;
-
- if (std::error_code E = Section.getName(SectionName))
- error(E);
- W.startLine() << "String dump of section '" << SectionName << "':\n";
-
- StringRef SectionContent;
- Section.getContents(SectionContent);
-
- const uint8_t *SecContent = SectionContent.bytes_begin();
- const uint8_t *CurrentWord = SecContent;
- const uint8_t *SecEnd = SectionContent.bytes_end();
-
- while (CurrentWord <= SecEnd) {
- size_t WordSize = strnlen(reinterpret_cast<const char *>(CurrentWord),
- SecEnd - CurrentWord);
- if (!WordSize) {
- CurrentWord++;
- continue;
+void ObjDumper::printSectionsAsString(const object::ObjectFile *Obj,
+ ArrayRef<std::string> Sections) {
+ bool First = true;
+ for (object::SectionRef Section :
+ getSectionRefsByNameOrIndex(Obj, Sections)) {
+ StringRef SectionName;
+ error(Section.getName(SectionName));
+ if (!First)
+ W.startLine() << '\n';
+ First = false;
+ W.startLine() << "String dump of section '" << SectionName << "':\n";
+
+ StringRef SectionContent = unwrapOrError(Section.getContents());
+
+ const uint8_t *SecContent = SectionContent.bytes_begin();
+ const uint8_t *CurrentWord = SecContent;
+ const uint8_t *SecEnd = SectionContent.bytes_end();
+
+ while (CurrentWord <= SecEnd) {
+ size_t WordSize = strnlen(reinterpret_cast<const char *>(CurrentWord),
+ SecEnd - CurrentWord);
+ if (!WordSize) {
+ CurrentWord++;
+ continue;
+ }
+ W.startLine() << format("[%6tx] ", CurrentWord - SecContent);
+ printAsPrintable(W.startLine(), CurrentWord, WordSize);
+ W.startLine() << '\n';
+ CurrentWord += WordSize + 1;
}
- W.startLine() << format("[%6tx] ", CurrentWord - SecContent);
- printAsPrintable(W.startLine(), CurrentWord, WordSize);
- W.startLine() << '\n';
- CurrentWord += WordSize + 1;
}
}
-void ObjDumper::printSectionAsHex(const object::ObjectFile *Obj,
- StringRef SecName) {
- Expected<object::SectionRef> SectionRefOrError =
- getSecNameOrIndexAsSecRef(Obj, SecName);
- if (!SectionRefOrError)
- error(std::move(SectionRefOrError));
- object::SectionRef Section = *SectionRefOrError;
- StringRef SectionName;
-
- if (std::error_code E = Section.getName(SectionName))
- error(E);
- W.startLine() << "Hex dump of section '" << SectionName << "':\n";
-
- StringRef SectionContent;
- Section.getContents(SectionContent);
- const uint8_t *SecContent = SectionContent.bytes_begin();
- const uint8_t *SecEnd = SecContent + SectionContent.size();
-
- for (const uint8_t *SecPtr = SecContent; SecPtr < SecEnd; SecPtr += 16) {
- const uint8_t *TmpSecPtr = SecPtr;
- uint8_t i;
- uint8_t k;
-
- W.startLine() << format_hex(SecPtr - SecContent, 10);
- W.startLine() << ' ';
- for (i = 0; TmpSecPtr < SecEnd && i < 4; ++i) {
- for (k = 0; TmpSecPtr < SecEnd && k < 4; k++, TmpSecPtr++) {
- uint8_t Val = *(reinterpret_cast<const uint8_t *>(TmpSecPtr));
- W.startLine() << format_hex_no_prefix(Val, 2);
- }
+void ObjDumper::printSectionsAsHex(const object::ObjectFile *Obj,
+ ArrayRef<std::string> Sections) {
+ bool First = true;
+ for (object::SectionRef Section :
+ getSectionRefsByNameOrIndex(Obj, Sections)) {
+ StringRef SectionName;
+ error(Section.getName(SectionName));
+ if (!First)
+ W.startLine() << '\n';
+ First = false;
+ W.startLine() << "Hex dump of section '" << SectionName << "':\n";
+
+ StringRef SectionContent = unwrapOrError(Section.getContents());
+ const uint8_t *SecContent = SectionContent.bytes_begin();
+ const uint8_t *SecEnd = SecContent + SectionContent.size();
+
+ for (const uint8_t *SecPtr = SecContent; SecPtr < SecEnd; SecPtr += 16) {
+ const uint8_t *TmpSecPtr = SecPtr;
+ uint8_t i;
+ uint8_t k;
+
+ W.startLine() << format_hex(Section.getAddress() + (SecPtr - SecContent),
+ 10);
W.startLine() << ' ';
- }
+ for (i = 0; TmpSecPtr < SecEnd && i < 4; ++i) {
+ for (k = 0; TmpSecPtr < SecEnd && k < 4; k++, TmpSecPtr++) {
+ uint8_t Val = *(reinterpret_cast<const uint8_t *>(TmpSecPtr));
+ W.startLine() << format_hex_no_prefix(Val, 2);
+ }
+ W.startLine() << ' ';
+ }
- // We need to print the correct amount of spaces to match the format.
- // We are adding the (4 - i) last rows that are 8 characters each.
- // Then, the (4 - i) spaces that are in between the rows.
- // Least, if we cut in a middle of a row, we add the remaining characters,
- // which is (8 - (k * 2))
- if (i < 4)
- W.startLine() << format("%*c", (4 - i) * 8 + (4 - i) + (8 - (k * 2)),
- ' ');
-
- TmpSecPtr = SecPtr;
- for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i)
- W.startLine() << (isPrint(TmpSecPtr[i]) ? static_cast<char>(TmpSecPtr[i])
- : '.');
-
- W.startLine() << '\n';
+ // We need to print the correct amount of spaces to match the format.
+ // We are adding the (4 - i) last rows that are 8 characters each.
+ // Then, the (4 - i) spaces that are in between the rows.
+ // Least, if we cut in a middle of a row, we add the remaining characters,
+ // which is (8 - (k * 2)).
+ if (i < 4)
+ W.startLine() << format("%*c", (4 - i) * 8 + (4 - i) + (8 - (k * 2)),
+ ' ');
+
+ TmpSecPtr = SecPtr;
+ for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i)
+ W.startLine() << (isPrint(TmpSecPtr[i])
+ ? static_cast<char>(TmpSecPtr[i])
+ : '.');
+
+ W.startLine() << '\n';
+ }
}
}
diff --git a/contrib/llvm/tools/llvm-readobj/ObjDumper.h b/contrib/llvm/tools/llvm-readobj/ObjDumper.h
index 13de563469ab..aaabfa2ca2e8 100644
--- a/contrib/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/contrib/llvm/tools/llvm-readobj/ObjDumper.h
@@ -1,9 +1,8 @@
//===-- ObjDumper.h ---------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -15,6 +14,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/CommandLine.h"
namespace llvm {
namespace object {
@@ -22,8 +22,9 @@ class COFFImportFile;
class ObjectFile;
}
namespace codeview {
+class GlobalTypeTableBuilder;
class MergingTypeTableBuilder;
-}
+} // namespace codeview
class ScopedPrinter;
@@ -35,18 +36,30 @@ public:
virtual void printFileHeaders() = 0;
virtual void printSectionHeaders() = 0;
virtual void printRelocations() = 0;
- virtual void printSymbols() = 0;
- virtual void printDynamicSymbols() = 0;
+ virtual void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) {
+ if (PrintSymbols)
+ printSymbols();
+ if (PrintDynamicSymbols)
+ printDynamicSymbols();
+ }
+ virtual void printProgramHeaders(bool PrintProgramHeaders,
+ cl::boolOrDefault PrintSectionMapping) {
+ if (PrintProgramHeaders)
+ printProgramHeaders();
+ if (PrintSectionMapping == cl::BOU_TRUE)
+ printSectionMapping();
+ }
+
virtual void printUnwindInfo() = 0;
// Only implemented for ELF at this time.
virtual void printDynamicRelocations() { }
virtual void printDynamicTable() { }
virtual void printNeededLibraries() { }
- virtual void printProgramHeaders() { }
virtual void printSectionAsHex(StringRef SectionName) {}
virtual void printHashTable() { }
virtual void printGnuHashTable() { }
+ virtual void printHashSymbols() {}
virtual void printLoadName() {}
virtual void printVersionInfo() {}
virtual void printGroupSections() {}
@@ -76,7 +89,10 @@ public:
virtual void printCodeViewDebugInfo() { }
virtual void
mergeCodeViewTypes(llvm::codeview::MergingTypeTableBuilder &CVIDs,
- llvm::codeview::MergingTypeTableBuilder &CVTypes) {}
+ llvm::codeview::MergingTypeTableBuilder &CVTypes,
+ llvm::codeview::GlobalTypeTableBuilder &GlobalCVIDs,
+ llvm::codeview::GlobalTypeTableBuilder &GlobalCVTypes,
+ bool GHash) {}
// Only implemented for MachO.
virtual void printMachODataInCode() { }
@@ -88,11 +104,19 @@ public:
virtual void printStackMap() const = 0;
- void printSectionAsString(const object::ObjectFile *Obj, StringRef SecName);
- void printSectionAsHex(const object::ObjectFile *Obj, StringRef SecName);
+ void printSectionsAsString(const object::ObjectFile *Obj,
+ ArrayRef<std::string> Sections);
+ void printSectionsAsHex(const object::ObjectFile *Obj,
+ ArrayRef<std::string> Sections);
protected:
ScopedPrinter &W;
+
+private:
+ virtual void printSymbols() {}
+ virtual void printDynamicSymbols() {}
+ virtual void printProgramHeaders() {}
+ virtual void printSectionMapping() {}
};
std::error_code createCOFFDumper(const object::ObjectFile *Obj,
@@ -111,12 +135,16 @@ std::error_code createWasmDumper(const object::ObjectFile *Obj,
ScopedPrinter &Writer,
std::unique_ptr<ObjDumper> &Result);
+std::error_code createXCOFFDumper(const object::ObjectFile *Obj,
+ ScopedPrinter &Writer,
+ std::unique_ptr<ObjDumper> &Result);
+
void dumpCOFFImportFile(const object::COFFImportFile *File,
ScopedPrinter &Writer);
-void dumpCodeViewMergedTypes(
- ScopedPrinter &Writer, llvm::codeview::MergingTypeTableBuilder &IDTable,
- llvm::codeview::MergingTypeTableBuilder &TypeTable);
+void dumpCodeViewMergedTypes(ScopedPrinter &Writer,
+ ArrayRef<ArrayRef<uint8_t>> IpiRecords,
+ ArrayRef<ArrayRef<uint8_t>> TpiRecords);
} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-readobj/StackMapPrinter.h b/contrib/llvm/tools/llvm-readobj/StackMapPrinter.h
index 77a054b178a5..ef7575640268 100644
--- a/contrib/llvm/tools/llvm-readobj/StackMapPrinter.h
+++ b/contrib/llvm/tools/llvm-readobj/StackMapPrinter.h
@@ -1,9 +1,8 @@
//===-------- StackMapPrinter.h - Pretty-print stackmaps --------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -48,24 +47,24 @@ void prettyPrintStackMap(ScopedPrinter &W, const StackMapParserT &SMP) {
OS << " #" << ++LocationIndex << ": ";
switch (Loc.getKind()) {
case StackMapParserT::LocationKind::Register:
- OS << "Register R#" << Loc.getDwarfRegNum() << "\n";
+ OS << "Register R#" << Loc.getDwarfRegNum();
break;
case StackMapParserT::LocationKind::Direct:
- OS << "Direct R#" << Loc.getDwarfRegNum() << " + " << Loc.getOffset()
- << "\n";
+ OS << "Direct R#" << Loc.getDwarfRegNum() << " + " << Loc.getOffset();
break;
case StackMapParserT::LocationKind::Indirect:
OS << "Indirect [R#" << Loc.getDwarfRegNum() << " + " << Loc.getOffset()
- << "]\n";
+ << "]";
break;
case StackMapParserT::LocationKind::Constant:
- OS << "Constant " << Loc.getSmallConstant() << "\n";
+ OS << "Constant " << Loc.getSmallConstant();
break;
case StackMapParserT::LocationKind::ConstantIndex:
OS << "ConstantIndex #" << Loc.getConstantIndex() << " ("
- << SMP.getConstant(Loc.getConstantIndex()).getValue() << ")\n";
+ << SMP.getConstant(Loc.getConstantIndex()).getValue() << ")";
break;
}
+ OS << ", size: " << Loc.getSizeInBytes() << "\n";
}
raw_ostream &OS = W.startLine();
diff --git a/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp b/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp
index 79d3db4e2d29..041a9a15bdb6 100644
--- a/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp
+++ b/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp
@@ -1,9 +1,8 @@
//===-- WasmDumper.cpp - Wasm-specific object file dumper -----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -33,11 +32,25 @@ static const EnumEntry<unsigned> WasmSymbolTypes[] = {
static const EnumEntry<uint32_t> WasmSectionTypes[] = {
#define ENUM_ENTRY(X) \
{ #X, wasm::WASM_SEC_##X }
- ENUM_ENTRY(CUSTOM), ENUM_ENTRY(TYPE), ENUM_ENTRY(IMPORT),
- ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE), ENUM_ENTRY(MEMORY),
- ENUM_ENTRY(GLOBAL), ENUM_ENTRY(EVENT), ENUM_ENTRY(EXPORT),
- ENUM_ENTRY(START), ENUM_ENTRY(ELEM), ENUM_ENTRY(CODE),
- ENUM_ENTRY(DATA),
+ ENUM_ENTRY(CUSTOM), ENUM_ENTRY(TYPE), ENUM_ENTRY(IMPORT),
+ ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE), ENUM_ENTRY(MEMORY),
+ ENUM_ENTRY(GLOBAL), ENUM_ENTRY(EVENT), ENUM_ENTRY(EXPORT),
+ ENUM_ENTRY(START), ENUM_ENTRY(ELEM), ENUM_ENTRY(CODE),
+ ENUM_ENTRY(DATA), ENUM_ENTRY(DATACOUNT),
+#undef ENUM_ENTRY
+};
+
+static const EnumEntry<unsigned> WasmSymbolFlags[] = {
+#define ENUM_ENTRY(X) \
+ { #X, wasm::WASM_SYMBOL_##X }
+ ENUM_ENTRY(BINDING_GLOBAL),
+ ENUM_ENTRY(BINDING_WEAK),
+ ENUM_ENTRY(BINDING_LOCAL),
+ ENUM_ENTRY(VISIBILITY_DEFAULT),
+ ENUM_ENTRY(VISIBILITY_HIDDEN),
+ ENUM_ENTRY(UNDEFINED),
+ ENUM_ENTRY(EXPORTED),
+ ENUM_ENTRY(EXPLICIT_NAME),
#undef ENUM_ENTRY
};
@@ -49,8 +62,6 @@ public:
void printFileHeaders() override;
void printSectionHeaders() override;
void printRelocations() override;
- void printSymbols() override;
- void printDynamicSymbols() override { llvm_unreachable("unimplemented"); }
void printUnwindInfo() override { llvm_unreachable("unimplemented"); }
void printStackMap() const override { llvm_unreachable("unimplemented"); }
@@ -59,6 +70,9 @@ protected:
void printRelocation(const SectionRef &Section, const RelocationRef &Reloc);
private:
+ void printSymbols() override;
+ void printDynamicSymbols() override { llvm_unreachable("unimplemented"); }
+
const WasmObjectFile *Obj;
};
@@ -80,11 +94,11 @@ void WasmDumper::printRelocation(const SectionRef &Section,
bool HasAddend = false;
switch (RelocType) {
- case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
- case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
- case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
- case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
- case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
+ case wasm::R_WASM_MEMORY_ADDR_LEB:
+ case wasm::R_WASM_MEMORY_ADDR_SLEB:
+ case wasm::R_WASM_MEMORY_ADDR_I32:
+ case wasm::R_WASM_FUNCTION_OFFSET_I32:
+ case wasm::R_WASM_SECTION_OFFSET_I32:
HasAddend = true;
break;
default:
@@ -209,7 +223,19 @@ void WasmDumper::printSymbol(const SymbolRef &Sym) {
WasmSymbol Symbol = Obj->getWasmSymbol(Sym.getRawDataRefImpl());
W.printString("Name", Symbol.Info.Name);
W.printEnum("Type", Symbol.Info.Kind, makeArrayRef(WasmSymbolTypes));
- W.printHex("Flags", Symbol.Info.Flags);
+ W.printFlags("Flags", Symbol.Info.Flags, makeArrayRef(WasmSymbolFlags));
+
+ if (Symbol.Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) {
+ W.printString("ImportName", Symbol.Info.ImportName);
+ W.printString("ImportModule", Symbol.Info.ImportModule);
+ }
+ if (Symbol.Info.Kind != wasm::WASM_SYMBOL_TYPE_DATA) {
+ W.printHex("ElementIndex", Symbol.Info.ElementIndex);
+ } else if (!(Symbol.Info.Flags & wasm::WASM_SYMBOL_UNDEFINED)) {
+ W.printHex("Offset", Symbol.Info.DataRef.Offset);
+ W.printHex("Segment", Symbol.Info.DataRef.Segment);
+ W.printHex("Size", Symbol.Info.DataRef.Size);
+ }
}
} // namespace
@@ -219,7 +245,7 @@ namespace llvm {
std::error_code createWasmDumper(const object::ObjectFile *Obj,
ScopedPrinter &Writer,
std::unique_ptr<ObjDumper> &Result) {
- const WasmObjectFile *WasmObj = dyn_cast<WasmObjectFile>(Obj);
+ const auto *WasmObj = dyn_cast<WasmObjectFile>(Obj);
assert(WasmObj && "createWasmDumper called with non-wasm object");
Result.reset(new WasmDumper(WasmObj, Writer));
diff --git a/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp
index f7e56b361542..e64b8f157180 100644
--- a/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp
+++ b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp
@@ -1,9 +1,8 @@
//===- Win64EHDumper.cpp - Win64 EH Printer ---------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-readobj/Win64EHDumper.h b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.h
index 772f68bf283f..97458c916bec 100644
--- a/contrib/llvm/tools/llvm-readobj/Win64EHDumper.h
+++ b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.h
@@ -1,9 +1,8 @@
//===- Win64EHDumper.h - Win64 EH Printing ----------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp b/contrib/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp
index 1f568a963671..13989f696d9d 100644
--- a/contrib/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp
+++ b/contrib/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp
@@ -1,9 +1,8 @@
//===-- WindowsResourceDumper.cpp - Windows Resource printer --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-readobj/WindowsResourceDumper.h b/contrib/llvm/tools/llvm-readobj/WindowsResourceDumper.h
index ca6da4046605..6a5878804eb1 100644
--- a/contrib/llvm/tools/llvm-readobj/WindowsResourceDumper.h
+++ b/contrib/llvm/tools/llvm-readobj/WindowsResourceDumper.h
@@ -1,9 +1,8 @@
//===- WindowsResourceDumper.h - Windows Resource printer -------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/contrib/llvm/tools/llvm-readobj/XCOFFDumper.cpp
new file mode 100644
index 000000000000..6f260f91537f
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/XCOFFDumper.cpp
@@ -0,0 +1,190 @@
+//===-- XCOFFDumper.cpp - XCOFF dumping utility -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements an XCOFF specific dumper for llvm-readobj.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "ObjDumper.h"
+#include "llvm-readobj.h"
+#include "llvm/Object/XCOFFObjectFile.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace object;
+
+namespace {
+
+class XCOFFDumper : public ObjDumper {
+public:
+ XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer)
+ : ObjDumper(Writer), Obj(Obj) {}
+
+ void printFileHeaders() override;
+ void printSectionHeaders() override;
+ void printRelocations() override;
+ void printSymbols() override;
+ void printDynamicSymbols() override;
+ void printUnwindInfo() override;
+ void printStackMap() const override;
+ void printNeededLibraries() override;
+
+private:
+ template <typename T> void printSectionHeaders(ArrayRef<T> Sections);
+
+ const XCOFFObjectFile &Obj;
+
+ // Least significant 3 bits are reserved.
+ static constexpr unsigned SectionFlagsReservedMask = 0x7;
+};
+} // anonymous namespace
+
+void XCOFFDumper::printFileHeaders() {
+ DictScope DS(W, "FileHeader");
+ W.printHex("Magic", Obj.getMagic());
+ W.printNumber("NumberOfSections", Obj.getNumberOfSections());
+
+ // Negative timestamp values are reserved for future use.
+ int32_t TimeStamp = Obj.getTimeStamp();
+ if (TimeStamp > 0) {
+ // This handling of the time stamp assumes that the host system's time_t is
+ // compatible with AIX time_t. If a platform is not compatible, the lit
+ // tests will let us know.
+ time_t TimeDate = TimeStamp;
+
+ char FormattedTime[21] = {};
+ size_t BytesWritten =
+ strftime(FormattedTime, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate));
+ if (BytesWritten)
+ W.printHex("TimeStamp", FormattedTime, TimeStamp);
+ else
+ W.printHex("Timestamp", TimeStamp);
+ } else {
+ W.printHex("TimeStamp", TimeStamp == 0 ? "None" : "Reserved Value",
+ TimeStamp);
+ }
+
+ // The number of symbol table entries is an unsigned value in 64-bit objects
+ // and a signed value (with negative values being 'reserved') in 32-bit
+ // objects.
+ if (Obj.is64Bit()) {
+ W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64());
+ W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64());
+ } else {
+ W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32());
+ int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32();
+ if (SymTabEntries >= 0)
+ W.printNumber("SymbolTableEntries", SymTabEntries);
+ else
+ W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries);
+ }
+
+ W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize());
+ W.printHex("Flags", Obj.getFlags());
+
+ // TODO FIXME Add support for the auxiliary header (if any) once
+ // XCOFFObjectFile has the necessary support.
+}
+
+void XCOFFDumper::printSectionHeaders() {
+ if (Obj.is64Bit())
+ printSectionHeaders(Obj.sections64());
+ else
+ printSectionHeaders(Obj.sections32());
+}
+
+void XCOFFDumper::printRelocations() {
+ llvm_unreachable("Unimplemented functionality for XCOFFDumper");
+}
+
+void XCOFFDumper::printSymbols() {
+ llvm_unreachable("Unimplemented functionality for XCOFFDumper");
+}
+
+void XCOFFDumper::printDynamicSymbols() {
+ llvm_unreachable("Unimplemented functionality for XCOFFDumper");
+}
+
+void XCOFFDumper::printUnwindInfo() {
+ llvm_unreachable("Unimplemented functionality for XCOFFDumper");
+}
+
+void XCOFFDumper::printStackMap() const {
+ llvm_unreachable("Unimplemented functionality for XCOFFDumper");
+}
+
+void XCOFFDumper::printNeededLibraries() {
+ llvm_unreachable("Unimplemented functionality for XCOFFDumper");
+}
+
+static const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {
+#define ECase(X) \
+ { #X, XCOFF::X }
+ ECase(STYP_PAD), ECase(STYP_DWARF), ECase(STYP_TEXT),
+ ECase(STYP_DATA), ECase(STYP_BSS), ECase(STYP_EXCEPT),
+ ECase(STYP_INFO), ECase(STYP_TDATA), ECase(STYP_TBSS),
+ ECase(STYP_LOADER), ECase(STYP_DEBUG), ECase(STYP_TYPCHK),
+ ECase(STYP_OVRFLO)
+#undef ECase
+};
+
+template <typename T>
+void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) {
+ ListScope Group(W, "Sections");
+
+ uint16_t Index = 1;
+ for (const T &Sec : Sections) {
+ DictScope SecDS(W, "Section");
+
+ W.printNumber("Index", Index++);
+ W.printString("Name", Sec.getName());
+
+ W.printHex("PhysicalAddress", Sec.PhysicalAddress);
+ W.printHex("VirtualAddress", Sec.VirtualAddress);
+ W.printHex("Size", Sec.SectionSize);
+ W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
+ W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
+ W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
+
+ // TODO Need to add overflow handling when NumberOfX == _OVERFLOW_MARKER
+ // in 32-bit object files.
+ W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations);
+ W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers);
+
+ // The most significant 16-bits represent the DWARF section subtype. For
+ // now we just dump the section type flags.
+ uint16_t Flags = Sec.Flags & 0xffffu;
+ if (Flags & SectionFlagsReservedMask)
+ W.printHex("Flags", "Reserved", Flags);
+ else
+ W.printEnum("Type", Flags, makeArrayRef(SectionTypeFlagsNames));
+ }
+
+ if (opts::SectionRelocations)
+ report_fatal_error("Dumping section relocations is unimplemented");
+
+ if (opts::SectionSymbols)
+ report_fatal_error("Dumping symbols is unimplemented");
+
+ if (opts::SectionData)
+ report_fatal_error("Dumping section data is unimplemented");
+}
+
+namespace llvm {
+std::error_code createXCOFFDumper(const object::ObjectFile *Obj,
+ ScopedPrinter &Writer,
+ std::unique_ptr<ObjDumper> &Result) {
+ const XCOFFObjectFile *XObj = dyn_cast<XCOFFObjectFile>(Obj);
+ if (!XObj)
+ return readobj_error::unsupported_obj_file_format;
+
+ Result.reset(new XCOFFDumper(*XObj, Writer));
+ return readobj_error::success;
+}
+} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp
index 81ce7a590364..1bd5bb74bf29 100644
--- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -1,9 +1,8 @@
//===- llvm-readobj.cpp - Dump contents of an Object File -----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -23,6 +22,7 @@
#include "Error.h"
#include "ObjDumper.h"
#include "WindowsResourceDumper.h"
+#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFFImportFile.h"
@@ -39,6 +39,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/WithColor.h"
using namespace llvm;
using namespace llvm::object;
@@ -48,7 +49,7 @@ namespace opts {
cl::desc("<input object files>"),
cl::ZeroOrMore);
- // -all, -a
+ // --all, -a
cl::opt<bool>
All("all",
cl::desc("Equivalent to setting: --file-headers, --program-headers, "
@@ -65,7 +66,7 @@ namespace opts {
cl::alias HeadersShort("e", cl::desc("Alias for --headers"),
cl::aliasopt(Headers));
- // -wide, -W
+ // --wide, -W
cl::opt<bool>
WideOutput("wide", cl::desc("Ignored for compatibility with GNU readelf"),
cl::Hidden);
@@ -73,7 +74,7 @@ namespace opts {
cl::desc("Alias for --wide"),
cl::aliasopt(WideOutput));
- // -file-headers, -file-header, -h
+ // --file-headers, --file-header, -h
cl::opt<bool> FileHeaders("file-headers",
cl::desc("Display file headers "));
cl::alias FileHeadersShort("h", cl::desc("Alias for --file-headers"),
@@ -82,7 +83,7 @@ namespace opts {
cl::desc("Alias for --file-headers"),
cl::aliasopt(FileHeaders));
- // -section-headers, -sections, -S
+ // --section-headers, --sections, -S
// Also -s in llvm-readobj mode.
cl::opt<bool> SectionHeaders("section-headers",
cl::desc("Display all section headers."));
@@ -92,22 +93,27 @@ namespace opts {
cl::desc("Alias for --section-headers"),
cl::aliasopt(SectionHeaders), cl::NotHidden);
- // -section-relocations
- // Also -sr in llvm-readobj mode.
+ // --section-relocations
+ // Also --sr in llvm-readobj mode.
cl::opt<bool> SectionRelocations("section-relocations",
cl::desc("Display relocations for each section shown."));
- // -section-symbols
- // Also -st in llvm-readobj mode.
+ // --section-symbols
+ // Also --st in llvm-readobj mode.
cl::opt<bool> SectionSymbols("section-symbols",
cl::desc("Display symbols for each section shown."));
- // -section-data
- // Also -sd in llvm-readobj mode.
+ // --section-data
+ // Also --sd in llvm-readobj mode.
cl::opt<bool> SectionData("section-data",
cl::desc("Display section data for each section shown."));
- // -relocations, -relocs, -r
+ // --section-mapping
+ cl::opt<cl::boolOrDefault>
+ SectionMapping("section-mapping",
+ cl::desc("Display the section to segment mapping."));
+
+ // --relocations, --relocs, -r
cl::opt<bool> Relocations("relocations",
cl::desc("Display the relocation entries in the file"));
cl::alias RelocationsShort("r", cl::desc("Alias for --relocations"),
@@ -115,36 +121,43 @@ namespace opts {
cl::alias RelocationsGNU("relocs", cl::desc("Alias for --relocations"),
cl::aliasopt(Relocations));
- // -notes, -n
+ // --notes, -n
cl::opt<bool> Notes("notes", cl::desc("Display the ELF notes in the file"));
cl::alias NotesShort("n", cl::desc("Alias for --notes"), cl::aliasopt(Notes));
- // -dyn-relocations
+ // --dyn-relocations
cl::opt<bool> DynRelocs("dyn-relocations",
cl::desc("Display the dynamic relocation entries in the file"));
- // -symbols
+ // --symbols
// Also -s in llvm-readelf mode, or -t in llvm-readobj mode.
- cl::opt<bool> Symbols("symbols",
- cl::desc("Display the symbol table"));
+ cl::opt<bool>
+ Symbols("symbols",
+ cl::desc("Display the symbol table. Also display the dynamic "
+ "symbol table when using GNU output style for ELF"));
cl::alias SymbolsGNU("syms", cl::desc("Alias for --symbols"),
cl::aliasopt(Symbols));
- // -dyn-symbols, -dyn-syms
- // Also -dt in llvm-readobj mode.
+ // --dyn-symbols, --dyn-syms
+ // Also --dt in llvm-readobj mode.
cl::opt<bool> DynamicSymbols("dyn-symbols",
cl::desc("Display the dynamic symbol table"));
cl::alias DynSymsGNU("dyn-syms", cl::desc("Alias for --dyn-symbols"),
cl::aliasopt(DynamicSymbols));
- // -unwind, -u
+ // --hash-symbols
+ cl::opt<bool> HashSymbols(
+ "hash-symbols",
+ cl::desc("Display the dynamic symbols derived from the hash section"));
+
+ // --unwind, -u
cl::opt<bool> UnwindInfo("unwind",
cl::desc("Display unwind information"));
cl::alias UnwindInfoShort("u",
cl::desc("Alias for --unwind"),
cl::aliasopt(UnwindInfo));
- // -dynamic-table, -dynamic, -d
+ // --dynamic-table, --dynamic, -d
cl::opt<bool> DynamicTable("dynamic-table",
cl::desc("Display the ELF .dynamic section table"));
cl::alias DynamicTableShort("d", cl::desc("Alias for --dynamic-table"),
@@ -152,11 +165,11 @@ namespace opts {
cl::alias DynamicTableAlias("dynamic", cl::desc("Alias for --dynamic-table"),
cl::aliasopt(DynamicTable));
- // -needed-libs
+ // --needed-libs
cl::opt<bool> NeededLibraries("needed-libs",
cl::desc("Display the needed libraries"));
- // -program-headers, -segments, -l
+ // --program-headers, --segments, -l
cl::opt<bool> ProgramHeaders("program-headers",
cl::desc("Display ELF program headers"));
cl::alias ProgramHeadersShort("l", cl::desc("Alias for --program-headers"),
@@ -164,149 +177,161 @@ namespace opts {
cl::alias SegmentsAlias("segments", cl::desc("Alias for --program-headers"),
cl::aliasopt(ProgramHeaders));
- // -string-dump, -p
+ // --string-dump, -p
cl::list<std::string> StringDump("string-dump", cl::desc("<number|name>"),
cl::ZeroOrMore);
cl::alias StringDumpShort("p", cl::desc("Alias for --string-dump"),
- cl::aliasopt(StringDump));
+ cl::aliasopt(StringDump), cl::Prefix);
- // -hex-dump, -x
+ // --hex-dump, -x
cl::list<std::string> HexDump("hex-dump", cl::desc("<number|name>"),
cl::ZeroOrMore);
cl::alias HexDumpShort("x", cl::desc("Alias for --hex-dump"),
- cl::aliasopt(HexDump));
+ cl::aliasopt(HexDump), cl::Prefix);
- // -hash-table
+ // --demangle, -C
+ cl::opt<bool> Demangle("demangle",
+ cl::desc("Demangle symbol names in output"));
+ cl::alias DemangleShort("C", cl::desc("Alias for --demangle"),
+ cl::aliasopt(Demangle), cl::NotHidden);
+
+ // --hash-table
cl::opt<bool> HashTable("hash-table",
cl::desc("Display ELF hash table"));
- // -gnu-hash-table
+ // --gnu-hash-table
cl::opt<bool> GnuHashTable("gnu-hash-table",
cl::desc("Display ELF .gnu.hash section"));
- // -expand-relocs
+ // --expand-relocs
cl::opt<bool> ExpandRelocs("expand-relocs",
cl::desc("Expand each shown relocation to multiple lines"));
- // -raw-relr
+ // --raw-relr
cl::opt<bool> RawRelr("raw-relr",
cl::desc("Do not decode relocations in SHT_RELR section, display raw contents"));
- // -codeview
+ // --codeview
cl::opt<bool> CodeView("codeview",
cl::desc("Display CodeView debug information"));
- // -codeview-merged-types
+ // --codeview-merged-types
cl::opt<bool>
CodeViewMergedTypes("codeview-merged-types",
cl::desc("Display the merged CodeView type stream"));
- // -codeview-subsection-bytes
+ // --codeview-ghash
+ cl::opt<bool> CodeViewEnableGHash(
+ "codeview-ghash",
+ cl::desc(
+ "Enable global hashing for CodeView type stream de-duplication"));
+
+ // --codeview-subsection-bytes
cl::opt<bool> CodeViewSubsectionBytes(
"codeview-subsection-bytes",
cl::desc("Dump raw contents of codeview debug sections and records"));
- // -arm-attributes
+ // --arm-attributes
cl::opt<bool> ARMAttributes("arm-attributes",
cl::desc("Display the ARM attributes section"));
- // -mips-plt-got
+ // --mips-plt-got
cl::opt<bool>
MipsPLTGOT("mips-plt-got",
cl::desc("Display the MIPS GOT and PLT GOT sections"));
- // -mips-abi-flags
+ // --mips-abi-flags
cl::opt<bool> MipsABIFlags("mips-abi-flags",
cl::desc("Display the MIPS.abiflags section"));
- // -mips-reginfo
+ // --mips-reginfo
cl::opt<bool> MipsReginfo("mips-reginfo",
cl::desc("Display the MIPS .reginfo section"));
- // -mips-options
+ // --mips-options
cl::opt<bool> MipsOptions("mips-options",
cl::desc("Display the MIPS .MIPS.options section"));
- // -coff-imports
+ // --coff-imports
cl::opt<bool>
COFFImports("coff-imports", cl::desc("Display the PE/COFF import table"));
- // -coff-exports
+ // --coff-exports
cl::opt<bool>
COFFExports("coff-exports", cl::desc("Display the PE/COFF export table"));
- // -coff-directives
+ // --coff-directives
cl::opt<bool>
COFFDirectives("coff-directives",
cl::desc("Display the PE/COFF .drectve section"));
- // -coff-basereloc
+ // --coff-basereloc
cl::opt<bool>
COFFBaseRelocs("coff-basereloc",
cl::desc("Display the PE/COFF .reloc section"));
- // -coff-debug-directory
+ // --coff-debug-directory
cl::opt<bool>
COFFDebugDirectory("coff-debug-directory",
cl::desc("Display the PE/COFF debug directory"));
- // -coff-resources
+ // --coff-resources
cl::opt<bool> COFFResources("coff-resources",
cl::desc("Display the PE/COFF .rsrc section"));
- // -coff-load-config
+ // --coff-load-config
cl::opt<bool>
COFFLoadConfig("coff-load-config",
cl::desc("Display the PE/COFF load config"));
- // -elf-linker-options
+ // --elf-linker-options
cl::opt<bool>
ELFLinkerOptions("elf-linker-options",
cl::desc("Display the ELF .linker-options section"));
- // -macho-data-in-code
+ // --macho-data-in-code
cl::opt<bool>
MachODataInCode("macho-data-in-code",
cl::desc("Display MachO Data in Code command"));
- // -macho-indirect-symbols
+ // --macho-indirect-symbols
cl::opt<bool>
MachOIndirectSymbols("macho-indirect-symbols",
cl::desc("Display MachO indirect symbols"));
- // -macho-linker-options
+ // --macho-linker-options
cl::opt<bool>
MachOLinkerOptions("macho-linker-options",
cl::desc("Display MachO linker options"));
- // -macho-segment
+ // --macho-segment
cl::opt<bool>
MachOSegment("macho-segment",
cl::desc("Display MachO Segment command"));
- // -macho-version-min
+ // --macho-version-min
cl::opt<bool>
MachOVersionMin("macho-version-min",
cl::desc("Display MachO version min command"));
- // -macho-dysymtab
+ // --macho-dysymtab
cl::opt<bool>
MachODysymtab("macho-dysymtab",
cl::desc("Display MachO Dysymtab command"));
- // -stackmap
+ // --stackmap
cl::opt<bool>
PrintStackMap("stackmap",
cl::desc("Display contents of stackmap section"));
- // -version-info, -V
+ // --version-info, -V
cl::opt<bool>
VersionInfo("version-info",
cl::desc("Display ELF version sections (if present)"));
cl::alias VersionInfoShort("V", cl::desc("Alias for -version-info"),
cl::aliasopt(VersionInfo));
- // -elf-section-groups, -section-groups, -g
+ // --elf-section-groups, --section-groups, -g
cl::opt<bool> SectionGroups("elf-section-groups",
cl::desc("Display ELF section group contents"));
cl::alias SectionGroupsAlias("section-groups",
@@ -315,7 +340,7 @@ namespace opts {
cl::alias SectionGroupsShort("g", cl::desc("Alias for -elf-sections-groups"),
cl::aliasopt(SectionGroups));
- // -elf-hash-histogram, -histogram, -I
+ // --elf-hash-histogram, --histogram, -I
cl::opt<bool> HashHistogram(
"elf-hash-histogram",
cl::desc("Display bucket list histogram for hash sections"));
@@ -325,7 +350,7 @@ namespace opts {
cl::desc("Alias for --elf-hash-histogram"),
cl::aliasopt(HashHistogram));
- // -elf-cg-profile
+ // --elf-cg-profile
cl::opt<bool> CGProfile("elf-cg-profile", cl::desc("Display callgraph profile section"));
// -addrsig
@@ -338,16 +363,38 @@ namespace opts {
cl::values(clEnumVal(LLVM, "LLVM default style"),
clEnumVal(GNU, "GNU readelf style")),
cl::init(LLVM));
+
+ cl::extrahelp
+ HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
} // namespace opts
namespace llvm {
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) {
- errs() << "\nError reading file: " << Msg << ".\n";
- errs().flush();
+ fouts().flush();
+ errs() << "\n";
+ WithColor::error(errs()) << Msg << "\n";
exit(1);
}
+void reportError(StringRef Input, Error Err) {
+ if (Input == "-")
+ Input = "<stdin>";
+ error(createFileError(Input, std::move(Err)));
+}
+
+void reportWarning(Twine Msg) {
+ fouts().flush();
+ errs() << "\n";
+ WithColor::warning(errs()) << Msg << "\n";
+}
+
+void warn(Error Err) {
+ handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
+ reportWarning(EI.message());
+ });
+}
+
void error(Error EC) {
if (!EC)
return;
@@ -361,28 +408,10 @@ void error(std::error_code EC) {
reportError(EC.message());
}
-bool relocAddressLess(RelocationRef a, RelocationRef b) {
- return a.getOffset() < b.getOffset();
-}
-
} // namespace llvm
static void reportError(StringRef Input, std::error_code EC) {
- if (Input == "-")
- Input = "<stdin>";
-
- reportError(Twine(Input) + ": " + EC.message());
-}
-
-static void reportError(StringRef Input, Error Err) {
- if (Input == "-")
- Input = "<stdin>";
- std::string ErrMsg;
- {
- raw_string_ostream ErrStream(ErrMsg);
- logAllUnhandledErrors(std::move(Err), ErrStream, Input + ": ");
- }
- reportError(ErrMsg);
+ reportError(Input, errorCodeToError(EC));
}
static bool isMipsArch(unsigned Arch) {
@@ -399,13 +428,17 @@ static bool isMipsArch(unsigned Arch) {
namespace {
struct ReadObjTypeTableBuilder {
ReadObjTypeTableBuilder()
- : Allocator(), IDTable(Allocator), TypeTable(Allocator) {}
+ : Allocator(), IDTable(Allocator), TypeTable(Allocator),
+ GlobalIDTable(Allocator), GlobalTypeTable(Allocator) {}
llvm::BumpPtrAllocator Allocator;
llvm::codeview::MergingTypeTableBuilder IDTable;
llvm::codeview::MergingTypeTableBuilder TypeTable;
+ llvm::codeview::GlobalTypeTableBuilder GlobalIDTable;
+ llvm::codeview::GlobalTypeTableBuilder GlobalTypeTable;
+ std::vector<OwningBinary<Binary>> Binaries;
};
-}
+} // namespace
static ReadObjTypeTableBuilder CVTypes;
/// Creates an format-specific object file dumper.
@@ -423,25 +456,34 @@ static std::error_code createDumper(const ObjectFile *Obj,
return createMachODumper(Obj, Writer, Result);
if (Obj->isWasm())
return createWasmDumper(Obj, Writer, Result);
+ if (Obj->isXCOFF())
+ return createXCOFFDumper(Obj, Writer, Result);
return readobj_error::unsupported_obj_file_format;
}
/// Dumps the specified object file.
-static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer) {
+static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,
+ const Archive *A = nullptr) {
+ std::string FileStr =
+ A ? Twine(A->getFileName() + "(" + Obj->getFileName() + ")").str()
+ : Obj->getFileName().str();
+
std::unique_ptr<ObjDumper> Dumper;
if (std::error_code EC = createDumper(Obj, Writer, Dumper))
- reportError(Obj->getFileName(), EC);
+ reportError(FileStr, EC);
+ Writer.startLine() << "\n";
if (opts::Output == opts::LLVM) {
- Writer.startLine() << "\n";
- Writer.printString("File", Obj->getFileName());
+ Writer.printString("File", FileStr);
Writer.printString("Format", Obj->getFileFormatName());
Writer.printString("Arch", Triple::getArchTypeName(
(llvm::Triple::ArchType)Obj->getArch()));
Writer.printString("AddressSize",
formatv("{0}bit", 8 * Obj->getBytesInAddress()));
Dumper->printLoadName();
+ } else if (opts::Output == opts::GNU && A) {
+ Writer.printString("File", FileStr);
}
if (opts::FileHeaders)
@@ -452,26 +494,22 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer) {
Dumper->printRelocations();
if (opts::DynRelocs)
Dumper->printDynamicRelocations();
- if (opts::Symbols)
- Dumper->printSymbols();
- if (opts::DynamicSymbols)
- Dumper->printDynamicSymbols();
+ if (opts::Symbols || opts::DynamicSymbols)
+ Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols);
+ if (opts::HashSymbols)
+ Dumper->printHashSymbols();
if (opts::UnwindInfo)
Dumper->printUnwindInfo();
if (opts::DynamicTable)
Dumper->printDynamicTable();
if (opts::NeededLibraries)
Dumper->printNeededLibraries();
- if (opts::ProgramHeaders)
- Dumper->printProgramHeaders();
+ if (opts::ProgramHeaders || opts::SectionMapping == cl::BOU_TRUE)
+ Dumper->printProgramHeaders(opts::ProgramHeaders, opts::SectionMapping);
if (!opts::StringDump.empty())
- llvm::for_each(opts::StringDump, [&Dumper, Obj](StringRef SectionName) {
- Dumper->printSectionAsString(Obj, SectionName);
- });
+ Dumper->printSectionsAsString(Obj, opts::StringDump);
if (!opts::HexDump.empty())
- llvm::for_each(opts::HexDump, [&Dumper, Obj](StringRef SectionName) {
- Dumper->printSectionAsHex(Obj, SectionName);
- });
+ Dumper->printSectionsAsHex(Obj, opts::HexDump);
if (opts::HashTable)
Dumper->printHashTable();
if (opts::GnuHashTable)
@@ -525,7 +563,9 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer) {
if (opts::CodeView)
Dumper->printCodeViewDebugInfo();
if (opts::CodeViewMergedTypes)
- Dumper->mergeCodeViewTypes(CVTypes.IDTable, CVTypes.TypeTable);
+ Dumper->mergeCodeViewTypes(CVTypes.IDTable, CVTypes.TypeTable,
+ CVTypes.GlobalIDTable, CVTypes.GlobalTypeTable,
+ opts::CodeViewEnableGHash);
}
if (Obj->isMachO()) {
if (opts::MachODataInCode)
@@ -552,12 +592,12 @@ static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) {
Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
if (!ChildOrErr) {
if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) {
- reportError(Arc->getFileName(), ChildOrErr.takeError());
+ reportError(Arc->getFileName(), std::move(E));
}
continue;
}
if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get()))
- dumpObject(Obj, Writer);
+ dumpObject(Obj, Writer, Arc);
else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(&*ChildOrErr.get()))
dumpCOFFImportFile(Imp, Writer);
else
@@ -583,8 +623,8 @@ static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary,
}
/// Dumps \a WinRes, Windows Resource (.res) file;
-static void dumpWindowsResourceFile(WindowsResource *WinRes) {
- ScopedPrinter Printer{outs()};
+static void dumpWindowsResourceFile(WindowsResource *WinRes,
+ ScopedPrinter &Printer) {
WindowsRes::Dumper Dumper(WinRes, Printer);
if (auto Err = Dumper.printData())
reportError(WinRes->getFileName(), std::move(Err));
@@ -592,9 +632,7 @@ static void dumpWindowsResourceFile(WindowsResource *WinRes) {
/// Opens \a File and dumps it.
-static void dumpInput(StringRef File) {
- ScopedPrinter Writer(outs());
-
+static void dumpInput(StringRef File, ScopedPrinter &Writer) {
// Attempt to open the binary.
Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
if (!BinaryOrErr)
@@ -611,9 +649,11 @@ static void dumpInput(StringRef File) {
else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(&Binary))
dumpCOFFImportFile(Import, Writer);
else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(&Binary))
- dumpWindowsResourceFile(WinRes);
+ dumpWindowsResourceFile(WinRes, Writer);
else
reportError(File, readobj_error::unrecognized_file_format);
+
+ CVTypes.Binaries.push_back(std::move(*BinaryOrErr));
}
/// Registers aliases that should only be allowed by readobj.
@@ -656,7 +696,7 @@ static void registerReadelfAliases() {
StringRef ArgName = OptEntry.getKey();
cl::Option *Option = OptEntry.getValue();
if (ArgName.size() == 1)
- Option->setFormattingFlag(cl::Grouping);
+ apply(Option, cl::Grouping);
}
}
@@ -699,11 +739,17 @@ int main(int argc, const char *argv[]) {
if (opts::InputFilenames.empty())
opts::InputFilenames.push_back("-");
- llvm::for_each(opts::InputFilenames, dumpInput);
+ ScopedPrinter Writer(fouts());
+ for (const std::string &I : opts::InputFilenames)
+ dumpInput(I, Writer);
if (opts::CodeViewMergedTypes) {
- ScopedPrinter W(outs());
- dumpCodeViewMergedTypes(W, CVTypes.IDTable, CVTypes.TypeTable);
+ if (opts::CodeViewEnableGHash)
+ dumpCodeViewMergedTypes(Writer, CVTypes.GlobalIDTable.records(),
+ CVTypes.GlobalTypeTable.records());
+ else
+ dumpCodeViewMergedTypes(Writer, CVTypes.IDTable.records(),
+ CVTypes.TypeTable.records());
}
return 0;
diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h
index 92ed098dc642..0e02da4cb847 100644
--- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h
+++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h
@@ -1,9 +1,8 @@
//===-- llvm-readobj.h ----------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -23,6 +22,9 @@ namespace llvm {
// Various helper functions.
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
+ void reportError(StringRef Input, Error Err);
+ void reportWarning(Twine Msg);
+ void warn(llvm::Error Err);
void error(std::error_code EC);
void error(llvm::Error EC);
template <typename T> T error(llvm::Expected<T> &&E) {
@@ -44,18 +46,16 @@ namespace llvm {
OS.flush();
reportError(Buf);
}
- bool relocAddressLess(object::RelocationRef A,
- object::RelocationRef B);
} // namespace llvm
namespace opts {
extern llvm::cl::opt<bool> SectionRelocations;
extern llvm::cl::opt<bool> SectionSymbols;
extern llvm::cl::opt<bool> SectionData;
- extern llvm::cl::opt<bool> DynamicSymbols;
extern llvm::cl::opt<bool> ExpandRelocs;
extern llvm::cl::opt<bool> RawRelr;
extern llvm::cl::opt<bool> CodeViewSubsectionBytes;
+ extern llvm::cl::opt<bool> Demangle;
enum OutputStyleTy { LLVM, GNU };
extern llvm::cl::opt<OutputStyleTy> Output;
} // namespace opts
diff --git a/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp b/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
index 975638ed82d1..a7cc1deb8cf6 100644
--- a/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
+++ b/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
@@ -1,9 +1,8 @@
//===-- llvm-rtdyld.cpp - MCJIT Testing Tool ------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -30,9 +29,13 @@
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/MSVCErrorWorkarounds.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
+
+#include <future>
#include <list>
using namespace llvm;
@@ -74,6 +77,10 @@ Dylibs("dylib",
cl::desc("Add library."),
cl::ZeroOrMore);
+static cl::list<std::string> InputArgv("args", cl::Positional,
+ cl::desc("<program arguments>..."),
+ cl::ZeroOrMore, cl::PositionalEatsArgs);
+
static cl::opt<std::string>
TripleName("triple", cl::desc("Target triple for disassembler"));
@@ -88,35 +95,28 @@ CheckFiles("check",
cl::desc("File containing RuntimeDyld verifier checks."),
cl::ZeroOrMore);
-// Tracking BUG: 19665
-// http://llvm.org/bugs/show_bug.cgi?id=19665
-//
-// Do not change these options to cl::opt<uint64_t> since this silently breaks
-// argument parsing.
-static cl::opt<unsigned long long>
-PreallocMemory("preallocate",
- cl::desc("Allocate memory upfront rather than on-demand"),
- cl::init(0));
-
-static cl::opt<unsigned long long>
-TargetAddrStart("target-addr-start",
- cl::desc("For -verify only: start of phony target address "
- "range."),
- cl::init(4096), // Start at "page 1" - no allocating at "null".
- cl::Hidden);
-
-static cl::opt<unsigned long long>
-TargetAddrEnd("target-addr-end",
- cl::desc("For -verify only: end of phony target address range."),
- cl::init(~0ULL),
- cl::Hidden);
-
-static cl::opt<unsigned long long>
-TargetSectionSep("target-section-sep",
- cl::desc("For -verify only: Separation between sections in "
- "phony target address space."),
- cl::init(0),
- cl::Hidden);
+static cl::opt<uint64_t>
+ PreallocMemory("preallocate",
+ cl::desc("Allocate memory upfront rather than on-demand"),
+ cl::init(0));
+
+static cl::opt<uint64_t> TargetAddrStart(
+ "target-addr-start",
+ cl::desc("For -verify only: start of phony target address "
+ "range."),
+ cl::init(4096), // Start at "page 1" - no allocating at "null".
+ cl::Hidden);
+
+static cl::opt<uint64_t> TargetAddrEnd(
+ "target-addr-end",
+ cl::desc("For -verify only: end of phony target address range."),
+ cl::init(~0ULL), cl::Hidden);
+
+static cl::opt<uint64_t> TargetSectionSep(
+ "target-section-sep",
+ cl::desc("For -verify only: Separation between sections in "
+ "phony target address space."),
+ cl::init(0), cl::Hidden);
static cl::list<std::string>
SpecificSectionMappings("map-section",
@@ -138,14 +138,50 @@ PrintAllocationRequests("print-alloc-requests",
"manager by RuntimeDyld"),
cl::Hidden);
+ExitOnError ExitOnErr;
+
/* *** */
+using SectionIDMap = StringMap<unsigned>;
+using FileToSectionIDMap = StringMap<SectionIDMap>;
+
+void dumpFileToSectionIDMap(const FileToSectionIDMap &FileToSecIDMap) {
+ for (const auto &KV : FileToSecIDMap) {
+ llvm::dbgs() << "In " << KV.first() << "\n";
+ for (auto &KV2 : KV.second)
+ llvm::dbgs() << " \"" << KV2.first() << "\" -> " << KV2.second << "\n";
+ }
+}
+
+Expected<unsigned> getSectionId(const FileToSectionIDMap &FileToSecIDMap,
+ StringRef FileName, StringRef SectionName) {
+ auto I = FileToSecIDMap.find(FileName);
+ if (I == FileToSecIDMap.end())
+ return make_error<StringError>("No file named " + FileName,
+ inconvertibleErrorCode());
+ auto &SectionIDs = I->second;
+ auto J = SectionIDs.find(SectionName);
+ if (J == SectionIDs.end())
+ return make_error<StringError>("No section named \"" + SectionName +
+ "\" in file " + FileName,
+ inconvertibleErrorCode());
+ return J->second;
+}
+
// A trivial memory manager that doesn't do anything fancy, just uses the
// support library allocation routines directly.
class TrivialMemoryManager : public RTDyldMemoryManager {
public:
- SmallVector<sys::MemoryBlock, 16> FunctionMemory;
- SmallVector<sys::MemoryBlock, 16> DataMemory;
+ struct SectionInfo {
+ SectionInfo(StringRef Name, sys::MemoryBlock MB, unsigned SectionID)
+ : Name(Name), MB(std::move(MB)), SectionID(SectionID) {}
+ std::string Name;
+ sys::MemoryBlock MB;
+ unsigned SectionID = ~0U;
+ };
+
+ SmallVector<SectionInfo, 16> FunctionMemory;
+ SmallVector<SectionInfo, 16> DataMemory;
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID,
@@ -154,6 +190,11 @@ public:
unsigned SectionID, StringRef SectionName,
bool IsReadOnly) override;
+ /// If non null, records subsequent Name -> SectionID mappings.
+ void setSectionIDsMap(SectionIDMap *SecIDMap) {
+ this->SecIDMap = SecIDMap;
+ }
+
void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true) override {
return nullptr;
@@ -171,7 +212,15 @@ public:
if (I != DummyExterns.end())
return JITSymbol(I->second, JITSymbolFlags::Exported);
- return RTDyldMemoryManager::findSymbol(Name);
+ if (auto Sym = RTDyldMemoryManager::findSymbol(Name))
+ return Sym;
+ else if (auto Err = Sym.takeError())
+ ExitOnErr(std::move(Err));
+ else
+ ExitOnErr(make_error<StringError>("Could not find definition for \"" +
+ Name + "\"",
+ inconvertibleErrorCode()));
+ llvm_unreachable("Should have returned or exited by now");
}
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
@@ -193,7 +242,8 @@ public:
SlabSize = Size;
}
- uint8_t *allocateFromSlab(uintptr_t Size, unsigned Alignment, bool isCode) {
+ uint8_t *allocateFromSlab(uintptr_t Size, unsigned Alignment, bool isCode,
+ StringRef SectionName, unsigned SectionID) {
Size = alignTo(Size, Alignment);
if (CurrentSlabOffset + Size > SlabSize)
report_fatal_error("Can't allocate enough memory. Tune --preallocate");
@@ -201,9 +251,9 @@ public:
uintptr_t OldSlabOffset = CurrentSlabOffset;
sys::MemoryBlock MB((void *)OldSlabOffset, Size);
if (isCode)
- FunctionMemory.push_back(MB);
+ FunctionMemory.push_back(SectionInfo(SectionName, MB, SectionID));
else
- DataMemory.push_back(MB);
+ DataMemory.push_back(SectionInfo(SectionName, MB, SectionID));
CurrentSlabOffset += Size;
return (uint8_t*)OldSlabOffset;
}
@@ -214,6 +264,7 @@ private:
bool UsePreallocation = false;
uintptr_t SlabSize = 0;
uintptr_t CurrentSlabOffset = 0;
+ SectionIDMap *SecIDMap = nullptr;
};
uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,
@@ -224,8 +275,12 @@ uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,
outs() << "allocateCodeSection(Size = " << Size << ", Alignment = "
<< Alignment << ", SectionName = " << SectionName << ")\n";
+ if (SecIDMap)
+ (*SecIDMap)[SectionName] = SectionID;
+
if (UsePreallocation)
- return allocateFromSlab(Size, Alignment, true /* isCode */);
+ return allocateFromSlab(Size, Alignment, true /* isCode */,
+ SectionName, SectionID);
std::error_code EC;
sys::MemoryBlock MB =
@@ -235,7 +290,7 @@ uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,
EC);
if (!MB.base())
report_fatal_error("MemoryManager allocation failed: " + EC.message());
- FunctionMemory.push_back(MB);
+ FunctionMemory.push_back(SectionInfo(SectionName, MB, SectionID));
return (uint8_t*)MB.base();
}
@@ -248,8 +303,12 @@ uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,
outs() << "allocateDataSection(Size = " << Size << ", Alignment = "
<< Alignment << ", SectionName = " << SectionName << ")\n";
+ if (SecIDMap)
+ (*SecIDMap)[SectionName] = SectionID;
+
if (UsePreallocation)
- return allocateFromSlab(Size, Alignment, false /* isCode */);
+ return allocateFromSlab(Size, Alignment, false /* isCode */, SectionName,
+ SectionID);
std::error_code EC;
sys::MemoryBlock MB =
@@ -259,7 +318,7 @@ uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,
EC);
if (!MB.base())
report_fatal_error("MemoryManager allocation failed: " + EC.message());
- DataMemory.push_back(MB);
+ DataMemory.push_back(SectionInfo(SectionName, MB, SectionID));
return (uint8_t*)MB.base();
}
@@ -368,6 +427,8 @@ static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) {
}
uint64_t Addr = *AddrOrErr;
+ object::SectionedAddress Address;
+
uint64_t Size = P.second;
// If we're not using the debug object, compute the address of the
// symbol in memory (rather than that in the unrelocated object file)
@@ -382,16 +443,20 @@ static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) {
object::section_iterator Sec = *SecOrErr;
StringRef SecName;
Sec->getName(SecName);
+ Address.SectionIndex = Sec->getIndex();
uint64_t SectionLoadAddress =
LoadedObjInfo->getSectionLoadAddress(*Sec);
if (SectionLoadAddress != 0)
Addr += SectionLoadAddress - Sec->getAddress();
- }
+ } else if (auto SecOrErr = Sym.getSection())
+ Address.SectionIndex = SecOrErr.get()->getIndex();
outs() << "Function: " << *Name << ", Size = " << Size
<< ", Addr = " << Addr << "\n";
- DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
+ Address.Address = Addr;
+ DILineInfoTable Lines =
+ Context->getLineInfoForAddressRange(Address, Size);
for (auto &D : Lines) {
outs() << " Line info @ " << D.first - Addr << ": "
<< D.second.FileName << ", line:" << D.second.Line << "\n";
@@ -464,9 +529,11 @@ static int executeInput() {
// Invalidate the instruction cache for each loaded function.
for (auto &FM : MemMgr.FunctionMemory) {
+ auto &FM_MB = FM.MB;
+
// Make sure the memory is executable.
// setExecutable will call InvalidateInstructionCache.
- if (auto EC = sys::Memory::protectMappedMemory(FM,
+ if (auto EC = sys::Memory::protectMappedMemory(FM_MB,
sys::Memory::MF_READ |
sys::Memory::MF_EXEC))
ErrorAndExit("unable to mark function executable: '" + EC.message() +
@@ -478,11 +545,13 @@ static int executeInput() {
int (*Main)(int, const char**) =
(int(*)(int,const char**)) uintptr_t(MainAddress);
- const char **Argv = new const char*[2];
+ std::vector<const char *> Argv;
// Use the name of the first input object module as argv[0] for the target.
- Argv[0] = InputFileList[0].c_str();
- Argv[1] = nullptr;
- return Main(1, Argv);
+ Argv.push_back(InputFileList[0].data());
+ for (auto &Arg : InputArgv)
+ Argv.push_back(Arg.data());
+ Argv.push_back(nullptr);
+ return Main(Argv.size() - 1, Argv.data());
}
static int checkAllExpressions(RuntimeDyldChecker &Checker) {
@@ -500,10 +569,10 @@ static int checkAllExpressions(RuntimeDyldChecker &Checker) {
return 0;
}
-void applySpecificSectionMappings(RuntimeDyldChecker &Checker) {
+void applySpecificSectionMappings(RuntimeDyld &Dyld,
+ const FileToSectionIDMap &FileToSecIDMap) {
for (StringRef Mapping : SpecificSectionMappings) {
-
size_t EqualsIdx = Mapping.find_first_of("=");
std::string SectionIDStr = Mapping.substr(0, EqualsIdx);
size_t ComaIdx = Mapping.find_first_of(",");
@@ -514,17 +583,10 @@ void applySpecificSectionMappings(RuntimeDyldChecker &Checker) {
std::string FileName = SectionIDStr.substr(0, ComaIdx);
std::string SectionName = SectionIDStr.substr(ComaIdx + 1);
+ unsigned SectionID =
+ ExitOnErr(getSectionId(FileToSecIDMap, FileName, SectionName));
- uint64_t OldAddrInt;
- std::string ErrorMsg;
- std::tie(OldAddrInt, ErrorMsg) =
- Checker.getSectionAddr(FileName, SectionName, true);
-
- if (ErrorMsg != "")
- report_fatal_error(ErrorMsg);
-
- void* OldAddr = reinterpret_cast<void*>(static_cast<uintptr_t>(OldAddrInt));
-
+ auto* OldAddr = Dyld.getSectionContent(SectionID).data();
std::string NewAddrStr = Mapping.substr(EqualsIdx + 1);
uint64_t NewAddr;
@@ -532,7 +594,7 @@ void applySpecificSectionMappings(RuntimeDyldChecker &Checker) {
report_fatal_error("Invalid section address in mapping '" + Mapping +
"'.");
- Checker.getRTDyld().mapSectionAddress(OldAddr, NewAddr);
+ Dyld.mapSectionAddress(OldAddr, NewAddr);
}
}
@@ -548,21 +610,17 @@ void applySpecificSectionMappings(RuntimeDyldChecker &Checker) {
// (e.g. 1 << 32) to stress-test stubs, GOTs, etc.
//
static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple,
- TrivialMemoryManager &MemMgr,
- RuntimeDyldChecker &Checker) {
+ RuntimeDyld &Dyld,
+ TrivialMemoryManager &MemMgr) {
// Set up a work list (section addr/size pairs).
- typedef std::list<std::pair<void*, uint64_t>> WorklistT;
+ typedef std::list<const TrivialMemoryManager::SectionInfo*> WorklistT;
WorklistT Worklist;
for (const auto& CodeSection : MemMgr.FunctionMemory)
- Worklist.push_back(std::make_pair(CodeSection.base(), CodeSection.size()));
+ Worklist.push_back(&CodeSection);
for (const auto& DataSection : MemMgr.DataMemory)
- Worklist.push_back(std::make_pair(DataSection.base(), DataSection.size()));
-
- // Apply any section-specific mappings that were requested on the command
- // line.
- applySpecificSectionMappings(Checker);
+ Worklist.push_back(&DataSection);
// Keep an "already allocated" mapping of section target addresses to sizes.
// Sections whose address mappings aren't specified on the command line will
@@ -577,16 +635,16 @@ static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple,
I != E;) {
WorklistT::iterator Tmp = I;
++I;
- auto LoadAddr = Checker.getSectionLoadAddress(Tmp->first);
- if (LoadAddr &&
- *LoadAddr != static_cast<uint64_t>(
- reinterpret_cast<uintptr_t>(Tmp->first))) {
+ auto LoadAddr = Dyld.getSectionLoadAddress((*Tmp)->SectionID);
+
+ if (LoadAddr != static_cast<uint64_t>(
+ reinterpret_cast<uintptr_t>((*Tmp)->MB.base()))) {
// A section will have a LoadAddr of 0 if it wasn't loaded for whatever
// reason (e.g. zero byte COFF sections). Don't include those sections in
// the allocation map.
- if (*LoadAddr != 0)
- AlreadyAllocated[*LoadAddr] = Tmp->second;
+ if (LoadAddr != 0)
+ AlreadyAllocated[LoadAddr] = (*Tmp)->MB.allocatedSize();
Worklist.erase(Tmp);
}
}
@@ -604,19 +662,20 @@ static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple,
// Process any elements remaining in the worklist.
while (!Worklist.empty()) {
- std::pair<void*, uint64_t> CurEntry = Worklist.front();
+ auto *CurEntry = Worklist.front();
Worklist.pop_front();
uint64_t NextSectionAddr = TargetAddrStart;
for (const auto &Alloc : AlreadyAllocated)
- if (NextSectionAddr + CurEntry.second + TargetSectionSep <= Alloc.first)
+ if (NextSectionAddr + CurEntry->MB.allocatedSize() + TargetSectionSep <=
+ Alloc.first)
break;
else
NextSectionAddr = Alloc.first + Alloc.second + TargetSectionSep;
- AlreadyAllocated[NextSectionAddr] = CurEntry.second;
- Checker.getRTDyld().mapSectionAddress(CurEntry.first, NextSectionAddr);
+ Dyld.mapSectionAddress(CurEntry->MB.base(), NextSectionAddr);
+ AlreadyAllocated[NextSectionAddr] = CurEntry->MB.allocatedSize();
}
// Add dummy symbols to the memory manager.
@@ -688,18 +747,132 @@ static int linkAndVerify() {
// Instantiate a dynamic linker.
TrivialMemoryManager MemMgr;
doPreallocation(MemMgr);
+
+ struct StubID {
+ unsigned SectionID;
+ uint32_t Offset;
+ };
+ using StubInfos = StringMap<StubID>;
+ using StubContainers = StringMap<StubInfos>;
+
+ StubContainers StubMap;
RuntimeDyld Dyld(MemMgr, MemMgr);
Dyld.setProcessAllSections(true);
- RuntimeDyldChecker Checker(Dyld, Disassembler.get(), InstPrinter.get(),
- llvm::dbgs());
+
+ Dyld.setNotifyStubEmitted([&StubMap](StringRef FilePath,
+ StringRef SectionName,
+ StringRef SymbolName, unsigned SectionID,
+ uint32_t StubOffset) {
+ std::string ContainerName =
+ (sys::path::filename(FilePath) + "/" + SectionName).str();
+ StubMap[ContainerName][SymbolName] = {SectionID, StubOffset};
+ });
+
+ auto GetSymbolInfo =
+ [&Dyld, &MemMgr](
+ StringRef Symbol) -> Expected<RuntimeDyldChecker::MemoryRegionInfo> {
+ RuntimeDyldChecker::MemoryRegionInfo SymInfo;
+
+ // First get the target address.
+ if (auto InternalSymbol = Dyld.getSymbol(Symbol))
+ SymInfo.setTargetAddress(InternalSymbol.getAddress());
+ else {
+ // Symbol not found in RuntimeDyld. Fall back to external lookup.
+#ifdef _MSC_VER
+ using ExpectedLookupResult =
+ MSVCPExpected<JITSymbolResolver::LookupResult>;
+#else
+ using ExpectedLookupResult = Expected<JITSymbolResolver::LookupResult>;
+#endif
+
+ auto ResultP = std::make_shared<std::promise<ExpectedLookupResult>>();
+ auto ResultF = ResultP->get_future();
+
+ MemMgr.lookup(JITSymbolResolver::LookupSet({Symbol}),
+ [=](Expected<JITSymbolResolver::LookupResult> Result) {
+ ResultP->set_value(std::move(Result));
+ });
+
+ auto Result = ResultF.get();
+ if (!Result)
+ return Result.takeError();
+
+ auto I = Result->find(Symbol);
+ assert(I != Result->end() &&
+ "Expected symbol address if no error occurred");
+ SymInfo.setTargetAddress(I->second.getAddress());
+ }
+
+ // Now find the symbol content if possible (otherwise leave content as a
+ // default-constructed StringRef).
+ if (auto *SymAddr = Dyld.getSymbolLocalAddress(Symbol)) {
+ unsigned SectionID = Dyld.getSymbolSectionID(Symbol);
+ if (SectionID != ~0U) {
+ char *CSymAddr = static_cast<char *>(SymAddr);
+ StringRef SecContent = Dyld.getSectionContent(SectionID);
+ uint64_t SymSize = SecContent.size() - (CSymAddr - SecContent.data());
+ SymInfo.setContent(StringRef(CSymAddr, SymSize));
+ }
+ }
+ return SymInfo;
+ };
+
+ auto IsSymbolValid = [&Dyld, GetSymbolInfo](StringRef Symbol) {
+ if (Dyld.getSymbol(Symbol))
+ return true;
+ auto SymInfo = GetSymbolInfo(Symbol);
+ if (!SymInfo) {
+ logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");
+ return false;
+ }
+ return SymInfo->getTargetAddress() != 0;
+ };
+
+ FileToSectionIDMap FileToSecIDMap;
+
+ auto GetSectionInfo = [&Dyld, &FileToSecIDMap](StringRef FileName,
+ StringRef SectionName)
+ -> Expected<RuntimeDyldChecker::MemoryRegionInfo> {
+ auto SectionID = getSectionId(FileToSecIDMap, FileName, SectionName);
+ if (!SectionID)
+ return SectionID.takeError();
+ RuntimeDyldChecker::MemoryRegionInfo SecInfo;
+ SecInfo.setTargetAddress(Dyld.getSectionLoadAddress(*SectionID));
+ SecInfo.setContent(Dyld.getSectionContent(*SectionID));
+ return SecInfo;
+ };
+
+ auto GetStubInfo = [&Dyld, &StubMap](StringRef StubContainer,
+ StringRef SymbolName)
+ -> Expected<RuntimeDyldChecker::MemoryRegionInfo> {
+ if (!StubMap.count(StubContainer))
+ return make_error<StringError>("Stub container not found: " +
+ StubContainer,
+ inconvertibleErrorCode());
+ if (!StubMap[StubContainer].count(SymbolName))
+ return make_error<StringError>("Symbol name " + SymbolName +
+ " in stub container " + StubContainer,
+ inconvertibleErrorCode());
+ auto &SI = StubMap[StubContainer][SymbolName];
+ RuntimeDyldChecker::MemoryRegionInfo StubMemInfo;
+ StubMemInfo.setTargetAddress(Dyld.getSectionLoadAddress(SI.SectionID) +
+ SI.Offset);
+ StubMemInfo.setContent(
+ Dyld.getSectionContent(SI.SectionID).substr(SI.Offset));
+ return StubMemInfo;
+ };
+
+ // We will initialize this below once we have the first object file and can
+ // know the endianness.
+ std::unique_ptr<RuntimeDyldChecker> Checker;
// If we don't have any input files, read from stdin.
if (!InputFileList.size())
InputFileList.push_back("-");
- for (auto &Filename : InputFileList) {
+ for (auto &InputFile : InputFileList) {
// Load the input memory buffer.
ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =
- MemoryBuffer::getFileOrSTDIN(Filename);
+ MemoryBuffer::getFileOrSTDIN(InputFile);
if (std::error_code EC = InputBuffer.getError())
ErrorAndExit("unable to read input: '" + EC.message() + "'");
@@ -717,6 +890,15 @@ static int linkAndVerify() {
ObjectFile &Obj = **MaybeObj;
+ if (!Checker)
+ Checker = llvm::make_unique<RuntimeDyldChecker>(
+ IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo,
+ GetStubInfo, Obj.isLittleEndian() ? support::little : support::big,
+ Disassembler.get(), InstPrinter.get(), dbgs());
+
+ auto FileName = sys::path::filename(InputFile);
+ MemMgr.setSectionIDsMap(&FileToSecIDMap[FileName]);
+
// Load the object file
Dyld.loadObject(Obj);
if (Dyld.hasError()) {
@@ -726,7 +908,8 @@ static int linkAndVerify() {
// Re-map the section addresses into the phony target address space and add
// dummy symbols.
- remapSectionsAndSymbols(TheTriple, MemMgr, Checker);
+ applySpecificSectionMappings(Dyld, FileToSecIDMap);
+ remapSectionsAndSymbols(TheTriple, Dyld, MemMgr);
// Resolve all the relocations we can.
Dyld.resolveRelocations();
@@ -734,7 +917,7 @@ static int linkAndVerify() {
// Register EH frames.
Dyld.registerEHFrames();
- int ErrorCode = checkAllExpressions(Checker);
+ int ErrorCode = checkAllExpressions(*Checker);
if (Dyld.hasError())
ErrorAndExit("RTDyld reported an error applying relocations:\n " +
Dyld.getErrorString());
@@ -752,6 +935,8 @@ int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n");
+ ExitOnErr.setBanner(std::string(argv[0]) + ": ");
+
switch (Action) {
case AC_Execute:
return executeInput();
diff --git a/contrib/llvm/tools/llvm-stress/llvm-stress.cpp b/contrib/llvm/tools/llvm-stress/llvm-stress.cpp
index c29b7a7f7e46..a455bf13fe7b 100644
--- a/contrib/llvm/tools/llvm-stress/llvm-stress.cpp
+++ b/contrib/llvm/tools/llvm-stress/llvm-stress.cpp
@@ -1,9 +1,8 @@
//===- llvm-stress.cpp - Generate random LL files to stress-test LLVM -----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -277,7 +276,7 @@ protected:
/// Pick a random type.
Type *pickType() {
- return (getRandom() & 1 ? pickVectorType() : pickScalarType());
+ return (getRandom() & 1) ? pickVectorType() : pickScalarType();
}
/// Pick a random pointer type.
diff --git a/contrib/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/contrib/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 9d19f994b739..ea94cf9b69a1 100644
--- a/contrib/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/contrib/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -1,9 +1,8 @@
//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -39,12 +38,17 @@ ClUseSymbolTable("use-symbol-table", cl::init(true),
static cl::opt<FunctionNameKind> ClPrintFunctions(
"functions", cl::init(FunctionNameKind::LinkageName),
- cl::desc("Print function name for a given address:"),
+ cl::desc("Print function name for a given address"), cl::ValueOptional,
cl::values(clEnumValN(FunctionNameKind::None, "none", "omit function name"),
clEnumValN(FunctionNameKind::ShortName, "short",
"print short function name"),
clEnumValN(FunctionNameKind::LinkageName, "linkage",
- "print function linkage name")));
+ "print function linkage name"),
+ // Sentinel value for unspecified value.
+ clEnumValN(FunctionNameKind::LinkageName, "", "")));
+static cl::alias ClPrintFunctionsShort("f", cl::desc("Alias for -functions"),
+ cl::NotHidden, cl::Grouping,
+ cl::aliasopt(ClPrintFunctions));
static cl::opt<bool>
ClUseRelativeAddress("relative-address", cl::init(false),
@@ -54,13 +58,29 @@ static cl::opt<bool>
static cl::opt<bool>
ClPrintInlining("inlining", cl::init(true),
cl::desc("Print all inlined frames for a given address"));
+static cl::alias
+ ClPrintInliningAliasI("i", cl::desc("Alias for -inlining"),
+ cl::NotHidden, cl::aliasopt(ClPrintInlining),
+ cl::Grouping);
+static cl::alias
+ ClPrintInliningAliasInlines("inlines", cl::desc("Alias for -inlining"),
+ cl::NotHidden, cl::aliasopt(ClPrintInlining));
-// -demangle, -C
+// -basenames, -s
+static cl::opt<bool> ClBasenames("basenames", cl::init(false),
+ cl::desc("Strip directory names from paths"));
+static cl::alias ClBasenamesShort("s", cl::desc("Alias for -basenames"),
+ cl::NotHidden, cl::aliasopt(ClBasenames));
+
+// -demangle, -C, -no-demangle
static cl::opt<bool>
ClDemangle("demangle", cl::init(true), cl::desc("Demangle function names"));
static cl::alias
ClDemangleShort("C", cl::desc("Alias for -demangle"),
- cl::NotHidden, cl::aliasopt(ClDemangle));
+ cl::NotHidden, cl::aliasopt(ClDemangle), cl::Grouping);
+static cl::opt<bool>
+ClNoDemangle("no-demangle", cl::init(false),
+ cl::desc("Don't demangle function names"));
static cl::opt<std::string> ClDefaultArch("default-arch", cl::init(""),
cl::desc("Default architecture "
@@ -74,10 +94,9 @@ ClBinaryName("obj", cl::init(""),
static cl::alias
ClBinaryNameAliasExe("exe", cl::desc("Alias for -obj"),
cl::NotHidden, cl::aliasopt(ClBinaryName));
-static cl::alias
-ClBinaryNameAliasE("e", cl::desc("Alias for -obj"),
- cl::NotHidden, cl::aliasopt(ClBinaryName));
-
+static cl::alias ClBinaryNameAliasE("e", cl::desc("Alias for -obj"),
+ cl::NotHidden, cl::Grouping, cl::Prefix,
+ cl::aliasopt(ClBinaryName));
static cl::opt<std::string>
ClDwpName("dwp", cl::init(""),
@@ -97,7 +116,7 @@ ClPrintAddressAliasAddresses("addresses", cl::desc("Alias for -print-address"),
cl::NotHidden, cl::aliasopt(ClPrintAddress));
static cl::alias
ClPrintAddressAliasA("a", cl::desc("Alias for -print-address"),
- cl::NotHidden, cl::aliasopt(ClPrintAddress));
+ cl::NotHidden, cl::aliasopt(ClPrintAddress), cl::Grouping);
// -pretty-print, -p
static cl::opt<bool>
@@ -105,7 +124,7 @@ static cl::opt<bool>
cl::desc("Make the output more human friendly"));
static cl::alias ClPrettyPrintShort("p", cl::desc("Alias for -pretty-print"),
cl::NotHidden,
- cl::aliasopt(ClPrettyPrint));
+ cl::aliasopt(ClPrettyPrint), cl::Grouping);
static cl::opt<int> ClPrintSourceContextLines(
"print-source-context-lines", cl::init(0),
@@ -114,10 +133,30 @@ static cl::opt<int> ClPrintSourceContextLines(
static cl::opt<bool> ClVerbose("verbose", cl::init(false),
cl::desc("Print verbose line info"));
+// -adjust-vma
+static cl::opt<uint64_t>
+ ClAdjustVMA("adjust-vma", cl::init(0), cl::value_desc("offset"),
+ cl::desc("Add specified offset to object file addresses"));
+
static cl::list<std::string> ClInputAddresses(cl::Positional,
cl::desc("<input addresses>..."),
cl::ZeroOrMore);
+static cl::opt<std::string>
+ ClFallbackDebugPath("fallback-debug-path", cl::init(""),
+ cl::desc("Fallback path for debug binaries."));
+
+static cl::opt<DIPrinter::OutputStyle>
+ ClOutputStyle("output-style", cl::init(DIPrinter::OutputStyle::LLVM),
+ cl::desc("Specify print style"),
+ cl::values(clEnumValN(DIPrinter::OutputStyle::LLVM, "LLVM",
+ "LLVM default style"),
+ clEnumValN(DIPrinter::OutputStyle::GNU, "GNU",
+ "GNU addr2line style")));
+
+static cl::extrahelp
+ HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
+
template<typename T>
static bool error(Expected<T> &ResOrErr) {
if (ResOrErr)
@@ -127,17 +166,25 @@ static bool error(Expected<T> &ResOrErr) {
return true;
}
-static bool parseCommand(StringRef InputString, bool &IsData,
+enum class Command {
+ Code,
+ Data,
+ Frame,
+};
+
+static bool parseCommand(StringRef InputString, Command &Cmd,
std::string &ModuleName, uint64_t &ModuleOffset) {
const char kDelimiters[] = " \n\r";
ModuleName = "";
if (InputString.consume_front("CODE ")) {
- IsData = false;
+ Cmd = Command::Code;
} else if (InputString.consume_front("DATA ")) {
- IsData = true;
+ Cmd = Command::Data;
+ } else if (InputString.consume_front("FRAME ")) {
+ Cmd = Command::Frame;
} else {
// If no cmd, assume it's CODE.
- IsData = false;
+ Cmd = Command::Code;
}
const char *pos = InputString.data();
// Skip delimiters and parse input filename (if needed).
@@ -167,44 +214,85 @@ static bool parseCommand(StringRef InputString, bool &IsData,
static void symbolizeInput(StringRef InputString, LLVMSymbolizer &Symbolizer,
DIPrinter &Printer) {
- bool IsData = false;
+ Command Cmd;
std::string ModuleName;
- uint64_t ModuleOffset = 0;
- if (!parseCommand(StringRef(InputString), IsData, ModuleName, ModuleOffset)) {
+ uint64_t Offset = 0;
+ if (!parseCommand(StringRef(InputString), Cmd, ModuleName, Offset)) {
outs() << InputString;
return;
}
if (ClPrintAddress) {
outs() << "0x";
- outs().write_hex(ModuleOffset);
+ outs().write_hex(Offset);
StringRef Delimiter = ClPrettyPrint ? ": " : "\n";
outs() << Delimiter;
}
- if (IsData) {
- auto ResOrErr = Symbolizer.symbolizeData(ModuleName, ModuleOffset);
+ Offset -= ClAdjustVMA;
+ if (Cmd == Command::Data) {
+ auto ResOrErr = Symbolizer.symbolizeData(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
Printer << (error(ResOrErr) ? DIGlobal() : ResOrErr.get());
+ } else if (Cmd == Command::Frame) {
+ auto ResOrErr = Symbolizer.symbolizeFrame(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
+ if (!error(ResOrErr)) {
+ for (DILocal Local : *ResOrErr)
+ Printer << Local;
+ if (ResOrErr->empty())
+ outs() << "??\n";
+ }
} else if (ClPrintInlining) {
- auto ResOrErr =
- Symbolizer.symbolizeInlinedCode(ModuleName, ModuleOffset, ClDwpName);
+ auto ResOrErr = Symbolizer.symbolizeInlinedCode(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
Printer << (error(ResOrErr) ? DIInliningInfo() : ResOrErr.get());
+ } else if (ClOutputStyle == DIPrinter::OutputStyle::GNU) {
+ // With ClPrintFunctions == FunctionNameKind::LinkageName (default)
+ // and ClUseSymbolTable == true (also default), Symbolizer.symbolizeCode()
+ // may override the name of an inlined function with the name of the topmost
+ // caller function in the inlining chain. This contradicts the existing
+ // behavior of addr2line. Symbolizer.symbolizeInlinedCode() overrides only
+ // the topmost function, which suits our needs better.
+ auto ResOrErr = Symbolizer.symbolizeInlinedCode(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
+ Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get().getFrame(0));
} else {
- auto ResOrErr =
- Symbolizer.symbolizeCode(ModuleName, ModuleOffset, ClDwpName);
+ auto ResOrErr = Symbolizer.symbolizeCode(
+ ModuleName, {Offset, object::SectionedAddress::UndefSection});
Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get());
}
- outs() << "\n";
- outs().flush();
+ if (ClOutputStyle == DIPrinter::OutputStyle::LLVM)
+ outs() << "\n";
}
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
+ bool IsAddr2Line = sys::path::stem(argv[0]).contains("addr2line");
+
+ if (IsAddr2Line) {
+ ClDemangle.setInitialValue(false);
+ ClPrintFunctions.setInitialValue(FunctionNameKind::None);
+ ClPrintInlining.setInitialValue(false);
+ ClOutputStyle.setInitialValue(DIPrinter::OutputStyle::GNU);
+ }
+
llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
+ cl::ParseCommandLineOptions(argc, argv, IsAddr2Line ? "llvm-addr2line\n"
+ : "llvm-symbolizer\n");
- cl::ParseCommandLineOptions(argc, argv, "llvm-symbolizer\n");
- LLVMSymbolizer::Options Opts(ClPrintFunctions, ClUseSymbolTable, ClDemangle,
- ClUseRelativeAddress, ClDefaultArch);
+ // If both --demangle and --no-demangle are specified then pick the last one.
+ if (ClNoDemangle.getPosition() > ClDemangle.getPosition())
+ ClDemangle = !ClNoDemangle;
+
+ LLVMSymbolizer::Options Opts;
+ Opts.PrintFunctions = ClPrintFunctions;
+ Opts.UseSymbolTable = ClUseSymbolTable;
+ Opts.Demangle = ClDemangle;
+ Opts.RelativeAddresses = ClUseRelativeAddress;
+ Opts.DefaultArch = ClDefaultArch;
+ Opts.FallbackDebugPath = ClFallbackDebugPath;
+ Opts.DWPName = ClDwpName;
for (const auto &hint : ClDsymHint) {
if (sys::path::extension(hint) == ".dSYM") {
@@ -217,14 +305,17 @@ int main(int argc, char **argv) {
LLVMSymbolizer Symbolizer(Opts);
DIPrinter Printer(outs(), ClPrintFunctions != FunctionNameKind::None,
- ClPrettyPrint, ClPrintSourceContextLines, ClVerbose);
+ ClPrettyPrint, ClPrintSourceContextLines, ClVerbose,
+ ClBasenames, ClOutputStyle);
if (ClInputAddresses.empty()) {
const int kMaxInputStringLength = 1024;
char InputString[kMaxInputStringLength];
- while (fgets(InputString, sizeof(InputString), stdin))
+ while (fgets(InputString, sizeof(InputString), stdin)) {
symbolizeInput(InputString, Symbolizer, Printer);
+ outs().flush();
+ }
} else {
for (StringRef Address : ClInputAddresses)
symbolizeInput(Address, Symbolizer, Printer);
diff --git a/contrib/llvm/tools/llvm-xray/func-id-helper.cpp b/contrib/llvm/tools/llvm-xray/func-id-helper.cpp
index c2bef6ddfb39..dc821a420c67 100644
--- a/contrib/llvm/tools/llvm-xray/func-id-helper.cpp
+++ b/contrib/llvm/tools/llvm-xray/func-id-helper.cpp
@@ -1,9 +1,8 @@
//===- xray-fc-account.cpp: XRay Function Call Accounting Tool ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -30,7 +29,12 @@ std::string FuncIdConversionHelper::SymbolOrNumber(int32_t FuncId) const {
return F.str();
}
- if (auto ResOrErr = Symbolizer.symbolizeCode(BinaryInstrMap, It->second)) {
+ object::SectionedAddress ModuleAddress;
+ ModuleAddress.Address = It->second;
+ // TODO: set proper section index here.
+ // object::SectionedAddress::UndefSection works for only absolute addresses.
+ ModuleAddress.SectionIndex = object::SectionedAddress::UndefSection;
+ if (auto ResOrErr = Symbolizer.symbolizeCode(BinaryInstrMap, ModuleAddress)) {
auto &DI = *ResOrErr;
if (DI.FunctionName == "<invalid>")
F << "@(" << std::hex << It->second << ")";
@@ -52,7 +56,12 @@ std::string FuncIdConversionHelper::FileLineAndColumn(int32_t FuncId) const {
return "(unknown)";
std::ostringstream F;
- auto ResOrErr = Symbolizer.symbolizeCode(BinaryInstrMap, It->second);
+ object::SectionedAddress ModuleAddress;
+ ModuleAddress.Address = It->second;
+ // TODO: set proper section index here.
+ // object::SectionedAddress::UndefSection works for only absolute addresses.
+ ModuleAddress.SectionIndex = object::SectionedAddress::UndefSection;
+ auto ResOrErr = Symbolizer.symbolizeCode(BinaryInstrMap, ModuleAddress);
if (!ResOrErr) {
consumeError(ResOrErr.takeError());
return "(unknown)";
diff --git a/contrib/llvm/tools/llvm-xray/func-id-helper.h b/contrib/llvm/tools/llvm-xray/func-id-helper.h
index 3e0780d54f90..c6ce198170d5 100644
--- a/contrib/llvm/tools/llvm-xray/func-id-helper.h
+++ b/contrib/llvm/tools/llvm-xray/func-id-helper.h
@@ -1,9 +1,8 @@
//===- func-id-helper.h - XRay Function ID Conversion Helpers -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-xray/llvm-xray.cpp b/contrib/llvm/tools/llvm-xray/llvm-xray.cpp
index e74628f5025f..9ee653e97b2d 100644
--- a/contrib/llvm/tools/llvm-xray/llvm-xray.cpp
+++ b/contrib/llvm/tools/llvm-xray/llvm-xray.cpp
@@ -1,9 +1,8 @@
//===- llvm-xray.cpp: XRay Tool Main Program ------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-xray/trie-node.h b/contrib/llvm/tools/llvm-xray/trie-node.h
index e6ba4e215b91..47d4b8f1e78c 100644
--- a/contrib/llvm/tools/llvm-xray/trie-node.h
+++ b/contrib/llvm/tools/llvm-xray/trie-node.h
@@ -1,9 +1,8 @@
//===- trie-node.h - XRay Call Stack Data Structure -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-xray/xray-account.cpp b/contrib/llvm/tools/llvm-xray/xray-account.cpp
index 9985c9adcf6c..2b49a311d7e3 100644
--- a/contrib/llvm/tools/llvm-xray/xray-account.cpp
+++ b/contrib/llvm/tools/llvm-xray/xray-account.cpp
@@ -1,9 +1,8 @@
//===- xray-account.h - XRay Function Call Accounting ---------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -428,9 +427,7 @@ static CommandRegistration Unused(&Account, []() -> Error {
Twine("Cannot open file '") + AccountOutput + "' for writing.", EC);
const auto &FunctionAddresses = Map.getFunctionAddresses();
- symbolize::LLVMSymbolizer::Options Opts(
- symbolize::FunctionNameKind::LinkageName, true, true, false, "");
- symbolize::LLVMSymbolizer Symbolizer(Opts);
+ symbolize::LLVMSymbolizer Symbolizer;
llvm::xray::FuncIdConversionHelper FuncIdHelper(AccountInstrMap, Symbolizer,
FunctionAddresses);
xray::LatencyAccountant FCA(FuncIdHelper, AccountDeduceSiblingCalls);
diff --git a/contrib/llvm/tools/llvm-xray/xray-account.h b/contrib/llvm/tools/llvm-xray/xray-account.h
index 5c457f178166..b63ecc59b71a 100644
--- a/contrib/llvm/tools/llvm-xray/xray-account.h
+++ b/contrib/llvm/tools/llvm-xray/xray-account.h
@@ -1,9 +1,8 @@
//===- xray-account.h - XRay Function Call Accounting ---------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -29,12 +28,11 @@ namespace xray {
class LatencyAccountant {
public:
typedef std::map<int32_t, std::vector<uint64_t>> FunctionLatencyMap;
- typedef std::map<llvm::sys::procid_t, std::pair<uint64_t, uint64_t>>
+ typedef std::map<uint32_t, std::pair<uint64_t, uint64_t>>
PerThreadMinMaxTSCMap;
typedef std::map<uint8_t, std::pair<uint64_t, uint64_t>> PerCPUMinMaxTSCMap;
typedef std::vector<std::pair<int32_t, uint64_t>> FunctionStack;
- typedef std::map<llvm::sys::procid_t, FunctionStack>
- PerThreadFunctionStackMap;
+ typedef std::map<uint32_t, FunctionStack> PerThreadFunctionStackMap;
private:
PerThreadFunctionStackMap PerThreadFunctionStack;
@@ -78,13 +76,6 @@ public:
///
bool accountRecord(const XRayRecord &Record);
- const FunctionStack *getThreadFunctionStack(llvm::sys::procid_t TId) const {
- auto I = PerThreadFunctionStack.find(TId);
- if (I == PerThreadFunctionStack.end())
- return nullptr;
- return &I->second;
- }
-
const PerThreadFunctionStackMap &getPerThreadFunctionStack() const {
return PerThreadFunctionStack;
}
diff --git a/contrib/llvm/tools/llvm-xray/xray-color-helper.cpp b/contrib/llvm/tools/llvm-xray/xray-color-helper.cpp
index 78a264b73d8f..c09cad3ba7d2 100644
--- a/contrib/llvm/tools/llvm-xray/xray-color-helper.cpp
+++ b/contrib/llvm/tools/llvm-xray/xray-color-helper.cpp
@@ -1,9 +1,8 @@
//===-- xray-graph.cpp: XRay Function Call Graph Renderer -----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-xray/xray-color-helper.h b/contrib/llvm/tools/llvm-xray/xray-color-helper.h
index b2dcf626a65f..0940fc211343 100644
--- a/contrib/llvm/tools/llvm-xray/xray-color-helper.h
+++ b/contrib/llvm/tools/llvm-xray/xray-color-helper.h
@@ -1,9 +1,8 @@
//===-- xray-graph.h - XRay Function Call Graph Renderer --------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-xray/xray-converter.cpp b/contrib/llvm/tools/llvm-xray/xray-converter.cpp
index a682dbe53e3b..dfc757e0f276 100644
--- a/contrib/llvm/tools/llvm-xray/xray-converter.cpp
+++ b/contrib/llvm/tools/llvm-xray/xray-converter.cpp
@@ -1,9 +1,8 @@
//===- xray-converter.cpp: XRay Trace Conversion --------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -381,9 +380,7 @@ static CommandRegistration Unused(&Convert, []() -> Error {
}
const auto &FunctionAddresses = Map.getFunctionAddresses();
- symbolize::LLVMSymbolizer::Options Opts(
- symbolize::FunctionNameKind::LinkageName, true, true, false, "");
- symbolize::LLVMSymbolizer Symbolizer(Opts);
+ symbolize::LLVMSymbolizer Symbolizer;
llvm::xray::FuncIdConversionHelper FuncIdHelper(ConvertInstrMap, Symbolizer,
FunctionAddresses);
llvm::xray::TraceConverter TC(FuncIdHelper, ConvertSymbolize);
diff --git a/contrib/llvm/tools/llvm-xray/xray-converter.h b/contrib/llvm/tools/llvm-xray/xray-converter.h
index 5f0a3ee298eb..db6d2b1614ee 100644
--- a/contrib/llvm/tools/llvm-xray/xray-converter.h
+++ b/contrib/llvm/tools/llvm-xray/xray-converter.h
@@ -1,9 +1,8 @@
//===- xray-converter.h - XRay Trace Conversion ---------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-xray/xray-extract.cpp b/contrib/llvm/tools/llvm-xray/xray-extract.cpp
index 10fe7d8d6209..7c7d26b5a389 100644
--- a/contrib/llvm/tools/llvm-xray/xray-extract.cpp
+++ b/contrib/llvm/tools/llvm-xray/xray-extract.cpp
@@ -1,9 +1,8 @@
//===- xray-extract.cpp: XRay Instrumentation Map Extraction --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -87,9 +86,7 @@ static CommandRegistration Unused(&Extract, []() -> Error {
Twine("Cannot open file '") + ExtractOutput + "' for writing.", EC);
const auto &FunctionAddresses =
InstrumentationMapOrError->getFunctionAddresses();
- symbolize::LLVMSymbolizer::Options Opts(
- symbolize::FunctionNameKind::LinkageName, true, true, false, "");
- symbolize::LLVMSymbolizer Symbolizer(Opts);
+ symbolize::LLVMSymbolizer Symbolizer;
llvm::xray::FuncIdConversionHelper FuncIdHelper(ExtractInput, Symbolizer,
FunctionAddresses);
exportAsYAML(*InstrumentationMapOrError, OS, FuncIdHelper);
diff --git a/contrib/llvm/tools/llvm-xray/xray-fdr-dump.cpp b/contrib/llvm/tools/llvm-xray/xray-fdr-dump.cpp
index 389825605b62..81a93cac57c4 100644
--- a/contrib/llvm/tools/llvm-xray/xray-fdr-dump.cpp
+++ b/contrib/llvm/tools/llvm-xray/xray-fdr-dump.cpp
@@ -1,9 +1,8 @@
//===- xray-fdr-dump.cpp: XRay FDR Trace Dump Tool ------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -36,10 +35,9 @@ static cl::opt<bool> DumpVerify("verify",
static CommandRegistration Unused(&Dump, []() -> Error {
// Open the file provided.
- int Fd;
- if (auto EC = sys::fs::openFileForRead(DumpInput, Fd))
- return createStringError(EC, "Cannot open file '%s' for read.",
- DumpInput.c_str());
+ auto FDOrErr = sys::fs::openNativeFileForRead(DumpInput);
+ if (!FDOrErr)
+ return FDOrErr.takeError();
uint64_t FileSize;
if (auto EC = sys::fs::file_size(DumpInput, FileSize))
@@ -48,7 +46,9 @@ static CommandRegistration Unused(&Dump, []() -> Error {
std::error_code EC;
sys::fs::mapped_file_region MappedFile(
- Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC);
+ *FDOrErr, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0,
+ EC);
+ sys::fs::closeFile(*FDOrErr);
DataExtractor DE(StringRef(MappedFile.data(), MappedFile.size()), true, 8);
uint32_t OffsetPtr = 0;
diff --git a/contrib/llvm/tools/llvm-xray/xray-graph-diff.cpp b/contrib/llvm/tools/llvm-xray/xray-graph-diff.cpp
index a22f2a99811d..a514be97f40b 100644
--- a/contrib/llvm/tools/llvm-xray/xray-graph-diff.cpp
+++ b/contrib/llvm/tools/llvm-xray/xray-graph-diff.cpp
@@ -1,9 +1,8 @@
//===-- xray-graph-diff.cpp: XRay Function Call Graph Renderer ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-xray/xray-graph-diff.h b/contrib/llvm/tools/llvm-xray/xray-graph-diff.h
index 5abec91d8582..5d12c563f47c 100644
--- a/contrib/llvm/tools/llvm-xray/xray-graph-diff.h
+++ b/contrib/llvm/tools/llvm-xray/xray-graph-diff.h
@@ -1,9 +1,8 @@
//===-- xray-graph-diff.h - XRay Graph Diff Renderer ------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-xray/xray-graph.cpp b/contrib/llvm/tools/llvm-xray/xray-graph.cpp
index fe49cca20d57..c09357fcb502 100644
--- a/contrib/llvm/tools/llvm-xray/xray-graph.cpp
+++ b/contrib/llvm/tools/llvm-xray/xray-graph.cpp
@@ -1,9 +1,8 @@
//===-- xray-graph.cpp: XRay Function Call Graph Renderer -----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -437,9 +436,7 @@ Expected<GraphRenderer> GraphRenderer::Factory::getGraphRenderer() {
const auto &FunctionAddresses = Map.getFunctionAddresses();
- symbolize::LLVMSymbolizer::Options Opts(
- symbolize::FunctionNameKind::LinkageName, true, true, false, "");
- symbolize::LLVMSymbolizer Symbolizer(Opts);
+ symbolize::LLVMSymbolizer Symbolizer;
const auto &Header = Trace.getFileHeader();
llvm::xray::FuncIdConversionHelper FuncIdHelper(InstrMap, Symbolizer,
diff --git a/contrib/llvm/tools/llvm-xray/xray-graph.h b/contrib/llvm/tools/llvm-xray/xray-graph.h
index fc7f8bb470f2..23372d40f05e 100644
--- a/contrib/llvm/tools/llvm-xray/xray-graph.h
+++ b/contrib/llvm/tools/llvm-xray/xray-graph.h
@@ -1,9 +1,8 @@
//===-- xray-graph.h - XRay Function Call Graph Renderer --------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -79,8 +78,7 @@ public:
using FunctionStack = SmallVector<FunctionAttr, 4>;
- using PerThreadFunctionStackMap =
- DenseMap<llvm::sys::procid_t, FunctionStack>;
+ using PerThreadFunctionStackMap = DenseMap<uint32_t, FunctionStack>;
class GraphT : public Graph<FunctionStats, CallStats, int32_t> {
public:
diff --git a/contrib/llvm/tools/llvm-xray/xray-registry.cpp b/contrib/llvm/tools/llvm-xray/xray-registry.cpp
index fe58e4deaa1e..e5c253d2e8f1 100644
--- a/contrib/llvm/tools/llvm-xray/xray-registry.cpp
+++ b/contrib/llvm/tools/llvm-xray/xray-registry.cpp
@@ -1,9 +1,8 @@
//===- xray-registry.cpp: Implement a command registry. -------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-xray/xray-registry.h b/contrib/llvm/tools/llvm-xray/xray-registry.h
index 6eab016273f5..d6fae78ea53c 100644
--- a/contrib/llvm/tools/llvm-xray/xray-registry.h
+++ b/contrib/llvm/tools/llvm-xray/xray-registry.h
@@ -1,9 +1,8 @@
//===- xray-registry.h - Define registry mechanism for commands. ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/llvm-xray/xray-stacks.cpp b/contrib/llvm/tools/llvm-xray/xray-stacks.cpp
index d3af9e25e6f2..bcfc5cb1f1be 100644
--- a/contrib/llvm/tools/llvm-xray/xray-stacks.cpp
+++ b/contrib/llvm/tools/llvm-xray/xray-stacks.cpp
@@ -1,9 +1,8 @@
//===- xray-stacks.cpp: XRay Function Call Stack Accounting ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -634,10 +633,8 @@ public:
Top->ExtraData.TerminalDurations.end(), 0uLL);
{
auto E = std::make_pair(Top, TopSum);
- TopStacksBySum.insert(std::lower_bound(TopStacksBySum.begin(),
- TopStacksBySum.end(), E,
- greater_second),
- E);
+ TopStacksBySum.insert(
+ llvm::lower_bound(TopStacksBySum, E, greater_second), E);
if (TopStacksBySum.size() == 11)
TopStacksBySum.pop_back();
}
@@ -721,9 +718,7 @@ static CommandRegistration Unused(&Stack, []() -> Error {
"-all-stacks."),
std::make_error_code(std::errc::invalid_argument));
- symbolize::LLVMSymbolizer::Options Opts(
- symbolize::FunctionNameKind::LinkageName, true, true, false, "");
- symbolize::LLVMSymbolizer Symbolizer(Opts);
+ symbolize::LLVMSymbolizer Symbolizer;
FuncIdConversionHelper FuncIdHelper(StacksInstrMap, Symbolizer,
Map.getFunctionAddresses());
// TODO: Someday, support output to files instead of just directly to
diff --git a/contrib/llvm/tools/opt/AnalysisWrappers.cpp b/contrib/llvm/tools/opt/AnalysisWrappers.cpp
index cfdd2cf1582b..b888605a516c 100644
--- a/contrib/llvm/tools/opt/AnalysisWrappers.cpp
+++ b/contrib/llvm/tools/opt/AnalysisWrappers.cpp
@@ -1,9 +1,8 @@
//===- AnalysisWrappers.cpp - Wrappers around non-pass analyses -----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/opt/BreakpointPrinter.cpp b/contrib/llvm/tools/opt/BreakpointPrinter.cpp
index d3f54c034f55..a57a8c43c264 100644
--- a/contrib/llvm/tools/opt/BreakpointPrinter.cpp
+++ b/contrib/llvm/tools/opt/BreakpointPrinter.cpp
@@ -1,9 +1,8 @@
//===- BreakpointPrinter.cpp - Breakpoint location printer ----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -36,7 +35,7 @@ struct BreakpointPrinter : public ModulePass {
}
} else if (auto *TY = dyn_cast<DIType>(Context)) {
if (!TY->getName().empty()) {
- getContextName(TY->getScope().resolve(), N);
+ getContextName(TY->getScope(), N);
N = N + TY->getName().str() + "::";
}
}
@@ -50,7 +49,7 @@ struct BreakpointPrinter : public ModulePass {
auto *SP = cast_or_null<DISubprogram>(NMD->getOperand(i));
if (!SP)
continue;
- getContextName(SP->getScope().resolve(), Name);
+ getContextName(SP->getScope(), Name);
Name = Name + SP->getName().str();
if (!Name.empty() && Processed.insert(Name).second) {
Out << Name << "\n";
diff --git a/contrib/llvm/tools/opt/BreakpointPrinter.h b/contrib/llvm/tools/opt/BreakpointPrinter.h
index 57670e5ee8d8..2877555f852c 100644
--- a/contrib/llvm/tools/opt/BreakpointPrinter.h
+++ b/contrib/llvm/tools/opt/BreakpointPrinter.h
@@ -1,9 +1,8 @@
//===- BreakpointPrinter.h - Breakpoint location printer ------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
diff --git a/contrib/llvm/tools/opt/Debugify.cpp b/contrib/llvm/tools/opt/Debugify.cpp
index 3b1effba1592..222cc702bc1f 100644
--- a/contrib/llvm/tools/opt/Debugify.cpp
+++ b/contrib/llvm/tools/opt/Debugify.cpp
@@ -1,9 +1,8 @@
//===- Debugify.cpp - Attach synthetic debug info to everything -----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
diff --git a/contrib/llvm/tools/opt/Debugify.h b/contrib/llvm/tools/opt/Debugify.h
index d1a60c73e723..266f577951ae 100644
--- a/contrib/llvm/tools/opt/Debugify.h
+++ b/contrib/llvm/tools/opt/Debugify.h
@@ -1,9 +1,8 @@
//===- Debugify.h - Attach synthetic debug info to everything -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
diff --git a/contrib/llvm/tools/opt/GraphPrinters.cpp b/contrib/llvm/tools/opt/GraphPrinters.cpp
index a8bb12f3e018..611fb20513c9 100644
--- a/contrib/llvm/tools/opt/GraphPrinters.cpp
+++ b/contrib/llvm/tools/opt/GraphPrinters.cpp
@@ -1,9 +1,8 @@
//===- GraphPrinters.cpp - DOT printers for various graph types -----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/opt/NewPMDriver.cpp b/contrib/llvm/tools/opt/NewPMDriver.cpp
index 211a3b151fe1..efe0bec35d72 100644
--- a/contrib/llvm/tools/opt/NewPMDriver.cpp
+++ b/contrib/llvm/tools/opt/NewPMDriver.cpp
@@ -1,9 +1,8 @@
//===- NewPMDriver.cpp - Driver for opt with new PM -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -101,19 +100,11 @@ static cl::opt<std::string> OptimizerLastEPPipeline(
"the OptimizerLast extension point into default pipelines"),
cl::Hidden);
-enum PGOKind { NoPGO, InstrGen, InstrUse, SampleUse };
-static cl::opt<PGOKind> PGOKindFlag(
- "pgo-kind", cl::init(NoPGO), cl::Hidden,
- cl::desc("The kind of profile guided optimization"),
- cl::values(clEnumValN(NoPGO, "nopgo", "Do not use PGO."),
- clEnumValN(InstrGen, "new-pm-pgo-instr-gen-pipeline",
- "Instrument the IR to generate profile."),
- clEnumValN(InstrUse, "new-pm-pgo-instr-use-pipeline",
- "Use instrumented profile to guide PGO."),
- clEnumValN(SampleUse, "new-pm-pgo-sample-use-pipeline",
- "Use sampled profile to guide PGO.")));
-static cl::opt<std::string> ProfileFile(
- "profile-file", cl::desc("Path to the profile."), cl::Hidden);
+extern cl::opt<PGOKind> PGOKindFlag;
+extern cl::opt<std::string> ProfileFile;
+extern cl::opt<CSPGOKind> CSPGOKindFlag;
+extern cl::opt<std::string> CSProfileGenFile;
+
static cl::opt<std::string>
ProfileRemappingFile("profile-remapping-file",
cl::desc("Path to the profile remapping file."),
@@ -231,25 +222,46 @@ bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM,
Optional<PGOOptions> P;
switch (PGOKindFlag) {
case InstrGen:
- P = PGOOptions(ProfileFile, "", "", "", true);
+ P = PGOOptions(ProfileFile, "", "", PGOOptions::IRInstr);
break;
case InstrUse:
- P = PGOOptions("", ProfileFile, "", ProfileRemappingFile, false);
+ P = PGOOptions(ProfileFile, "", ProfileRemappingFile, PGOOptions::IRUse);
break;
case SampleUse:
- P = PGOOptions("", "", ProfileFile, ProfileRemappingFile, false);
+ P = PGOOptions(ProfileFile, "", ProfileRemappingFile,
+ PGOOptions::SampleUse);
break;
case NoPGO:
if (DebugInfoForProfiling)
- P = PGOOptions("", "", "", "", false, true);
+ P = PGOOptions("", "", "", PGOOptions::NoAction, PGOOptions::NoCSAction,
+ true);
else
P = None;
- }
+ }
+ if (CSPGOKindFlag != NoCSPGO) {
+ if (P && (P->Action == PGOOptions::IRInstr ||
+ P->Action == PGOOptions::SampleUse))
+ errs() << "CSPGOKind cannot be used with IRInstr or SampleUse";
+ if (CSPGOKindFlag == CSInstrGen) {
+ if (CSProfileGenFile.empty())
+ errs() << "CSInstrGen needs to specify CSProfileGenFile";
+ if (P) {
+ P->CSAction = PGOOptions::CSIRInstr;
+ P->CSProfileGenFile = CSProfileGenFile;
+ } else
+ P = PGOOptions("", CSProfileGenFile, ProfileRemappingFile,
+ PGOOptions::NoAction, PGOOptions::CSIRInstr);
+ } else /* CSPGOKindFlag == CSInstrUse */ {
+ if (!P)
+ errs() << "CSInstrUse needs to be together with InstrUse";
+ P->CSAction = PGOOptions::CSIRUse;
+ }
+ }
PassInstrumentationCallbacks PIC;
StandardInstrumentations SI;
SI.registerCallbacks(PIC);
- PassBuilder PB(TM, P, &PIC);
+ PassBuilder PB(TM, PipelineTuningOptions(), P, &PIC);
registerEPCallbacks(PB, VerifyEachPass, DebugPM);
// Load requested pass plugins and let them register pass builder callbacks
diff --git a/contrib/llvm/tools/opt/NewPMDriver.h b/contrib/llvm/tools/opt/NewPMDriver.h
index 7d74a5777d11..b672c97c9aa3 100644
--- a/contrib/llvm/tools/opt/NewPMDriver.h
+++ b/contrib/llvm/tools/opt/NewPMDriver.h
@@ -1,9 +1,8 @@
//===- NewPMDriver.h - Function to drive opt with the new PM ----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -40,6 +39,13 @@ enum VerifierKind {
VK_VerifyInAndOut,
VK_VerifyEachPass
};
+enum PGOKind {
+ NoPGO,
+ InstrGen,
+ InstrUse,
+ SampleUse
+};
+enum CSPGOKind { NoCSPGO, CSInstrGen, CSInstrUse };
}
/// Driver function to run the new pass manager over a module.
diff --git a/contrib/llvm/tools/opt/PassPrinters.cpp b/contrib/llvm/tools/opt/PassPrinters.cpp
index 310d491c06a5..70da6a43f8d9 100644
--- a/contrib/llvm/tools/opt/PassPrinters.cpp
+++ b/contrib/llvm/tools/opt/PassPrinters.cpp
@@ -1,9 +1,8 @@
//===- PassPrinters.cpp - Utilities to print analysis info for passes -----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
diff --git a/contrib/llvm/tools/opt/PassPrinters.h b/contrib/llvm/tools/opt/PassPrinters.h
index e66f3f457b7a..d4e7a4a97f31 100644
--- a/contrib/llvm/tools/opt/PassPrinters.h
+++ b/contrib/llvm/tools/opt/PassPrinters.h
@@ -1,9 +1,8 @@
//=- PassPrinters.h - Utilities to print analysis info for passes -*- C++ -*-=//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
diff --git a/contrib/llvm/tools/opt/PrintSCC.cpp b/contrib/llvm/tools/opt/PrintSCC.cpp
index 78ede2b72f84..419886d6cc60 100644
--- a/contrib/llvm/tools/opt/PrintSCC.cpp
+++ b/contrib/llvm/tools/opt/PrintSCC.cpp
@@ -1,9 +1,8 @@
//===- PrintSCC.cpp - Enumerate SCCs in some key graphs -------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/contrib/llvm/tools/opt/opt.cpp b/contrib/llvm/tools/opt/opt.cpp
index a4967a234d9c..ccf8b073b82b 100644
--- a/contrib/llvm/tools/opt/opt.cpp
+++ b/contrib/llvm/tools/opt/opt.cpp
@@ -1,9 +1,8 @@
//===- opt.cpp - The LLVM Modular Optimizer -------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -34,6 +33,7 @@
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/LegacyPassNameParser.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/RemarkStreamer.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/InitializePasses.h"
@@ -173,18 +173,9 @@ static cl::opt<std::string>
TargetTriple("mtriple", cl::desc("Override target triple for module"));
static cl::opt<bool>
-UnitAtATime("funit-at-a-time",
- cl::desc("Enable IPO. This corresponds to gcc's -funit-at-a-time"),
- cl::init(true));
-
-static cl::opt<bool>
DisableLoopUnrolling("disable-loop-unrolling",
cl::desc("Disable loop unrolling in all relevant passes"),
cl::init(false));
-static cl::opt<bool>
-DisableLoopVectorization("disable-loop-vectorization",
- cl::desc("Disable the loop vectorization pass"),
- cl::init(false));
static cl::opt<bool>
DisableSLPVectorization("disable-slp-vectorization",
@@ -260,21 +251,62 @@ static cl::opt<bool> Coroutines(
cl::desc("Enable coroutine passes."),
cl::init(false), cl::Hidden);
-static cl::opt<bool> PassRemarksWithHotness(
+static cl::opt<bool> RemarksWithHotness(
"pass-remarks-with-hotness",
cl::desc("With PGO, include profile count in optimization remarks"),
cl::Hidden);
-static cl::opt<unsigned> PassRemarksHotnessThreshold(
- "pass-remarks-hotness-threshold",
- cl::desc("Minimum profile count required for an optimization remark to be output"),
- cl::Hidden);
+static cl::opt<unsigned>
+ RemarksHotnessThreshold("pass-remarks-hotness-threshold",
+ cl::desc("Minimum profile count required for "
+ "an optimization remark to be output"),
+ cl::Hidden);
static cl::opt<std::string>
RemarksFilename("pass-remarks-output",
- cl::desc("YAML output filename for pass remarks"),
+ cl::desc("Output filename for pass remarks"),
cl::value_desc("filename"));
+static cl::opt<std::string>
+ RemarksPasses("pass-remarks-filter",
+ cl::desc("Only record optimization remarks from passes whose "
+ "names match the given regular expression"),
+ cl::value_desc("regex"));
+
+static cl::opt<std::string> RemarksFormat(
+ "pass-remarks-format",
+ cl::desc("The format used for serializing remarks (default: YAML)"),
+ cl::value_desc("format"), cl::init("yaml"));
+
+cl::opt<PGOKind>
+ PGOKindFlag("pgo-kind", cl::init(NoPGO), cl::Hidden,
+ cl::desc("The kind of profile guided optimization"),
+ cl::values(clEnumValN(NoPGO, "nopgo", "Do not use PGO."),
+ clEnumValN(InstrGen, "pgo-instr-gen-pipeline",
+ "Instrument the IR to generate profile."),
+ clEnumValN(InstrUse, "pgo-instr-use-pipeline",
+ "Use instrumented profile to guide PGO."),
+ clEnumValN(SampleUse, "pgo-sample-use-pipeline",
+ "Use sampled profile to guide PGO.")));
+cl::opt<std::string> ProfileFile("profile-file",
+ cl::desc("Path to the profile."), cl::Hidden);
+
+cl::opt<CSPGOKind> CSPGOKindFlag(
+ "cspgo-kind", cl::init(NoCSPGO), cl::Hidden,
+ cl::desc("The kind of context sensitive profile guided optimization"),
+ cl::values(
+ clEnumValN(NoCSPGO, "nocspgo", "Do not use CSPGO."),
+ clEnumValN(
+ CSInstrGen, "cspgo-instr-gen-pipeline",
+ "Instrument (context sensitive) the IR to generate profile."),
+ clEnumValN(
+ CSInstrUse, "cspgo-instr-use-pipeline",
+ "Use instrumented (context sensitive) profile to guide PGO.")));
+cl::opt<std::string> CSProfileGenFile(
+ "cs-profilegen-file",
+ cl::desc("Path to the instrumented context sensitive profile."),
+ cl::Hidden);
+
class OptCustomPassManager : public legacy::PassManager {
DebugifyStatsMap DIStatsMap;
@@ -348,15 +380,16 @@ static void AddOptimizationPasses(legacy::PassManagerBase &MPM,
} else {
Builder.Inliner = createAlwaysInlinerLegacyPass();
}
- Builder.DisableUnitAtATime = !UnitAtATime;
Builder.DisableUnrollLoops = (DisableLoopUnrolling.getNumOccurrences() > 0) ?
DisableLoopUnrolling : OptLevel == 0;
- // This is final, unless there is a #pragma vectorize enable
- if (DisableLoopVectorization)
- Builder.LoopVectorize = false;
- // If option wasn't forced via cmd line (-vectorize-loops, -loop-vectorize)
- else if (!Builder.LoopVectorize)
+ // Check if vectorization is explicitly disabled via -vectorize-loops=false.
+ // The flag enables vectorization in the LoopVectorize pass, it is on by
+ // default, and if it was disabled, leave it disabled here.
+ // Another flag that exists: -loop-vectorize, controls adding the pass to the
+ // pass manager. If set, the pass is added, and there is no additional check
+ // here for it.
+ if (Builder.LoopVectorize)
Builder.LoopVectorize = OptLevel > 1 && SizeLevel < 2;
// When #pragma vectorize is on for SLP, do the same as above
@@ -369,6 +402,32 @@ static void AddOptimizationPasses(legacy::PassManagerBase &MPM,
if (Coroutines)
addCoroutinePassesToExtensionPoints(Builder);
+ switch (PGOKindFlag) {
+ case InstrGen:
+ Builder.EnablePGOInstrGen = true;
+ Builder.PGOInstrGen = ProfileFile;
+ break;
+ case InstrUse:
+ Builder.PGOInstrUse = ProfileFile;
+ break;
+ case SampleUse:
+ Builder.PGOSampleUse = ProfileFile;
+ break;
+ default:
+ break;
+ }
+
+ switch (CSPGOKindFlag) {
+ case CSInstrGen:
+ Builder.EnablePGOCSInstrGen = true;
+ break;
+ case CSInstrUse:
+ Builder.EnablePGOCSInstrUse = true;
+ break;
+ default:
+ break;
+ }
+
Builder.populateFunctionPassManager(FPM);
Builder.populateModulePassManager(MPM);
}
@@ -464,6 +523,7 @@ int main(int argc, char **argv) {
initializeDwarfEHPreparePass(Registry);
initializeSafeStackLegacyPassPass(Registry);
initializeSjLjEHPreparePass(Registry);
+ initializeStackProtectorPass(Registry);
initializePreISelIntrinsicLoweringLegacyPassPass(Registry);
initializeGlobalMergePass(Registry);
initializeIndirectBrExpandPassPass(Registry);
@@ -475,6 +535,7 @@ int main(int argc, char **argv) {
initializeExpandReductionsPass(Registry);
initializeWasmEHPreparePass(Registry);
initializeWriteBitcodePassPass(Registry);
+ initializeHardwareLoopsPass(Registry);
#ifdef LINK_POLLY_INTO_TOOLS
polly::initializePollyPasses(Registry);
@@ -494,24 +555,15 @@ int main(int argc, char **argv) {
if (!DisableDITypeMap)
Context.enableDebugTypeODRUniquing();
- if (PassRemarksWithHotness)
- Context.setDiagnosticsHotnessRequested(true);
-
- if (PassRemarksHotnessThreshold)
- Context.setDiagnosticsHotnessThreshold(PassRemarksHotnessThreshold);
-
- std::unique_ptr<ToolOutputFile> OptRemarkFile;
- if (RemarksFilename != "") {
- std::error_code EC;
- OptRemarkFile =
- llvm::make_unique<ToolOutputFile>(RemarksFilename, EC, sys::fs::F_None);
- if (EC) {
- errs() << EC.message() << '\n';
- return 1;
- }
- Context.setDiagnosticsOutputFile(
- llvm::make_unique<yaml::Output>(OptRemarkFile->os()));
+ Expected<std::unique_ptr<ToolOutputFile>> RemarksFileOrErr =
+ setupOptimizationRemarks(Context, RemarksFilename, RemarksPasses,
+ RemarksFormat, RemarksWithHotness,
+ RemarksHotnessThreshold);
+ if (Error E = RemarksFileOrErr.takeError()) {
+ errs() << toString(std::move(E)) << '\n';
+ return 1;
}
+ std::unique_ptr<ToolOutputFile> RemarksFile = std::move(*RemarksFileOrErr);
// Load the input module...
std::unique_ptr<Module> M =
@@ -585,6 +637,11 @@ int main(int argc, char **argv) {
CPUStr = getCPUStr();
FeaturesStr = getFeaturesStr();
Machine = GetTargetMachine(ModuleTriple, CPUStr, FeaturesStr, Options);
+ } else if (ModuleTriple.getArchName() != "unknown" &&
+ ModuleTriple.getArchName() != "") {
+ errs() << argv[0] << ": unrecognized architecture '"
+ << ModuleTriple.getArchName() << "' provided.\n";
+ return 1;
}
std::unique_ptr<TargetMachine> TM(Machine);
@@ -620,7 +677,7 @@ int main(int argc, char **argv) {
// string. Hand off the rest of the functionality to the new code for that
// layer.
return runPassPipeline(argv[0], *M, TM.get(), Out.get(), ThinLinkOut.get(),
- OptRemarkFile.get(), PassPipeline, OK, VK,
+ RemarksFile.get(), PassPipeline, OK, VK,
PreserveAssemblyUseListOrder,
PreserveBitcodeUseListOrder, EmitSummaryIndex,
EmitModuleHash, EnableDebugify)
@@ -856,8 +913,8 @@ int main(int argc, char **argv) {
"the compile-twice option\n";
Out->os() << BOS->str();
Out->keep();
- if (OptRemarkFile)
- OptRemarkFile->keep();
+ if (RemarksFile)
+ RemarksFile->keep();
return 1;
}
Out->os() << BOS->str();
@@ -870,8 +927,8 @@ int main(int argc, char **argv) {
if (!NoOutput || PrintBreakpoints)
Out->keep();
- if (OptRemarkFile)
- OptRemarkFile->keep();
+ if (RemarksFile)
+ RemarksFile->keep();
if (ThinLinkOut)
ThinLinkOut->keep();