aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt13
-rw-r--r--tools/LLVMBuild.txt2
-rw-r--r--tools/Makefile4
-rw-r--r--tools/bugpoint/BugDriver.cpp8
-rw-r--r--tools/bugpoint/BugDriver.h4
-rw-r--r--tools/bugpoint/CMakeLists.txt3
-rw-r--r--tools/bugpoint/CrashDebugger.cpp12
-rw-r--r--tools/bugpoint/ExecutionDriver.cpp62
-rw-r--r--tools/bugpoint/ExtractFunction.cpp30
-rw-r--r--tools/bugpoint/FindBugs.cpp3
-rw-r--r--tools/bugpoint/LLVMBuild.txt2
-rw-r--r--tools/bugpoint/Makefile2
-rw-r--r--tools/bugpoint/Miscompilation.cpp101
-rw-r--r--tools/bugpoint/OptimizerDriver.cpp99
-rw-r--r--tools/bugpoint/ToolRunner.cpp199
-rw-r--r--tools/bugpoint/ToolRunner.h60
-rw-r--r--tools/gold/gold-plugin.cpp20
-rw-r--r--tools/llc/Android.mk2
-rw-r--r--tools/llc/CMakeLists.txt2
-rw-r--r--tools/llc/LLVMBuild.txt2
-rw-r--r--tools/llc/Makefile2
-rw-r--r--tools/llc/llc.cpp16
-rw-r--r--tools/lli/CMakeLists.txt2
-rw-r--r--tools/lli/LLVMBuild.txt2
-rw-r--r--tools/lli/Makefile2
-rw-r--r--tools/lli/RecordingMemoryManager.cpp11
-rw-r--r--tools/lli/RecordingMemoryManager.h7
-rw-r--r--tools/lli/lli.cpp49
-rw-r--r--tools/llvm-ar/CMakeLists.txt2
-rw-r--r--tools/llvm-ar/LLVMBuild.txt1
-rw-r--r--tools/llvm-ar/Makefile2
-rw-r--r--tools/llvm-ar/llvm-ar.cpp1106
-rw-r--r--tools/llvm-as/llvm-as.cpp7
-rw-r--r--tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp2
-rw-r--r--tools/llvm-config/llvm-config.cpp6
-rw-r--r--tools/llvm-diff/CMakeLists.txt2
-rw-r--r--tools/llvm-diff/LLVMBuild.txt2
-rw-r--r--tools/llvm-diff/Makefile2
-rw-r--r--tools/llvm-diff/llvm-diff.cpp2
-rw-r--r--tools/llvm-dis/llvm-dis.cpp7
-rw-r--r--tools/llvm-dwarfdump/llvm-dwarfdump.cpp1
-rw-r--r--tools/llvm-extract/CMakeLists.txt2
-rw-r--r--tools/llvm-extract/LLVMBuild.txt2
-rw-r--r--tools/llvm-extract/Makefile2
-rw-r--r--tools/llvm-extract/llvm-extract.cpp8
-rw-r--r--tools/llvm-jitlistener/CMakeLists.txt1
-rw-r--r--tools/llvm-jitlistener/LLVMBuild.txt2
-rw-r--r--tools/llvm-jitlistener/Makefile2
-rw-r--r--tools/llvm-jitlistener/llvm-jitlistener.cpp2
-rw-r--r--tools/llvm-link/Android.mk1
-rw-r--r--tools/llvm-link/CMakeLists.txt2
-rw-r--r--tools/llvm-link/LLVMBuild.txt2
-rw-r--r--tools/llvm-link/Makefile2
-rw-r--r--tools/llvm-link/llvm-link.cpp42
-rw-r--r--tools/llvm-mc/Disassembler.cpp72
-rw-r--r--tools/llvm-mc/llvm-mc.cpp15
-rw-r--r--tools/llvm-nm/CMakeLists.txt2
-rw-r--r--tools/llvm-nm/LLVMBuild.txt2
-rw-r--r--tools/llvm-nm/Makefile2
-rw-r--r--tools/llvm-nm/llvm-nm.cpp54
-rw-r--r--tools/llvm-objdump/CMakeLists.txt1
-rw-r--r--tools/llvm-objdump/COFFDump.cpp4
-rw-r--r--tools/llvm-objdump/ELFDump.cpp14
-rw-r--r--tools/llvm-objdump/MCFunction.cpp138
-rw-r--r--tools/llvm-objdump/MCFunction.h100
-rw-r--r--tools/llvm-objdump/MachODump.cpp532
-rw-r--r--tools/llvm-objdump/llvm-objdump.cpp244
-rw-r--r--tools/llvm-objdump/llvm-objdump.h19
-rw-r--r--tools/llvm-ranlib/CMakeLists.txt5
-rw-r--r--tools/llvm-ranlib/LLVMBuild.txt22
-rw-r--r--tools/llvm-ranlib/llvm-ranlib.cpp98
-rw-r--r--tools/llvm-readobj/CMakeLists.txt12
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp1114
-rw-r--r--tools/llvm-readobj/ELF.cpp196
-rw-r--r--tools/llvm-readobj/ELFDumper.cpp848
-rw-r--r--tools/llvm-readobj/Error.cpp62
-rw-r--r--tools/llvm-readobj/Error.h48
-rw-r--r--tools/llvm-readobj/LLVMBuild.txt2
-rw-r--r--tools/llvm-readobj/MachODumper.cpp433
-rw-r--r--tools/llvm-readobj/Makefile2
-rw-r--r--tools/llvm-readobj/ObjDumper.cpp33
-rw-r--r--tools/llvm-readobj/ObjDumper.h61
-rw-r--r--tools/llvm-readobj/StreamWriter.cpp79
-rw-r--r--tools/llvm-readobj/StreamWriter.h282
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp438
-rw-r--r--tools/llvm-readobj/llvm-readobj.h36
-rw-r--r--tools/llvm-rtdyld/llvm-rtdyld.cpp18
-rw-r--r--tools/llvm-shlib/Makefile11
-rw-r--r--tools/llvm-stress/Makefile2
-rw-r--r--tools/llvm-stress/llvm-stress.cpp2
-rw-r--r--tools/llvm-symbolizer/LLVMSymbolize.cpp157
-rw-r--r--tools/llvm-symbolizer/LLVMSymbolize.h40
-rw-r--r--tools/llvm-symbolizer/llvm-symbolizer.cpp29
-rw-r--r--tools/lto/LTOCodeGenerator.cpp189
-rw-r--r--tools/lto/LTOCodeGenerator.h56
-rw-r--r--tools/lto/LTOModule.cpp51
-rw-r--r--tools/lto/LTOModule.h1
-rw-r--r--tools/lto/Makefile5
-rw-r--r--tools/lto/lto.cpp15
-rw-r--r--tools/macho-dump/macho-dump.cpp424
-rw-r--r--tools/obj2yaml/CMakeLists.txt7
-rw-r--r--tools/obj2yaml/Makefile (renamed from tools/llvm-ranlib/Makefile)17
-rw-r--r--tools/obj2yaml/coff2yaml.cpp120
-rw-r--r--tools/obj2yaml/obj2yaml.cpp54
-rw-r--r--tools/obj2yaml/obj2yaml.h22
-rw-r--r--tools/opt/CMakeLists.txt3
-rw-r--r--tools/opt/LLVMBuild.txt2
-rw-r--r--tools/opt/Makefile2
-rw-r--r--tools/opt/opt.cpp27
-rw-r--r--tools/yaml2obj/CMakeLists.txt9
-rw-r--r--tools/yaml2obj/Makefile20
-rw-r--r--tools/yaml2obj/yaml2coff.cpp288
-rw-r--r--tools/yaml2obj/yaml2elf.cpp398
-rw-r--r--tools/yaml2obj/yaml2obj.cpp71
-rw-r--r--tools/yaml2obj/yaml2obj.h22
115 files changed, 6366 insertions, 2599 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 5e95604..e663781 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -14,7 +14,6 @@ add_subdirectory(llvm-dis)
add_subdirectory(llvm-mc)
add_subdirectory(llc)
-add_subdirectory(llvm-ranlib)
add_subdirectory(llvm-ar)
add_subdirectory(llvm-nm)
add_subdirectory(llvm-size)
@@ -43,6 +42,9 @@ add_subdirectory(llvm-mcmarkup)
add_subdirectory(llvm-symbolizer)
+add_subdirectory(obj2yaml)
+add_subdirectory(yaml2obj)
+
if( NOT WIN32 )
add_subdirectory(lto)
endif()
@@ -56,8 +58,11 @@ if( LLVM_ENABLE_PIC )
endif()
add_llvm_external_project(clang)
-add_llvm_external_project(lld)
-add_llvm_external_project(lldb)
-add_llvm_external_project(polly)
+
+if( NOT LLVM_INCLUDE_TOOLS STREQUAL "bootstrap-only" )
+ add_llvm_external_project(lld)
+ add_llvm_external_project(lldb)
+ add_llvm_external_project(polly)
+endif()
set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} PARENT_SCOPE)
diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt
index 25aa177..9ec89f3 100644
--- a/tools/LLVMBuild.txt
+++ b/tools/LLVMBuild.txt
@@ -16,7 +16,7 @@
;===------------------------------------------------------------------------===;
[common]
-subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-ranlib llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup
+subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup
[component_0]
type = Group
diff --git a/tools/Makefile b/tools/Makefile
index c405868..b7375c9 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -28,14 +28,14 @@ OPTIONAL_DIRS := lldb
# in parallel builds. Please retain this ordering.
DIRS := llvm-config
PARALLEL_DIRS := opt llvm-as llvm-dis \
- llc llvm-ranlib llvm-ar llvm-nm \
+ llc llvm-ar llvm-nm \
llvm-prof llvm-link \
lli llvm-extract llvm-mc \
bugpoint llvm-bcanalyzer \
llvm-diff macho-dump llvm-objdump llvm-readobj \
llvm-rtdyld llvm-dwarfdump llvm-cov \
llvm-size llvm-stress llvm-mcmarkup \
- llvm-symbolizer
+ llvm-symbolizer obj2yaml yaml2obj
# If Intel JIT Events support is configured, build an extra tool to test it.
ifeq ($(USE_INTEL_JITEVENTS), 1)
diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp
index cede4ac..a5436ba 100644
--- a/tools/bugpoint/BugDriver.cpp
+++ b/tools/bugpoint/BugDriver.cpp
@@ -16,12 +16,12 @@
#include "BugDriver.h"
#include "ToolRunner.h"
#include "llvm/IR/Module.h"
+#include "llvm/IRReader/IRReader.h"
#include "llvm/Linker.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Host.h"
-#include "llvm/Support/IRReader.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
@@ -122,7 +122,7 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) {
outs() << "Read input file : '" << Filenames[0] << "'\n";
for (unsigned i = 1, e = Filenames.size(); i != e; ++i) {
- std::auto_ptr<Module> M(ParseInputFile(Filenames[i], Context));
+ OwningPtr<Module> M(ParseInputFile(Filenames[i], Context));
if (M.get() == 0) return true;
outs() << "Linking in input file: '" << Filenames[i] << "'\n";
@@ -194,8 +194,8 @@ bool BugDriver::run(std::string &ErrMsg) {
// Make sure the reference output file gets deleted on exit from this
// function, if appropriate.
- sys::Path ROF(ReferenceOutputFile);
- FileRemover RemoverInstance(ROF.str(), CreatedOutput && !SaveTemps);
+ std::string ROF(ReferenceOutputFile);
+ FileRemover RemoverInstance(ROF, CreatedOutput && !SaveTemps);
// Diff the output of the raw program against the reference output. If it
// matches, then we assume there is a miscompilation bug and try to
diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h
index 2b621ec..27b37f4 100644
--- a/tools/bugpoint/BugDriver.h
+++ b/tools/bugpoint/BugDriver.h
@@ -191,7 +191,7 @@ public:
/// this function.
///
bool createReferenceFile(Module *M, const std::string &Filename
- = "bugpoint.reference.out");
+ = "bugpoint.reference.out-%%%%%%%");
/// diffProgram - This method executes the specified module and diffs the
/// output against the file specified by ReferenceOutputFile. If the output
@@ -275,6 +275,8 @@ public:
/// bitcode file. If an error occurs, true is returned.
///
bool writeProgramToFile(const std::string &Filename, const Module *M) const;
+ bool writeProgramToFile(const std::string &Filename, int FD,
+ const Module *M) const;
private:
/// runPasses - Just like the method above, but this just returns true or
diff --git a/tools/bugpoint/CMakeLists.txt b/tools/bugpoint/CMakeLists.txt
index 3c5e64f..0000d97 100644
--- a/tools/bugpoint/CMakeLists.txt
+++ b/tools/bugpoint/CMakeLists.txt
@@ -1,5 +1,5 @@
set(LLVM_LINK_COMPONENTS asmparser instrumentation scalaropts ipo
- linker bitreader bitwriter vectorize objcarcopts)
+ linker bitreader bitwriter irreader vectorize objcarcopts)
add_llvm_tool(bugpoint
BugDriver.cpp
@@ -12,3 +12,4 @@ add_llvm_tool(bugpoint
ToolRunner.cpp
bugpoint.cpp
)
+set_target_properties(bugpoint PROPERTIES ENABLE_EXPORTS 1)
diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp
index ed211a6..c8b4f6f 100644
--- a/tools/bugpoint/CrashDebugger.cpp
+++ b/tools/bugpoint/CrashDebugger.cpp
@@ -62,25 +62,23 @@ ReducePassList::TestResult
ReducePassList::doTest(std::vector<std::string> &Prefix,
std::vector<std::string> &Suffix,
std::string &Error) {
- sys::Path PrefixOutput;
+ std::string PrefixOutput;
Module *OrigProgram = 0;
if (!Prefix.empty()) {
outs() << "Checking to see if these passes crash: "
<< getPassesString(Prefix) << ": ";
- std::string PfxOutput;
- if (BD.runPasses(BD.getProgram(), Prefix, PfxOutput))
+ if (BD.runPasses(BD.getProgram(), Prefix, PrefixOutput))
return KeepPrefix;
- PrefixOutput.set(PfxOutput);
OrigProgram = BD.Program;
- BD.Program = ParseInputFile(PrefixOutput.str(), BD.getContext());
+ BD.Program = ParseInputFile(PrefixOutput, BD.getContext());
if (BD.Program == 0) {
errs() << BD.getToolName() << ": Error reading bitcode file '"
- << PrefixOutput.str() << "'!\n";
+ << PrefixOutput << "'!\n";
exit(1);
}
- PrefixOutput.eraseFromDisk();
+ sys::fs::remove(PrefixOutput);
}
outs() << "Checking to see if these passes crash: "
diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp
index da36045..3d3dac3 100644
--- a/tools/bugpoint/ExecutionDriver.cpp
+++ b/tools/bugpoint/ExecutionDriver.cpp
@@ -265,16 +265,18 @@ bool BugDriver::initializeExecutionEnvironment() {
///
void BugDriver::compileProgram(Module *M, std::string *Error) const {
// Emit the program to a bitcode file...
- sys::Path BitcodeFile (OutputPrefix + "-test-program.bc");
- std::string ErrMsg;
- if (BitcodeFile.makeUnique(true, &ErrMsg)) {
- errs() << ToolName << ": Error making unique filename: " << ErrMsg
+ SmallString<128> BitcodeFile;
+ int BitcodeFD;
+ error_code EC = sys::fs::createUniqueFile(
+ OutputPrefix + "-test-program-%%%%%%%.bc", BitcodeFD, BitcodeFile);
+ if (EC) {
+ errs() << ToolName << ": Error making unique filename: " << EC.message()
<< "\n";
exit(1);
}
- if (writeProgramToFile(BitcodeFile.str(), M)) {
- errs() << ToolName << ": Error emitting bitcode to file '"
- << BitcodeFile.str() << "'!\n";
+ if (writeProgramToFile(BitcodeFile.str(), BitcodeFD, M)) {
+ errs() << ToolName << ": Error emitting bitcode to file '" << BitcodeFile
+ << "'!\n";
exit(1);
}
@@ -302,15 +304,18 @@ std::string BugDriver::executeProgram(const Module *Program,
std::string ErrMsg;
if (BitcodeFile.empty()) {
// Emit the program to a bitcode file...
- sys::Path uniqueFilename(OutputPrefix + "-test-program.bc");
- if (uniqueFilename.makeUnique(true, &ErrMsg)) {
+ SmallString<128> UniqueFilename;
+ int UniqueFD;
+ error_code EC = sys::fs::createUniqueFile(
+ OutputPrefix + "-test-program-%%%%%%%.bc", UniqueFD, UniqueFilename);
+ if (EC) {
errs() << ToolName << ": Error making unique filename: "
- << ErrMsg << "!\n";
+ << EC.message() << "!\n";
exit(1);
}
- BitcodeFile = uniqueFilename.str();
+ BitcodeFile = UniqueFilename.str();
- if (writeProgramToFile(BitcodeFile, Program)) {
+ if (writeProgramToFile(BitcodeFile, UniqueFD, Program)) {
errs() << ToolName << ": Error emitting bitcode to file '"
<< BitcodeFile << "'!\n";
exit(1);
@@ -319,20 +324,21 @@ std::string BugDriver::executeProgram(const Module *Program,
}
// Remove the temporary bitcode file when we are done.
- sys::Path BitcodePath(BitcodeFile);
- FileRemover BitcodeFileRemover(BitcodePath.str(),
+ std::string BitcodePath(BitcodeFile);
+ FileRemover BitcodeFileRemover(BitcodePath,
CreatedBitcode && !SaveTemps);
- if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output";
+ if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output-%%%%%%%";
// Check to see if this is a valid output filename...
- sys::Path uniqueFile(OutputFile);
- if (uniqueFile.makeUnique(true, &ErrMsg)) {
+ SmallString<128> UniqueFile;
+ error_code EC = sys::fs::createUniqueFile(OutputFile, UniqueFile);
+ if (EC) {
errs() << ToolName << ": Error making unique filename: "
- << ErrMsg << "\n";
+ << EC.message() << "\n";
exit(1);
}
- OutputFile = uniqueFile.str();
+ OutputFile = UniqueFile.str();
// Figure out which shared objects to run, if any.
std::vector<std::string> SharedObjs(AdditionalSOs);
@@ -380,7 +386,7 @@ std::string BugDriver::executeProgramSafely(const Module *Program,
std::string BugDriver::compileSharedObject(const std::string &BitcodeFile,
std::string &Error) {
assert(Interpreter && "Interpreter should have been created already!");
- sys::Path OutputFile;
+ std::string OutputFile;
// Using the known-good backend.
GCC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile,
@@ -389,7 +395,7 @@ std::string BugDriver::compileSharedObject(const std::string &BitcodeFile,
return "";
std::string SharedObjectFile;
- bool Failure = gcc->MakeSharedObject(OutputFile.str(), FT, SharedObjectFile,
+ bool Failure = gcc->MakeSharedObject(OutputFile, FT, SharedObjectFile,
AdditionalLinkerArgs, Error);
if (!Error.empty())
return "";
@@ -397,7 +403,7 @@ std::string BugDriver::compileSharedObject(const std::string &BitcodeFile,
exit(1);
// Remove the intermediate C file
- OutputFile.eraseFromDisk();
+ sys::fs::remove(OutputFile);
return "./" + SharedObjectFile;
}
@@ -439,15 +445,15 @@ bool BugDriver::diffProgram(const Module *Program,
bool RemoveBitcode,
std::string *ErrMsg) const {
// Execute the program, generating an output file...
- sys::Path Output(executeProgram(Program, "", BitcodeFile, SharedObject, 0,
- ErrMsg));
+ std::string Output(
+ executeProgram(Program, "", BitcodeFile, SharedObject, 0, ErrMsg));
if (!ErrMsg->empty())
return false;
std::string Error;
bool FilesDifferent = false;
- if (int Diff = DiffFilesWithTolerance(sys::Path(ReferenceOutputFile),
- sys::Path(Output.str()),
+ if (int Diff = DiffFilesWithTolerance(ReferenceOutputFile,
+ Output,
AbsTolerance, RelTolerance, &Error)) {
if (Diff == 2) {
errs() << "While diffing output: " << Error << '\n';
@@ -457,12 +463,12 @@ bool BugDriver::diffProgram(const Module *Program,
}
else {
// Remove the generated output if there are no differences.
- Output.eraseFromDisk();
+ sys::fs::remove(Output);
}
// Remove the bitcode file if we are supposed to.
if (RemoveBitcode)
- sys::Path(BitcodeFile).eraseFromDisk();
+ sys::fs::remove(BitcodeFile);
return FilesDifferent;
}
diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp
index bb27767..2098928 100644
--- a/tools/bugpoint/ExtractFunction.cpp
+++ b/tools/bugpoint/ExtractFunction.cpp
@@ -363,25 +363,19 @@ llvm::SplitFunctionsOutOfModule(Module *M,
Module *BugDriver::ExtractMappedBlocksFromModule(const
std::vector<BasicBlock*> &BBs,
Module *M) {
- sys::Path uniqueFilename(OutputPrefix + "-extractblocks");
- std::string ErrMsg;
- if (uniqueFilename.createTemporaryFileOnDisk(true, &ErrMsg)) {
+ SmallString<128> Filename;
+ int FD;
+ error_code EC = sys::fs::createUniqueFile(
+ OutputPrefix + "-extractblocks%%%%%%%", FD, Filename);
+ if (EC) {
outs() << "*** Basic Block extraction failed!\n";
- errs() << "Error creating temporary file: " << ErrMsg << "\n";
+ errs() << "Error creating temporary file: " << EC.message() << "\n";
EmitProgressBitcode(M, "basicblockextractfail", true);
return 0;
}
- sys::RemoveFileOnSignal(uniqueFilename);
+ sys::RemoveFileOnSignal(Filename);
- std::string ErrorInfo;
- tool_output_file BlocksToNotExtractFile(uniqueFilename.c_str(), ErrorInfo);
- if (!ErrorInfo.empty()) {
- outs() << "*** Basic Block extraction failed!\n";
- errs() << "Error writing list of blocks to not extract: " << ErrorInfo
- << "\n";
- EmitProgressBitcode(M, "basicblockextractfail", true);
- return 0;
- }
+ tool_output_file BlocksToNotExtractFile(Filename.c_str(), FD);
for (std::vector<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end();
I != E; ++I) {
BasicBlock *BB = *I;
@@ -393,22 +387,22 @@ Module *BugDriver::ExtractMappedBlocksFromModule(const
}
BlocksToNotExtractFile.os().close();
if (BlocksToNotExtractFile.os().has_error()) {
- errs() << "Error writing list of blocks to not extract: " << ErrorInfo
- << "\n";
+ errs() << "Error writing list of blocks to not extract\n";
EmitProgressBitcode(M, "basicblockextractfail", true);
BlocksToNotExtractFile.os().clear_error();
return 0;
}
BlocksToNotExtractFile.keep();
- std::string uniqueFN = "--extract-blocks-file=" + uniqueFilename.str();
+ std::string uniqueFN = "--extract-blocks-file=";
+ uniqueFN += Filename.str();
const char *ExtraArg = uniqueFN.c_str();
std::vector<std::string> PI;
PI.push_back("extract-blocks");
Module *Ret = runPassesOn(M, PI, false, 1, &ExtraArg);
- uniqueFilename.eraseFromDisk(); // Free disk space
+ sys::fs::remove(Filename.c_str());
if (Ret == 0) {
outs() << "*** Basic Block extraction failed, please report a bug!\n";
diff --git a/tools/bugpoint/FindBugs.cpp b/tools/bugpoint/FindBugs.cpp
index a291f9f..e2941f6 100644
--- a/tools/bugpoint/FindBugs.cpp
+++ b/tools/bugpoint/FindBugs.cpp
@@ -17,6 +17,7 @@
#include "BugDriver.h"
#include "ToolRunner.h"
#include "llvm/Pass.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <ctime>
@@ -103,7 +104,7 @@ bool BugDriver::runManyPasses(const std::vector<std::string> &AllPasses,
}
outs() << "\n*** diff'd output matches!\n";
- sys::Path(Filename).eraseFromDisk();
+ sys::fs::remove(Filename);
outs() << "\n\n";
num++;
diff --git a/tools/bugpoint/LLVMBuild.txt b/tools/bugpoint/LLVMBuild.txt
index e03c594..0164355 100644
--- a/tools/bugpoint/LLVMBuild.txt
+++ b/tools/bugpoint/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = bugpoint
parent = Tools
-required_libraries = AsmParser BitReader BitWriter IPO Instrumentation Linker Scalar ObjCARC
+required_libraries = AsmParser BitReader BitWriter IRReader IPO Instrumentation Linker Scalar ObjCARC
diff --git a/tools/bugpoint/Makefile b/tools/bugpoint/Makefile
index 65ffc13..2049321 100644
--- a/tools/bugpoint/Makefile
+++ b/tools/bugpoint/Makefile
@@ -10,6 +10,6 @@
LEVEL := ../..
TOOLNAME := bugpoint
LINK_COMPONENTS := asmparser instrumentation scalaropts ipo linker bitreader \
- bitwriter vectorize objcarcopts
+ bitwriter irreader vectorize objcarcopts
include $(LEVEL)/Makefile.common
diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp
index c676a05..771ec34 100644
--- a/tools/bugpoint/Miscompilation.cpp
+++ b/tools/bugpoint/Miscompilation.cpp
@@ -120,7 +120,7 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix,
return InternalError;
if (Diff) {
outs() << " nope.\n";
- sys::Path(BitcodeResult).eraseFromDisk();
+ sys::fs::remove(BitcodeResult);
return KeepPrefix;
}
outs() << " yup.\n"; // No miscompilation!
@@ -130,12 +130,12 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix,
//
OwningPtr<Module> PrefixOutput(ParseInputFile(BitcodeResult,
BD.getContext()));
- if (PrefixOutput == 0) {
+ if (!PrefixOutput) {
errs() << BD.getToolName() << ": Error reading bitcode file '"
<< BitcodeResult << "'!\n";
exit(1);
}
- sys::Path(BitcodeResult).eraseFromDisk(); // No longer need the file on disk
+ sys::fs::remove(BitcodeResult);
// Don't check if there are no passes in the suffix.
if (Suffix.empty())
@@ -337,8 +337,13 @@ static bool ExtractLoops(BugDriver &BD,
false, Error, Failure);
if (!New)
return false;
+
// Delete the original and set the new program.
- delete BD.swapProgramIn(New);
+ Module *Old = BD.swapProgramIn(New);
+ for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i)
+ MiscompiledFunctions[i] = cast<Function>(VMap[MiscompiledFunctions[i]]);
+ delete Old;
+
if (Failure) {
BD.switchToInterpreter(AI);
@@ -366,21 +371,51 @@ static bool ExtractLoops(BugDriver &BD,
outs() << " Testing after loop extraction:\n";
// Clone modules, the tester function will free them.
- Module *TOLEBackup = CloneModule(ToOptimizeLoopExtracted);
- Module *TNOBackup = CloneModule(ToNotOptimize);
+ Module *TOLEBackup = CloneModule(ToOptimizeLoopExtracted, VMap);
+ Module *TNOBackup = CloneModule(ToNotOptimize, VMap);
+
+ for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i)
+ MiscompiledFunctions[i] = cast<Function>(VMap[MiscompiledFunctions[i]]);
+
Failure = TestFn(BD, ToOptimizeLoopExtracted, ToNotOptimize, Error);
if (!Error.empty())
return false;
+
+ ToOptimizeLoopExtracted = TOLEBackup;
+ ToNotOptimize = TNOBackup;
+
if (!Failure) {
outs() << "*** Loop extraction masked the problem. Undoing.\n";
// If the program is not still broken, then loop extraction did something
// that masked the error. Stop loop extraction now.
- delete TOLEBackup;
- delete TNOBackup;
+
+ std::vector<std::pair<std::string, FunctionType*> > MisCompFunctions;
+ for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) {
+ Function *F = MiscompiledFunctions[i];
+ MisCompFunctions.push_back(std::make_pair(F->getName(),
+ F->getFunctionType()));
+ }
+
+ std::string ErrorMsg;
+ if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted,
+ Linker::DestroySource, &ErrorMsg)){
+ errs() << BD.getToolName() << ": Error linking modules together:"
+ << ErrorMsg << '\n';
+ exit(1);
+ }
+
+ MiscompiledFunctions.clear();
+ for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) {
+ Function *NewF = ToNotOptimize->getFunction(MisCompFunctions[i].first);
+
+ assert(NewF && "Function not found??");
+ MiscompiledFunctions.push_back(NewF);
+ }
+
+ delete ToOptimizeLoopExtracted;
+ BD.setNewProgram(ToNotOptimize);
return MadeChange;
}
- ToOptimizeLoopExtracted = TOLEBackup;
- ToNotOptimize = TNOBackup;
outs() << "*** Loop extraction successful!\n";
@@ -926,14 +961,16 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe,
std::string &Error) {
CleanupAndPrepareModules(BD, Test, Safe);
- sys::Path TestModuleBC("bugpoint.test.bc");
- std::string ErrMsg;
- if (TestModuleBC.makeUnique(true, &ErrMsg)) {
+ SmallString<128> TestModuleBC;
+ int TestModuleFD;
+ error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc",
+ TestModuleFD, TestModuleBC);
+ if (EC) {
errs() << BD.getToolName() << "Error making unique filename: "
- << ErrMsg << "\n";
+ << EC.message() << "\n";
exit(1);
}
- if (BD.writeProgramToFile(TestModuleBC.str(), Test)) {
+ if (BD.writeProgramToFile(TestModuleBC.str(), TestModuleFD, Test)) {
errs() << "Error writing bitcode to `" << TestModuleBC.str()
<< "'\nExiting.";
exit(1);
@@ -943,14 +980,17 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe,
FileRemover TestModuleBCRemover(TestModuleBC.str(), !SaveTemps);
// Make the shared library
- sys::Path SafeModuleBC("bugpoint.safe.bc");
- if (SafeModuleBC.makeUnique(true, &ErrMsg)) {
+ SmallString<128> SafeModuleBC;
+ int SafeModuleFD;
+ EC = sys::fs::createTemporaryFile("bugpoint.safe", "bc", SafeModuleFD,
+ SafeModuleBC);
+ if (EC) {
errs() << BD.getToolName() << "Error making unique filename: "
- << ErrMsg << "\n";
+ << EC.message() << "\n";
exit(1);
}
- if (BD.writeProgramToFile(SafeModuleBC.str(), Safe)) {
+ if (BD.writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, Safe)) {
errs() << "Error writing bitcode to `" << SafeModuleBC.str()
<< "'\nExiting.";
exit(1);
@@ -1015,15 +1055,17 @@ bool BugDriver::debugCodeGenerator(std::string *Error) {
// Condition the modules
CleanupAndPrepareModules(*this, ToCodeGen, ToNotCodeGen);
- sys::Path TestModuleBC("bugpoint.test.bc");
- std::string ErrMsg;
- if (TestModuleBC.makeUnique(true, &ErrMsg)) {
+ SmallString<128> TestModuleBC;
+ int TestModuleFD;
+ error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc",
+ TestModuleFD, TestModuleBC);
+ if (EC) {
errs() << getToolName() << "Error making unique filename: "
- << ErrMsg << "\n";
+ << EC.message() << "\n";
exit(1);
}
- if (writeProgramToFile(TestModuleBC.str(), ToCodeGen)) {
+ if (writeProgramToFile(TestModuleBC.str(), TestModuleFD, ToCodeGen)) {
errs() << "Error writing bitcode to `" << TestModuleBC.str()
<< "'\nExiting.";
exit(1);
@@ -1031,14 +1073,17 @@ bool BugDriver::debugCodeGenerator(std::string *Error) {
delete ToCodeGen;
// Make the shared library
- sys::Path SafeModuleBC("bugpoint.safe.bc");
- if (SafeModuleBC.makeUnique(true, &ErrMsg)) {
+ SmallString<128> SafeModuleBC;
+ int SafeModuleFD;
+ EC = sys::fs::createTemporaryFile("bugpoint.safe", "bc", SafeModuleFD,
+ SafeModuleBC);
+ if (EC) {
errs() << getToolName() << "Error making unique filename: "
- << ErrMsg << "\n";
+ << EC.message() << "\n";
exit(1);
}
- if (writeProgramToFile(SafeModuleBC.str(), ToNotCodeGen)) {
+ if (writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, ToNotCodeGen)) {
errs() << "Error writing bitcode to `" << SafeModuleBC.str()
<< "'\nExiting.";
exit(1);
diff --git a/tools/bugpoint/OptimizerDriver.cpp b/tools/bugpoint/OptimizerDriver.cpp
index 87dc9f3..20c609c 100644
--- a/tools/bugpoint/OptimizerDriver.cpp
+++ b/tools/bugpoint/OptimizerDriver.cpp
@@ -33,6 +33,7 @@
#include "llvm/Support/PluginLoader.h"
#include <fstream>
+
using namespace llvm;
namespace llvm {
@@ -43,25 +44,36 @@ namespace {
// ChildOutput - This option captures the name of the child output file that
// is set up by the parent bugpoint process
cl::opt<std::string> ChildOutput("child-output", cl::ReallyHidden);
+ cl::opt<std::string> OptCmd("opt-command", cl::init(""),
+ cl::desc("Path to opt. (default: search path "
+ "for 'opt'.)"));
}
/// writeProgramToFile - This writes the current "Program" to the named bitcode
/// file. If an error occurs, true is returned.
///
+static bool writeProgramToFileAux(tool_output_file &Out, const Module *M) {
+ WriteBitcodeToFile(M, Out.os());
+ Out.os().close();
+ if (!Out.os().has_error()) {
+ Out.keep();
+ return false;
+ }
+ return true;
+}
+
+bool BugDriver::writeProgramToFile(const std::string &Filename, int FD,
+ const Module *M) const {
+ tool_output_file Out(Filename.c_str(), FD);
+ return writeProgramToFileAux(Out, M);
+}
+
bool BugDriver::writeProgramToFile(const std::string &Filename,
const Module *M) const {
std::string ErrInfo;
- tool_output_file Out(Filename.c_str(), ErrInfo,
- raw_fd_ostream::F_Binary);
- if (ErrInfo.empty()) {
- WriteBitcodeToFile(M, Out.os());
- Out.os().close();
- if (!Out.os().has_error()) {
- Out.keep();
- return false;
- }
- }
- Out.os().clear_error();
+ tool_output_file Out(Filename.c_str(), ErrInfo, sys::fs::F_Binary);
+ if (ErrInfo.empty())
+ return writeProgramToFileAux(Out, M);
return true;
}
@@ -114,41 +126,38 @@ bool BugDriver::runPasses(Module *Program,
const char * const *ExtraArgs) const {
// setup the output file name
outs().flush();
- sys::Path uniqueFilename(OutputPrefix + "-output.bc");
- std::string ErrMsg;
- if (uniqueFilename.makeUnique(true, &ErrMsg)) {
+ SmallString<128> UniqueFilename;
+ error_code EC = sys::fs::createUniqueFile(
+ OutputPrefix + "-output-%%%%%%%.bc", UniqueFilename);
+ if (EC) {
errs() << getToolName() << ": Error making unique filename: "
- << ErrMsg << "\n";
- return(1);
+ << EC.message() << "\n";
+ return 1;
}
- OutputFilename = uniqueFilename.str();
+ OutputFilename = UniqueFilename.str();
// set up the input file name
- sys::Path inputFilename(OutputPrefix + "-input.bc");
- if (inputFilename.makeUnique(true, &ErrMsg)) {
+ SmallString<128> InputFilename;
+ int InputFD;
+ EC = sys::fs::createUniqueFile(OutputPrefix + "-input-%%%%%%%.bc", InputFD,
+ InputFilename);
+ if (EC) {
errs() << getToolName() << ": Error making unique filename: "
- << ErrMsg << "\n";
- return(1);
+ << EC.message() << "\n";
+ return 1;
}
- std::string ErrInfo;
- tool_output_file InFile(inputFilename.c_str(), ErrInfo,
- raw_fd_ostream::F_Binary);
-
+ tool_output_file InFile(InputFilename.c_str(), InputFD);
- if (!ErrInfo.empty()) {
- errs() << "Error opening bitcode file: " << inputFilename.str() << "\n";
- return 1;
- }
WriteBitcodeToFile(Program, InFile.os());
InFile.os().close();
if (InFile.os().has_error()) {
- errs() << "Error writing bitcode file: " << inputFilename.str() << "\n";
+ errs() << "Error writing bitcode file: " << InputFilename << "\n";
InFile.os().clear_error();
return 1;
}
- sys::Path tool = sys::Program::FindProgramByName("opt");
+ std::string tool = OptCmd.empty()? sys::FindProgramByName("opt") : OptCmd;
if (tool.empty()) {
errs() << "Cannot find `opt' in PATH!\n";
return 1;
@@ -159,14 +168,13 @@ bool BugDriver::runPasses(Module *Program,
// setup the child process' arguments
SmallVector<const char*, 8> Args;
- std::string Opt = tool.str();
if (UseValgrind) {
Args.push_back("valgrind");
Args.push_back("--error-exitcode=1");
Args.push_back("-q");
Args.push_back(tool.c_str());
} else
- Args.push_back(Opt.c_str());
+ Args.push_back(tool.c_str());
Args.push_back("-o");
Args.push_back(OutputFilename.c_str());
@@ -183,7 +191,7 @@ bool BugDriver::runPasses(Module *Program,
for (std::vector<std::string>::const_iterator I = pass_args.begin(),
E = pass_args.end(); I != E; ++I )
Args.push_back(I->c_str());
- Args.push_back(inputFilename.c_str());
+ Args.push_back(InputFilename.c_str());
for (unsigned i = 0; i < NumExtraArgs; ++i)
Args.push_back(*ExtraArgs);
Args.push_back(0);
@@ -194,27 +202,28 @@ bool BugDriver::runPasses(Module *Program,
errs() << "\n";
);
- sys::Path prog;
+ std::string Prog;
if (UseValgrind)
- prog = sys::Program::FindProgramByName("valgrind");
+ Prog = sys::FindProgramByName("valgrind");
else
- prog = tool;
+ Prog = tool;
// Redirect stdout and stderr to nowhere if SilencePasses is given
- sys::Path Nowhere;
- const sys::Path *Redirects[3] = {0, &Nowhere, &Nowhere};
+ StringRef Nowhere;
+ const StringRef *Redirects[3] = {0, &Nowhere, &Nowhere};
- int result = sys::Program::ExecuteAndWait(prog, Args.data(), 0,
- (SilencePasses ? Redirects : 0),
- Timeout, MemoryLimit, &ErrMsg);
+ std::string ErrMsg;
+ int result = sys::ExecuteAndWait(Prog, Args.data(), 0,
+ (SilencePasses ? Redirects : 0), Timeout,
+ MemoryLimit, &ErrMsg);
// If we are supposed to delete the bitcode file or if the passes crashed,
// remove it now. This may fail if the file was never created, but that's ok.
if (DeleteOutput || result != 0)
- sys::Path(OutputFilename).eraseFromDisk();
+ sys::fs::remove(OutputFilename);
// Remove the temporary input file as well
- inputFilename.eraseFromDisk();
+ sys::fs::remove(InputFilename.c_str());
if (!Quiet) {
if (result == 0)
@@ -262,6 +271,6 @@ Module *BugDriver::runPassesOn(Module *M,
<< BitcodeResult << "'!\n";
exit(1);
}
- sys::Path(BitcodeResult).eraseFromDisk(); // No longer need the file on disk
+ sys::fs::remove(BitcodeResult);
return Ret;
}
diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp
index 735061d..107d0db 100644
--- a/tools/bugpoint/ToolRunner.cpp
+++ b/tools/bugpoint/ToolRunner.cpp
@@ -16,6 +16,7 @@
#include "llvm/Config/config.h" // for HAVE_LINK_R
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
@@ -53,18 +54,15 @@ namespace {
/// RunProgramWithTimeout - This function provides an alternate interface
/// to the sys::Program::ExecuteAndWait interface.
/// @see sys::Program::ExecuteAndWait
-static int RunProgramWithTimeout(const sys::Path &ProgramPath,
+static int RunProgramWithTimeout(StringRef ProgramPath,
const char **Args,
- const sys::Path &StdInFile,
- const sys::Path &StdOutFile,
- const sys::Path &StdErrFile,
+ StringRef StdInFile,
+ StringRef StdOutFile,
+ StringRef StdErrFile,
unsigned NumSeconds = 0,
unsigned MemoryLimit = 0,
std::string *ErrMsg = 0) {
- const sys::Path* redirects[3];
- redirects[0] = &StdInFile;
- redirects[1] = &StdOutFile;
- redirects[2] = &StdErrFile;
+ const StringRef *Redirects[3] = { &StdInFile, &StdOutFile, &StdErrFile };
#if 0 // For debug purposes
{
@@ -75,9 +73,8 @@ static int RunProgramWithTimeout(const sys::Path &ProgramPath,
}
#endif
- return
- sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects,
- NumSeconds, MemoryLimit, ErrMsg);
+ return sys::ExecuteAndWait(ProgramPath, Args, 0, Redirects,
+ NumSeconds, MemoryLimit, ErrMsg);
}
/// RunProgramRemotelyWithTimeout - This function runs the given program
@@ -86,17 +83,14 @@ static int RunProgramWithTimeout(const sys::Path &ProgramPath,
/// fails. Remote client is required to return 255 if it failed or program exit
/// code otherwise.
/// @see sys::Program::ExecuteAndWait
-static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath,
+static int RunProgramRemotelyWithTimeout(StringRef RemoteClientPath,
const char **Args,
- const sys::Path &StdInFile,
- const sys::Path &StdOutFile,
- const sys::Path &StdErrFile,
+ StringRef StdInFile,
+ StringRef StdOutFile,
+ StringRef StdErrFile,
unsigned NumSeconds = 0,
unsigned MemoryLimit = 0) {
- const sys::Path* redirects[3];
- redirects[0] = &StdInFile;
- redirects[1] = &StdOutFile;
- redirects[2] = &StdErrFile;
+ const StringRef *Redirects[3] = { &StdInFile, &StdOutFile, &StdErrFile };
#if 0 // For debug purposes
{
@@ -108,8 +102,8 @@ static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath,
#endif
// Run the program remotely with the remote client
- int ReturnCode = sys::Program::ExecuteAndWait(RemoteClientPath, Args,
- 0, redirects, NumSeconds, MemoryLimit);
+ int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, 0,
+ Redirects, NumSeconds, MemoryLimit);
// Has the remote client fail?
if (255 == ReturnCode) {
@@ -120,7 +114,8 @@ static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath,
OS << "\n";
// The error message is in the output file, let's print it out from there.
- std::ifstream ErrorFile(StdOutFile.c_str());
+ std::string StdOutFileName = StdOutFile.str();
+ std::ifstream ErrorFile(StdOutFileName.c_str());
if (ErrorFile) {
std::copy(std::istreambuf_iterator<char>(ErrorFile),
std::istreambuf_iterator<char>(),
@@ -134,7 +129,7 @@ static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath,
return ReturnCode;
}
-static std::string ProcessFailure(sys::Path ProgPath, const char** Args,
+static std::string ProcessFailure(StringRef ProgPath, const char** Args,
unsigned Timeout = 0,
unsigned MemoryLimit = 0) {
std::ostringstream OS;
@@ -144,14 +139,16 @@ static std::string ProcessFailure(sys::Path ProgPath, const char** Args,
OS << "\n";
// Rerun the compiler, capturing any error messages to print them.
- sys::Path ErrorFilename("bugpoint.program_error_messages");
- std::string ErrMsg;
- if (ErrorFilename.makeUnique(true, &ErrMsg)) {
- errs() << "Error making unique filename: " << ErrMsg << "\n";
+ SmallString<128> ErrorFilename;
+ int ErrorFD;
+ error_code EC = sys::fs::createTemporaryFile(
+ "bugpoint.program_error_messages", "", ErrorFD, ErrorFilename);
+ if (EC) {
+ errs() << "Error making unique filename: " << EC.message() << "\n";
exit(1);
}
- RunProgramWithTimeout(ProgPath, Args, sys::Path(""), ErrorFilename,
- ErrorFilename, Timeout, MemoryLimit);
+ RunProgramWithTimeout(ProgPath, Args, "", ErrorFilename.str(),
+ ErrorFilename.str(), Timeout, MemoryLimit);
// FIXME: check return code ?
// Print out the error messages generated by GCC if possible...
@@ -163,7 +160,7 @@ static std::string ProcessFailure(sys::Path ProgPath, const char** Args,
ErrorFile.close();
}
- ErrorFilename.eraseFromDisk();
+ sys::fs::remove(ErrorFilename.c_str());
return OS.str();
}
@@ -229,19 +226,50 @@ int LLI::ExecuteProgram(const std::string &Bitcode,
errs() << " " << LLIArgs[i];
errs() << "\n";
);
- return RunProgramWithTimeout(sys::Path(LLIPath), &LLIArgs[0],
- sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
+ return RunProgramWithTimeout(LLIPath, &LLIArgs[0],
+ InputFile, OutputFile, OutputFile,
Timeout, MemoryLimit, Error);
}
void AbstractInterpreter::anchor() { }
+#if defined(LLVM_ON_UNIX)
+const char EXESuffix[] = "";
+#elif defined (LLVM_ON_WIN32)
+const char EXESuffix[] = "exe";
+#endif
+
+/// Prepend the path to the program being executed
+/// to \p ExeName, given the value of argv[0] and the address of main()
+/// itself. This allows us to find another LLVM tool if it is built in the same
+/// directory. An empty string is returned on error; note that this function
+/// just mainpulates the path and doesn't check for executability.
+/// @brief Find a named executable.
+static std::string PrependMainExecutablePath(const std::string &ExeName,
+ const char *Argv0,
+ void *MainAddr) {
+ // Check the directory that the calling program is in. We can do
+ // this if ProgramPath contains at least one / character, indicating that it
+ // is a relative path to the executable itself.
+ std::string Main = sys::fs::getMainExecutable(Argv0, MainAddr);
+ StringRef Result = sys::path::parent_path(Main);
+
+ if (!Result.empty()) {
+ SmallString<128> Storage = Result;
+ sys::path::append(Storage, ExeName);
+ sys::path::replace_extension(Storage, EXESuffix);
+ return Storage.str();
+ }
+
+ return Result.str();
+}
+
// LLI create method - Try to find the LLI executable
AbstractInterpreter *AbstractInterpreter::createLLI(const char *Argv0,
std::string &Message,
const std::vector<std::string> *ToolArgs) {
std::string LLIPath =
- PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t)&createLLI).str();
+ PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t) & createLLI);
if (!LLIPath.empty()) {
Message = "Found lli: " + LLIPath + "\n";
return new LLI(LLIPath, ToolArgs);
@@ -305,10 +333,10 @@ void CustomCompiler::compileProgram(const std::string &Bitcode,
for (unsigned i = 0, e = CompilerArgs.size(); i != e; ++i)
ProgramArgs.push_back(CompilerArgs[i].c_str());
- if (RunProgramWithTimeout( sys::Path(CompilerCommand), &ProgramArgs[0],
- sys::Path(), sys::Path(), sys::Path(),
+ if (RunProgramWithTimeout(CompilerCommand, &ProgramArgs[0],
+ "", "", "",
Timeout, MemoryLimit, Error))
- *Error = ProcessFailure(sys::Path(CompilerCommand), &ProgramArgs[0],
+ *Error = ProcessFailure(CompilerCommand, &ProgramArgs[0],
Timeout, MemoryLimit);
}
@@ -363,9 +391,9 @@ int CustomExecutor::ExecuteProgram(const std::string &Bitcode,
ProgramArgs.push_back(Args[i].c_str());
return RunProgramWithTimeout(
- sys::Path(ExecutionCommand),
- &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile),
- sys::Path(OutputFile), Timeout, MemoryLimit, Error);
+ ExecutionCommand,
+ &ProgramArgs[0], InputFile, OutputFile,
+ OutputFile, Timeout, MemoryLimit, Error);
}
// Tokenize the CommandLine to the command and the args to allow
@@ -398,7 +426,7 @@ static void lexCommand(std::string &Message, const std::string &CommandLine,
pos = CommandLine.find_first_of(delimiters, lastPos);
}
- CmdPath = sys::Program::FindProgramByName(Command).str();
+ CmdPath = sys::FindProgramByName(Command);
if (CmdPath.empty()) {
Message =
std::string("Cannot find '") + Command +
@@ -444,16 +472,18 @@ AbstractInterpreter *AbstractInterpreter::createCustomExecutor(
// LLC Implementation of AbstractIntepreter interface
//
GCC::FileType LLC::OutputCode(const std::string &Bitcode,
- sys::Path &OutputAsmFile, std::string &Error,
+ std::string &OutputAsmFile, std::string &Error,
unsigned Timeout, unsigned MemoryLimit) {
const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s");
- sys::Path uniqueFile(Bitcode + Suffix);
- std::string ErrMsg;
- if (uniqueFile.makeUnique(true, &ErrMsg)) {
- errs() << "Error making unique filename: " << ErrMsg << "\n";
+
+ SmallString<128> UniqueFile;
+ error_code EC =
+ sys::fs::createUniqueFile(Bitcode + "-%%%%%%%" + Suffix, UniqueFile);
+ if (EC) {
+ errs() << "Error making unique filename: " << EC.message() << "\n";
exit(1);
}
- OutputAsmFile = uniqueFile;
+ OutputAsmFile = UniqueFile.str();
std::vector<const char *> LLCArgs;
LLCArgs.push_back(LLCPath.c_str());
@@ -477,19 +507,19 @@ GCC::FileType LLC::OutputCode(const std::string &Bitcode,
errs() << " " << LLCArgs[i];
errs() << "\n";
);
- if (RunProgramWithTimeout(sys::Path(LLCPath), &LLCArgs[0],
- sys::Path(), sys::Path(), sys::Path(),
+ if (RunProgramWithTimeout(LLCPath, &LLCArgs[0],
+ "", "", "",
Timeout, MemoryLimit))
- Error = ProcessFailure(sys::Path(LLCPath), &LLCArgs[0],
+ Error = ProcessFailure(LLCPath, &LLCArgs[0],
Timeout, MemoryLimit);
return UseIntegratedAssembler ? GCC::ObjectFile : GCC::AsmFile;
}
void LLC::compileProgram(const std::string &Bitcode, std::string *Error,
unsigned Timeout, unsigned MemoryLimit) {
- sys::Path OutputAsmFile;
+ std::string OutputAsmFile;
OutputCode(Bitcode, OutputAsmFile, *Error, Timeout, MemoryLimit);
- OutputAsmFile.eraseFromDisk();
+ sys::fs::remove(OutputAsmFile);
}
int LLC::ExecuteProgram(const std::string &Bitcode,
@@ -502,16 +532,16 @@ int LLC::ExecuteProgram(const std::string &Bitcode,
unsigned Timeout,
unsigned MemoryLimit) {
- sys::Path OutputAsmFile;
+ std::string OutputAsmFile;
GCC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile, *Error, Timeout,
MemoryLimit);
- FileRemover OutFileRemover(OutputAsmFile.str(), !SaveTemps);
+ FileRemover OutFileRemover(OutputAsmFile, !SaveTemps);
std::vector<std::string> GCCArgs(ArgsForGCC);
GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end());
// Assuming LLC worked, compile the result with GCC and run it.
- return gcc->ExecuteProgram(OutputAsmFile.str(), Args, FileKind,
+ return gcc->ExecuteProgram(OutputAsmFile, Args, FileKind,
InputFile, OutputFile, Error, GCCArgs,
Timeout, MemoryLimit);
}
@@ -525,7 +555,7 @@ LLC *AbstractInterpreter::createLLC(const char *Argv0,
const std::vector<std::string> *GCCArgs,
bool UseIntegratedAssembler) {
std::string LLCPath =
- PrependMainExecutablePath("llc", Argv0, (void *)(intptr_t)&createLLC).str();
+ PrependMainExecutablePath("llc", Argv0, (void *)(intptr_t) & createLLC);
if (LLCPath.empty()) {
Message = "Cannot find `llc' in executable directory!\n";
return 0;
@@ -603,8 +633,8 @@ int JIT::ExecuteProgram(const std::string &Bitcode,
errs() << "\n";
);
DEBUG(errs() << "\nSending output to " << OutputFile << "\n");
- return RunProgramWithTimeout(sys::Path(LLIPath), &JITArgs[0],
- sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
+ return RunProgramWithTimeout(LLIPath, &JITArgs[0],
+ InputFile, OutputFile, OutputFile,
Timeout, MemoryLimit, Error);
}
@@ -613,7 +643,7 @@ int JIT::ExecuteProgram(const std::string &Bitcode,
AbstractInterpreter *AbstractInterpreter::createJIT(const char *Argv0,
std::string &Message, const std::vector<std::string> *Args) {
std::string LLIPath =
- PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t)&createJIT).str();
+ PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t) & createJIT);
if (!LLIPath.empty()) {
Message = "Found lli: " + LLIPath + "\n";
return new JIT(LLIPath, Args);
@@ -682,10 +712,12 @@ int GCC::ExecuteProgram(const std::string &ProgramFile,
GCCArgs.push_back("-x");
GCCArgs.push_back("none");
GCCArgs.push_back("-o");
- sys::Path OutputBinary (ProgramFile+".gcc.exe");
- std::string ErrMsg;
- if (OutputBinary.makeUnique(true, &ErrMsg)) {
- errs() << "Error making unique filename: " << ErrMsg << "\n";
+
+ SmallString<128> OutputBinary;
+ error_code EC =
+ sys::fs::createUniqueFile(ProgramFile + "-%%%%%%%.gcc.exe", OutputBinary);
+ if (EC) {
+ errs() << "Error making unique filename: " << EC.message() << "\n";
exit(1);
}
GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file...
@@ -712,8 +744,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile,
errs() << " " << GCCArgs[i];
errs() << "\n";
);
- if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(),
- sys::Path())) {
+ if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "", "", "")) {
*Error = ProcessFailure(GCCPath, &GCCArgs[0]);
return -1;
}
@@ -724,7 +755,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile,
// ProgramArgs is used.
std::string Exec;
- if (RemoteClientPath.isEmpty())
+ if (RemoteClientPath.empty())
ProgramArgs.push_back(OutputBinary.c_str());
else {
ProgramArgs.push_back(RemoteClientPath.c_str());
@@ -766,11 +797,11 @@ int GCC::ExecuteProgram(const std::string &ProgramFile,
FileRemover OutputBinaryRemover(OutputBinary.str(), !SaveTemps);
- if (RemoteClientPath.isEmpty()) {
+ if (RemoteClientPath.empty()) {
DEBUG(errs() << "<run locally>");
- int ExitCode = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
- sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
- Timeout, MemoryLimit, Error);
+ int ExitCode = RunProgramWithTimeout(OutputBinary.str(), &ProgramArgs[0],
+ InputFile, OutputFile, OutputFile,
+ Timeout, MemoryLimit, Error);
// Treat a signal (usually SIGSEGV) or timeout as part of the program output
// so that crash-causing miscompilation is handled seamlessly.
if (ExitCode < -1) {
@@ -782,9 +813,9 @@ int GCC::ExecuteProgram(const std::string &ProgramFile,
return ExitCode;
} else {
outs() << "<run remotely>"; outs().flush();
- return RunProgramRemotelyWithTimeout(sys::Path(RemoteClientPath),
- &ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile),
- sys::Path(OutputFile), Timeout, MemoryLimit);
+ return RunProgramRemotelyWithTimeout(RemoteClientPath,
+ &ProgramArgs[0], InputFile, OutputFile,
+ OutputFile, Timeout, MemoryLimit);
}
}
@@ -792,13 +823,14 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
std::string &OutputFile,
const std::vector<std::string> &ArgsForGCC,
std::string &Error) {
- sys::Path uniqueFilename(InputFile+LTDL_SHLIB_EXT);
- std::string ErrMsg;
- if (uniqueFilename.makeUnique(true, &ErrMsg)) {
- errs() << "Error making unique filename: " << ErrMsg << "\n";
+ SmallString<128> UniqueFilename;
+ error_code EC = sys::fs::createUniqueFile(
+ InputFile + "-%%%%%%%" + LTDL_SHLIB_EXT, UniqueFilename);
+ if (EC) {
+ errs() << "Error making unique filename: " << EC.message() << "\n";
exit(1);
}
- OutputFile = uniqueFilename.str();
+ OutputFile = UniqueFilename.str();
std::vector<const char*> GCCArgs;
@@ -862,8 +894,7 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
errs() << " " << GCCArgs[i];
errs() << "\n";
);
- if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(),
- sys::Path())) {
+ if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "", "", "")) {
Error = ProcessFailure(GCCPath, &GCCArgs[0]);
return 1;
}
@@ -875,16 +906,16 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
GCC *GCC::create(std::string &Message,
const std::string &GCCBinary,
const std::vector<std::string> *Args) {
- sys::Path GCCPath = sys::Program::FindProgramByName(GCCBinary);
- if (GCCPath.isEmpty()) {
+ std::string GCCPath = sys::FindProgramByName(GCCBinary);
+ if (GCCPath.empty()) {
Message = "Cannot find `"+ GCCBinary +"' in PATH!\n";
return 0;
}
- sys::Path RemoteClientPath;
+ std::string RemoteClientPath;
if (!RemoteClient.empty())
- RemoteClientPath = sys::Program::FindProgramByName(RemoteClient);
+ RemoteClientPath = sys::FindProgramByName(RemoteClient);
- Message = "Found gcc: " + GCCPath.str() + "\n";
+ Message = "Found gcc: " + GCCPath + "\n";
return new GCC(GCCPath, RemoteClientPath, Args);
}
diff --git a/tools/bugpoint/ToolRunner.h b/tools/bugpoint/ToolRunner.h
index bb83ce4..bc2be46 100644
--- a/tools/bugpoint/ToolRunner.h
+++ b/tools/bugpoint/ToolRunner.h
@@ -30,17 +30,16 @@ namespace llvm {
extern cl::opt<bool> SaveTemps;
extern Triple TargetTriple;
-class CBE;
class LLC;
//===---------------------------------------------------------------------===//
// GCC abstraction
//
class GCC {
- sys::Path GCCPath; // The path to the gcc executable.
- sys::Path RemoteClientPath; // The path to the rsh / ssh executable.
+ std::string GCCPath; // The path to the gcc executable.
+ std::string RemoteClientPath; // The path to the rsh / ssh executable.
std::vector<std::string> gccArgs; // GCC-specific arguments.
- GCC(const sys::Path &gccPath, const sys::Path &RemotePath,
+ GCC(StringRef gccPath, StringRef RemotePath,
const std::vector<std::string> *GCCArgs)
: GCCPath(gccPath), RemoteClientPath(RemotePath) {
if (GCCArgs) gccArgs = *GCCArgs;
@@ -88,10 +87,6 @@ public:
class AbstractInterpreter {
virtual void anchor();
public:
- static CBE *createCBE(const char *Argv0, std::string &Message,
- const std::string &GCCBinary,
- const std::vector<std::string> *Args = 0,
- const std::vector<std::string> *GCCArgs = 0);
static LLC *createLLC(const char *Argv0, std::string &Message,
const std::string &GCCBinary,
const std::vector<std::string> *Args = 0,
@@ -126,7 +121,7 @@ public:
/// fails, it sets Error, otherwise, this function returns the type of code
/// emitted.
virtual GCC::FileType OutputCode(const std::string &Bitcode,
- sys::Path &OutFile, std::string &Error,
+ std::string &OutFile, std::string &Error,
unsigned Timeout = 0,
unsigned MemoryLimit = 0) {
Error = "OutputCode not supported by this AbstractInterpreter!";
@@ -152,51 +147,6 @@ public:
};
//===---------------------------------------------------------------------===//
-// CBE Implementation of AbstractIntepreter interface
-//
-class CBE : public AbstractInterpreter {
- sys::Path LLCPath; // The path to the `llc' executable.
- std::vector<std::string> ToolArgs; // Extra args to pass to LLC.
- GCC *gcc;
-public:
- CBE(const sys::Path &llcPath, GCC *Gcc,
- const std::vector<std::string> *Args)
- : LLCPath(llcPath), gcc(Gcc) {
- ToolArgs.clear ();
- if (Args) ToolArgs = *Args;
- }
- ~CBE() { delete gcc; }
-
- /// compileProgram - Compile the specified program from bitcode to executable
- /// code. This does not produce any output, it is only used when debugging
- /// the code generator. Returns false if the code generator fails.
- virtual void compileProgram(const std::string &Bitcode, std::string *Error,
- unsigned Timeout = 0, unsigned MemoryLimit = 0);
-
- virtual int ExecuteProgram(const std::string &Bitcode,
- const std::vector<std::string> &Args,
- const std::string &InputFile,
- const std::string &OutputFile,
- std::string *Error,
- const std::vector<std::string> &GCCArgs =
- std::vector<std::string>(),
- const std::vector<std::string> &SharedLibs =
- std::vector<std::string>(),
- unsigned Timeout = 0,
- unsigned MemoryLimit = 0);
-
- /// OutputCode - Compile the specified program from bitcode to code
- /// understood by the GCC driver (either C or asm). If the code generator
- /// fails, it sets Error, otherwise, this function returns the type of code
- /// emitted.
- virtual GCC::FileType OutputCode(const std::string &Bitcode,
- sys::Path &OutFile, std::string &Error,
- unsigned Timeout = 0,
- unsigned MemoryLimit = 0);
-};
-
-
-//===---------------------------------------------------------------------===//
// LLC Implementation of AbstractIntepreter interface
//
class LLC : public AbstractInterpreter {
@@ -238,7 +188,7 @@ public:
/// fails, it sets Error, otherwise, this function returns the type of code
/// emitted.
virtual GCC::FileType OutputCode(const std::string &Bitcode,
- sys::Path &OutFile, std::string &Error,
+ std::string &OutFile, std::string &Error,
unsigned Timeout = 0,
unsigned MemoryLimit = 0);
};
diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp
index 40f5fd6..7771709 100644
--- a/tools/gold/gold-plugin.cpp
+++ b/tools/gold/gold-plugin.cpp
@@ -17,6 +17,7 @@
#include "llvm-c/lto.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/Errno.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
@@ -64,7 +65,7 @@ namespace {
lto_codegen_model output_type = LTO_CODEGEN_PIC_MODEL_STATIC;
std::string output_name = "";
std::list<claimed_file> Modules;
- std::vector<sys::Path> Cleanup;
+ std::vector<std::string> Cleanup;
lto_code_gen_t code_gen = NULL;
}
@@ -251,9 +252,8 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
if (file->offset) {
offset = file->offset;
}
- if (error_code ec =
- MemoryBuffer::getOpenFile(file->fd, file->name, buffer, file->filesize,
- -1, offset, false)) {
+ if (error_code ec = MemoryBuffer::getOpenFileSlice(
+ file->fd, file->name, buffer, file->filesize, offset)) {
(*message)(LDPL_ERROR, ec.message().c_str());
return LDPS_ERR;
}
@@ -447,18 +447,18 @@ static ld_plugin_status all_symbols_read_hook(void) {
}
if (options::obj_path.empty())
- Cleanup.push_back(sys::Path(objPath));
+ Cleanup.push_back(objPath);
return LDPS_OK;
}
static ld_plugin_status cleanup_hook(void) {
- std::string ErrMsg;
-
- for (int i = 0, e = Cleanup.size(); i != e; ++i)
- if (Cleanup[i].eraseFromDisk(false, &ErrMsg))
+ for (int i = 0, e = Cleanup.size(); i != e; ++i) {
+ error_code EC = sys::fs::remove(Cleanup[i]);
+ if (EC)
(*message)(LDPL_ERROR, "Failed to delete '%s': %s", Cleanup[i].c_str(),
- ErrMsg.c_str());
+ EC.message().c_str());
+ }
return LDPS_OK;
}
diff --git a/tools/llc/Android.mk b/tools/llc/Android.mk
index c141f8a..bc19e9b 100644
--- a/tools/llc/Android.mk
+++ b/tools/llc/Android.mk
@@ -36,6 +36,7 @@ llvm_llc_arm_STATIC_LIBRARIES := \
llvm_llc_STATIC_LIBRARIES := \
libLLVMAsmPrinter \
+ libLLVMIRReader \
libLLVMAsmParser \
libLLVMBitReader \
libLLVMBitWriter \
@@ -43,6 +44,7 @@ llvm_llc_STATIC_LIBRARIES := \
libLLVMInstCombine \
libLLVMInstrumentation \
libLLVMCodeGen \
+ libLLVMObject \
libLLVMipo \
libLLVMipa \
libLLVMLinker \
diff --git a/tools/llc/CMakeLists.txt b/tools/llc/CMakeLists.txt
index 683f298..e5a5550 100644
--- a/tools/llc/CMakeLists.txt
+++ b/tools/llc/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser)
+set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser irreader)
add_llvm_tool(llc
llc.cpp
diff --git a/tools/llc/LLVMBuild.txt b/tools/llc/LLVMBuild.txt
index 8c8794f..45cdc64 100644
--- a/tools/llc/LLVMBuild.txt
+++ b/tools/llc/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llc
parent = Tools
-required_libraries = AsmParser BitReader all-targets
+required_libraries = AsmParser BitReader IRReader all-targets
diff --git a/tools/llc/Makefile b/tools/llc/Makefile
index b32d557..c24f378 100644
--- a/tools/llc/Makefile
+++ b/tools/llc/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llc
-LINK_COMPONENTS := all-targets bitreader asmparser
+LINK_COMPONENTS := all-targets bitreader asmparser irreader
include $(LEVEL)/Makefile.common
diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp
index aa65223..6aac8ff 100644
--- a/tools/llc/llc.cpp
+++ b/tools/llc/llc.cpp
@@ -13,6 +13,7 @@
//
//===----------------------------------------------------------------------===//
+
#include "llvm/IR/LLVMContext.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Assembly/PrintModulePass.h"
@@ -21,6 +22,7 @@
#include "llvm/CodeGen/LinkAllCodegenComponents.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Module.h"
+#include "llvm/IRReader/IRReader.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Pass.h"
#include "llvm/PassManager.h"
@@ -28,11 +30,11 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Host.h"
-#include "llvm/Support/IRReader.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
@@ -143,8 +145,9 @@ static tool_output_file *GetOutputStream(const char *TargetName,
// Open the file.
std::string error;
- unsigned OpenFlags = 0;
- if (Binary) OpenFlags |= raw_fd_ostream::F_Binary;
+ sys::fs::OpenFlags OpenFlags = sys::fs::F_None;
+ if (Binary)
+ OpenFlags |= sys::fs::F_Binary;
tool_output_file *FDOut = new tool_output_file(OutputFilename.c_str(), error,
OpenFlags);
if (!error.empty()) {
@@ -199,7 +202,7 @@ int main(int argc, char **argv) {
static int compileModule(char **argv, LLVMContext &Context) {
// Load the module to be compiled...
SMDiagnostic Err;
- std::auto_ptr<Module> M;
+ OwningPtr<Module> M;
Module *mod = 0;
Triple TheTriple;
@@ -259,7 +262,6 @@ static int compileModule(char **argv, LLVMContext &Context) {
TargetOptions Options;
Options.LessPreciseFPMADOption = EnableFPMAD;
Options.NoFramePointerElim = DisableFPElim;
- Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf;
Options.AllowFPOpFusion = FuseFPOps;
Options.UnsafeFPMath = EnableUnsafeFPMath;
Options.NoInfsFPMath = EnableNoInfsFPMath;
@@ -273,14 +275,12 @@ static int compileModule(char **argv, LLVMContext &Context) {
Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt;
Options.DisableTailCalls = DisableTailCalls;
Options.StackAlignmentOverride = OverrideStackAlignment;
- Options.RealignStack = EnableRealignStack;
Options.TrapFuncName = TrapFuncName;
Options.PositionIndependentExecutable = EnablePIE;
Options.EnableSegmentedStacks = SegmentedStacks;
Options.UseInitArray = UseInitArray;
- Options.SSPBufferSize = SSPBufferSize;
- std::auto_ptr<TargetMachine>
+ OwningPtr<TargetMachine>
target(TheTarget->createTargetMachine(TheTriple.getTriple(),
MCPU, FeaturesStr, Options,
RelocModel, CMModel, OLvl));
diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt
index 356233f..98f411d 100644
--- a/tools/lli/CMakeLists.txt
+++ b/tools/lli/CMakeLists.txt
@@ -1,5 +1,5 @@
-set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser selectiondag native)
+set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag native instrumentation)
if( LLVM_USE_OPROFILE )
set(LLVM_LINK_COMPONENTS
diff --git a/tools/lli/LLVMBuild.txt b/tools/lli/LLVMBuild.txt
index 36ceb39..c96a9e8 100644
--- a/tools/lli/LLVMBuild.txt
+++ b/tools/lli/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = lli
parent = Tools
-required_libraries = AsmParser BitReader Interpreter JIT MCJIT NativeCodeGen SelectionDAG Native
+required_libraries = AsmParser BitReader IRReader Instrumentation Interpreter JIT MCJIT NativeCodeGen SelectionDAG Native
diff --git a/tools/lli/Makefile b/tools/lli/Makefile
index 85ac6b4..7a40427 100644
--- a/tools/lli/Makefile
+++ b/tools/lli/Makefile
@@ -12,7 +12,7 @@ TOOLNAME := lli
include $(LEVEL)/Makefile.config
-LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser selectiondag native
+LINK_COMPONENTS := mcjit jit instrumentation interpreter nativecodegen bitreader asmparser irreader selectiondag native
# If Intel JIT Events support is confiured, link against the LLVM Intel JIT
# Events interface library
diff --git a/tools/lli/RecordingMemoryManager.cpp b/tools/lli/RecordingMemoryManager.cpp
index e4d992d..1fa8176 100644
--- a/tools/lli/RecordingMemoryManager.cpp
+++ b/tools/lli/RecordingMemoryManager.cpp
@@ -98,17 +98,6 @@ uint8_t *RecordingMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignme
void RecordingMemoryManager::deallocateFunctionBody(void *Body) {
llvm_unreachable("Unexpected!");
}
-uint8_t* RecordingMemoryManager::startExceptionTable(const Function* F, uintptr_t &ActualSize) {
- llvm_unreachable("Unexpected!");
- return 0;
-}
-void RecordingMemoryManager::endExceptionTable(const Function *F, uint8_t *TableStart,
- uint8_t *TableEnd, uint8_t* FrameRegister) {
- llvm_unreachable("Unexpected!");
-}
-void RecordingMemoryManager::deallocateExceptionTable(void *ET) {
- llvm_unreachable("Unexpected!");
-}
static int jit_noop() {
return 0;
diff --git a/tools/lli/RecordingMemoryManager.h b/tools/lli/RecordingMemoryManager.h
index 991f535..b2919c3 100644
--- a/tools/lli/RecordingMemoryManager.h
+++ b/tools/lli/RecordingMemoryManager.h
@@ -58,7 +58,7 @@ public:
void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true);
- bool applyPermissions(std::string *ErrMsg) { return false; }
+ bool finalizeMemory(std::string *ErrMsg) { return false; }
// The following obsolete JITMemoryManager calls are stubbed out for
// this model.
@@ -75,11 +75,6 @@ public:
uint8_t *allocateSpace(intptr_t Size, unsigned Alignment);
uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment);
void deallocateFunctionBody(void *Body);
- uint8_t* startExceptionTable(const Function* F, uintptr_t &ActualSize);
- void endExceptionTable(const Function *F, uint8_t *TableStart,
- uint8_t *TableEnd, uint8_t* FrameRegister);
- void deallocateExceptionTable(void *ET);
-
};
} // end namespace llvm
diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp
index 332660f..8d74b23 100644
--- a/tools/lli/lli.cpp
+++ b/tools/lli/lli.cpp
@@ -29,11 +29,11 @@
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
+#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/IRReader.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Memory.h"
@@ -42,8 +42,10 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Instrumentation.h"
#include <cerrno>
#ifdef __CYGWIN__
@@ -70,6 +72,10 @@ namespace {
"use-mcjit", cl::desc("Enable use of the MC-based JIT (if available)"),
cl::init(false));
+ cl::opt<bool> DebugIR(
+ "debug-ir", cl::desc("Generate debug information to allow debugging IR."),
+ cl::init(false));
+
// The MCJIT supports building for a target address space separate from
// the JIT compilation process. Use a forked process and a copying
// memory manager with IPC to execute using this functionality.
@@ -158,11 +164,6 @@ namespace {
clEnumValEnd));
cl::opt<bool>
- EnableJITExceptionHandling("jit-enable-eh",
- cl::desc("Emit exception handling information"),
- cl::init(false));
-
- cl::opt<bool>
GenerateSoftFloatCalls("soft-float",
cl::desc("Generate software floating point library calls"),
cl::init(false));
@@ -258,7 +259,7 @@ void layoutRemoteTargetMemory(RemoteTarget *T, RecordingMemoryManager *JMM) {
EE->mapSectionAddress(const_cast<void*>(Offsets[i].first), Addr);
DEBUG(dbgs() << " Mapping local: " << Offsets[i].first
- << " to remote: " << format("%p", Addr) << "\n");
+ << " to remote: 0x" << format("%llx", Addr) << "\n");
}
@@ -273,12 +274,12 @@ void layoutRemoteTargetMemory(RemoteTarget *T, RecordingMemoryManager *JMM) {
T->loadCode(Addr, Offsets[i].first, Sizes[i]);
DEBUG(dbgs() << " loading code: " << Offsets[i].first
- << " to remote: " << format("%p", Addr) << "\n");
+ << " to remote: 0x" << format("%llx", Addr) << "\n");
} else {
T->loadData(Addr, Offsets[i].first, Sizes[i]);
DEBUG(dbgs() << " loading data: " << Offsets[i].first
- << " to remote: " << format("%p", Addr) << "\n");
+ << " to remote: 0x" << format("%llx", Addr) << "\n");
}
}
@@ -325,6 +326,17 @@ int main(int argc, char **argv, char * const *envp) {
}
}
+ if (DebugIR) {
+ if (!UseMCJIT) {
+ errs() << "warning: -debug-ir used without -use-mcjit. Only partial debug"
+ << " information will be emitted by the non-MC JIT engine. To see full"
+ << " source debug information, enable the flag '-use-mcjit'.\n";
+
+ }
+ ModulePass *DebugIRPass = createDebugIRPass();
+ DebugIRPass->runOnModule(*Mod);
+ }
+
EngineBuilder builder(Mod);
builder.setMArch(MArch);
builder.setMCPU(MCPU);
@@ -341,14 +353,14 @@ int main(int argc, char **argv, char * const *envp) {
Mod->setTargetTriple(Triple::normalize(TargetTriple));
// Enable MCJIT if desired.
- JITMemoryManager *JMM = 0;
+ RTDyldMemoryManager *RTDyldMM = 0;
if (UseMCJIT && !ForceInterpreter) {
builder.setUseMCJIT(true);
if (RemoteMCJIT)
- JMM = new RecordingMemoryManager();
+ RTDyldMM = new RecordingMemoryManager();
else
- JMM = new SectionMemoryManager();
- builder.setJITMemoryManager(JMM);
+ RTDyldMM = new SectionMemoryManager();
+ builder.setMCJITMemoryManager(RTDyldMM);
} else {
if (RemoteMCJIT) {
errs() << "error: Remote process execution requires -use-mcjit\n";
@@ -380,7 +392,6 @@ int main(int argc, char **argv, char * const *envp) {
// Remote target execution doesn't handle EH or debug registration.
if (!RemoteMCJIT) {
- Options.JITExceptionHandling = EnableJITExceptionHandling;
Options.JITEmitDebugInfo = EmitJitDebugInfo;
Options.JITEmitDebugInfoToDisk = EmitJitDebugInfoToDisk;
}
@@ -466,7 +477,7 @@ int main(int argc, char **argv, char * const *envp) {
int Result;
if (RemoteMCJIT) {
- RecordingMemoryManager *MM = static_cast<RecordingMemoryManager*>(JMM);
+ RecordingMemoryManager *MM = static_cast<RecordingMemoryManager*>(RTDyldMM);
// Everything is prepared now, so lay out our program for the target
// address space, assign the section addresses to resolve any relocations,
// and send it to the target.
@@ -488,8 +499,8 @@ int main(int argc, char **argv, char * const *envp) {
// FIXME: argv and envp handling.
uint64_t Entry = (uint64_t)EE->getPointerToFunction(EntryFn);
- DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at "
- << format("%p", Entry) << "\n");
+ DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x"
+ << format("%llx", Entry) << "\n");
if (Target.executeCode(Entry, Result))
errs() << "ERROR: " << Target.getErrorMsg() << "\n";
@@ -500,8 +511,8 @@ int main(int argc, char **argv, char * const *envp) {
// invalidated will be known.
(void)EE->getPointerToFunction(EntryFn);
// Clear instruction cache before code will be executed.
- if (JMM)
- static_cast<SectionMemoryManager*>(JMM)->invalidateInstructionCache();
+ if (RTDyldMM)
+ static_cast<SectionMemoryManager*>(RTDyldMM)->invalidateInstructionCache();
// Run main.
Result = EE->runFunctionAsMain(EntryFn, InputArgv, envp);
diff --git a/tools/llvm-ar/CMakeLists.txt b/tools/llvm-ar/CMakeLists.txt
index 70eb760..503999c 100644
--- a/tools/llvm-ar/CMakeLists.txt
+++ b/tools/llvm-ar/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS archive)
+set(LLVM_LINK_COMPONENTS support object bitreader)
add_llvm_tool(llvm-ar
llvm-ar.cpp
diff --git a/tools/llvm-ar/LLVMBuild.txt b/tools/llvm-ar/LLVMBuild.txt
index 1f61a32..236b465 100644
--- a/tools/llvm-ar/LLVMBuild.txt
+++ b/tools/llvm-ar/LLVMBuild.txt
@@ -19,4 +19,3 @@
type = Tool
name = llvm-ar
parent = Tools
-required_libraries = Archive
diff --git a/tools/llvm-ar/Makefile b/tools/llvm-ar/Makefile
index fafb14b..15fb090 100644
--- a/tools/llvm-ar/Makefile
+++ b/tools/llvm-ar/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-ar
-LINK_COMPONENTS := archive
+LINK_COMPONENTS := bitreader support object
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp
index 86eb8e2..6026fa7 100644
--- a/tools/llvm-ar/llvm-ar.cpp
+++ b/tools/llvm-ar/llvm-ar.cpp
@@ -13,21 +13,56 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/LLVMContext.h"
-#include "llvm/Bitcode/Archive.h"
#include "llvm/IR/Module.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdlib>
-#include <fstream>
#include <memory>
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
using namespace llvm;
+// The name this program was invoked as.
+static StringRef ToolName;
+
+static const char *TemporaryOutput;
+static int TmpArchiveFD = -1;
+
+// fail - Show the error message and exit.
+LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) {
+ outs() << ToolName << ": " << Error << ".\n";
+ if (TmpArchiveFD != -1)
+ close(TmpArchiveFD);
+ if (TemporaryOutput)
+ sys::fs::remove(TemporaryOutput);
+ exit(1);
+}
+
+static void failIfError(error_code EC, Twine Context = "") {
+ if (!EC)
+ return;
+
+ std::string ContextStr = Context.str();
+ if (ContextStr == "")
+ fail(EC.message());
+ fail(Context + ": " + EC.message());
+}
+
// Option for compatibility with AIX, not used but must allow it to be present.
static cl::opt<bool>
X32Option ("X32_64", cl::Hidden,
@@ -57,123 +92,72 @@ static cl::extrahelp MoreHelp(
"\nMODIFIERS (operation specific):\n"
" [a] - put file(s) after [relpos]\n"
" [b] - put file(s) before [relpos] (same as [i])\n"
- " [f] - truncate inserted file names\n"
" [i] - put file(s) before [relpos] (same as [b])\n"
- " [k] - always print bitcode files (default is to skip them)\n"
" [N] - use instance [count] of name\n"
" [o] - preserve original dates\n"
- " [P] - use full path names when matching\n"
- " [R] - recurse through directories when inserting\n"
" [s] - create an archive index (cf. ranlib)\n"
" [S] - do not build a symbol table\n"
" [u] - update only files newer than archive contents\n"
"\nMODIFIERS (generic):\n"
" [c] - do not warn if the library had to be created\n"
" [v] - be verbose about actions taken\n"
- " [V] - be *really* verbose about actions taken\n"
);
// This enumeration delineates the kinds of operations on an archive
// that are permitted.
enum ArchiveOperation {
- NoOperation, ///< An operation hasn't been specified
Print, ///< Print the contents of the archive
Delete, ///< Delete the specified members
Move, ///< Move members to end or as given by {a,b,i} modifiers
QuickAppend, ///< Quickly append to end of archive
ReplaceOrInsert, ///< Replace or Insert members
DisplayTable, ///< Display the table of contents
- Extract ///< Extract files back to file system
+ Extract, ///< Extract files back to file system
+ CreateSymTab ///< Create a symbol table in an existing archive
};
// Modifiers to follow operation to vary behavior
-bool AddAfter = false; ///< 'a' modifier
-bool AddBefore = false; ///< 'b' modifier
-bool Create = false; ///< 'c' modifier
-bool TruncateNames = false; ///< 'f' modifier
-bool InsertBefore = false; ///< 'i' modifier
-bool DontSkipBitcode = false; ///< 'k' modifier
-bool UseCount = false; ///< 'N' modifier
-bool OriginalDates = false; ///< 'o' modifier
-bool FullPath = false; ///< 'P' modifier
-bool RecurseDirectories = false; ///< 'R' modifier
-bool SymTable = true; ///< 's' & 'S' modifiers
-bool OnlyUpdate = false; ///< 'u' modifier
-bool Verbose = false; ///< 'v' modifier
-bool ReallyVerbose = false; ///< 'V' 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 OnlyUpdate = false; ///< 'u' modifier
+static bool Verbose = false; ///< 'v' modifier
+static bool Symtab = true; ///< 's' modifier
// Relative Positional Argument (for insert/move). This variable holds
// the name of the archive member to which the 'a', 'b' or 'i' modifier
// refers. Only one of 'a', 'b' or 'i' can be specified so we only need
// one variable.
-std::string RelPos;
-
-// Select which of multiple entries in the archive with the same name should be
-// used (specified with -N) for the delete and extract operations.
-int Count = 1;
+static std::string RelPos;
// This variable holds the name of the archive file as given on the
// command line.
-std::string ArchiveName;
+static std::string ArchiveName;
// This variable holds the list of member files to proecess, as given
// on the command line.
-std::vector<std::string> Members;
-
-// This variable holds the (possibly expanded) list of path objects that
-// correspond to files we will
-std::set<sys::Path> Paths;
-
-// The Archive object to which all the editing operations will be sent.
-Archive* TheArchive = 0;
-
-// The name this program was invoked as.
-static const char *program_name;
+static std::vector<std::string> Members;
// show_help - Show the error message, the help message and exit.
LLVM_ATTRIBUTE_NORETURN static void
show_help(const std::string &msg) {
- errs() << program_name << ": " << msg << "\n\n";
+ errs() << ToolName << ": " << msg << "\n\n";
cl::PrintHelpMessage();
- if (TheArchive)
- delete TheArchive;
- std::exit(1);
-}
-
-// fail - Show the error message and exit.
-LLVM_ATTRIBUTE_NORETURN static void
-fail(const std::string &msg) {
- errs() << program_name << ": " << msg << "\n\n";
- if (TheArchive)
- delete TheArchive;
std::exit(1);
}
// getRelPos - Extract the member filename from the command line for
// the [relpos] argument associated with a, b, and i modifiers
-void getRelPos() {
+static void getRelPos() {
if(RestOfArgs.size() == 0)
show_help("Expected [relpos] for a, b, or i modifier");
RelPos = RestOfArgs[0];
RestOfArgs.erase(RestOfArgs.begin());
}
-// getCount - Extract the [count] argument associated with the N modifier
-// from the command line and check its value.
-void getCount() {
- if(RestOfArgs.size() == 0)
- show_help("Expected [count] value with N modifier");
-
- Count = atoi(RestOfArgs[0].c_str());
- RestOfArgs.erase(RestOfArgs.begin());
-
- // Non-positive counts are not allowed
- if (Count < 1)
- show_help("Invalid [count] value (not a positive integer)");
-}
-
// getArchive - Get the archive file name from the command line
-void getArchive() {
+static void getArchive() {
if(RestOfArgs.size() == 0)
show_help("An archive name must be specified");
ArchiveName = RestOfArgs[0];
@@ -182,7 +166,7 @@ void getArchive() {
// getMembers - Copy over remaining items in RestOfArgs to our Members vector
// This is just for clarity.
-void getMembers() {
+static void getMembers() {
if(RestOfArgs.size() > 0)
Members = std::vector<std::string>(RestOfArgs);
}
@@ -190,7 +174,7 @@ void getMembers() {
// parseCommandLine - Parse the command line options as presented and return the
// operation specified. Process all modifiers and check to make sure that
// constraints on modifier/operation pairs have not been violated.
-ArchiveOperation parseCommandLine() {
+static ArchiveOperation parseCommandLine() {
// Keep track of number of operations. We can only specify one
// per execution.
@@ -201,7 +185,9 @@ ArchiveOperation parseCommandLine() {
unsigned NumPositional = 0;
// Keep track of which operation was requested
- ArchiveOperation Operation = NoOperation;
+ ArchiveOperation Operation;
+
+ bool MaybeJustCreateSymTab = false;
for(unsigned i=0; i<Options.size(); ++i) {
switch(Options[i]) {
@@ -213,17 +199,17 @@ ArchiveOperation parseCommandLine() {
case 't': ++NumOperations; Operation = DisplayTable; break;
case 'x': ++NumOperations; Operation = Extract; break;
case 'c': Create = true; break;
- case 'f': TruncateNames = true; break;
- case 'k': DontSkipBitcode = true; break;
case 'l': /* accepted but unused */ break;
case 'o': OriginalDates = true; break;
- case 'P': FullPath = true; break;
- case 'R': RecurseDirectories = true; break;
- case 's': SymTable = true; break;
- case 'S': SymTable = false; break;
+ case 's':
+ Symtab = true;
+ MaybeJustCreateSymTab = true;
+ break;
+ case 'S':
+ Symtab = false;
+ break;
case 'u': OnlyUpdate = true; break;
case 'v': Verbose = true; break;
- case 'V': Verbose = ReallyVerbose = true; break;
case 'a':
getRelPos();
AddAfter = true;
@@ -236,13 +222,9 @@ ArchiveOperation parseCommandLine() {
break;
case 'i':
getRelPos();
- InsertBefore = true;
+ AddBefore = true;
NumPositional++;
break;
- case 'N':
- getCount();
- UseCount = true;
- break;
default:
cl::PrintHelpMessage();
}
@@ -255,6 +237,13 @@ ArchiveOperation parseCommandLine() {
// Everything on the command line at this point is a member.
getMembers();
+ if (NumOperations == 0 && MaybeJustCreateSymTab) {
+ NumOperations = 1;
+ Operation = CreateSymTab;
+ if (!Members.empty())
+ show_help("The s operation takes only an archive as argument");
+ }
+
// Perform various checks on the operation/modifier specification
// to make sure we are dealing with a legal request.
if (NumOperations == 0)
@@ -263,140 +252,33 @@ ArchiveOperation parseCommandLine() {
show_help("Only one operation may be specified");
if (NumPositional > 1)
show_help("You may only specify one of a, b, and i modifiers");
- if (AddAfter || AddBefore || InsertBefore) {
+ if (AddAfter || AddBefore) {
if (Operation != Move && Operation != ReplaceOrInsert)
show_help("The 'a', 'b' and 'i' modifiers can only be specified with "
"the 'm' or 'r' operations");
}
- if (RecurseDirectories && Operation != ReplaceOrInsert)
- show_help("The 'R' modifiers is only applicabe to the 'r' operation");
if (OriginalDates && Operation != Extract)
show_help("The 'o' modifier is only applicable to the 'x' operation");
- if (TruncateNames && Operation!=QuickAppend && Operation!=ReplaceOrInsert)
- show_help("The 'f' modifier is only applicable to the 'q' and 'r' "
- "operations");
if (OnlyUpdate && Operation != ReplaceOrInsert)
show_help("The 'u' modifier is only applicable to the 'r' operation");
- if (Count > 1 && Members.size() > 1)
- show_help("Only one member name may be specified with the 'N' modifier");
// Return the parsed operation to the caller
return Operation;
}
-// recurseDirectories - Implements the "R" modifier. This function scans through
-// the Paths vector (built by buildPaths, below) and replaces any directories it
-// finds with all the files in that directory (recursively). It uses the
-// sys::Path::getDirectoryContent method to perform the actual directory scans.
-bool
-recurseDirectories(const sys::Path& path,
- std::set<sys::Path>& result, std::string* ErrMsg) {
- result.clear();
- if (RecurseDirectories) {
- std::set<sys::Path> content;
- if (path.getDirectoryContents(content, ErrMsg))
- return true;
-
- for (std::set<sys::Path>::iterator I = content.begin(), E = content.end();
- I != E; ++I) {
- // Make sure it exists and is a directory
- sys::PathWithStatus PwS(*I);
- const sys::FileStatus *Status = PwS.getFileStatus(false, ErrMsg);
- if (!Status)
- return true;
- if (Status->isDir) {
- std::set<sys::Path> moreResults;
- if (recurseDirectories(*I, moreResults, ErrMsg))
- return true;
- result.insert(moreResults.begin(), moreResults.end());
- } else {
- result.insert(*I);
- }
- }
- }
- return false;
-}
+// Implements the 'p' operation. This function traverses the archive
+// looking for members that match the path list.
+static void doPrint(StringRef Name, object::Archive::child_iterator I) {
+ if (Verbose)
+ outs() << "Printing " << Name << "\n";
-// buildPaths - Convert the strings in the Members vector to sys::Path objects
-// and make sure they are valid and exist exist. This check is only needed for
-// the operations that add/replace files to the archive ('q' and 'r')
-bool buildPaths(bool checkExistence, std::string* ErrMsg) {
- for (unsigned i = 0; i < Members.size(); i++) {
- sys::Path aPath;
- if (!aPath.set(Members[i]))
- fail(std::string("File member name invalid: ") + Members[i]);
- if (checkExistence) {
- bool Exists;
- if (sys::fs::exists(aPath.str(), Exists) || !Exists)
- fail(std::string("File does not exist: ") + Members[i]);
- std::string Err;
- sys::PathWithStatus PwS(aPath);
- const sys::FileStatus *si = PwS.getFileStatus(false, &Err);
- if (!si)
- fail(Err);
- if (si->isDir) {
- std::set<sys::Path> dirpaths;
- if (recurseDirectories(aPath, dirpaths, ErrMsg))
- return true;
- Paths.insert(dirpaths.begin(),dirpaths.end());
- } else {
- Paths.insert(aPath);
- }
- } else {
- Paths.insert(aPath);
- }
- }
- return false;
-}
-
-// printSymbolTable - print out the archive's symbol table.
-void printSymbolTable() {
- outs() << "\nArchive Symbol Table:\n";
- const Archive::SymTabType& symtab = TheArchive->getSymbolTable();
- for (Archive::SymTabType::const_iterator I=symtab.begin(), E=symtab.end();
- I != E; ++I ) {
- unsigned offset = TheArchive->getFirstFileOffset() + I->second;
- outs() << " " << format("%9u", offset) << "\t" << I->first <<"\n";
- }
-}
-
-// doPrint - Implements the 'p' operation. This function traverses the archive
-// looking for members that match the path list. It is careful to uncompress
-// things that should be and to skip bitcode files unless the 'k' modifier was
-// given.
-bool doPrint(std::string* ErrMsg) {
- if (buildPaths(false, ErrMsg))
- return true;
- unsigned countDown = Count;
- for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
- I != E; ++I ) {
- if (Paths.empty() ||
- (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
- if (countDown == 1) {
- const char* data = reinterpret_cast<const char*>(I->getData());
-
- // Skip things that don't make sense to print
- if (I->isLLVMSymbolTable() || I->isSVR4SymbolTable() ||
- I->isBSD4SymbolTable() || (!DontSkipBitcode && I->isBitcode()))
- continue;
-
- if (Verbose)
- outs() << "Printing " << I->getPath().str() << "\n";
-
- unsigned len = I->getSize();
- outs().write(data, len);
- } else {
- countDown--;
- }
- }
- }
- return false;
+ StringRef Data = I->getBuffer();
+ outs().write(Data.data(), Data.size());
}
// putMode - utility function for printing out the file mode when the 't'
// operation is in verbose mode.
-void
-printMode(unsigned mode) {
+static void printMode(unsigned mode) {
if (mode & 004)
outs() << "r";
else
@@ -411,303 +293,576 @@ printMode(unsigned mode) {
outs() << "-";
}
-// doDisplayTable - Implement the 't' operation. This function prints out just
+// Implement the 't' operation. This function prints out just
// the file names of each of the members. However, if verbose mode is requested
// ('v' modifier) then the file type, permission mode, user, group, size, and
// modification time are also printed.
-bool
-doDisplayTable(std::string* ErrMsg) {
- if (buildPaths(false, ErrMsg))
- return true;
- for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
- I != E; ++I ) {
- if (Paths.empty() ||
- (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
- if (Verbose) {
- // FIXME: Output should be this format:
- // Zrw-r--r-- 500/ 500 525 Nov 8 17:42 2004 Makefile
- if (I->isBitcode())
- outs() << "b";
- else
- outs() << " ";
- unsigned mode = I->getMode();
- printMode((mode >> 6) & 007);
- printMode((mode >> 3) & 007);
- printMode(mode & 007);
- outs() << " " << format("%4u", I->getUser());
- outs() << "/" << format("%4u", I->getGroup());
- outs() << " " << format("%8u", I->getSize());
- outs() << " " << format("%20s", I->getModTime().str().substr(4).c_str());
- outs() << " " << I->getPath().str() << "\n";
- } else {
- outs() << I->getPath().str() << "\n";
- }
- }
+static void doDisplayTable(StringRef Name, object::Archive::child_iterator I) {
+ if (Verbose) {
+ sys::fs::perms Mode = I->getAccessMode();
+ printMode((Mode >> 6) & 007);
+ printMode((Mode >> 3) & 007);
+ printMode(Mode & 007);
+ outs() << ' ' << I->getUID();
+ outs() << '/' << I->getGID();
+ outs() << ' ' << format("%6llu", I->getSize());
+ outs() << ' ' << I->getLastModified().str();
+ outs() << ' ';
}
- if (ReallyVerbose)
- printSymbolTable();
- return false;
+ outs() << Name << "\n";
}
-// doExtract - Implement the 'x' operation. This function extracts files back to
-// the file system.
-bool
-doExtract(std::string* ErrMsg) {
- if (buildPaths(false, ErrMsg))
- return true;
- for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
- I != E; ++I ) {
- if (Paths.empty() ||
- (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
-
- // Make sure the intervening directories are created
- if (I->hasPath()) {
- sys::Path dirs(I->getPath());
- dirs.eraseComponent();
- if (dirs.createDirectoryOnDisk(/*create_parents=*/true, ErrMsg))
- return true;
- }
+// Implement the 'x' operation. This function extracts files back to the file
+// system.
+static void doExtract(StringRef Name, object::Archive::child_iterator I) {
+ // Retain the original mode.
+ sys::fs::perms Mode = I->getAccessMode();
+ SmallString<128> Storage = Name;
- // Open up a file stream for writing
- std::ios::openmode io_mode = std::ios::out | std::ios::trunc |
- std::ios::binary;
- std::ofstream file(I->getPath().c_str(), io_mode);
+ int FD;
+ failIfError(
+ sys::fs::openFileForWrite(Storage.c_str(), FD, sys::fs::F_Binary, Mode),
+ Storage.c_str());
- // Get the data and its length
- const char* data = reinterpret_cast<const char*>(I->getData());
- unsigned len = I->getSize();
+ {
+ raw_fd_ostream file(FD, false);
- // Write the data.
- file.write(data,len);
- file.close();
+ // Get the data and its length
+ StringRef Data = I->getBuffer();
- // If we're supposed to retain the original modification times, etc. do so
- // now.
- if (OriginalDates)
- I->getPath().setStatusInfoOnDisk(I->getFileStatus());
- }
+ // Write the data.
+ file.write(Data.data(), Data.size());
}
- return false;
+
+ // If we're supposed to retain the original modification times, etc. do so
+ // now.
+ if (OriginalDates)
+ failIfError(
+ sys::fs::setLastModificationAndAccessTime(FD, I->getLastModified()));
+
+ if (close(FD))
+ fail("Could not close the file");
}
-// doDelete - Implement the delete operation. This function deletes zero or more
-// members from the archive. Note that if the count is specified, there should
-// be no more than one path in the Paths list or else this algorithm breaks.
-// That check is enforced in parseCommandLine (above).
-bool
-doDelete(std::string* ErrMsg) {
- if (buildPaths(false, ErrMsg))
- return true;
- if (Paths.empty())
+static bool shouldCreateArchive(ArchiveOperation Op) {
+ switch (Op) {
+ case Print:
+ case Delete:
+ case Move:
+ case DisplayTable:
+ case Extract:
+ case CreateSymTab:
return false;
- unsigned countDown = Count;
- for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
- I != E; ) {
- if (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end()) {
- if (countDown == 1) {
- Archive::iterator J = I;
- ++I;
- TheArchive->erase(J);
- } else
- countDown--;
- } else {
- ++I;
+
+ case QuickAppend:
+ case ReplaceOrInsert:
+ return true;
+ }
+
+ llvm_unreachable("Missing entry in covered switch.");
+}
+
+static void performReadOperation(ArchiveOperation Operation,
+ object::Archive *OldArchive) {
+ for (object::Archive::child_iterator I = OldArchive->begin_children(),
+ E = OldArchive->end_children();
+ I != E; ++I) {
+ StringRef Name;
+ failIfError(I->getName(Name));
+
+ if (!Members.empty() &&
+ std::find(Members.begin(), Members.end(), Name) == Members.end())
+ continue;
+
+ switch (Operation) {
+ default:
+ llvm_unreachable("Not a read operation");
+ case Print:
+ doPrint(Name, I);
+ break;
+ case DisplayTable:
+ doDisplayTable(Name, I);
+ break;
+ case Extract:
+ doExtract(Name, I);
+ break;
}
}
+}
- // We're done editting, reconstruct the archive.
- if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg))
- return true;
- if (ReallyVerbose)
- printSymbolTable();
- return false;
+namespace {
+class NewArchiveIterator {
+ bool IsNewMember;
+ StringRef Name;
+ object::Archive::child_iterator OldI;
+ std::string NewFilename;
+
+public:
+ NewArchiveIterator(object::Archive::child_iterator I, StringRef Name);
+ NewArchiveIterator(std::string *I, StringRef Name);
+ NewArchiveIterator();
+ bool isNewMember() const;
+ object::Archive::child_iterator getOld() const;
+ const char *getNew() const;
+ StringRef getName() const;
+};
}
-// doMore - Implement the move operation. This function re-arranges just the
-// order of the archive members so that when the archive is written the move
-// of the members is accomplished. Note the use of the RelPos variable to
-// determine where the items should be moved to.
-bool
-doMove(std::string* ErrMsg) {
- if (buildPaths(false, ErrMsg))
- return true;
+NewArchiveIterator::NewArchiveIterator() {}
+
+NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I,
+ StringRef Name)
+ : IsNewMember(false), Name(Name), OldI(I) {}
+
+NewArchiveIterator::NewArchiveIterator(std::string *NewFilename, StringRef Name)
+ : IsNewMember(true), Name(Name), NewFilename(*NewFilename) {}
+
+StringRef NewArchiveIterator::getName() const { return Name; }
+
+bool NewArchiveIterator::isNewMember() const { return IsNewMember; }
+
+object::Archive::child_iterator NewArchiveIterator::getOld() const {
+ assert(!IsNewMember);
+ return OldI;
+}
+
+const char *NewArchiveIterator::getNew() const {
+ assert(IsNewMember);
+ return NewFilename.c_str();
+}
- // By default and convention the place to move members to is the end of the
- // archive.
- Archive::iterator moveto_spot = TheArchive->end();
-
- // However, if the relative positioning modifiers were used, we need to scan
- // the archive to find the member in question. If we don't find it, its no
- // crime, we just move to the end.
- if (AddBefore || InsertBefore || AddAfter) {
- for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end();
- I != E; ++I ) {
- if (RelPos == I->getPath().str()) {
- if (AddAfter) {
- moveto_spot = I;
- moveto_spot++;
- } else {
- moveto_spot = I;
- }
+template <typename T>
+void addMember(std::vector<NewArchiveIterator> &Members, T I, StringRef Name,
+ int Pos = -1) {
+ NewArchiveIterator NI(I, Name);
+ if (Pos == -1)
+ Members.push_back(NI);
+ else
+ Members[Pos] = NI;
+}
+
+namespace {
+class HasName {
+ StringRef Name;
+
+public:
+ HasName(StringRef Name) : Name(Name) {}
+ bool operator()(StringRef Path) { return Name == sys::path::filename(Path); }
+};
+}
+
+enum InsertAction {
+ IA_AddOldMember,
+ IA_AddNewMeber,
+ IA_Delete,
+ IA_MoveOldMember,
+ IA_MoveNewMember
+};
+
+static InsertAction
+computeInsertAction(ArchiveOperation Operation,
+ object::Archive::child_iterator I, StringRef Name,
+ std::vector<std::string>::iterator &Pos) {
+ if (Operation == QuickAppend || Members.empty())
+ return IA_AddOldMember;
+
+ std::vector<std::string>::iterator MI =
+ std::find_if(Members.begin(), Members.end(), HasName(Name));
+
+ if (MI == Members.end())
+ return IA_AddOldMember;
+
+ Pos = MI;
+
+ if (Operation == Delete)
+ return IA_Delete;
+
+ if (Operation == Move)
+ return IA_MoveOldMember;
+
+ if (Operation == ReplaceOrInsert) {
+ StringRef PosName = sys::path::filename(RelPos);
+ if (!OnlyUpdate) {
+ if (PosName.empty())
+ return IA_AddNewMeber;
+ return IA_MoveNewMember;
+ }
+
+ // We could try to optimize this to a fstat, but it is not a common
+ // operation.
+ sys::fs::file_status Status;
+ failIfError(sys::fs::status(*MI, Status));
+ if (Status.getLastModificationTime() < I->getLastModified()) {
+ if (PosName.empty())
+ return IA_AddOldMember;
+ return IA_MoveOldMember;
+ }
+
+ if (PosName.empty())
+ return IA_AddNewMeber;
+ return IA_MoveNewMember;
+ }
+ llvm_unreachable("No such operation");
+}
+
+// We have to walk this twice and computing it is not trivial, so creating an
+// explicit std::vector is actually fairly efficient.
+static std::vector<NewArchiveIterator>
+computeNewArchiveMembers(ArchiveOperation Operation,
+ object::Archive *OldArchive) {
+ std::vector<NewArchiveIterator> Ret;
+ std::vector<NewArchiveIterator> Moved;
+ int InsertPos = -1;
+ StringRef PosName = sys::path::filename(RelPos);
+ if (OldArchive) {
+ for (object::Archive::child_iterator I = OldArchive->begin_children(),
+ E = OldArchive->end_children();
+ I != E; ++I) {
+ int Pos = Ret.size();
+ StringRef Name;
+ failIfError(I->getName(Name));
+ if (Name == PosName) {
+ assert(AddAfter || AddBefore);
+ if (AddBefore)
+ InsertPos = Pos;
+ else
+ InsertPos = Pos + 1;
+ }
+
+ std::vector<std::string>::iterator MemberI = Members.end();
+ InsertAction Action = computeInsertAction(Operation, I, Name, MemberI);
+ switch (Action) {
+ case IA_AddOldMember:
+ addMember(Ret, I, Name);
+ break;
+ case IA_AddNewMeber:
+ addMember(Ret, &*MemberI, Name);
+ break;
+ case IA_Delete:
+ break;
+ case IA_MoveOldMember:
+ addMember(Moved, I, Name);
+ break;
+ case IA_MoveNewMember:
+ addMember(Moved, &*MemberI, Name);
break;
}
+ if (MemberI != Members.end())
+ Members.erase(MemberI);
}
}
- // Keep a list of the paths remaining to be moved
- std::set<sys::Path> remaining(Paths);
-
- // Scan the archive again, this time looking for the members to move to the
- // moveto_spot.
- for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end();
- I != E && !remaining.empty(); ++I ) {
- std::set<sys::Path>::iterator found =
- std::find(remaining.begin(),remaining.end(),I->getPath());
- if (found != remaining.end()) {
- if (I != moveto_spot)
- TheArchive->splice(moveto_spot,*TheArchive,I);
- remaining.erase(found);
- }
+ if (Operation == Delete)
+ return Ret;
+
+ if (!RelPos.empty() && InsertPos == -1)
+ fail("Insertion point not found");
+
+ if (RelPos.empty())
+ InsertPos = Ret.size();
+
+ assert(unsigned(InsertPos) <= Ret.size());
+ Ret.insert(Ret.begin() + InsertPos, Moved.begin(), Moved.end());
+
+ Ret.insert(Ret.begin() + InsertPos, Members.size(), NewArchiveIterator());
+ int Pos = InsertPos;
+ for (std::vector<std::string>::iterator I = Members.begin(),
+ E = Members.end();
+ I != E; ++I, ++Pos) {
+ StringRef Name = sys::path::filename(*I);
+ addMember(Ret, &*I, Name, Pos);
}
- // We're done editting, reconstruct the archive.
- if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg))
- return true;
- if (ReallyVerbose)
- printSymbolTable();
- return false;
+ return Ret;
}
-// doQuickAppend - Implements the 'q' operation. This function just
-// indiscriminantly adds the members to the archive and rebuilds it.
-bool
-doQuickAppend(std::string* ErrMsg) {
- // Get the list of paths to append.
- if (buildPaths(true, ErrMsg))
- return true;
- if (Paths.empty())
- return false;
+template <typename T>
+static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
+ uint64_t OldPos = OS.tell();
+ OS << Data;
+ unsigned SizeSoFar = OS.tell() - OldPos;
+ assert(Size >= SizeSoFar && "Data doesn't fit in Size");
+ unsigned Remaining = Size - SizeSoFar;
+ for (unsigned I = 0; I < Remaining; ++I)
+ OS << ' ';
+}
- // Append them quickly.
- for (std::set<sys::Path>::iterator PI = Paths.begin(), PE = Paths.end();
- PI != PE; ++PI) {
- if (TheArchive->addFileBefore(*PI,TheArchive->end(),ErrMsg))
- return true;
+static void print32BE(raw_fd_ostream &Out, unsigned Val) {
+ for (int I = 3; I >= 0; --I) {
+ char V = (Val >> (8 * I)) & 0xff;
+ Out << V;
}
+}
- // We're done editting, reconstruct the archive.
- if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg))
- return true;
- if (ReallyVerbose)
- printSymbolTable();
- return false;
+static void printRestOfMemberHeader(raw_fd_ostream &Out,
+ const sys::TimeValue &ModTime, unsigned UID,
+ unsigned GID, unsigned Perms,
+ unsigned Size) {
+ printWithSpacePadding(Out, ModTime.toEpochTime(), 12);
+ printWithSpacePadding(Out, UID, 6);
+ printWithSpacePadding(Out, GID, 6);
+ printWithSpacePadding(Out, format("%o", Perms), 8);
+ printWithSpacePadding(Out, Size, 10);
+ Out << "`\n";
}
-// doReplaceOrInsert - Implements the 'r' operation. This function will replace
-// any existing files or insert new ones into the archive.
-bool
-doReplaceOrInsert(std::string* ErrMsg) {
+static void printMemberHeader(raw_fd_ostream &Out, StringRef Name,
+ const sys::TimeValue &ModTime, unsigned UID,
+ unsigned GID, unsigned Perms, unsigned Size) {
+ printWithSpacePadding(Out, Twine(Name) + "/", 16);
+ printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size);
+}
- // Build the list of files to be added/replaced.
- if (buildPaths(true, ErrMsg))
- return true;
- if (Paths.empty())
- return false;
+static void printMemberHeader(raw_fd_ostream &Out, unsigned NameOffset,
+ const sys::TimeValue &ModTime, unsigned UID,
+ unsigned GID, unsigned Perms, unsigned Size) {
+ Out << '/';
+ printWithSpacePadding(Out, NameOffset, 15);
+ printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size);
+}
- // Keep track of the paths that remain to be inserted.
- std::set<sys::Path> remaining(Paths);
-
- // Default the insertion spot to the end of the archive
- Archive::iterator insert_spot = TheArchive->end();
-
- // Iterate over the archive contents
- for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
- I != E && !remaining.empty(); ++I ) {
-
- // Determine if this archive member matches one of the paths we're trying
- // to replace.
-
- std::set<sys::Path>::iterator found = remaining.end();
- for (std::set<sys::Path>::iterator RI = remaining.begin(),
- RE = remaining.end(); RI != RE; ++RI ) {
- std::string compare(RI->str());
- if (TruncateNames && compare.length() > 15) {
- const char* nm = compare.c_str();
- unsigned len = compare.length();
- size_t slashpos = compare.rfind('/');
- if (slashpos != std::string::npos) {
- nm += slashpos + 1;
- len -= slashpos +1;
- }
- if (len > 15)
- len = 15;
- compare.assign(nm,len);
- }
- if (compare == I->getPath().str()) {
- found = RI;
- break;
- }
+static void writeStringTable(raw_fd_ostream &Out,
+ ArrayRef<NewArchiveIterator> Members,
+ std::vector<unsigned> &StringMapIndexes) {
+ unsigned StartOffset = 0;
+ for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(),
+ E = Members.end();
+ I != E; ++I) {
+ StringRef Name = I->getName();
+ if (Name.size() < 16)
+ continue;
+ if (StartOffset == 0) {
+ printWithSpacePadding(Out, "//", 58);
+ Out << "`\n";
+ StartOffset = Out.tell();
}
+ StringMapIndexes.push_back(Out.tell() - StartOffset);
+ Out << Name << "/\n";
+ }
+ if (StartOffset == 0)
+ return;
+ if (Out.tell() % 2)
+ Out << '\n';
+ int Pos = Out.tell();
+ Out.seek(StartOffset - 12);
+ printWithSpacePadding(Out, Pos - StartOffset, 10);
+ Out.seek(Pos);
+}
- if (found != remaining.end()) {
- std::string Err;
- sys::PathWithStatus PwS(*found);
- const sys::FileStatus *si = PwS.getFileStatus(false, &Err);
- if (!si)
- return true;
- if (!si->isDir) {
- if (OnlyUpdate) {
- // Replace the item only if it is newer.
- if (si->modTime > I->getModTime())
- if (I->replaceWith(*found, ErrMsg))
- return true;
- } else {
- // Replace the item regardless of time stamp
- if (I->replaceWith(*found, ErrMsg))
- return true;
- }
+static void writeSymbolTable(
+ raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members,
+ std::vector<std::pair<unsigned, unsigned> > &MemberOffsetRefs) {
+ unsigned StartOffset = 0;
+ unsigned MemberNum = 0;
+ std::vector<StringRef> SymNames;
+ std::vector<object::ObjectFile *> DeleteIt;
+ for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(),
+ E = Members.end();
+ I != E; ++I, ++MemberNum) {
+ object::ObjectFile *Obj;
+ if (I->isNewMember()) {
+ const char *Filename = I->getNew();
+ Obj = object::ObjectFile::createObjectFile(Filename);
+ } else {
+ object::Archive::child_iterator OldMember = I->getOld();
+ OwningPtr<object::Binary> Binary;
+ error_code EC = OldMember->getAsBinary(Binary);
+ if (EC) { // FIXME: check only for "not an object file" errors.
+ Obj = NULL;
} else {
- // We purposefully ignore directories.
+ Obj = dyn_cast<object::ObjectFile>(Binary.get());
+ if (Obj)
+ Binary.take();
}
-
- // Remove it from our "to do" list
- remaining.erase(found);
+ }
+ if (!Obj)
+ continue;
+ DeleteIt.push_back(Obj);
+ if (!StartOffset) {
+ printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0);
+ StartOffset = Out.tell();
+ print32BE(Out, 0);
}
- // Determine if this is the place where we should insert
- if ((AddBefore || InsertBefore) && RelPos == I->getPath().str())
- insert_spot = I;
- else if (AddAfter && RelPos == I->getPath().str()) {
- insert_spot = I;
- insert_spot++;
+ error_code Err;
+ for (object::symbol_iterator I = Obj->begin_symbols(),
+ E = Obj->end_symbols();
+ I != E; I.increment(Err), failIfError(Err)) {
+ uint32_t Symflags;
+ failIfError(I->getFlags(Symflags));
+ if (Symflags & object::SymbolRef::SF_FormatSpecific)
+ continue;
+ if (!(Symflags & object::SymbolRef::SF_Global))
+ continue;
+ if (Symflags & object::SymbolRef::SF_Undefined)
+ continue;
+ StringRef Name;
+ failIfError(I->getName(Name));
+ SymNames.push_back(Name);
+ MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum));
+ print32BE(Out, 0);
}
}
+ for (std::vector<StringRef>::iterator I = SymNames.begin(),
+ E = SymNames.end();
+ I != E; ++I) {
+ Out << *I;
+ Out << '\0';
+ }
+
+ for (std::vector<object::ObjectFile *>::iterator I = DeleteIt.begin(),
+ E = DeleteIt.end();
+ I != E; ++I) {
+ object::ObjectFile *O = *I;
+ delete O;
+ }
+
+ if (StartOffset == 0)
+ return;
+
+ if (Out.tell() % 2)
+ Out << '\0';
+
+ unsigned Pos = Out.tell();
+ Out.seek(StartOffset - 12);
+ printWithSpacePadding(Out, Pos - StartOffset, 10);
+ Out.seek(StartOffset);
+ print32BE(Out, SymNames.size());
+ Out.seek(Pos);
+}
+
+static void performWriteOperation(ArchiveOperation Operation,
+ object::Archive *OldArchive) {
+ SmallString<128> TmpArchive;
+ failIfError(sys::fs::createUniqueFile(ArchiveName + ".temp-archive-%%%%%%%.a",
+ TmpArchiveFD, TmpArchive));
+
+ TemporaryOutput = TmpArchive.c_str();
+ tool_output_file Output(TemporaryOutput, TmpArchiveFD);
+ raw_fd_ostream &Out = Output.os();
+ Out << "!<arch>\n";
+
+ std::vector<NewArchiveIterator> NewMembers =
+ computeNewArchiveMembers(Operation, OldArchive);
+
+ std::vector<std::pair<unsigned, unsigned> > MemberOffsetRefs;
+
+ if (Symtab) {
+ writeSymbolTable(Out, NewMembers, MemberOffsetRefs);
+ }
+
+ std::vector<unsigned> StringMapIndexes;
+ writeStringTable(Out, NewMembers, StringMapIndexes);
+
+ std::vector<std::pair<unsigned, unsigned> >::iterator MemberRefsI =
+ MemberOffsetRefs.begin();
- // If we didn't replace all the members, some will remain and need to be
- // inserted at the previously computed insert-spot.
- if (!remaining.empty()) {
- for (std::set<sys::Path>::iterator PI = remaining.begin(),
- PE = remaining.end(); PI != PE; ++PI) {
- if (TheArchive->addFileBefore(*PI,insert_spot, ErrMsg))
- return true;
+ unsigned MemberNum = 0;
+ unsigned LongNameMemberNum = 0;
+ for (std::vector<NewArchiveIterator>::iterator I = NewMembers.begin(),
+ E = NewMembers.end();
+ I != E; ++I, ++MemberNum) {
+
+ unsigned Pos = Out.tell();
+ while (MemberRefsI != MemberOffsetRefs.end() &&
+ MemberRefsI->second == MemberNum) {
+ Out.seek(MemberRefsI->first);
+ print32BE(Out, Pos);
+ ++MemberRefsI;
+ }
+ Out.seek(Pos);
+
+ if (I->isNewMember()) {
+ const char *FileName = I->getNew();
+
+ int FD;
+ failIfError(sys::fs::openFileForRead(FileName, FD), FileName);
+
+ sys::fs::file_status Status;
+ failIfError(sys::fs::status(FD, Status), FileName);
+
+ OwningPtr<MemoryBuffer> File;
+ failIfError(MemoryBuffer::getOpenFile(FD, FileName, File,
+ Status.getSize(), false),
+ FileName);
+
+ StringRef Name = sys::path::filename(FileName);
+ if (Name.size() < 16)
+ printMemberHeader(Out, Name, Status.getLastModificationTime(),
+ Status.getUser(), Status.getGroup(),
+ Status.permissions(), Status.getSize());
+ else
+ printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++],
+ Status.getLastModificationTime(), Status.getUser(),
+ Status.getGroup(), Status.permissions(),
+ Status.getSize());
+ Out << File->getBuffer();
+ } else {
+ object::Archive::child_iterator OldMember = I->getOld();
+ StringRef Name = I->getName();
+
+ if (Name.size() < 16)
+ printMemberHeader(Out, Name, OldMember->getLastModified(),
+ OldMember->getUID(), OldMember->getGID(),
+ OldMember->getAccessMode(), OldMember->getSize());
+ else
+ printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++],
+ OldMember->getLastModified(), OldMember->getUID(),
+ OldMember->getGID(), OldMember->getAccessMode(),
+ OldMember->getSize());
+ Out << OldMember->getBuffer();
}
+
+ if (Out.tell() % 2)
+ Out << '\n';
}
+ Output.keep();
+ Out.close();
+ sys::fs::rename(TemporaryOutput, ArchiveName);
+ TemporaryOutput = NULL;
+}
- // We're done editting, reconstruct the archive.
- if (TheArchive->writeToDisk(SymTable,TruncateNames,ErrMsg))
- return true;
- if (ReallyVerbose)
- printSymbolTable();
- return false;
+static void createSymbolTable(object::Archive *OldArchive) {
+ // When an archive is created or modified, if the s option is given, the
+ // resulting archive will have a current symbol table. If the S option
+ // is given, it will have no symbol table.
+ // In summary, we only need to update the symbol table if we have none.
+ // This is actually very common because of broken build systems that think
+ // they have to run ranlib.
+ if (OldArchive->hasSymbolTable())
+ return;
+
+ performWriteOperation(CreateSymTab, OldArchive);
+}
+
+static void performOperation(ArchiveOperation Operation,
+ object::Archive *OldArchive) {
+ switch (Operation) {
+ case Print:
+ case DisplayTable:
+ case Extract:
+ performReadOperation(Operation, OldArchive);
+ return;
+
+ case Delete:
+ case Move:
+ case QuickAppend:
+ case ReplaceOrInsert:
+ performWriteOperation(Operation, OldArchive);
+ return;
+ case CreateSymTab:
+ createSymbolTable(OldArchive);
+ return;
+ }
+ llvm_unreachable("Unknown operation.");
}
// main - main program for llvm-ar .. see comments in the code
int main(int argc, char **argv) {
- program_name = argv[0];
+ ToolName = argv[0];
// Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal();
PrettyStackTraceProgram X(argc, argv);
- LLVMContext &Context = getGlobalContext();
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
// Have the command line options parsed and handle things
@@ -717,63 +872,42 @@ int main(int argc, char **argv) {
" This program archives bitcode files into single libraries\n"
);
- int exitCode = 0;
-
// Do our own parsing of the command line because the CommandLine utility
// can't handle the grouped positional parameters without a dash.
ArchiveOperation Operation = parseCommandLine();
- // Check the path name of the archive
- sys::Path ArchivePath;
- if (!ArchivePath.set(ArchiveName)) {
- errs() << argv[0] << ": Archive name invalid: " << ArchiveName << "\n";
+ // Create or open the archive object.
+ OwningPtr<MemoryBuffer> Buf;
+ error_code EC = MemoryBuffer::getFile(ArchiveName, Buf, -1, false);
+ if (EC && EC != llvm::errc::no_such_file_or_directory) {
+ errs() << argv[0] << ": error opening '" << ArchiveName
+ << "': " << EC.message() << "!\n";
return 1;
}
- // Create or open the archive object.
- bool Exists;
- if (llvm::sys::fs::exists(ArchivePath.str(), Exists) || !Exists) {
- // Produce a warning if we should and we're creating the archive
- if (!Create)
- errs() << argv[0] << ": creating " << ArchivePath.str() << "\n";
- TheArchive = Archive::CreateEmpty(ArchivePath, Context);
- TheArchive->writeToDisk();
- } else {
- std::string Error;
- TheArchive = Archive::OpenAndLoad(ArchivePath, Context, &Error);
- if (TheArchive == 0) {
- errs() << argv[0] << ": error loading '" << ArchivePath.str() << "': "
- << Error << "!\n";
+ if (!EC) {
+ object::Archive Archive(Buf.take(), EC);
+
+ if (EC) {
+ errs() << argv[0] << ": error loading '" << ArchiveName
+ << "': " << EC.message() << "!\n";
return 1;
}
+ performOperation(Operation, &Archive);
+ return 0;
}
- // Make sure we're not fooling ourselves.
- assert(TheArchive && "Unable to instantiate the archive");
+ assert(EC == llvm::errc::no_such_file_or_directory);
- // Perform the operation
- std::string ErrMsg;
- bool haveError = false;
- switch (Operation) {
- case Print: haveError = doPrint(&ErrMsg); break;
- case Delete: haveError = doDelete(&ErrMsg); break;
- case Move: haveError = doMove(&ErrMsg); break;
- case QuickAppend: haveError = doQuickAppend(&ErrMsg); break;
- case ReplaceOrInsert: haveError = doReplaceOrInsert(&ErrMsg); break;
- case DisplayTable: haveError = doDisplayTable(&ErrMsg); break;
- case Extract: haveError = doExtract(&ErrMsg); break;
- case NoOperation:
- errs() << argv[0] << ": No operation was selected.\n";
- break;
- }
- if (haveError) {
- errs() << argv[0] << ": " << ErrMsg << "\n";
- return 1;
+ if (!shouldCreateArchive(Operation)) {
+ failIfError(EC, Twine("error loading '") + ArchiveName + "'");
+ } else {
+ if (!Create) {
+ // Produce a warning if we should and we're creating the archive
+ errs() << argv[0] << ": creating " << ArchiveName << "\n";
+ }
}
- delete TheArchive;
- TheArchive = 0;
-
- // Return result code back to operating system.
- return exitCode;
+ performOperation(Operation, NULL);
+ return 0;
}
diff --git a/tools/llvm-as/llvm-as.cpp b/tools/llvm-as/llvm-as.cpp
index 273c427..b2e44ef 100644
--- a/tools/llvm-as/llvm-as.cpp
+++ b/tools/llvm-as/llvm-as.cpp
@@ -69,9 +69,8 @@ static void WriteOutputFile(const Module *M) {
}
std::string ErrorInfo;
- OwningPtr<tool_output_file> Out
- (new tool_output_file(OutputFilename.c_str(), ErrorInfo,
- raw_fd_ostream::F_Binary));
+ OwningPtr<tool_output_file> Out(new tool_output_file(
+ OutputFilename.c_str(), ErrorInfo, sys::fs::F_Binary));
if (!ErrorInfo.empty()) {
errs() << ErrorInfo << '\n';
exit(1);
@@ -94,7 +93,7 @@ int main(int argc, char **argv) {
// Parse the file now...
SMDiagnostic Err;
- std::auto_ptr<Module> M(ParseAssemblyFile(InputFilename, Err, Context));
+ OwningPtr<Module> M(ParseAssemblyFile(InputFilename, Err, Context));
if (M.get() == 0) {
Err.print(argv[0], errs());
return 1;
diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
index 99479a4..186eea9 100644
--- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
+++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
@@ -481,7 +481,7 @@ static int AnalyzeBitcode() {
OwningPtr<MemoryBuffer> MemBuf;
if (error_code ec =
- MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), MemBuf))
+ MemoryBuffer::getFileOrSTDIN(InputFilename, MemBuf))
return Error("Error reading '" + InputFilename + "': " + ec.message());
if (MemBuf->getBufferSize() & 3)
diff --git a/tools/llvm-config/llvm-config.cpp b/tools/llvm-config/llvm-config.cpp
index 7edf5ec..3924e2e 100644
--- a/tools/llvm-config/llvm-config.cpp
+++ b/tools/llvm-config/llvm-config.cpp
@@ -161,11 +161,11 @@ Typical components:\n\
}
/// \brief Compute the path to the main executable.
-llvm::sys::Path GetExecutablePath(const char *Argv0) {
+std::string GetExecutablePath(const char *Argv0) {
// This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however.
void *P = (void*) (intptr_t) GetExecutablePath;
- return llvm::sys::Path::GetMainExecutable(Argv0, P);
+ return llvm::sys::fs::getMainExecutable(Argv0, P);
}
int main(int argc, char **argv) {
@@ -179,7 +179,7 @@ int main(int argc, char **argv) {
// tree.
bool IsInDevelopmentTree;
enum { MakefileStyle, CMakeStyle, CMakeBuildModeStyle } DevelopmentTreeLayout;
- llvm::SmallString<256> CurrentPath(GetExecutablePath(argv[0]).str());
+ llvm::SmallString<256> CurrentPath(GetExecutablePath(argv[0]));
std::string CurrentExecPrefix;
std::string ActiveObjRoot;
diff --git a/tools/llvm-diff/CMakeLists.txt b/tools/llvm-diff/CMakeLists.txt
index c59d69e..0df8b9e 100644
--- a/tools/llvm-diff/CMakeLists.txt
+++ b/tools/llvm-diff/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS support asmparser bitreader)
+set(LLVM_LINK_COMPONENTS support asmparser bitreader irreader)
add_llvm_tool(llvm-diff
llvm-diff.cpp
diff --git a/tools/llvm-diff/LLVMBuild.txt b/tools/llvm-diff/LLVMBuild.txt
index fa06a03..5adfdc2 100644
--- a/tools/llvm-diff/LLVMBuild.txt
+++ b/tools/llvm-diff/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-diff
parent = Tools
-required_libraries = AsmParser BitReader
+required_libraries = AsmParser BitReader IRReader
diff --git a/tools/llvm-diff/Makefile b/tools/llvm-diff/Makefile
index f7fa715..bd97a6a 100644
--- a/tools/llvm-diff/Makefile
+++ b/tools/llvm-diff/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-diff
-LINK_COMPONENTS := asmparser bitreader
+LINK_COMPONENTS := asmparser bitreader irreader
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-diff/llvm-diff.cpp b/tools/llvm-diff/llvm-diff.cpp
index 0b9e92b..6eca1e2 100644
--- a/tools/llvm-diff/llvm-diff.cpp
+++ b/tools/llvm-diff/llvm-diff.cpp
@@ -19,8 +19,8 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
+#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/IRReader.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/tools/llvm-dis/llvm-dis.cpp b/tools/llvm-dis/llvm-dis.cpp
index 2baa91d..87eb347 100644
--- a/tools/llvm-dis/llvm-dis.cpp
+++ b/tools/llvm-dis/llvm-dis.cpp
@@ -123,7 +123,7 @@ int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n");
std::string ErrorMessage;
- std::auto_ptr<Module> M;
+ OwningPtr<Module> M;
// Use the bitcode streaming interface
DataStreamer *streamer = getDataFileStreamer(InputFilename, &ErrorMessage);
@@ -168,9 +168,8 @@ int main(int argc, char **argv) {
}
std::string ErrorInfo;
- OwningPtr<tool_output_file>
- Out(new tool_output_file(OutputFilename.c_str(), ErrorInfo,
- raw_fd_ostream::F_Binary));
+ OwningPtr<tool_output_file> Out(new tool_output_file(
+ OutputFilename.c_str(), ErrorInfo, sys::fs::F_Binary));
if (!ErrorInfo.empty()) {
errs() << ErrorInfo << '\n';
return 1;
diff --git a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index 8094856..eef6f79 100644
--- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -63,6 +63,7 @@ DumpType("debug-dump", cl::init(DIDT_All),
clEnumValN(DIDT_Info, "info", ".debug_info"),
clEnumValN(DIDT_InfoDwo, "info.dwo", ".debug_info.dwo"),
clEnumValN(DIDT_Line, "line", ".debug_line"),
+ clEnumValN(DIDT_Loc, "loc", ".debug_loc"),
clEnumValN(DIDT_Frames, "frames", ".debug_frame"),
clEnumValN(DIDT_Ranges, "ranges", ".debug_ranges"),
clEnumValN(DIDT_Pubnames, "pubnames", ".debug_pubnames"),
diff --git a/tools/llvm-extract/CMakeLists.txt b/tools/llvm-extract/CMakeLists.txt
index a4e3266..3163c4b 100644
--- a/tools/llvm-extract/CMakeLists.txt
+++ b/tools/llvm-extract/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS asmparser ipo bitreader bitwriter)
+set(LLVM_LINK_COMPONENTS asmparser ipo bitreader bitwriter irreader)
add_llvm_tool(llvm-extract
llvm-extract.cpp
diff --git a/tools/llvm-extract/LLVMBuild.txt b/tools/llvm-extract/LLVMBuild.txt
index 1b1a4c3..70e3507 100644
--- a/tools/llvm-extract/LLVMBuild.txt
+++ b/tools/llvm-extract/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-extract
parent = Tools
-required_libraries = AsmParser BitReader BitWriter IPO
+required_libraries = AsmParser BitReader BitWriter IRReader IPO
diff --git a/tools/llvm-extract/Makefile b/tools/llvm-extract/Makefile
index a1e93f5..d371c54 100644
--- a/tools/llvm-extract/Makefile
+++ b/tools/llvm-extract/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-extract
-LINK_COMPONENTS := ipo bitreader bitwriter asmparser
+LINK_COMPONENTS := ipo bitreader bitwriter asmparser irreader
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp
index 85a9211..9ba68b4 100644
--- a/tools/llvm-extract/llvm-extract.cpp
+++ b/tools/llvm-extract/llvm-extract.cpp
@@ -19,13 +19,14 @@
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Module.h"
+#include "llvm/IRReader/IRReader.h"
#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/IRReader.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Transforms/IPO.h"
@@ -99,7 +100,7 @@ int main(int argc, char **argv) {
// Use lazy loading, since we only care about selected global values.
SMDiagnostic Err;
- std::auto_ptr<Module> M;
+ OwningPtr<Module> M;
M.reset(getLazyIRFileModule(InputFilename, Err, Context));
if (M.get() == 0) {
@@ -264,8 +265,7 @@ int main(int argc, char **argv) {
Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls
std::string ErrorInfo;
- tool_output_file Out(OutputFilename.c_str(), ErrorInfo,
- raw_fd_ostream::F_Binary);
+ tool_output_file Out(OutputFilename.c_str(), ErrorInfo, sys::fs::F_Binary);
if (!ErrorInfo.empty()) {
errs() << ErrorInfo << '\n';
return 1;
diff --git a/tools/llvm-jitlistener/CMakeLists.txt b/tools/llvm-jitlistener/CMakeLists.txt
index d429af9..c9704fb 100644
--- a/tools/llvm-jitlistener/CMakeLists.txt
+++ b/tools/llvm-jitlistener/CMakeLists.txt
@@ -9,6 +9,7 @@ set(LLVM_LINK_COMPONENTS
debuginfo
inteljitevents
interpreter
+ irreader
jit
mcjit
nativecodegen
diff --git a/tools/llvm-jitlistener/LLVMBuild.txt b/tools/llvm-jitlistener/LLVMBuild.txt
index c436dd9..1ce78ac 100644
--- a/tools/llvm-jitlistener/LLVMBuild.txt
+++ b/tools/llvm-jitlistener/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-jitlistener
parent = Tools
-required_libraries = AsmParser BitReader Interpreter JIT MCJIT NativeCodeGen Object SelectionDAG Native
+required_libraries = AsmParser BitReader IRReader Interpreter JIT MCJIT NativeCodeGen Object SelectionDAG Native
diff --git a/tools/llvm-jitlistener/Makefile b/tools/llvm-jitlistener/Makefile
index 3018235..b132227 100644
--- a/tools/llvm-jitlistener/Makefile
+++ b/tools/llvm-jitlistener/Makefile
@@ -12,7 +12,7 @@ TOOLNAME := llvm-jitlistener
include $(LEVEL)/Makefile.config
-LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser selectiondag Object
+LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag Object
# If Intel JIT Events support is configured, link against the LLVM Intel JIT
# Events interface library. If not, this tool will do nothing useful, but it
diff --git a/tools/llvm-jitlistener/llvm-jitlistener.cpp b/tools/llvm-jitlistener/llvm-jitlistener.cpp
index d6f5032..dbaf075 100644
--- a/tools/llvm-jitlistener/llvm-jitlistener.cpp
+++ b/tools/llvm-jitlistener/llvm-jitlistener.cpp
@@ -22,9 +22,9 @@
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/ObjectImage.h"
#include "llvm/IR/Module.h"
+#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Host.h"
-#include "llvm/Support/IRReader.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
diff --git a/tools/llvm-link/Android.mk b/tools/llvm-link/Android.mk
index 4398246..db8f2af 100644
--- a/tools/llvm-link/Android.mk
+++ b/tools/llvm-link/Android.mk
@@ -5,6 +5,7 @@ llvm_link_SRC_FILES := \
llvm_link_STATIC_LIBRARIES := \
libLLVMLinker \
+ libLLVMIRReader \
libLLVMBitReader \
libLLVMBitWriter \
libLLVMAsmParser \
diff --git a/tools/llvm-link/CMakeLists.txt b/tools/llvm-link/CMakeLists.txt
index 11933f7..4df5356 100644
--- a/tools/llvm-link/CMakeLists.txt
+++ b/tools/llvm-link/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS linker bitreader bitwriter asmparser)
+set(LLVM_LINK_COMPONENTS linker bitreader bitwriter asmparser irreader)
add_llvm_tool(llvm-link
llvm-link.cpp
diff --git a/tools/llvm-link/LLVMBuild.txt b/tools/llvm-link/LLVMBuild.txt
index 6399ded..2e386f3 100644
--- a/tools/llvm-link/LLVMBuild.txt
+++ b/tools/llvm-link/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-link
parent = Tools
-required_libraries = AsmParser BitReader BitWriter Linker
+required_libraries = AsmParser BitReader BitWriter IRReader Linker
diff --git a/tools/llvm-link/Makefile b/tools/llvm-link/Makefile
index 2553db0..ed30d2d 100644
--- a/tools/llvm-link/Makefile
+++ b/tools/llvm-link/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-link
-LINK_COMPONENTS := linker bitreader bitwriter asmparser
+LINK_COMPONENTS := linker bitreader bitwriter asmparser irreader
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp
index f6c9f11..652c414 100644
--- a/tools/llvm-link/llvm-link.cpp
+++ b/tools/llvm-link/llvm-link.cpp
@@ -17,12 +17,13 @@
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
+#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/IRReader.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/ToolOutputFile.h"
#include <memory>
@@ -52,25 +53,17 @@ DumpAsm("d", cl::desc("Print assembly as linked"), cl::Hidden);
// LoadFile - Read the specified bitcode file in and return it. This routine
// searches the link path for the specified file to try to find it...
//
-static inline std::auto_ptr<Module> LoadFile(const char *argv0,
- const std::string &FN,
- LLVMContext& Context) {
- sys::Path Filename;
- if (!Filename.set(FN)) {
- errs() << "Invalid file name: '" << FN << "'\n";
- return std::auto_ptr<Module>();
- }
-
+static inline Module *LoadFile(const char *argv0, const std::string &FN,
+ LLVMContext& Context) {
SMDiagnostic Err;
- if (Verbose) errs() << "Loading '" << Filename.c_str() << "'\n";
+ if (Verbose) errs() << "Loading '" << FN << "'\n";
Module* Result = 0;
-
- const std::string &FNStr = Filename.str();
- Result = ParseIRFile(FNStr, Err, Context);
- if (Result) return std::auto_ptr<Module>(Result); // Load successful!
+
+ Result = ParseIRFile(FN, Err, Context);
+ if (Result) return Result; // Load successful!
Err.print(argv0, errs());
- return std::auto_ptr<Module>();
+ return NULL;
}
int main(int argc, char **argv) {
@@ -85,17 +78,17 @@ int main(int argc, char **argv) {
unsigned BaseArg = 0;
std::string ErrorMessage;
- std::auto_ptr<Module> Composite(LoadFile(argv[0],
- InputFilenames[BaseArg], Context));
+ OwningPtr<Module> Composite(LoadFile(argv[0],
+ InputFilenames[BaseArg], Context));
if (Composite.get() == 0) {
errs() << argv[0] << ": error loading file '"
<< InputFilenames[BaseArg] << "'\n";
return 1;
}
+ Linker L(Composite.get());
for (unsigned i = BaseArg+1; i < InputFilenames.size(); ++i) {
- std::auto_ptr<Module> M(LoadFile(argv[0],
- InputFilenames[i], Context));
+ OwningPtr<Module> M(LoadFile(argv[0], InputFilenames[i], Context));
if (M.get() == 0) {
errs() << argv[0] << ": error loading file '" <<InputFilenames[i]<< "'\n";
return 1;
@@ -103,22 +96,17 @@ int main(int argc, char **argv) {
if (Verbose) errs() << "Linking in '" << InputFilenames[i] << "'\n";
- if (Linker::LinkModules(Composite.get(), M.get(), Linker::DestroySource,
- &ErrorMessage)) {
+ if (L.linkInModule(M.get(), &ErrorMessage)) {
errs() << argv[0] << ": link error in '" << InputFilenames[i]
<< "': " << ErrorMessage << "\n";
return 1;
}
}
- // TODO: Iterate over the -l list and link in any modules containing
- // global symbols that have not been resolved so far.
-
if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite;
std::string ErrorInfo;
- tool_output_file Out(OutputFilename.c_str(), ErrorInfo,
- raw_fd_ostream::F_Binary);
+ tool_output_file Out(OutputFilename.c_str(), ErrorInfo, sys::fs::F_Binary);
if (!ErrorInfo.empty()) {
errs() << ErrorInfo << '\n';
return 1;
diff --git a/tools/llvm-mc/Disassembler.cpp b/tools/llvm-mc/Disassembler.cpp
index 06c7721..81a0045 100644
--- a/tools/llvm-mc/Disassembler.cpp
+++ b/tools/llvm-mc/Disassembler.cpp
@@ -51,7 +51,7 @@ public:
static bool PrintInsts(const MCDisassembler &DisAsm,
const ByteArrayTy &Bytes,
SourceMgr &SM, raw_ostream &Out,
- MCStreamer &Streamer) {
+ MCStreamer &Streamer, bool InAtomicBlock) {
// Wrap the vector in a MemoryObject.
VectorMemoryObject memoryObject(Bytes);
@@ -70,8 +70,13 @@ static bool PrintInsts(const MCDisassembler &DisAsm,
SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second),
SourceMgr::DK_Warning,
"invalid instruction encoding");
+ // Don't try to resynchronise the stream in a block
+ if (InAtomicBlock)
+ return true;
+
if (Size == 0)
Size = 1; // skip illegible bytes
+
break;
case MCDisassembler::SoftFail:
@@ -89,14 +94,11 @@ static bool PrintInsts(const MCDisassembler &DisAsm,
return false;
}
-static bool ByteArrayFromString(ByteArrayTy &ByteArray,
- StringRef &Str,
- SourceMgr &SM) {
- while (!Str.empty()) {
- // Strip horizontal whitespace.
- if (size_t Pos = Str.find_first_not_of(" \t\r")) {
+static bool SkipToToken(StringRef &Str) {
+ while (!Str.empty() && Str.find_first_not_of(" \t\r\n#,") != 0) {
+ // Strip horizontal whitespace and commas.
+ if (size_t Pos = Str.find_first_not_of(" \t\r,")) {
Str = Str.substr(Pos);
- continue;
}
// If this is the end of a line or start of a comment, remove the rest of
@@ -113,9 +115,22 @@ static bool ByteArrayFromString(ByteArrayTy &ByteArray,
}
continue;
}
+ }
+
+ return !Str.empty();
+}
+
+
+static bool ByteArrayFromString(ByteArrayTy &ByteArray,
+ StringRef &Str,
+ SourceMgr &SM) {
+ while (SkipToToken(Str)) {
+ // Handled by higher level
+ if (Str[0] == '[' || Str[0] == ']')
+ return false;
// Get the current token.
- size_t Next = Str.find_first_of(" \t\n\r#");
+ size_t Next = Str.find_first_of(" \t\n\r,#[]");
StringRef Value = Str.substr(0, Next);
// Convert to a byte and add to the byte vector.
@@ -157,11 +172,44 @@ int Disassembler::disassemble(const Target &T,
// Convert the input to a vector for disassembly.
ByteArrayTy ByteArray;
StringRef Str = Buffer.getBuffer();
+ bool InAtomicBlock = false;
+
+ while (SkipToToken(Str)) {
+ ByteArray.clear();
+
+ if (Str[0] == '[') {
+ if (InAtomicBlock) {
+ SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
+ "nested atomic blocks make no sense");
+ ErrorOccurred = true;
+ }
+ InAtomicBlock = true;
+ Str = Str.drop_front();
+ continue;
+ } else if (Str[0] == ']') {
+ if (!InAtomicBlock) {
+ SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
+ "attempt to close atomic block without opening");
+ ErrorOccurred = true;
+ }
+ InAtomicBlock = false;
+ Str = Str.drop_front();
+ continue;
+ }
- ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM);
+ // It's a real token, get the bytes and emit them
+ ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM);
- if (!ByteArray.empty())
- ErrorOccurred |= PrintInsts(*DisAsm, ByteArray, SM, Out, Streamer);
+ if (!ByteArray.empty())
+ ErrorOccurred |= PrintInsts(*DisAsm, ByteArray, SM, Out, Streamer,
+ InAtomicBlock);
+ }
+
+ if (InAtomicBlock) {
+ SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
+ "unclosed atomic block");
+ ErrorOccurred = true;
+ }
return ErrorOccurred;
}
diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp
index 243899b..f10a614 100644
--- a/tools/llvm-mc/llvm-mc.cpp
+++ b/tools/llvm-mc/llvm-mc.cpp
@@ -16,7 +16,6 @@
#include "llvm/ADT/OwningPtr.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCInstrInfo.h"
@@ -27,7 +26,6 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetAsmParser.h"
-#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/FormattedStream.h"
@@ -40,7 +38,6 @@
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Support/system_error.h"
using namespace llvm;
static cl::opt<std::string>
@@ -213,8 +210,8 @@ static tool_output_file *GetOutputStream() {
OutputFilename = "-";
std::string Err;
- tool_output_file *Out = new tool_output_file(OutputFilename.c_str(), Err,
- raw_fd_ostream::F_Binary);
+ tool_output_file *Out =
+ new tool_output_file(OutputFilename.c_str(), Err, sys::fs::F_Binary);
if (!Err.empty()) {
errs() << Err << '\n';
delete Out;
@@ -382,16 +379,16 @@ int main(int argc, char **argv) {
// it later.
SrcMgr.setIncludeDirs(IncludeDirs);
- llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TripleName));
- assert(MAI && "Unable to create target asm info!");
-
llvm::OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
assert(MRI && "Unable to create target register info!");
+ llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName));
+ assert(MAI && "Unable to create target asm info!");
+
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
- MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
+ MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr);
MOFI->InitMCObjectFileInfo(TripleName, RelocModel, CMModel, Ctx);
if (SaveTempLabels)
diff --git a/tools/llvm-nm/CMakeLists.txt b/tools/llvm-nm/CMakeLists.txt
index b6cd80b..b1672ff 100644
--- a/tools/llvm-nm/CMakeLists.txt
+++ b/tools/llvm-nm/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS archive bitreader object)
+set(LLVM_LINK_COMPONENTS bitreader object)
add_llvm_tool(llvm-nm
llvm-nm.cpp
diff --git a/tools/llvm-nm/LLVMBuild.txt b/tools/llvm-nm/LLVMBuild.txt
index 38ecbfd..3e64577 100644
--- a/tools/llvm-nm/LLVMBuild.txt
+++ b/tools/llvm-nm/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-nm
parent = Tools
-required_libraries = Archive BitReader Object
+required_libraries = BitReader Object
diff --git a/tools/llvm-nm/Makefile b/tools/llvm-nm/Makefile
index d9cee98..b95e920 100644
--- a/tools/llvm-nm/Makefile
+++ b/tools/llvm-nm/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-nm
-LINK_COMPONENTS := archive bitreader object
+LINK_COMPONENTS := bitreader object
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp
index a24aae6..01dd1c3 100644
--- a/tools/llvm-nm/llvm-nm.cpp
+++ b/tools/llvm-nm/llvm-nm.cpp
@@ -17,10 +17,10 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/LLVMContext.h"
-#include "llvm/Bitcode/Archive.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/Module.h"
#include "llvm/Object/Archive.h"
+#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
@@ -121,6 +121,8 @@ namespace {
bool MultipleFiles = false;
+ bool HadError = false;
+
std::string ToolName;
}
@@ -132,6 +134,7 @@ static void error(Twine message, Twine path = Twine()) {
static bool error(error_code ec, Twine path = Twine()) {
if (ec) {
error(ec.message(), path);
+ HadError = true;
return true;
}
return false;
@@ -362,21 +365,24 @@ static void DumpSymbolNamesFromFile(std::string &Filename) {
if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) {
if (ArchiveMap) {
- outs() << "Archive map" << "\n";
- for (object::Archive::symbol_iterator i = a->begin_symbols(),
- e = a->end_symbols(); i != e; ++i) {
- object::Archive::child_iterator c;
- StringRef symname;
- StringRef filename;
- if (error(i->getMember(c)))
+ object::Archive::symbol_iterator I = a->begin_symbols();
+ object::Archive::symbol_iterator E = a->end_symbols();
+ if (I !=E) {
+ outs() << "Archive map" << "\n";
+ for (; I != E; ++I) {
+ object::Archive::child_iterator c;
+ StringRef symname;
+ StringRef filename;
+ if (error(I->getMember(c)))
return;
- if (error(i->getName(symname)))
+ if (error(I->getName(symname)))
return;
- if (error(c->getName(filename)))
+ if (error(c->getName(filename)))
return;
- outs() << symname << " in " << filename << "\n";
+ outs() << symname << " in " << filename << "\n";
+ }
+ outs() << "\n";
}
- outs() << "\n";
}
for (object::Archive::child_iterator i = a->begin_children(),
@@ -403,6 +409,23 @@ static void DumpSymbolNamesFromFile(std::string &Filename) {
}
}
}
+ } else if (magic == sys::fs::file_magic::macho_universal_binary) {
+ OwningPtr<Binary> Bin;
+ if (error(object::createBinary(Buffer.take(), Bin), Filename))
+ return;
+
+ object::MachOUniversalBinary *UB =
+ cast<object::MachOUniversalBinary>(Bin.get());
+ for (object::MachOUniversalBinary::object_iterator
+ I = UB->begin_objects(),
+ E = UB->end_objects();
+ I != E; ++I) {
+ OwningPtr<ObjectFile> Obj;
+ if (!I->getAsObjectFile(Obj)) {
+ outs() << Obj->getFileName() << ":\n";
+ DumpSymbolNamesFromObject(Obj.get());
+ }
+ }
} else if (magic.is_object()) {
OwningPtr<Binary> obj;
if (error(object::createBinary(Buffer.take(), obj), Filename))
@@ -412,6 +435,7 @@ static void DumpSymbolNamesFromFile(std::string &Filename) {
} else {
errs() << ToolName << ": " << Filename << ": "
<< "unrecognizable file type\n";
+ HadError = true;
return;
}
}
@@ -425,7 +449,7 @@ int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n");
// llvm-nm only reads binary files.
- if (error(sys::Program::ChangeStdinToBinary()))
+ if (error(sys::ChangeStdinToBinary()))
return 1;
ToolName = argv[0];
@@ -446,5 +470,9 @@ int main(int argc, char **argv) {
std::for_each(InputFilenames.begin(), InputFilenames.end(),
DumpSymbolNamesFromFile);
+
+ if (HadError)
+ return 1;
+
return 0;
}
diff --git a/tools/llvm-objdump/CMakeLists.txt b/tools/llvm-objdump/CMakeLists.txt
index 0c49d0b..e983ec9 100644
--- a/tools/llvm-objdump/CMakeLists.txt
+++ b/tools/llvm-objdump/CMakeLists.txt
@@ -12,5 +12,4 @@ add_llvm_tool(llvm-objdump
COFFDump.cpp
ELFDump.cpp
MachODump.cpp
- MCFunction.cpp
)
diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp
index 2ada683..bca6fc9 100644
--- a/tools/llvm-objdump/COFFDump.cpp
+++ b/tools/llvm-objdump/COFFDump.cpp
@@ -178,7 +178,7 @@ static error_code resolveSymbol(const std::vector<RelocationRef> &Rels,
uint64_t Ofs;
if (error_code ec = I->getOffset(Ofs)) return ec;
if (Ofs == Offset) {
- if (error_code ec = I->getSymbol(Sym)) return ec;
+ Sym = *I->getSymbol();
break;
}
}
@@ -229,7 +229,7 @@ static void printCOFFSymbolAddress(llvm::raw_ostream &Out,
void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
const coff_file_header *Header;
- if (error(Obj->getHeader(Header))) return;
+ if (error(Obj->getCOFFHeader(Header))) return;
if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) {
errs() << "Unsupported image machine type "
diff --git a/tools/llvm-objdump/ELFDump.cpp b/tools/llvm-objdump/ELFDump.cpp
index bd15231..ef1f0e9 100644
--- a/tools/llvm-objdump/ELFDump.cpp
+++ b/tools/llvm-objdump/ELFDump.cpp
@@ -63,7 +63,7 @@ void printProgramHeaders(
<< format(Fmt, (uint64_t)pi->p_vaddr)
<< "paddr "
<< format(Fmt, (uint64_t)pi->p_paddr)
- << format("align 2**%u\n", CountTrailingZeros_64(pi->p_align))
+ << format("align 2**%u\n", countTrailingZeros<uint64_t>(pi->p_align))
<< " filesz "
<< format(Fmt, (uint64_t)pi->p_filesz)
<< "memsz "
@@ -79,22 +79,18 @@ void printProgramHeaders(
void llvm::printELFFileHeader(const object::ObjectFile *Obj) {
// Little-endian 32-bit
- if (const ELFObjectFile<ELFType<support::little, 4, false> > *ELFObj =
- dyn_cast<ELFObjectFile<ELFType<support::little, 4, false> > >(Obj))
+ if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
printProgramHeaders(ELFObj);
// Big-endian 32-bit
- if (const ELFObjectFile<ELFType<support::big, 4, false> > *ELFObj =
- dyn_cast<ELFObjectFile<ELFType<support::big, 4, false> > >(Obj))
+ if (const ELF32BEObjectFile *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
printProgramHeaders(ELFObj);
// Little-endian 64-bit
- if (const ELFObjectFile<ELFType<support::little, 8, true> > *ELFObj =
- dyn_cast<ELFObjectFile<ELFType<support::little, 8, true> > >(Obj))
+ if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
printProgramHeaders(ELFObj);
// Big-endian 64-bit
- if (const ELFObjectFile<ELFType<support::big, 8, true> > *ELFObj =
- dyn_cast<ELFObjectFile<ELFType<support::big, 8, true> > >(Obj))
+ if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj))
printProgramHeaders(ELFObj);
}
diff --git a/tools/llvm-objdump/MCFunction.cpp b/tools/llvm-objdump/MCFunction.cpp
deleted file mode 100644
index 5c67f1b..0000000
--- a/tools/llvm-objdump/MCFunction.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-//===-- MCFunction.cpp ----------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the algorithm to break down a region of machine code
-// into basic blocks and try to reconstruct a CFG from it.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MCFunction.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/MC/MCDisassembler.h"
-#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCInstPrinter.h"
-#include "llvm/MC/MCInstrAnalysis.h"
-#include "llvm/MC/MCInstrDesc.h"
-#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/Support/MemoryObject.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/system_error.h"
-#include <set>
-using namespace llvm;
-
-MCFunction
-MCFunction::createFunctionFromMC(StringRef Name, const MCDisassembler *DisAsm,
- const MemoryObject &Region, uint64_t Start,
- uint64_t End, const MCInstrAnalysis *Ana,
- raw_ostream &DebugOut,
- SmallVectorImpl<uint64_t> &Calls) {
- std::vector<MCDecodedInst> Instructions;
- std::set<uint64_t> Splits;
- Splits.insert(Start);
- uint64_t Size;
-
- MCFunction f(Name);
-
- {
- DenseSet<uint64_t> VisitedInsts;
- SmallVector<uint64_t, 16> WorkList;
- WorkList.push_back(Start);
- // Disassemble code and gather basic block split points.
- while (!WorkList.empty()) {
- uint64_t Index = WorkList.pop_back_val();
- if (VisitedInsts.find(Index) != VisitedInsts.end())
- continue; // Already visited this location.
-
- for (;Index < End; Index += Size) {
- VisitedInsts.insert(Index);
-
- MCInst Inst;
- if (DisAsm->getInstruction(Inst, Size, Region, Index, DebugOut, nulls())){
- Instructions.push_back(MCDecodedInst(Index, Size, Inst));
- if (Ana->isBranch(Inst)) {
- uint64_t targ = Ana->evaluateBranch(Inst, Index, Size);
- if (targ != -1ULL && targ == Index+Size)
- continue; // Skip nop jumps.
-
- // If we could determine the branch target, make a note to start a
- // new basic block there and add the target to the worklist.
- if (targ != -1ULL) {
- Splits.insert(targ);
- WorkList.push_back(targ);
- WorkList.push_back(Index+Size);
- }
- Splits.insert(Index+Size);
- break;
- } else if (Ana->isReturn(Inst)) {
- // Return instruction. This basic block ends here.
- Splits.insert(Index+Size);
- break;
- } else if (Ana->isCall(Inst)) {
- uint64_t targ = Ana->evaluateBranch(Inst, Index, Size);
- // Add the call to the call list if the destination is known.
- if (targ != -1ULL && targ != Index+Size)
- Calls.push_back(targ);
- }
- } else {
- errs().write_hex(Index) << ": warning: invalid instruction encoding\n";
- if (Size == 0)
- Size = 1; // skip illegible bytes
- }
- }
- }
- }
-
- // Make sure the instruction list is sorted.
- std::sort(Instructions.begin(), Instructions.end());
-
- // Create basic blocks.
- unsigned ii = 0, ie = Instructions.size();
- for (std::set<uint64_t>::iterator spi = Splits.begin(),
- spe = llvm::prior(Splits.end()); spi != spe; ++spi) {
- MCBasicBlock BB;
- uint64_t BlockEnd = *llvm::next(spi);
- // Add instructions to the BB.
- for (; ii != ie; ++ii) {
- if (Instructions[ii].Address < *spi ||
- Instructions[ii].Address >= BlockEnd)
- break;
- BB.addInst(Instructions[ii]);
- }
- f.addBlock(*spi, BB);
- }
-
- std::sort(f.Blocks.begin(), f.Blocks.end());
-
- // Calculate successors of each block.
- for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i) {
- MCBasicBlock &BB = const_cast<MCBasicBlock&>(i->second);
- if (BB.getInsts().empty()) continue;
- const MCDecodedInst &Inst = BB.getInsts().back();
-
- if (Ana->isBranch(Inst.Inst)) {
- uint64_t targ = Ana->evaluateBranch(Inst.Inst, Inst.Address, Inst.Size);
- if (targ == -1ULL) {
- // Indirect branch. Bail and add all blocks of the function as a
- // successor.
- for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i)
- BB.addSucc(i->first);
- } else if (targ != Inst.Address+Inst.Size)
- BB.addSucc(targ);
- // Conditional branches can also fall through to the next block.
- if (Ana->isConditionalBranch(Inst.Inst) && llvm::next(i) != e)
- BB.addSucc(llvm::next(i)->first);
- } else {
- // No branch. Fall through to the next block.
- if (!Ana->isReturn(Inst.Inst) && llvm::next(i) != e)
- BB.addSucc(llvm::next(i)->first);
- }
- }
-
- return f;
-}
diff --git a/tools/llvm-objdump/MCFunction.h b/tools/llvm-objdump/MCFunction.h
deleted file mode 100644
index 6d3a548..0000000
--- a/tools/llvm-objdump/MCFunction.h
+++ /dev/null
@@ -1,100 +0,0 @@
-//===-- MCFunction.h ------------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the data structures to hold a CFG reconstructed from
-// machine code.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_OBJECTDUMP_MCFUNCTION_H
-#define LLVM_OBJECTDUMP_MCFUNCTION_H
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/MC/MCInst.h"
-#include <map>
-
-namespace llvm {
-
-class MCDisassembler;
-class MCInstrAnalysis;
-class MemoryObject;
-class raw_ostream;
-
-/// MCDecodedInst - Small container to hold an MCInst and associated info like
-/// address and size.
-struct MCDecodedInst {
- uint64_t Address;
- uint64_t Size;
- MCInst Inst;
-
- MCDecodedInst() {}
- MCDecodedInst(uint64_t Address, uint64_t Size, MCInst Inst)
- : Address(Address), Size(Size), Inst(Inst) {}
-
- bool operator<(const MCDecodedInst &RHS) const {
- return Address < RHS.Address;
- }
-};
-
-/// MCBasicBlock - Consists of multiple MCDecodedInsts and a list of successing
-/// MCBasicBlocks.
-class MCBasicBlock {
- std::vector<MCDecodedInst> Insts;
- typedef DenseSet<uint64_t> SetTy;
- SetTy Succs;
-public:
- ArrayRef<MCDecodedInst> getInsts() const { return Insts; }
-
- typedef SetTy::const_iterator succ_iterator;
- succ_iterator succ_begin() const { return Succs.begin(); }
- succ_iterator succ_end() const { return Succs.end(); }
-
- bool contains(uint64_t Addr) const { return Succs.count(Addr); }
-
- void addInst(const MCDecodedInst &Inst) { Insts.push_back(Inst); }
- void addSucc(uint64_t Addr) { Succs.insert(Addr); }
-
- bool operator<(const MCBasicBlock &RHS) const {
- return Insts.size() < RHS.Insts.size();
- }
-};
-
-/// MCFunction - Represents a named function in machine code, containing
-/// multiple MCBasicBlocks.
-class MCFunction {
- const StringRef Name;
- // Keep BBs sorted by address.
- typedef std::vector<std::pair<uint64_t, MCBasicBlock> > MapTy;
- MapTy Blocks;
-public:
- MCFunction(StringRef Name) : Name(Name) {}
-
- // Create an MCFunction from a region of binary machine code.
- static MCFunction
- createFunctionFromMC(StringRef Name, const MCDisassembler *DisAsm,
- const MemoryObject &Region, uint64_t Start, uint64_t End,
- const MCInstrAnalysis *Ana, raw_ostream &DebugOut,
- SmallVectorImpl<uint64_t> &Calls);
-
- typedef MapTy::const_iterator iterator;
- iterator begin() const { return Blocks.begin(); }
- iterator end() const { return Blocks.end(); }
-
- StringRef getName() const { return Name; }
-
- MCBasicBlock &addBlock(uint64_t Address, const MCBasicBlock &BB) {
- Blocks.push_back(std::make_pair(Address, BB));
- return Blocks.back().second;
- }
-};
-
-}
-
-#endif
diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp
index c324ff1..e0ec9cc 100644
--- a/tools/llvm-objdump/MachODump.cpp
+++ b/tools/llvm-objdump/MachODump.cpp
@@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "llvm-objdump.h"
-#include "MCFunction.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/MC/MCAsmInfo.h"
@@ -27,6 +27,7 @@
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Object/MachO.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
@@ -43,36 +44,16 @@ using namespace llvm;
using namespace object;
static cl::opt<bool>
- CFG("cfg", cl::desc("Create a CFG for every symbol in the object file and"
- " write it to a graphviz file (MachO-only)"));
-
-static cl::opt<bool>
UseDbg("g", cl::desc("Print line information from debug info if available"));
static cl::opt<std::string>
DSYMFile("dsym", cl::desc("Use .dSYM file for debug info"));
-static const Target *GetTarget(const MachOObject *MachOObj) {
+static const Target *GetTarget(const MachOObjectFile *MachOObj) {
// Figure out the target triple.
if (TripleName.empty()) {
llvm::Triple TT("unknown-unknown-unknown");
- switch (MachOObj->getHeader().CPUType) {
- case llvm::MachO::CPUTypeI386:
- TT.setArch(Triple::ArchType(Triple::x86));
- break;
- case llvm::MachO::CPUTypeX86_64:
- TT.setArch(Triple::ArchType(Triple::x86_64));
- break;
- case llvm::MachO::CPUTypeARM:
- TT.setArch(Triple::ArchType(Triple::arm));
- break;
- case llvm::MachO::CPUTypePowerPC:
- TT.setArch(Triple::ArchType(Triple::ppc));
- break;
- case llvm::MachO::CPUTypePowerPC64:
- TT.setArch(Triple::ArchType(Triple::ppc64));
- break;
- }
+ TT.setArch(Triple::ArchType(MachOObj->getArch()));
TripleName = TT.str();
}
@@ -106,105 +87,73 @@ struct SymbolSorter {
}
};
-// Print additional information about an address, if available.
-static void DumpAddress(uint64_t Address, ArrayRef<SectionRef> Sections,
- MachOObject *MachOObj, raw_ostream &OS) {
- for (unsigned i = 0; i != Sections.size(); ++i) {
- uint64_t SectAddr = 0, SectSize = 0;
- Sections[i].getAddress(SectAddr);
- Sections[i].getSize(SectSize);
- uint64_t addr = SectAddr;
- if (SectAddr <= Address &&
- SectAddr + SectSize > Address) {
- StringRef bytes, name;
- Sections[i].getContents(bytes);
- Sections[i].getName(name);
- // Print constant strings.
- if (!name.compare("__cstring"))
- OS << '"' << bytes.substr(addr, bytes.find('\0', addr)) << '"';
- // Print constant CFStrings.
- if (!name.compare("__cfstring"))
- OS << "@\"" << bytes.substr(addr, bytes.find('\0', addr)) << '"';
- }
- }
-}
+// Types for the storted data in code table that is built before disassembly
+// and the predicate function to sort them.
+typedef std::pair<uint64_t, DiceRef> DiceTableEntry;
+typedef std::vector<DiceTableEntry> DiceTable;
+typedef DiceTable::iterator dice_table_iterator;
-typedef std::map<uint64_t, MCFunction*> FunctionMapTy;
-typedef SmallVector<MCFunction, 16> FunctionListTy;
-static void createMCFunctionAndSaveCalls(StringRef Name,
- const MCDisassembler *DisAsm,
- MemoryObject &Object, uint64_t Start,
- uint64_t End,
- MCInstrAnalysis *InstrAnalysis,
- uint64_t Address,
- raw_ostream &DebugOut,
- FunctionMapTy &FunctionMap,
- FunctionListTy &Functions) {
- SmallVector<uint64_t, 16> Calls;
- MCFunction f =
- MCFunction::createFunctionFromMC(Name, DisAsm, Object, Start, End,
- InstrAnalysis, DebugOut, Calls);
- Functions.push_back(f);
- FunctionMap[Address] = &Functions.back();
-
- // Add the gathered callees to the map.
- for (unsigned i = 0, e = Calls.size(); i != e; ++i)
- FunctionMap.insert(std::make_pair(Calls[i], (MCFunction*)0));
+static bool
+compareDiceTableEntries(const DiceTableEntry i,
+ const DiceTableEntry j) {
+ return i.first == j.first;
}
-// Write a graphviz file for the CFG inside an MCFunction.
-static void emitDOTFile(const char *FileName, const MCFunction &f,
- MCInstPrinter *IP) {
- // Start a new dot file.
- std::string Error;
- raw_fd_ostream Out(FileName, Error);
- if (!Error.empty()) {
- errs() << "llvm-objdump: warning: " << Error << '\n';
- return;
- }
-
- Out << "digraph " << f.getName() << " {\n";
- Out << "graph [ rankdir = \"LR\" ];\n";
- for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i) {
- bool hasPreds = false;
- // Only print blocks that have predecessors.
- // FIXME: Slow.
- for (MCFunction::iterator pi = f.begin(), pe = f.end(); pi != pe;
- ++pi)
- if (pi->second.contains(i->first)) {
- hasPreds = true;
- break;
- }
-
- if (!hasPreds && i != f.begin())
- continue;
-
- Out << '"' << i->first << "\" [ label=\"<a>";
- // Print instructions.
- for (unsigned ii = 0, ie = i->second.getInsts().size(); ii != ie;
- ++ii) {
- // Escape special chars and print the instruction in mnemonic form.
- std::string Str;
- raw_string_ostream OS(Str);
- IP->printInst(&i->second.getInsts()[ii].Inst, OS, "");
- Out << DOT::EscapeString(OS.str()) << '|';
+static void DumpDataInCode(const char *bytes, uint64_t Size,
+ unsigned short Kind) {
+ uint64_t Value;
+
+ switch (Kind) {
+ case macho::Data:
+ switch (Size) {
+ case 4:
+ Value = bytes[3] << 24 |
+ bytes[2] << 16 |
+ bytes[1] << 8 |
+ bytes[0];
+ outs() << "\t.long " << Value;
+ break;
+ case 2:
+ Value = bytes[1] << 8 |
+ bytes[0];
+ outs() << "\t.short " << Value;
+ break;
+ case 1:
+ Value = bytes[0];
+ outs() << "\t.byte " << Value;
+ break;
}
- Out << "<o>\" shape=\"record\" ];\n";
-
- // Add edges.
- for (MCBasicBlock::succ_iterator si = i->second.succ_begin(),
- se = i->second.succ_end(); si != se; ++si)
- Out << i->first << ":o -> " << *si <<":a\n";
+ outs() << "\t@ KIND_DATA\n";
+ break;
+ case macho::JumpTable8:
+ Value = bytes[0];
+ outs() << "\t.byte " << Value << "\t@ KIND_JUMP_TABLE8";
+ break;
+ case macho::JumpTable16:
+ Value = bytes[1] << 8 |
+ bytes[0];
+ outs() << "\t.short " << Value << "\t@ KIND_JUMP_TABLE16";
+ break;
+ case macho::JumpTable32:
+ Value = bytes[3] << 24 |
+ bytes[2] << 16 |
+ bytes[1] << 8 |
+ bytes[0];
+ outs() << "\t.long " << Value << "\t@ KIND_JUMP_TABLE32";
+ break;
+ default:
+ outs() << "\t@ data in code kind = " << Kind << "\n";
+ break;
}
- Out << "}\n";
}
-static void getSectionsAndSymbols(const macho::Header &Header,
- MachOObjectFile *MachOObj,
- InMemoryStruct<macho::SymtabLoadCommand> *SymtabLC,
- std::vector<SectionRef> &Sections,
- std::vector<SymbolRef> &Symbols,
- SmallVectorImpl<uint64_t> &FoundFns) {
+static void
+getSectionsAndSymbols(const macho::Header Header,
+ MachOObjectFile *MachOObj,
+ std::vector<SectionRef> &Sections,
+ std::vector<SymbolRef> &Symbols,
+ SmallVectorImpl<uint64_t> &FoundFns,
+ uint64_t &BaseSegmentAddress) {
error_code ec;
for (symbol_iterator SI = MachOObj->begin_symbols(),
SE = MachOObj->end_symbols(); SI != SE; SI.increment(ec))
@@ -218,20 +167,38 @@ static void getSectionsAndSymbols(const macho::Header &Header,
Sections.push_back(*SI);
}
- for (unsigned i = 0; i != Header.NumLoadCommands; ++i) {
- const MachOObject::LoadCommandInfo &LCI =
- MachOObj->getObject()->getLoadCommandInfo(i);
- if (LCI.Command.Type == macho::LCT_FunctionStarts) {
+ MachOObjectFile::LoadCommandInfo Command =
+ MachOObj->getFirstLoadCommandInfo();
+ bool BaseSegmentAddressSet = false;
+ for (unsigned i = 0; ; ++i) {
+ if (Command.C.Type == macho::LCT_FunctionStarts) {
// We found a function starts segment, parse the addresses for later
// consumption.
- InMemoryStruct<macho::LinkeditDataLoadCommand> LLC;
- MachOObj->getObject()->ReadLinkeditDataLoadCommand(LCI, LLC);
+ macho::LinkeditDataLoadCommand LLC =
+ MachOObj->getLinkeditDataLoadCommand(Command);
- MachOObj->getObject()->ReadULEB128s(LLC->DataOffset, FoundFns);
+ MachOObj->ReadULEB128s(LLC.DataOffset, FoundFns);
}
+ else if (Command.C.Type == macho::LCT_Segment) {
+ macho::SegmentLoadCommand SLC =
+ MachOObj->getSegmentLoadCommand(Command);
+ StringRef SegName = SLC.Name;
+ if(!BaseSegmentAddressSet && SegName != "__PAGEZERO") {
+ BaseSegmentAddressSet = true;
+ BaseSegmentAddress = SLC.VMAddress;
+ }
+ }
+
+ if (i == Header.NumLoadCommands - 1)
+ break;
+ else
+ Command = MachOObj->getNextLoadCommandInfo(Command);
}
}
+static void DisassembleInputMachO2(StringRef Filename,
+ MachOObjectFile *MachOOF);
+
void llvm::DisassembleInputMachO(StringRef Filename) {
OwningPtr<MemoryBuffer> Buff;
@@ -242,9 +209,13 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
OwningPtr<MachOObjectFile> MachOOF(static_cast<MachOObjectFile*>(
ObjectFile::createMachOObjectFile(Buff.take())));
- MachOObject *MachOObj = MachOOF->getObject();
- const Target *TheTarget = GetTarget(MachOObj);
+ DisassembleInputMachO2(Filename, MachOOF.get());
+}
+
+static void DisassembleInputMachO2(StringRef Filename,
+ MachOObjectFile *MachOOF) {
+ const Target *TheTarget = GetTarget(MachOOF);
if (!TheTarget) {
// GetTarget prints out stuff.
return;
@@ -254,11 +225,12 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
InstrAnalysis(TheTarget->createMCInstrAnalysis(InstrInfo.get()));
// Set up disassembler.
- OwningPtr<const MCAsmInfo> AsmInfo(TheTarget->createMCAsmInfo(TripleName));
+ OwningPtr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
+ OwningPtr<const MCAsmInfo> AsmInfo(
+ TheTarget->createMCAsmInfo(*MRI, TripleName));
OwningPtr<const MCSubtargetInfo>
STI(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI));
- OwningPtr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
OwningPtr<MCInstPrinter>
IP(TheTarget->createMCInstPrinter(AsmPrinterVariant, *AsmInfo, *InstrInfo,
@@ -272,37 +244,43 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
outs() << '\n' << Filename << ":\n\n";
- const macho::Header &Header = MachOObj->getHeader();
-
- const MachOObject::LoadCommandInfo *SymtabLCI = 0;
- // First, find the symbol table segment.
- for (unsigned i = 0; i != Header.NumLoadCommands; ++i) {
- const MachOObject::LoadCommandInfo &LCI = MachOObj->getLoadCommandInfo(i);
- if (LCI.Command.Type == macho::LCT_Symtab) {
- SymtabLCI = &LCI;
- break;
- }
- }
-
- // Read and register the symbol table data.
- InMemoryStruct<macho::SymtabLoadCommand> SymtabLC;
- if (SymtabLCI) {
- MachOObj->ReadSymtabLoadCommand(*SymtabLCI, SymtabLC);
- MachOObj->RegisterStringTable(*SymtabLC);
- }
+ macho::Header Header = MachOOF->getHeader();
+ // FIXME: FoundFns isn't used anymore. Using symbols/LC_FUNCTION_STARTS to
+ // determine function locations will eventually go in MCObjectDisassembler.
+ // FIXME: Using the -cfg command line option, this code used to be able to
+ // annotate relocations with the referenced symbol's name, and if this was
+ // inside a __[cf]string section, the data it points to. This is now replaced
+ // by the upcoming MCSymbolizer, which needs the appropriate setup done above.
std::vector<SectionRef> Sections;
std::vector<SymbolRef> Symbols;
SmallVector<uint64_t, 8> FoundFns;
+ uint64_t BaseSegmentAddress;
- getSectionsAndSymbols(Header, MachOOF.get(), &SymtabLC, Sections, Symbols,
- FoundFns);
+ getSectionsAndSymbols(Header, MachOOF, Sections, Symbols, FoundFns,
+ BaseSegmentAddress);
// Make a copy of the unsorted symbol list. FIXME: duplication
std::vector<SymbolRef> UnsortedSymbols(Symbols);
// Sort the symbols by address, just in case they didn't come in that way.
std::sort(Symbols.begin(), Symbols.end(), SymbolSorter());
+ // Build a data in code table that is sorted on by the address of each entry.
+ uint64_t BaseAddress = 0;
+ if (Header.FileType == macho::HFT_Object)
+ Sections[0].getAddress(BaseAddress);
+ else
+ BaseAddress = BaseSegmentAddress;
+ DiceTable Dices;
+ error_code ec;
+ for (dice_iterator DI = MachOOF->begin_dices(), DE = MachOOF->end_dices();
+ DI != DE; DI.increment(ec)){
+ uint32_t Offset;
+ DI->getOffset(Offset);
+ Dices.push_back(std::make_pair(BaseAddress + Offset, *DI));
+ }
+ array_pod_sort(Dices.begin(), Dices.end());
+
#ifndef NDEBUG
raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls();
#else
@@ -310,14 +288,14 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
#endif
OwningPtr<DIContext> diContext;
- ObjectFile *DbgObj = MachOOF.get();
+ ObjectFile *DbgObj = MachOOF;
// Try to find debug info and set up the DIContext for it.
if (UseDbg) {
// 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()) {
OwningPtr<MemoryBuffer> Buf;
- if (error_code ec = MemoryBuffer::getFileOrSTDIN(DSYMFile.c_str(), Buf)) {
+ if (error_code ec = MemoryBuffer::getFileOrSTDIN(DSYMFile, Buf)) {
errs() << "llvm-objdump: " << Filename << ": " << ec.message() << '\n';
return;
}
@@ -328,31 +306,23 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
diContext.reset(DIContext::getDWARFContext(DbgObj));
}
- FunctionMapTy FunctionMap;
- FunctionListTy Functions;
-
for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {
+
+ bool SectIsText = false;
+ Sections[SectIdx].isText(SectIsText);
+ if (SectIsText == false)
+ continue;
+
StringRef SectName;
if (Sections[SectIdx].getName(SectName) ||
SectName != "__text")
continue; // Skip non-text sections
- StringRef SegmentName;
DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl();
- if (MachOOF->getSectionFinalSegmentName(DR, SegmentName) ||
- SegmentName != "__TEXT")
- continue;
- // Insert the functions from the function starts segment into our map.
- uint64_t VMAddr;
- Sections[SectIdx].getAddress(VMAddr);
- for (unsigned i = 0, e = FoundFns.size(); i != e; ++i) {
- StringRef SectBegin;
- Sections[SectIdx].getContents(SectBegin);
- uint64_t Offset = (uint64_t)SectBegin.data();
- FunctionMap.insert(std::make_pair(VMAddr + FoundFns[i]-Offset,
- (MCFunction*)0));
- }
+ StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR);
+ if (SegmentName != "__TEXT")
+ continue;
StringRef Bytes;
Sections[SectIdx].getContents(Bytes);
@@ -365,14 +335,13 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
for (relocation_iterator RI = Sections[SectIdx].begin_relocations(),
RE = Sections[SectIdx].end_relocations(); RI != RE; RI.increment(ec)) {
uint64_t RelocOffset, SectionAddress;
- RI->getAddress(RelocOffset);
+ RI->getOffset(RelocOffset);
Sections[SectIdx].getAddress(SectionAddress);
RelocOffset -= SectionAddress;
- SymbolRef RelocSym;
- RI->getSymbol(RelocSym);
+ symbol_iterator RelocSym = RI->getSymbol();
- Relocs.push_back(std::make_pair(RelocOffset, RelocSym));
+ Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));
}
array_pod_sort(Relocs.begin(), Relocs.end());
@@ -424,52 +393,56 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
symbolTableWorked = true;
- if (!CFG) {
- // Normal disassembly, print addresses, bytes and mnemonic form.
- StringRef SymName;
- Symbols[SymIdx].getName(SymName);
-
- outs() << SymName << ":\n";
- DILineInfo lastLine;
- for (uint64_t Index = Start; Index < End; Index += Size) {
- MCInst Inst;
-
- if (DisAsm->getInstruction(Inst, Size, memoryObject, Index,
- DebugOut, nulls())) {
- uint64_t SectAddress = 0;
- Sections[SectIdx].getAddress(SectAddress);
- outs() << format("%8" PRIx64 ":\t", SectAddress + Index);
-
- DumpBytes(StringRef(Bytes.data() + Index, Size));
- IP->printInst(&Inst, outs(), "");
-
- // Print debug info.
- if (diContext) {
- DILineInfo dli =
- diContext->getLineInfoForAddress(SectAddress + Index);
- // Print valid line info if it changed.
- if (dli != lastLine && dli.getLine() != 0)
- outs() << "\t## " << dli.getFileName() << ':'
- << dli.getLine() << ':' << dli.getColumn();
- lastLine = dli;
- }
- outs() << "\n";
- } else {
- errs() << "llvm-objdump: warning: invalid instruction encoding\n";
- if (Size == 0)
- Size = 1; // skip illegible bytes
+ outs() << SymName << ":\n";
+ DILineInfo lastLine;
+ for (uint64_t Index = Start; Index < End; Index += Size) {
+ MCInst Inst;
+
+ uint64_t SectAddress = 0;
+ Sections[SectIdx].getAddress(SectAddress);
+ outs() << format("%8" PRIx64 ":\t", SectAddress + Index);
+
+ // Check the data in code table here to see if this is data not an
+ // instruction to be disassembled.
+ DiceTable Dice;
+ Dice.push_back(std::make_pair(SectAddress + Index, DiceRef()));
+ dice_table_iterator DTI = std::search(Dices.begin(), Dices.end(),
+ Dice.begin(), Dice.end(),
+ compareDiceTableEntries);
+ if (DTI != Dices.end()){
+ uint16_t Length;
+ DTI->second.getLength(Length);
+ DumpBytes(StringRef(Bytes.data() + Index, Length));
+ uint16_t Kind;
+ DTI->second.getKind(Kind);
+ DumpDataInCode(Bytes.data() + Index, Length, Kind);
+ continue;
+ }
+
+ if (DisAsm->getInstruction(Inst, Size, memoryObject, Index,
+ DebugOut, nulls())) {
+ DumpBytes(StringRef(Bytes.data() + Index, Size));
+ IP->printInst(&Inst, outs(), "");
+
+ // Print debug info.
+ if (diContext) {
+ DILineInfo dli =
+ diContext->getLineInfoForAddress(SectAddress + Index);
+ // Print valid line info if it changed.
+ if (dli != lastLine && dli.getLine() != 0)
+ outs() << "\t## " << dli.getFileName() << ':'
+ << dli.getLine() << ':' << dli.getColumn();
+ lastLine = dli;
}
+ outs() << "\n";
+ } else {
+ errs() << "llvm-objdump: warning: invalid instruction encoding\n";
+ if (Size == 0)
+ Size = 1; // skip illegible bytes
}
- } else {
- // Create CFG and use it for disassembly.
- StringRef SymName;
- Symbols[SymIdx].getName(SymName);
- createMCFunctionAndSaveCalls(
- SymName, DisAsm.get(), memoryObject, Start, End,
- InstrAnalysis.get(), Start, DebugOut, FunctionMap, Functions);
}
}
- if (!CFG && !symbolTableWorked) {
+ if (!symbolTableWorked) {
// Reading the symbol table didn't work, disassemble the whole section.
uint64_t SectAddress;
Sections[SectIdx].getAddress(SectAddress);
@@ -492,142 +465,5 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
}
}
}
-
- if (CFG) {
- if (!symbolTableWorked) {
- // Reading the symbol table didn't work, create a big __TEXT symbol.
- uint64_t SectSize = 0, SectAddress = 0;
- Sections[SectIdx].getSize(SectSize);
- Sections[SectIdx].getAddress(SectAddress);
- createMCFunctionAndSaveCalls("__TEXT", DisAsm.get(), memoryObject,
- 0, SectSize,
- InstrAnalysis.get(),
- SectAddress, DebugOut,
- FunctionMap, Functions);
- }
- for (std::map<uint64_t, MCFunction*>::iterator mi = FunctionMap.begin(),
- me = FunctionMap.end(); mi != me; ++mi)
- if (mi->second == 0) {
- // Create functions for the remaining callees we have gathered,
- // but we didn't find a name for them.
- uint64_t SectSize = 0;
- Sections[SectIdx].getSize(SectSize);
-
- SmallVector<uint64_t, 16> Calls;
- MCFunction f =
- MCFunction::createFunctionFromMC("unknown", DisAsm.get(),
- memoryObject, mi->first,
- SectSize,
- InstrAnalysis.get(), DebugOut,
- Calls);
- Functions.push_back(f);
- mi->second = &Functions.back();
- for (unsigned i = 0, e = Calls.size(); i != e; ++i) {
- std::pair<uint64_t, MCFunction*> p(Calls[i], (MCFunction*)0);
- if (FunctionMap.insert(p).second)
- mi = FunctionMap.begin();
- }
- }
-
- DenseSet<uint64_t> PrintedBlocks;
- for (unsigned ffi = 0, ffe = Functions.size(); ffi != ffe; ++ffi) {
- MCFunction &f = Functions[ffi];
- for (MCFunction::iterator fi = f.begin(), fe = f.end(); fi != fe; ++fi){
- if (!PrintedBlocks.insert(fi->first).second)
- continue; // We already printed this block.
-
- // We assume a block has predecessors when it's the first block after
- // a symbol.
- bool hasPreds = FunctionMap.find(fi->first) != FunctionMap.end();
-
- // See if this block has predecessors.
- // FIXME: Slow.
- for (MCFunction::iterator pi = f.begin(), pe = f.end(); pi != pe;
- ++pi)
- if (pi->second.contains(fi->first)) {
- hasPreds = true;
- break;
- }
-
- uint64_t SectSize = 0, SectAddress;
- Sections[SectIdx].getSize(SectSize);
- Sections[SectIdx].getAddress(SectAddress);
-
- // No predecessors, this is a data block. Print as .byte directives.
- if (!hasPreds) {
- uint64_t End = llvm::next(fi) == fe ? SectSize :
- llvm::next(fi)->first;
- outs() << "# " << End-fi->first << " bytes of data:\n";
- for (unsigned pos = fi->first; pos != End; ++pos) {
- outs() << format("%8x:\t", SectAddress + pos);
- DumpBytes(StringRef(Bytes.data() + pos, 1));
- outs() << format("\t.byte 0x%02x\n", (uint8_t)Bytes[pos]);
- }
- continue;
- }
-
- if (fi->second.contains(fi->first)) // Print a header for simple loops
- outs() << "# Loop begin:\n";
-
- DILineInfo lastLine;
- // Walk over the instructions and print them.
- for (unsigned ii = 0, ie = fi->second.getInsts().size(); ii != ie;
- ++ii) {
- const MCDecodedInst &Inst = fi->second.getInsts()[ii];
-
- // If there's a symbol at this address, print its name.
- if (FunctionMap.find(SectAddress + Inst.Address) !=
- FunctionMap.end())
- outs() << FunctionMap[SectAddress + Inst.Address]-> getName()
- << ":\n";
-
- outs() << format("%8" PRIx64 ":\t", SectAddress + Inst.Address);
- DumpBytes(StringRef(Bytes.data() + Inst.Address, Inst.Size));
-
- if (fi->second.contains(fi->first)) // Indent simple loops.
- outs() << '\t';
-
- IP->printInst(&Inst.Inst, outs(), "");
-
- // Look for relocations inside this instructions, if there is one
- // print its target and additional information if available.
- for (unsigned j = 0; j != Relocs.size(); ++j)
- if (Relocs[j].first >= SectAddress + Inst.Address &&
- Relocs[j].first < SectAddress + Inst.Address + Inst.Size) {
- StringRef SymName;
- uint64_t Addr;
- Relocs[j].second.getAddress(Addr);
- Relocs[j].second.getName(SymName);
-
- outs() << "\t# " << SymName << ' ';
- DumpAddress(Addr, Sections, MachOObj, outs());
- }
-
- // If this instructions contains an address, see if we can evaluate
- // it and print additional information.
- uint64_t targ = InstrAnalysis->evaluateBranch(Inst.Inst,
- Inst.Address,
- Inst.Size);
- if (targ != -1ULL)
- DumpAddress(targ, Sections, MachOObj, outs());
-
- // Print debug info.
- if (diContext) {
- DILineInfo dli =
- diContext->getLineInfoForAddress(SectAddress + Inst.Address);
- // Print valid line info if it changed.
- if (dli != lastLine && dli.getLine() != 0)
- outs() << "\t## " << dli.getFileName() << ':'
- << dli.getLine() << ':' << dli.getColumn();
- lastLine = dli;
- }
-
- outs() << '\n';
- }
- }
-
- emitDOTFile((f.getName().str() + ".dot").c_str(), f, IP.get());
- }
- }
}
}
diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp
index 322bd21..122ac83 100644
--- a/tools/llvm-objdump/llvm-objdump.cpp
+++ b/tools/llvm-objdump/llvm-objdump.cpp
@@ -17,17 +17,25 @@
//===----------------------------------------------------------------------===//
#include "llvm-objdump.h"
-#include "MCFunction.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCAtom.h"
+#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler.h"
+#include "llvm/MC/MCFunction.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCModule.h"
+#include "llvm/MC/MCObjectDisassembler.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCObjectSymbolizer.h"
#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCRelocationInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFF.h"
@@ -123,6 +131,14 @@ static cl::alias
PrivateHeadersShort("p", cl::desc("Alias for --private-headers"),
cl::aliasopt(PrivateHeaders));
+static cl::opt<bool>
+Symbolize("symbolize", cl::desc("When disassembling instructions, "
+ "try to symbolize operands."));
+
+static cl::opt<bool>
+CFG("cfg", cl::desc("Create a CFG for every function found in the object"
+ " and write it to a graphviz file"));
+
static StringRef ToolName;
bool llvm::error(error_code ec) {
@@ -137,8 +153,13 @@ static const Target *getTarget(const ObjectFile *Obj = NULL) {
// Figure out the target triple.
llvm::Triple TheTriple("unknown-unknown-unknown");
if (TripleName.empty()) {
- if (Obj)
+ if (Obj) {
TheTriple.setArch(Triple::ArchType(Obj->getArch()));
+ // TheTriple defaults to ELF, and COFF doesn't have an environment:
+ // the best we can do here is indicate that it is mach-o.
+ if (Obj->isMachO())
+ TheTriple.setEnvironment(Triple::MachO);
+ }
} else
TheTriple.setTriple(Triple::normalize(TripleName));
@@ -156,7 +177,51 @@ static const Target *getTarget(const ObjectFile *Obj = NULL) {
return TheTarget;
}
-void llvm::StringRefMemoryObject::anchor() { }
+// Write a graphviz file for the CFG inside an MCFunction.
+static void emitDOTFile(const char *FileName, const MCFunction &f,
+ MCInstPrinter *IP) {
+ // Start a new dot file.
+ std::string Error;
+ raw_fd_ostream Out(FileName, Error);
+ if (!Error.empty()) {
+ errs() << "llvm-objdump: warning: " << Error << '\n';
+ return;
+ }
+
+ Out << "digraph \"" << f.getName() << "\" {\n";
+ Out << "graph [ rankdir = \"LR\" ];\n";
+ for (MCFunction::const_iterator i = f.begin(), e = f.end(); i != e; ++i) {
+ // Only print blocks that have predecessors.
+ bool hasPreds = (*i)->pred_begin() != (*i)->pred_end();
+
+ if (!hasPreds && i != f.begin())
+ continue;
+
+ Out << '"' << (*i)->getInsts()->getBeginAddr() << "\" [ label=\"<a>";
+ // Print instructions.
+ for (unsigned ii = 0, ie = (*i)->getInsts()->size(); ii != ie;
+ ++ii) {
+ if (ii != 0) // Not the first line, start a new row.
+ Out << '|';
+ if (ii + 1 == ie) // Last line, add an end id.
+ Out << "<o>";
+
+ // Escape special chars and print the instruction in mnemonic form.
+ std::string Str;
+ raw_string_ostream OS(Str);
+ IP->printInst(&(*i)->getInsts()->at(ii).Inst, OS, "");
+ Out << DOT::EscapeString(OS.str());
+ }
+ Out << "\" shape=\"record\" ];\n";
+
+ // Add edges.
+ for (MCBasicBlock::succ_const_iterator si = (*i)->succ_begin(),
+ se = (*i)->succ_end(); si != se; ++si)
+ Out << (*i)->getInsts()->getBeginAddr() << ":o -> "
+ << (*si)->getInsts()->getBeginAddr() << ":a\n";
+ }
+ Out << "}\n";
+}
void llvm::DumpBytes(StringRef bytes) {
static const char hex_rep[] = "0123456789abcdef";
@@ -186,8 +251,8 @@ void llvm::DumpBytes(StringRef bytes) {
bool llvm::RelocAddressLess(RelocationRef a, RelocationRef b) {
uint64_t a_addr, b_addr;
- if (error(a.getAddress(a_addr))) return false;
- if (error(b.getAddress(b_addr))) return false;
+ if (error(a.getOffset(a_addr))) return false;
+ if (error(b.getOffset(b_addr))) return false;
return a_addr < b_addr;
}
@@ -207,6 +272,96 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
FeaturesStr = Features.getString();
}
+ OwningPtr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
+ if (!MRI) {
+ errs() << "error: no register info for target " << TripleName << "\n";
+ return;
+ }
+
+ // Set up disassembler.
+ OwningPtr<const MCAsmInfo> AsmInfo(
+ TheTarget->createMCAsmInfo(*MRI, TripleName));
+ if (!AsmInfo) {
+ errs() << "error: no assembly info for target " << TripleName << "\n";
+ return;
+ }
+
+ OwningPtr<const MCSubtargetInfo> STI(
+ TheTarget->createMCSubtargetInfo(TripleName, "", FeaturesStr));
+ if (!STI) {
+ errs() << "error: no subtarget info for target " << TripleName << "\n";
+ return;
+ }
+
+ OwningPtr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
+ if (!MII) {
+ errs() << "error: no instruction info for target " << TripleName << "\n";
+ return;
+ }
+
+ OwningPtr<MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI));
+ if (!DisAsm) {
+ errs() << "error: no disassembler for target " << TripleName << "\n";
+ return;
+ }
+
+ OwningPtr<const MCObjectFileInfo> MOFI;
+ OwningPtr<MCContext> Ctx;
+
+ if (Symbolize) {
+ MOFI.reset(new MCObjectFileInfo);
+ Ctx.reset(new MCContext(AsmInfo.get(), MRI.get(), MOFI.get()));
+ OwningPtr<MCRelocationInfo> RelInfo(
+ TheTarget->createMCRelocationInfo(TripleName, *Ctx.get()));
+ if (RelInfo) {
+ OwningPtr<MCSymbolizer> Symzer(
+ MCObjectSymbolizer::createObjectSymbolizer(*Ctx.get(), RelInfo, Obj));
+ if (Symzer)
+ DisAsm->setSymbolizer(Symzer);
+ }
+ }
+
+ OwningPtr<const MCInstrAnalysis>
+ MIA(TheTarget->createMCInstrAnalysis(MII.get()));
+
+ int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
+ OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
+ AsmPrinterVariant, *AsmInfo, *MII, *MRI, *STI));
+ if (!IP) {
+ errs() << "error: no instruction printer for target " << TripleName
+ << '\n';
+ return;
+ }
+
+ if (CFG) {
+ OwningPtr<MCObjectDisassembler> OD(
+ new MCObjectDisassembler(*Obj, *DisAsm, *MIA));
+ OwningPtr<MCModule> Mod(OD->buildModule(/* withCFG */ true));
+ for (MCModule::const_atom_iterator AI = Mod->atom_begin(),
+ AE = Mod->atom_end();
+ AI != AE; ++AI) {
+ outs() << "Atom " << (*AI)->getName() << ": \n";
+ if (const MCTextAtom *TA = dyn_cast<MCTextAtom>(*AI)) {
+ for (MCTextAtom::const_iterator II = TA->begin(), IE = TA->end();
+ II != IE;
+ ++II) {
+ IP->printInst(&II->Inst, outs(), "");
+ outs() << "\n";
+ }
+ }
+ }
+ for (MCModule::const_func_iterator FI = Mod->func_begin(),
+ FE = Mod->func_end();
+ FI != FE; ++FI) {
+ static int filenum = 0;
+ emitDOTFile((Twine((*FI)->getName()) + "_" +
+ utostr(filenum) + ".dot").str().c_str(),
+ **FI, IP.get());
+ ++filenum;
+ }
+ }
+
+
error_code ec;
for (section_iterator i = Obj->begin_sections(),
e = Obj->end_sections();
@@ -228,6 +383,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
if (!error(i->containsSymbol(*si, contains)) && contains) {
uint64_t Address;
if (error(si->getAddress(Address))) break;
+ if (Address == UnknownAddressOrSize) continue;
Address -= SectionAddr;
StringRef Name;
@@ -254,10 +410,10 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
std::sort(Rels.begin(), Rels.end(), RelocAddressLess);
StringRef SegmentName = "";
- if (const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj)) {
+ if (const MachOObjectFile *MachO =
+ dyn_cast<const MachOObjectFile>(Obj)) {
DataRefImpl DR = i->getRawDataRefImpl();
- if (error(MachO->getSectionFinalSegmentName(DR, SegmentName)))
- break;
+ SegmentName = MachO->getSectionFinalSegmentName(DR);
}
StringRef name;
if (error(i->getName(name))) break;
@@ -271,53 +427,13 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
if (Symbols.empty())
Symbols.push_back(std::make_pair(0, name));
- // Set up disassembler.
- OwningPtr<const MCAsmInfo> AsmInfo(TheTarget->createMCAsmInfo(TripleName));
- if (!AsmInfo) {
- errs() << "error: no assembly info for target " << TripleName << "\n";
- return;
- }
-
- OwningPtr<const MCSubtargetInfo> STI(
- TheTarget->createMCSubtargetInfo(TripleName, "", FeaturesStr));
-
- if (!STI) {
- errs() << "error: no subtarget info for target " << TripleName << "\n";
- return;
- }
-
- OwningPtr<const MCDisassembler> DisAsm(
- TheTarget->createMCDisassembler(*STI));
- if (!DisAsm) {
- errs() << "error: no disassembler for target " << TripleName << "\n";
- return;
- }
-
- OwningPtr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
- if (!MRI) {
- errs() << "error: no register info for target " << TripleName << "\n";
- return;
- }
-
- OwningPtr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
- if (!MII) {
- errs() << "error: no instruction info for target " << TripleName << "\n";
- return;
- }
-
- int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
- OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
- AsmPrinterVariant, *AsmInfo, *MII, *MRI, *STI));
- if (!IP) {
- errs() << "error: no instruction printer for target " << TripleName
- << '\n';
- return;
- }
+ SmallString<40> Comments;
+ raw_svector_ostream CommentStream(Comments);
StringRef Bytes;
if (error(i->getContents(Bytes))) break;
- StringRefMemoryObject memoryObject(Bytes);
+ StringRefMemoryObject memoryObject(Bytes, SectionAddr);
uint64_t Size;
uint64_t Index;
uint64_t SectSize;
@@ -351,14 +467,17 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
for (Index = Start; Index < End; Index += Size) {
MCInst Inst;
- if (DisAsm->getInstruction(Inst, Size, memoryObject, Index,
- DebugOut, nulls())) {
+ if (DisAsm->getInstruction(Inst, Size, memoryObject,
+ SectionAddr + Index,
+ DebugOut, CommentStream)) {
outs() << format("%8" PRIx64 ":", SectionAddr + Index);
if (!NoShowRawInsn) {
outs() << "\t";
DumpBytes(StringRef(Bytes.data() + Index, Size));
}
IP->printInst(&Inst, outs(), "");
+ outs() << CommentStream.str();
+ Comments.clear();
outs() << "\n";
} else {
errs() << ToolName << ": warning: invalid instruction encoding\n";
@@ -377,7 +496,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
if (error(rel_cur->getHidden(hidden))) goto skip_print_rel;
if (hidden) goto skip_print_rel;
- if (error(rel_cur->getAddress(addr))) goto skip_print_rel;
+ if (error(rel_cur->getOffset(addr))) goto skip_print_rel;
// Stop when rel_cur's address is past the current instruction.
if (addr >= Index + Size) break;
if (error(rel_cur->getTypeName(name))) goto skip_print_rel;
@@ -416,7 +535,7 @@ static void PrintRelocations(const ObjectFile *o) {
if (error(ri->getHidden(hidden))) continue;
if (hidden) continue;
if (error(ri->getTypeName(relocname))) continue;
- if (error(ri->getAddress(address))) continue;
+ if (error(ri->getOffset(address))) continue;
if (error(ri->getValueString(valuestr))) continue;
outs() << address << " " << relocname << " " << valuestr << "\n";
}
@@ -459,11 +578,19 @@ static void PrintSectionContents(const ObjectFile *o) {
StringRef Name;
StringRef Contents;
uint64_t BaseAddr;
+ bool BSS;
if (error(si->getName(Name))) continue;
if (error(si->getContents(Contents))) continue;
if (error(si->getAddress(BaseAddr))) continue;
+ if (error(si->isBSS(BSS))) continue;
outs() << "Contents of section " << Name << ":\n";
+ if (BSS) {
+ outs() << format("<skipping contents of bss section at [%04" PRIx64
+ ", %04" PRIx64 ")>\n", BaseAddr,
+ BaseAddr + Contents.size());
+ continue;
+ }
// Dump out the content as hex and printable ascii characters.
for (std::size_t addr = 0, end = Contents.size(); addr < end; addr += 16) {
@@ -591,11 +718,10 @@ static void PrintSymbolTable(const ObjectFile *o) {
else if (Section == o->end_sections())
outs() << "*UND*";
else {
- if (const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(o)) {
- StringRef SegmentName;
+ if (const MachOObjectFile *MachO =
+ dyn_cast<const MachOObjectFile>(o)) {
DataRefImpl DR = Section->getRawDataRefImpl();
- if (error(MachO->getSectionFinalSegmentName(DR, SegmentName)))
- SegmentName = "";
+ StringRef SegmentName = MachO->getSectionFinalSegmentName(DR);
outs() << SegmentName << ",";
}
StringRef SectionName;
diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h
index ca7bced..87f19ba 100644
--- a/tools/llvm-objdump/llvm-objdump.h
+++ b/tools/llvm-objdump/llvm-objdump.h
@@ -13,7 +13,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DataTypes.h"
-#include "llvm/Support/MemoryObject.h"
+#include "llvm/Support/StringRefMemoryObject.h"
namespace llvm {
@@ -35,23 +35,6 @@ void DisassembleInputMachO(StringRef Filename);
void printCOFFUnwindInfo(const object::COFFObjectFile* o);
void printELFFileHeader(const object::ObjectFile *o);
-class StringRefMemoryObject : public MemoryObject {
- virtual void anchor();
- StringRef Bytes;
-public:
- StringRefMemoryObject(StringRef bytes) : Bytes(bytes) {}
-
- uint64_t getBase() const { return 0; }
- uint64_t getExtent() const { return Bytes.size(); }
-
- int readByte(uint64_t Addr, uint8_t *Byte) const {
- if (Addr >= getExtent())
- return -1;
- *Byte = Bytes[Addr];
- return 0;
- }
-};
-
}
#endif
diff --git a/tools/llvm-ranlib/CMakeLists.txt b/tools/llvm-ranlib/CMakeLists.txt
deleted file mode 100644
index 2d7defe..0000000
--- a/tools/llvm-ranlib/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-set(LLVM_LINK_COMPONENTS archive)
-
-add_llvm_tool(llvm-ranlib
- llvm-ranlib.cpp
- )
diff --git a/tools/llvm-ranlib/LLVMBuild.txt b/tools/llvm-ranlib/LLVMBuild.txt
deleted file mode 100644
index 23015c5..0000000
--- a/tools/llvm-ranlib/LLVMBuild.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-;===- ./tools/llvm-ranlib/LLVMBuild.txt ------------------------*- Conf -*--===;
-;
-; The LLVM Compiler Infrastructure
-;
-; This file is distributed under the University of Illinois Open Source
-; License. See LICENSE.TXT for details.
-;
-;===------------------------------------------------------------------------===;
-;
-; This is an LLVMBuild description file for the components in this subdirectory.
-;
-; For more information on the LLVMBuild system, please see:
-;
-; http://llvm.org/docs/LLVMBuild.html
-;
-;===------------------------------------------------------------------------===;
-
-[component_0]
-type = Tool
-name = llvm-ranlib
-parent = Tools
-required_libraries = Archive
diff --git a/tools/llvm-ranlib/llvm-ranlib.cpp b/tools/llvm-ranlib/llvm-ranlib.cpp
deleted file mode 100644
index fe9d3e2..0000000
--- a/tools/llvm-ranlib/llvm-ranlib.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-//===-- llvm-ranlib.cpp - LLVM archive index generator --------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Adds or updates an index (symbol table) for an LLVM archive file.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/Bitcode/Archive.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Signals.h"
-#include "llvm/Support/raw_ostream.h"
-#include <memory>
-using namespace llvm;
-
-// llvm-ar operation code and modifier flags
-static cl::opt<std::string>
-ArchiveName(cl::Positional, cl::Optional, cl::desc("<archive-file>"));
-
-static cl::opt<bool>
-Verbose("verbose",cl::Optional,cl::init(false),
- cl::desc("Print the symbol table"));
-
-// printSymbolTable - print out the archive's symbol table.
-void printSymbolTable(Archive* TheArchive) {
- outs() << "\nArchive Symbol Table:\n";
- const Archive::SymTabType& symtab = TheArchive->getSymbolTable();
- for (Archive::SymTabType::const_iterator I=symtab.begin(), E=symtab.end();
- I != E; ++I ) {
- unsigned offset = TheArchive->getFirstFileOffset() + I->second;
- outs() << " " << format("%9u", offset) << "\t" << I->first <<"\n";
- }
-}
-
-int main(int argc, char **argv) {
- // Print a stack trace if we signal out.
- llvm::sys::PrintStackTraceOnErrorSignal();
- llvm::PrettyStackTraceProgram X(argc, argv);
-
- LLVMContext &Context = getGlobalContext();
- llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
-
- // Have the command line options parsed and handle things
- // like --help and --version.
- cl::ParseCommandLineOptions(argc, argv,
- "LLVM Archive Index Generator (llvm-ranlib)\n\n"
- " This program adds or updates an index of bitcode symbols\n"
- " to an LLVM archive file."
- );
-
- int exitCode = 0;
-
- // Check the path name of the archive
- sys::Path ArchivePath;
- if (!ArchivePath.set(ArchiveName)) {
- errs() << argv[0] << ": " << "Archive name invalid: " << ArchiveName <<
- "\n";
- return 1;
- }
-
- // Make sure it exists, we don't create empty archives
- bool Exists;
- if (llvm::sys::fs::exists(ArchivePath.str(), Exists) || !Exists) {
- errs() << argv[0] << ": " << "Archive file does not exist" <<
- ArchivePath.str() << "\n";
- return 1;
- }
-
- std::string err_msg;
- std::auto_ptr<Archive>
- AutoArchive(Archive::OpenAndLoad(ArchivePath, Context, &err_msg));
- Archive* TheArchive = AutoArchive.get();
- if (!TheArchive) {
- errs() << argv[0] << ": " << err_msg << "\n";
- return 1;
- }
-
- if (TheArchive->writeToDisk(true, false, &err_msg )) {
- errs() << argv[0] << ": " << err_msg << "\n";
- return 1;
- }
-
- if (Verbose)
- printSymbolTable(TheArchive);
-
- return exitCode;
-}
diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt
index 676c23d..90997a8 100644
--- a/tools/llvm-readobj/CMakeLists.txt
+++ b/tools/llvm-readobj/CMakeLists.txt
@@ -1,6 +1,14 @@
-set(LLVM_LINK_COMPONENTS archive bitreader object)
+set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ bitreader
+ object)
add_llvm_tool(llvm-readobj
- ELF.cpp
llvm-readobj.cpp
+ ObjDumper.cpp
+ COFFDumper.cpp
+ ELFDumper.cpp
+ MachODumper.cpp
+ Error.cpp
+ StreamWriter.cpp
)
diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp
new file mode 100644
index 0000000..2f309e3
--- /dev/null
+++ b/tools/llvm-readobj/COFFDumper.cpp
@@ -0,0 +1,1114 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements the COFF-specific dumper for llvm-readobj.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm-readobj.h"
+#include "ObjDumper.h"
+
+#include "Error.h"
+#include "StreamWriter.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/Win64EH.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+
+#include <algorithm>
+#include <cstring>
+#include <time.h>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::Win64EH;
+
+namespace {
+
+class COFFDumper : public ObjDumper {
+public:
+ COFFDumper(const llvm::object::COFFObjectFile *Obj, StreamWriter& Writer)
+ : ObjDumper(Writer)
+ , Obj(Obj) {
+ cacheRelocations();
+ }
+
+ virtual void printFileHeaders() LLVM_OVERRIDE;
+ virtual void printSections() LLVM_OVERRIDE;
+ virtual void printRelocations() LLVM_OVERRIDE;
+ virtual void printSymbols() LLVM_OVERRIDE;
+ virtual void printDynamicSymbols() LLVM_OVERRIDE;
+ virtual void printUnwindInfo() LLVM_OVERRIDE;
+
+private:
+ void printSymbol(symbol_iterator SymI);
+
+ void printRelocation(section_iterator SecI, relocation_iterator RelI);
+
+ void printDataDirectory(uint32_t Index, const std::string &FieldName);
+
+ void printX64UnwindInfo();
+
+ void printRuntimeFunction(
+ const RuntimeFunction& RTF,
+ uint64_t OffsetInSection,
+ const std::vector<RelocationRef> &Rels);
+
+ void printUnwindInfo(
+ const Win64EH::UnwindInfo& UI,
+ uint64_t OffsetInSection,
+ const std::vector<RelocationRef> &Rels);
+
+ void printUnwindCode(const Win64EH::UnwindInfo& UI, ArrayRef<UnwindCode> UCs);
+
+ void cacheRelocations();
+
+ error_code getSectionContents(
+ const std::vector<RelocationRef> &Rels,
+ uint64_t Offset,
+ ArrayRef<uint8_t> &Contents,
+ uint64_t &Addr);
+
+ error_code getSection(
+ const std::vector<RelocationRef> &Rels,
+ uint64_t Offset,
+ const coff_section **Section,
+ uint64_t *AddrPtr);
+
+ typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy;
+
+ const llvm::object::COFFObjectFile *Obj;
+ RelocMapTy RelocMap;
+ std::vector<RelocationRef> EmptyRelocs;
+};
+
+} // namespace
+
+
+namespace llvm {
+
+error_code createCOFFDumper(const object::ObjectFile *Obj,
+ StreamWriter& Writer,
+ OwningPtr<ObjDumper> &Result) {
+ const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(Obj);
+ if (!COFFObj)
+ return readobj_error::unsupported_obj_file_format;
+
+ Result.reset(new COFFDumper(COFFObj, Writer));
+ return readobj_error::success;
+}
+
+} // namespace llvm
+
+
+// Returns the name of the unwind code.
+static StringRef getUnwindCodeTypeName(uint8_t Code) {
+ switch(Code) {
+ default: llvm_unreachable("Invalid unwind code");
+ case UOP_PushNonVol: return "PUSH_NONVOL";
+ case UOP_AllocLarge: return "ALLOC_LARGE";
+ case UOP_AllocSmall: return "ALLOC_SMALL";
+ case UOP_SetFPReg: return "SET_FPREG";
+ case UOP_SaveNonVol: return "SAVE_NONVOL";
+ case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR";
+ case UOP_SaveXMM128: return "SAVE_XMM128";
+ case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR";
+ case UOP_PushMachFrame: return "PUSH_MACHFRAME";
+ }
+}
+
+// Returns the name of a referenced register.
+static StringRef getUnwindRegisterName(uint8_t Reg) {
+ switch(Reg) {
+ default: llvm_unreachable("Invalid register");
+ case 0: return "RAX";
+ case 1: return "RCX";
+ case 2: return "RDX";
+ case 3: return "RBX";
+ case 4: return "RSP";
+ case 5: return "RBP";
+ case 6: return "RSI";
+ case 7: return "RDI";
+ case 8: return "R8";
+ case 9: return "R9";
+ case 10: return "R10";
+ case 11: return "R11";
+ case 12: return "R12";
+ case 13: return "R13";
+ case 14: return "R14";
+ case 15: return "R15";
+ }
+}
+
+// Calculates the number of array slots required for the unwind code.
+static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
+ switch (UnwindCode.getUnwindOp()) {
+ default: llvm_unreachable("Invalid unwind code");
+ case UOP_PushNonVol:
+ case UOP_AllocSmall:
+ case UOP_SetFPReg:
+ case UOP_PushMachFrame:
+ return 1;
+ case UOP_SaveNonVol:
+ case UOP_SaveXMM128:
+ return 2;
+ case UOP_SaveNonVolBig:
+ case UOP_SaveXMM128Big:
+ return 3;
+ case UOP_AllocLarge:
+ return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
+ }
+}
+
+// Given a symbol sym this functions returns the address and section of it.
+static error_code resolveSectionAndAddress(const COFFObjectFile *Obj,
+ const SymbolRef &Sym,
+ const coff_section *&ResolvedSection,
+ uint64_t &ResolvedAddr) {
+ if (error_code EC = Sym.getAddress(ResolvedAddr))
+ return EC;
+
+ section_iterator iter(Obj->begin_sections());
+ if (error_code EC = Sym.getSection(iter))
+ return EC;
+
+ ResolvedSection = Obj->getCOFFSection(iter);
+ return object_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 error_code resolveSymbol(const std::vector<RelocationRef> &Rels,
+ uint64_t Offset, SymbolRef &Sym) {
+ for (std::vector<RelocationRef>::const_iterator RelI = Rels.begin(),
+ RelE = Rels.end();
+ RelI != RelE; ++RelI) {
+ uint64_t Ofs;
+ if (error_code EC = RelI->getOffset(Ofs))
+ return EC;
+
+ if (Ofs == Offset) {
+ Sym = *RelI->getSymbol();
+ return readobj_error::success;
+ }
+ }
+
+ return readobj_error::unknown_symbol;
+}
+
+// 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 error_code resolveSymbolName(const std::vector<RelocationRef> &Rels,
+ uint64_t Offset, StringRef &Name) {
+ SymbolRef Sym;
+ if (error_code EC = resolveSymbol(Rels, Offset, Sym)) return EC;
+ if (error_code EC = Sym.getName(Name)) return EC;
+ return object_error::success;
+}
+
+static const EnumEntry<COFF::MachineTypes> ImageFileMachineType[] = {
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_UNKNOWN ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AM33 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AMD64 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMV7 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_IA64 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_M32R ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPS16 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU16),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPC ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPCFP),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_R4000 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3DSP ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH4 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH5 ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_THUMB ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_WCEMIPSV2)
+};
+
+static const EnumEntry<COFF::Characteristics> ImageFileCharacteristics[] = {
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_RELOCS_STRIPPED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_EXECUTABLE_IMAGE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LINE_NUMS_STRIPPED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LOCAL_SYMS_STRIPPED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_AGGRESSIVE_WS_TRIM ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LARGE_ADDRESS_AWARE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_LO ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_32BIT_MACHINE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DEBUG_STRIPPED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_NET_RUN_FROM_SWAP ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_SYSTEM ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DLL ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_UP_SYSTEM_ONLY ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_HI )
+};
+
+static const EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = {
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_UNKNOWN ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_NATIVE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_GUI ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CUI ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_POSIX_CUI ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_APPLICATION ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_ROM ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_XBOX ),
+};
+
+static const EnumEntry<COFF::DLLCharacteristics> PEDLLCharacteristics[] = {
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_SEH ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_BIND ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE),
+};
+
+static const EnumEntry<COFF::SectionCharacteristics>
+ImageSectionCharacteristics[] = {
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_GPREL ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ ),
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE )
+};
+
+static const EnumEntry<COFF::SymbolBaseType> ImageSymType[] = {
+ { "Null" , COFF::IMAGE_SYM_TYPE_NULL },
+ { "Void" , COFF::IMAGE_SYM_TYPE_VOID },
+ { "Char" , COFF::IMAGE_SYM_TYPE_CHAR },
+ { "Short" , COFF::IMAGE_SYM_TYPE_SHORT },
+ { "Int" , COFF::IMAGE_SYM_TYPE_INT },
+ { "Long" , COFF::IMAGE_SYM_TYPE_LONG },
+ { "Float" , COFF::IMAGE_SYM_TYPE_FLOAT },
+ { "Double", COFF::IMAGE_SYM_TYPE_DOUBLE },
+ { "Struct", COFF::IMAGE_SYM_TYPE_STRUCT },
+ { "Union" , COFF::IMAGE_SYM_TYPE_UNION },
+ { "Enum" , COFF::IMAGE_SYM_TYPE_ENUM },
+ { "MOE" , COFF::IMAGE_SYM_TYPE_MOE },
+ { "Byte" , COFF::IMAGE_SYM_TYPE_BYTE },
+ { "Word" , COFF::IMAGE_SYM_TYPE_WORD },
+ { "UInt" , COFF::IMAGE_SYM_TYPE_UINT },
+ { "DWord" , COFF::IMAGE_SYM_TYPE_DWORD }
+};
+
+static const EnumEntry<COFF::SymbolComplexType> ImageSymDType[] = {
+ { "Null" , COFF::IMAGE_SYM_DTYPE_NULL },
+ { "Pointer" , COFF::IMAGE_SYM_DTYPE_POINTER },
+ { "Function", COFF::IMAGE_SYM_DTYPE_FUNCTION },
+ { "Array" , COFF::IMAGE_SYM_DTYPE_ARRAY }
+};
+
+static const EnumEntry<COFF::SymbolStorageClass> ImageSymClass[] = {
+ { "EndOfFunction" , COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION },
+ { "Null" , COFF::IMAGE_SYM_CLASS_NULL },
+ { "Automatic" , COFF::IMAGE_SYM_CLASS_AUTOMATIC },
+ { "External" , COFF::IMAGE_SYM_CLASS_EXTERNAL },
+ { "Static" , COFF::IMAGE_SYM_CLASS_STATIC },
+ { "Register" , COFF::IMAGE_SYM_CLASS_REGISTER },
+ { "ExternalDef" , COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF },
+ { "Label" , COFF::IMAGE_SYM_CLASS_LABEL },
+ { "UndefinedLabel" , COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL },
+ { "MemberOfStruct" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT },
+ { "Argument" , COFF::IMAGE_SYM_CLASS_ARGUMENT },
+ { "StructTag" , COFF::IMAGE_SYM_CLASS_STRUCT_TAG },
+ { "MemberOfUnion" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION },
+ { "UnionTag" , COFF::IMAGE_SYM_CLASS_UNION_TAG },
+ { "TypeDefinition" , COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION },
+ { "UndefinedStatic", COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC },
+ { "EnumTag" , COFF::IMAGE_SYM_CLASS_ENUM_TAG },
+ { "MemberOfEnum" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM },
+ { "RegisterParam" , COFF::IMAGE_SYM_CLASS_REGISTER_PARAM },
+ { "BitField" , COFF::IMAGE_SYM_CLASS_BIT_FIELD },
+ { "Block" , COFF::IMAGE_SYM_CLASS_BLOCK },
+ { "Function" , COFF::IMAGE_SYM_CLASS_FUNCTION },
+ { "EndOfStruct" , COFF::IMAGE_SYM_CLASS_END_OF_STRUCT },
+ { "File" , COFF::IMAGE_SYM_CLASS_FILE },
+ { "Section" , COFF::IMAGE_SYM_CLASS_SECTION },
+ { "WeakExternal" , COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL },
+ { "CLRToken" , COFF::IMAGE_SYM_CLASS_CLR_TOKEN }
+};
+
+static const EnumEntry<COFF::COMDATType> ImageCOMDATSelect[] = {
+ { "NoDuplicates", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES },
+ { "Any" , COFF::IMAGE_COMDAT_SELECT_ANY },
+ { "SameSize" , COFF::IMAGE_COMDAT_SELECT_SAME_SIZE },
+ { "ExactMatch" , COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH },
+ { "Associative" , COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE },
+ { "Largest" , COFF::IMAGE_COMDAT_SELECT_LARGEST },
+ { "Newest" , COFF::IMAGE_COMDAT_SELECT_NEWEST }
+};
+
+static const EnumEntry<COFF::WeakExternalCharacteristics>
+WeakExternalCharacteristics[] = {
+ { "NoLibrary", COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY },
+ { "Library" , COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY },
+ { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS }
+};
+
+static const EnumEntry<unsigned> UnwindFlags[] = {
+ { "ExceptionHandler", Win64EH::UNW_ExceptionHandler },
+ { "TerminateHandler", Win64EH::UNW_TerminateHandler },
+ { "ChainInfo" , Win64EH::UNW_ChainInfo }
+};
+
+static const EnumEntry<unsigned> UnwindOpInfo[] = {
+ { "RAX", 0 },
+ { "RCX", 1 },
+ { "RDX", 2 },
+ { "RBX", 3 },
+ { "RSP", 4 },
+ { "RBP", 5 },
+ { "RSI", 6 },
+ { "RDI", 7 },
+ { "R8", 8 },
+ { "R9", 9 },
+ { "R10", 10 },
+ { "R11", 11 },
+ { "R12", 12 },
+ { "R13", 13 },
+ { "R14", 14 },
+ { "R15", 15 }
+};
+
+// Some additional COFF structures not defined by llvm::object.
+namespace {
+ struct coff_aux_function_definition {
+ support::ulittle32_t TagIndex;
+ support::ulittle32_t TotalSize;
+ support::ulittle32_t PointerToLineNumber;
+ support::ulittle32_t PointerToNextFunction;
+ uint8_t Unused[2];
+ };
+
+ struct coff_aux_weak_external_definition {
+ support::ulittle32_t TagIndex;
+ support::ulittle32_t Characteristics;
+ uint8_t Unused[10];
+ };
+
+ struct coff_aux_file_record {
+ char FileName[18];
+ };
+
+ struct coff_aux_clr_token {
+ support::ulittle8_t AuxType;
+ support::ulittle8_t Reserved;
+ support::ulittle32_t SymbolTableIndex;
+ uint8_t Unused[12];
+ };
+} // namespace
+
+static uint64_t getOffsetOfLSDA(const Win64EH::UnwindInfo& UI) {
+ return static_cast<const char*>(UI.getLanguageSpecificData())
+ - reinterpret_cast<const char*>(&UI);
+}
+
+static uint32_t getLargeSlotValue(ArrayRef<UnwindCode> UCs) {
+ if (UCs.size() < 3)
+ return 0;
+
+ return UCs[1].FrameOffset + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16);
+}
+
+template<typename T>
+static error_code getSymbolAuxData(const COFFObjectFile *Obj,
+ const coff_symbol *Symbol, const T* &Aux) {
+ ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol);
+ Aux = reinterpret_cast<const T*>(AuxData.data());
+ return readobj_error::success;
+}
+
+static std::string formatSymbol(const std::vector<RelocationRef> &Rels,
+ uint64_t Offset, uint32_t Disp) {
+ std::string Buffer;
+ raw_string_ostream Str(Buffer);
+
+ StringRef Sym;
+ if (resolveSymbolName(Rels, Offset, Sym)) {
+ Str << format(" (0x%" PRIX64 ")", Offset);
+ return Str.str();
+ }
+
+ Str << Sym;
+ if (Disp > 0) {
+ Str << format(" +0x%X (0x%" PRIX64 ")", Disp, Offset);
+ } else {
+ Str << format(" (0x%" PRIX64 ")", Offset);
+ }
+
+ return Str.str();
+}
+
+// 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.
+error_code COFFDumper::getSectionContents(
+ const std::vector<RelocationRef> &Rels, uint64_t Offset,
+ ArrayRef<uint8_t> &Contents, uint64_t &Addr) {
+
+ SymbolRef Sym;
+ const coff_section *Section;
+
+ if (error_code EC = resolveSymbol(Rels, Offset, Sym))
+ return EC;
+ if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr))
+ return EC;
+ if (error_code EC = Obj->getSectionContents(Section, Contents))
+ return EC;
+
+ return object_error::success;
+}
+
+error_code COFFDumper::getSection(
+ const std::vector<RelocationRef> &Rels, uint64_t Offset,
+ const coff_section **SectionPtr, uint64_t *AddrPtr) {
+
+ SymbolRef Sym;
+ if (error_code EC = resolveSymbol(Rels, Offset, Sym))
+ return EC;
+
+ const coff_section *Section;
+ uint64_t Addr;
+ if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr))
+ return EC;
+
+ if (SectionPtr)
+ *SectionPtr = Section;
+ if (AddrPtr)
+ *AddrPtr = Addr;
+
+ return object_error::success;
+}
+
+void COFFDumper::cacheRelocations() {
+ error_code EC;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ if (error(EC))
+ break;
+
+ const coff_section *Section = Obj->getCOFFSection(SecI);
+
+ for (relocation_iterator RelI = SecI->begin_relocations(),
+ RelE = SecI->end_relocations();
+ RelI != RelE; RelI.increment(EC)) {
+ if (error(EC))
+ break;
+
+ RelocMap[Section].push_back(*RelI);
+ }
+
+ // Sort relocations by address.
+ std::sort(RelocMap[Section].begin(), RelocMap[Section].end(),
+ relocAddressLess);
+ }
+}
+
+void COFFDumper::printDataDirectory(uint32_t Index, const std::string &FieldName) {
+ const data_directory *Data;
+ if (Obj->getDataDirectory(Index, Data))
+ return;
+ W.printHex(FieldName + "RVA", Data->RelativeVirtualAddress);
+ W.printHex(FieldName + "Size", Data->Size);
+}
+
+void COFFDumper::printFileHeaders() {
+ // Print COFF header
+ const coff_file_header *COFFHeader = 0;
+ if (error(Obj->getCOFFHeader(COFFHeader)))
+ return;
+
+ time_t TDS = COFFHeader->TimeDateStamp;
+ char FormattedTime[20] = { };
+ strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
+
+ {
+ DictScope D(W, "ImageFileHeader");
+ W.printEnum ("Machine", COFFHeader->Machine,
+ makeArrayRef(ImageFileMachineType));
+ W.printNumber("SectionCount", COFFHeader->NumberOfSections);
+ W.printHex ("TimeDateStamp", FormattedTime, COFFHeader->TimeDateStamp);
+ W.printHex ("PointerToSymbolTable", COFFHeader->PointerToSymbolTable);
+ W.printNumber("SymbolCount", COFFHeader->NumberOfSymbols);
+ W.printNumber("OptionalHeaderSize", COFFHeader->SizeOfOptionalHeader);
+ W.printFlags ("Characteristics", COFFHeader->Characteristics,
+ makeArrayRef(ImageFileCharacteristics));
+ }
+
+ // Print PE header. This header does not exist if this is an object file and
+ // not an executable.
+ const pe32_header *PEHeader = 0;
+ if (error(Obj->getPE32Header(PEHeader)))
+ return;
+
+ if (PEHeader) {
+ DictScope D(W, "ImageOptionalHeader");
+ W.printNumber("MajorLinkerVersion", PEHeader->MajorLinkerVersion);
+ W.printNumber("MinorLinkerVersion", PEHeader->MinorLinkerVersion);
+ W.printNumber("SizeOfCode", PEHeader->SizeOfCode);
+ W.printNumber("SizeOfInitializedData", PEHeader->SizeOfInitializedData);
+ W.printNumber("SizeOfUninitializedData", PEHeader->SizeOfUninitializedData);
+ W.printHex ("AddressOfEntryPoint", PEHeader->AddressOfEntryPoint);
+ W.printHex ("BaseOfCode", PEHeader->BaseOfCode);
+ W.printHex ("BaseOfData", PEHeader->BaseOfData);
+ W.printHex ("ImageBase", PEHeader->ImageBase);
+ W.printNumber("SectionAlignment", PEHeader->SectionAlignment);
+ W.printNumber("FileAlignment", PEHeader->FileAlignment);
+ W.printNumber("MajorOperatingSystemVersion",
+ PEHeader->MajorOperatingSystemVersion);
+ W.printNumber("MinorOperatingSystemVersion",
+ PEHeader->MinorOperatingSystemVersion);
+ W.printNumber("MajorImageVersion", PEHeader->MajorImageVersion);
+ W.printNumber("MinorImageVersion", PEHeader->MinorImageVersion);
+ W.printNumber("MajorSubsystemVersion", PEHeader->MajorSubsystemVersion);
+ W.printNumber("MinorSubsystemVersion", PEHeader->MinorSubsystemVersion);
+ W.printNumber("SizeOfImage", PEHeader->SizeOfImage);
+ W.printNumber("SizeOfHeaders", PEHeader->SizeOfHeaders);
+ W.printEnum ("Subsystem", PEHeader->Subsystem,
+ makeArrayRef(PEWindowsSubsystem));
+ W.printFlags ("Subsystem", PEHeader->DLLCharacteristics,
+ makeArrayRef(PEDLLCharacteristics));
+ W.printNumber("SizeOfStackReserve", PEHeader->SizeOfStackReserve);
+ W.printNumber("SizeOfStackCommit", PEHeader->SizeOfStackCommit);
+ W.printNumber("SizeOfHeapReserve", PEHeader->SizeOfHeapReserve);
+ W.printNumber("SizeOfHeapCommit", PEHeader->SizeOfHeapCommit);
+ W.printNumber("NumberOfRvaAndSize", PEHeader->NumberOfRvaAndSize);
+
+ if (PEHeader->NumberOfRvaAndSize > 0) {
+ DictScope D(W, "DataDirectory");
+ static const char * const directory[] = {
+ "ExportTable", "ImportTable", "ResourceTable", "ExceptionTable",
+ "CertificateTable", "BaseRelocationTable", "Debug", "Architecture",
+ "GlobalPtr", "TLSTable", "LoadConfigTable", "BoundImport", "IAT",
+ "DelayImportDescriptor", "CLRRuntimeHeader", "Reserved"
+ };
+
+ for (uint32_t i = 0; i < PEHeader->NumberOfRvaAndSize; ++i) {
+ printDataDirectory(i, directory[i]);
+ }
+ }
+ }
+}
+
+void COFFDumper::printSections() {
+ error_code EC;
+
+ ListScope SectionsD(W, "Sections");
+ int SectionNumber = 0;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ if (error(EC))
+ break;
+
+ ++SectionNumber;
+ const coff_section *Section = Obj->getCOFFSection(SecI);
+
+ StringRef Name;
+ if (error(SecI->getName(Name)))
+ Name = "";
+
+ DictScope D(W, "Section");
+ W.printNumber("Number", SectionNumber);
+ W.printBinary("Name", Name, Section->Name);
+ W.printHex ("VirtualSize", Section->VirtualSize);
+ W.printHex ("VirtualAddress", Section->VirtualAddress);
+ W.printNumber("RawDataSize", Section->SizeOfRawData);
+ W.printHex ("PointerToRawData", Section->PointerToRawData);
+ W.printHex ("PointerToRelocations", Section->PointerToRelocations);
+ W.printHex ("PointerToLineNumbers", Section->PointerToLinenumbers);
+ W.printNumber("RelocationCount", Section->NumberOfRelocations);
+ W.printNumber("LineNumberCount", Section->NumberOfLinenumbers);
+ W.printFlags ("Characteristics", Section->Characteristics,
+ makeArrayRef(ImageSectionCharacteristics),
+ COFF::SectionCharacteristics(0x00F00000));
+
+ if (opts::SectionRelocations) {
+ ListScope D(W, "Relocations");
+ for (relocation_iterator RelI = SecI->begin_relocations(),
+ RelE = SecI->end_relocations();
+ RelI != RelE; RelI.increment(EC)) {
+ if (error(EC)) break;
+
+ printRelocation(SecI, RelI);
+ }
+ }
+
+ if (opts::SectionSymbols) {
+ ListScope D(W, "Symbols");
+ for (symbol_iterator SymI = Obj->begin_symbols(),
+ SymE = Obj->end_symbols();
+ SymI != SymE; SymI.increment(EC)) {
+ if (error(EC)) break;
+
+ bool Contained = false;
+ if (SecI->containsSymbol(*SymI, Contained) || !Contained)
+ continue;
+
+ printSymbol(SymI);
+ }
+ }
+
+ if (opts::SectionData) {
+ StringRef Data;
+ if (error(SecI->getContents(Data))) break;
+
+ W.printBinaryBlock("SectionData", Data);
+ }
+ }
+}
+
+void COFFDumper::printRelocations() {
+ ListScope D(W, "Relocations");
+
+ error_code EC;
+ int SectionNumber = 0;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ ++SectionNumber;
+ if (error(EC))
+ break;
+
+ StringRef Name;
+ if (error(SecI->getName(Name)))
+ continue;
+
+ bool PrintedGroup = false;
+ for (relocation_iterator RelI = SecI->begin_relocations(),
+ RelE = SecI->end_relocations();
+ RelI != RelE; RelI.increment(EC)) {
+ if (error(EC)) break;
+
+ if (!PrintedGroup) {
+ W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n";
+ W.indent();
+ PrintedGroup = true;
+ }
+
+ printRelocation(SecI, RelI);
+ }
+
+ if (PrintedGroup) {
+ W.unindent();
+ W.startLine() << "}\n";
+ }
+ }
+}
+
+void COFFDumper::printRelocation(section_iterator SecI,
+ relocation_iterator RelI) {
+ uint64_t Offset;
+ uint64_t RelocType;
+ SmallString<32> RelocName;
+ StringRef SymbolName;
+ StringRef Contents;
+ if (error(RelI->getOffset(Offset))) return;
+ if (error(RelI->getType(RelocType))) return;
+ if (error(RelI->getTypeName(RelocName))) return;
+ symbol_iterator Symbol = RelI->getSymbol();
+ if (error(Symbol->getName(SymbolName))) return;
+ if (error(SecI->getContents(Contents))) return;
+
+ if (opts::ExpandRelocs) {
+ DictScope Group(W, "Relocation");
+ W.printHex("Offset", Offset);
+ W.printNumber("Type", RelocName, RelocType);
+ W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-");
+ } else {
+ raw_ostream& OS = W.startLine();
+ OS << W.hex(Offset)
+ << " " << RelocName
+ << " " << (SymbolName.size() > 0 ? SymbolName : "-")
+ << "\n";
+ }
+}
+
+void COFFDumper::printSymbols() {
+ ListScope Group(W, "Symbols");
+
+ error_code EC;
+ for (symbol_iterator SymI = Obj->begin_symbols(),
+ SymE = Obj->end_symbols();
+ SymI != SymE; SymI.increment(EC)) {
+ if (error(EC)) break;
+
+ printSymbol(SymI);
+ }
+}
+
+void COFFDumper::printDynamicSymbols() {
+ ListScope Group(W, "DynamicSymbols");
+}
+
+void COFFDumper::printSymbol(symbol_iterator SymI) {
+ DictScope D(W, "Symbol");
+
+ const coff_symbol *Symbol = Obj->getCOFFSymbol(SymI);
+ const coff_section *Section;
+ if (error_code EC = Obj->getSection(Symbol->SectionNumber, Section)) {
+ W.startLine() << "Invalid section number: " << EC.message() << "\n";
+ W.flush();
+ return;
+ }
+
+ StringRef SymbolName;
+ if (Obj->getSymbolName(Symbol, SymbolName))
+ SymbolName = "";
+
+ StringRef SectionName = "";
+ if (Section)
+ Obj->getSectionName(Section, SectionName);
+
+ W.printString("Name", SymbolName);
+ W.printNumber("Value", Symbol->Value);
+ W.printNumber("Section", SectionName, Symbol->SectionNumber);
+ W.printEnum ("BaseType", Symbol->getBaseType(), makeArrayRef(ImageSymType));
+ W.printEnum ("ComplexType", Symbol->getComplexType(),
+ makeArrayRef(ImageSymDType));
+ W.printEnum ("StorageClass", Symbol->StorageClass,
+ makeArrayRef(ImageSymClass));
+ W.printNumber("AuxSymbolCount", Symbol->NumberOfAuxSymbols);
+
+ for (unsigned I = 0; I < Symbol->NumberOfAuxSymbols; ++I) {
+ if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL &&
+ Symbol->getBaseType() == COFF::IMAGE_SYM_TYPE_NULL &&
+ Symbol->getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION &&
+ Symbol->SectionNumber > 0) {
+ const coff_aux_function_definition *Aux;
+ if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ break;
+
+ DictScope AS(W, "AuxFunctionDef");
+ W.printNumber("TagIndex", Aux->TagIndex);
+ W.printNumber("TotalSize", Aux->TotalSize);
+ W.printHex("PointerToLineNumber", Aux->PointerToLineNumber);
+ W.printHex("PointerToNextFunction", Aux->PointerToNextFunction);
+ W.printBinary("Unused", makeArrayRef(Aux->Unused));
+
+ } else if (
+ Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL ||
+ (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL &&
+ Symbol->SectionNumber == 0 &&
+ Symbol->Value == 0)) {
+ const coff_aux_weak_external_definition *Aux;
+ if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ break;
+
+ const coff_symbol *Linked;
+ StringRef LinkedName;
+ error_code EC;
+ if ((EC = Obj->getSymbol(Aux->TagIndex, Linked)) ||
+ (EC = Obj->getSymbolName(Linked, LinkedName))) {
+ LinkedName = "";
+ error(EC);
+ }
+
+ DictScope AS(W, "AuxWeakExternal");
+ W.printNumber("Linked", LinkedName, Aux->TagIndex);
+ W.printEnum ("Search", Aux->Characteristics,
+ makeArrayRef(WeakExternalCharacteristics));
+ W.printBinary("Unused", Aux->Unused);
+
+ } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_FILE) {
+ const coff_aux_file_record *Aux;
+ if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ break;
+
+ DictScope AS(W, "AuxFileRecord");
+ W.printString("FileName", StringRef(Aux->FileName));
+
+ } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC ||
+ (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL &&
+ Symbol->SectionNumber != COFF::IMAGE_SYM_UNDEFINED)) {
+ const coff_aux_section_definition *Aux;
+ if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ break;
+
+ DictScope AS(W, "AuxSectionDef");
+ W.printNumber("Length", Aux->Length);
+ W.printNumber("RelocationCount", Aux->NumberOfRelocations);
+ W.printNumber("LineNumberCount", Aux->NumberOfLinenumbers);
+ W.printHex("Checksum", Aux->CheckSum);
+ W.printNumber("Number", Aux->Number);
+ W.printEnum("Selection", Aux->Selection, makeArrayRef(ImageCOMDATSelect));
+ W.printBinary("Unused", makeArrayRef(Aux->Unused));
+
+ if (Section && Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT
+ && Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ const coff_section *Assoc;
+ StringRef AssocName;
+ error_code EC;
+ if ((EC = Obj->getSection(Aux->Number, Assoc)) ||
+ (EC = Obj->getSectionName(Assoc, AssocName))) {
+ AssocName = "";
+ error(EC);
+ }
+
+ W.printNumber("AssocSection", AssocName, Aux->Number);
+ }
+ } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_CLR_TOKEN) {
+ const coff_aux_clr_token *Aux;
+ if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ break;
+
+ DictScope AS(W, "AuxCLRToken");
+ W.printNumber("AuxType", Aux->AuxType);
+ W.printNumber("Reserved", Aux->Reserved);
+ W.printNumber("SymbolTableIndex", Aux->SymbolTableIndex);
+ W.printBinary("Unused", Aux->Unused);
+
+ } else {
+ W.startLine() << "<unhandled auxiliary record>\n";
+ }
+ }
+}
+
+void COFFDumper::printUnwindInfo() {
+ const coff_file_header *Header;
+ if (error(Obj->getCOFFHeader(Header)))
+ return;
+
+ ListScope D(W, "UnwindInformation");
+ if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) {
+ W.startLine() << "Unsupported image machine type "
+ "(currently only AMD64 is supported).\n";
+ return;
+ }
+
+ printX64UnwindInfo();
+}
+
+void COFFDumper::printX64UnwindInfo() {
+ error_code EC;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ if (error(EC)) break;
+
+ StringRef Name;
+ if (error(SecI->getName(Name)))
+ continue;
+ if (Name != ".pdata" && !Name.startswith(".pdata$"))
+ continue;
+
+ const coff_section *PData = Obj->getCOFFSection(SecI);
+
+ ArrayRef<uint8_t> Contents;
+ if (error(Obj->getSectionContents(PData, Contents)) ||
+ Contents.empty())
+ continue;
+
+ ArrayRef<RuntimeFunction> RFs(
+ reinterpret_cast<const RuntimeFunction *>(Contents.data()),
+ Contents.size() / sizeof(RuntimeFunction));
+
+ for (const RuntimeFunction *I = RFs.begin(), *E = RFs.end(); I < E; ++I) {
+ const uint64_t OffsetInSection = std::distance(RFs.begin(), I)
+ * sizeof(RuntimeFunction);
+
+ printRuntimeFunction(*I, OffsetInSection, RelocMap[PData]);
+ }
+ }
+}
+
+void COFFDumper::printRuntimeFunction(
+ const RuntimeFunction& RTF,
+ uint64_t OffsetInSection,
+ const std::vector<RelocationRef> &Rels) {
+
+ DictScope D(W, "RuntimeFunction");
+ W.printString("StartAddress",
+ formatSymbol(Rels, OffsetInSection + 0, RTF.StartAddress));
+ W.printString("EndAddress",
+ formatSymbol(Rels, OffsetInSection + 4, RTF.EndAddress));
+ W.printString("UnwindInfoAddress",
+ formatSymbol(Rels, OffsetInSection + 8, RTF.UnwindInfoOffset));
+
+ const coff_section* XData = 0;
+ uint64_t UnwindInfoOffset = 0;
+ if (error(getSection(Rels, OffsetInSection + 8, &XData, &UnwindInfoOffset)))
+ return;
+
+ ArrayRef<uint8_t> XContents;
+ if (error(Obj->getSectionContents(XData, XContents)) || XContents.empty())
+ return;
+
+ UnwindInfoOffset += RTF.UnwindInfoOffset;
+ if (UnwindInfoOffset > XContents.size())
+ return;
+
+ const Win64EH::UnwindInfo *UI =
+ reinterpret_cast<const Win64EH::UnwindInfo *>(
+ XContents.data() + UnwindInfoOffset);
+
+ printUnwindInfo(*UI, UnwindInfoOffset, RelocMap[XData]);
+}
+
+void COFFDumper::printUnwindInfo(
+ const Win64EH::UnwindInfo& UI,
+ uint64_t OffsetInSection,
+ const std::vector<RelocationRef> &Rels) {
+ DictScope D(W, "UnwindInfo");
+ W.printNumber("Version", UI.getVersion());
+ W.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags));
+ W.printNumber("PrologSize", UI.PrologSize);
+ if (UI.getFrameRegister() != 0) {
+ W.printEnum("FrameRegister", UI.getFrameRegister(),
+ makeArrayRef(UnwindOpInfo));
+ W.printHex("FrameOffset", UI.getFrameOffset());
+ } else {
+ W.printString("FrameRegister", StringRef("-"));
+ W.printString("FrameOffset", StringRef("-"));
+ }
+
+ W.printNumber("UnwindCodeCount", UI.NumCodes);
+ {
+ ListScope CodesD(W, "UnwindCodes");
+ ArrayRef<UnwindCode> UCs(&UI.UnwindCodes[0], UI.NumCodes);
+ for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ++I) {
+ unsigned UsedSlots = getNumUsedSlots(*I);
+ if (UsedSlots > UCs.size()) {
+ errs() << "Corrupt unwind data";
+ return;
+ }
+ printUnwindCode(UI, ArrayRef<UnwindCode>(I, E));
+ I += UsedSlots - 1;
+ }
+ }
+
+ uint64_t LSDAOffset = OffsetInSection + getOffsetOfLSDA(UI);
+ if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {
+ W.printString("Handler", formatSymbol(Rels, LSDAOffset,
+ UI.getLanguageSpecificHandlerOffset()));
+ } else if (UI.getFlags() & UNW_ChainInfo) {
+ const RuntimeFunction *Chained = UI.getChainedFunctionEntry();
+ if (Chained) {
+ DictScope D(W, "Chained");
+ W.printString("StartAddress", formatSymbol(Rels, LSDAOffset + 0,
+ Chained->StartAddress));
+ W.printString("EndAddress", formatSymbol(Rels, LSDAOffset + 4,
+ Chained->EndAddress));
+ W.printString("UnwindInfoAddress", formatSymbol(Rels, LSDAOffset + 8,
+ Chained->UnwindInfoOffset));
+ }
+ }
+}
+
+// Prints one unwind code. Because an unwind code can occupy up to 3 slots in
+// the unwind codes array, this function requires that the correct number of
+// slots is provided.
+void COFFDumper::printUnwindCode(const Win64EH::UnwindInfo& UI,
+ ArrayRef<UnwindCode> UCs) {
+ assert(UCs.size() >= getNumUsedSlots(UCs[0]));
+
+ W.startLine() << format("0x%02X: ", unsigned(UCs[0].u.CodeOffset))
+ << getUnwindCodeTypeName(UCs[0].getUnwindOp());
+
+ uint32_t AllocSize = 0;
+
+ switch (UCs[0].getUnwindOp()) {
+ case UOP_PushNonVol:
+ outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo());
+ break;
+
+ case UOP_AllocLarge:
+ if (UCs[0].getOpInfo() == 0) {
+ AllocSize = UCs[1].FrameOffset * 8;
+ } else {
+ AllocSize = getLargeSlotValue(UCs);
+ }
+ outs() << " size=" << AllocSize;
+ break;
+ case UOP_AllocSmall:
+ outs() << " size=" << ((UCs[0].getOpInfo() + 1) * 8);
+ break;
+ case UOP_SetFPReg:
+ if (UI.getFrameRegister() == 0) {
+ outs() << " reg=<invalid>";
+ } else {
+ outs() << " reg=" << getUnwindRegisterName(UI.getFrameRegister())
+ << format(", offset=0x%X", UI.getFrameOffset() * 16);
+ }
+ break;
+ case UOP_SaveNonVol:
+ outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo())
+ << format(", offset=0x%X", UCs[1].FrameOffset * 8);
+ break;
+ case UOP_SaveNonVolBig:
+ outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo())
+ << format(", offset=0x%X", getLargeSlotValue(UCs));
+ break;
+ case UOP_SaveXMM128:
+ outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
+ << format(", offset=0x%X", UCs[1].FrameOffset * 16);
+ break;
+ case UOP_SaveXMM128Big:
+ outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
+ << format(", offset=0x%X", getLargeSlotValue(UCs));
+ break;
+ case UOP_PushMachFrame:
+ outs() << " errcode=" << (UCs[0].getOpInfo() == 0 ? "no" : "yes");
+ break;
+ }
+
+ outs() << "\n";
+}
diff --git a/tools/llvm-readobj/ELF.cpp b/tools/llvm-readobj/ELF.cpp
deleted file mode 100644
index 07f15b3..0000000
--- a/tools/llvm-readobj/ELF.cpp
+++ /dev/null
@@ -1,196 +0,0 @@
-//===- llvm-readobj/ELF.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.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm-readobj.h"
-
-#include "llvm/Object/ELF.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/Format.h"
-
-namespace llvm {
-using namespace object;
-using namespace ELF;
-
-const char *getTypeString(uint64_t Type) {
- switch (Type) {
- case DT_BIND_NOW:
- return "(BIND_NOW)";
- case DT_DEBUG:
- return "(DEBUG)";
- case DT_FINI:
- return "(FINI)";
- case DT_FINI_ARRAY:
- return "(FINI_ARRAY)";
- case DT_FINI_ARRAYSZ:
- return "(FINI_ARRAYSZ)";
- case DT_FLAGS:
- return "(FLAGS)";
- case DT_HASH:
- return "(HASH)";
- case DT_INIT:
- return "(INIT)";
- case DT_INIT_ARRAY:
- return "(INIT_ARRAY)";
- case DT_INIT_ARRAYSZ:
- return "(INIT_ARRAYSZ)";
- case DT_PREINIT_ARRAY:
- return "(PREINIT_ARRAY)";
- case DT_PREINIT_ARRAYSZ:
- return "(PREINIT_ARRAYSZ)";
- case DT_JMPREL:
- return "(JMPREL)";
- case DT_NEEDED:
- return "(NEEDED)";
- case DT_NULL:
- return "(NULL)";
- case DT_PLTGOT:
- return "(PLTGOT)";
- case DT_PLTREL:
- return "(PLTREL)";
- case DT_PLTRELSZ:
- return "(PLTRELSZ)";
- case DT_REL:
- return "(REL)";
- case DT_RELA:
- return "(RELA)";
- case DT_RELENT:
- return "(RELENT)";
- case DT_RELSZ:
- return "(RELSZ)";
- case DT_RELAENT:
- return "(RELAENT)";
- case DT_RELASZ:
- return "(RELASZ)";
- case DT_RPATH:
- return "(RPATH)";
- case DT_RUNPATH:
- return "(RUNPATH)";
- case DT_SONAME:
- return "(SONAME)";
- case DT_STRSZ:
- return "(STRSZ)";
- case DT_STRTAB:
- return "(STRTAB)";
- case DT_SYMBOLIC:
- return "(SYMBOLIC)";
- case DT_SYMENT:
- return "(SYMENT)";
- case DT_SYMTAB:
- return "(SYMTAB)";
- case DT_TEXTREL:
- return "(TEXTREL)";
- default:
- return "unknown";
- }
-}
-
-template <class ELFT>
-void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type, uint64_t Value,
- bool Is64, raw_ostream &OS) {
- switch (Type) {
- case DT_PLTREL:
- if (Value == DT_REL) {
- OS << "REL";
- break;
- } else if (Value == DT_RELA) {
- OS << "RELA";
- break;
- }
- // Fallthrough.
- case DT_PLTGOT:
- case DT_HASH:
- case DT_STRTAB:
- case DT_SYMTAB:
- case DT_RELA:
- case DT_INIT:
- case DT_FINI:
- case DT_REL:
- case DT_JMPREL:
- case DT_INIT_ARRAY:
- case DT_FINI_ARRAY:
- case DT_PREINIT_ARRAY:
- case DT_DEBUG:
- case DT_NULL:
- OS << format("0x%" PRIx64, Value);
- break;
- case DT_PLTRELSZ:
- case DT_RELASZ:
- case DT_RELAENT:
- case DT_STRSZ:
- case DT_SYMENT:
- case DT_RELSZ:
- case DT_RELENT:
- case DT_INIT_ARRAYSZ:
- case DT_FINI_ARRAYSZ:
- case DT_PREINIT_ARRAYSZ:
- OS << Value << " (bytes)";
- break;
- case DT_NEEDED:
- OS << "Shared library: ["
- << O->getString(O->getDynamicStringTableSectionHeader(), Value) << "]";
- break;
- case DT_SONAME:
- OS << "Library soname: ["
- << O->getString(O->getDynamicStringTableSectionHeader(), Value) << "]";
- break;
- }
-}
-
-template <class ELFT>
-ErrorOr<void> dumpDynamicTable(const ELFObjectFile<ELFT> *O, raw_ostream &OS) {
- typedef ELFObjectFile<ELFT> ELFO;
- typedef typename ELFO::Elf_Dyn_iterator EDI;
- EDI Start = O->begin_dynamic_table(),
- End = O->end_dynamic_table(true);
-
- if (Start == End)
- return error_code::success();
-
- ptrdiff_t Total = std::distance(Start, End);
- OS << "Dynamic section contains " << Total << " entries\n";
-
- bool Is64 = O->getBytesInAddress() == 8;
-
- OS << " Tag" << (Is64 ? " " : " ") << "Type"
- << " " << "Name/Value\n";
- for (; Start != End; ++Start) {
- OS << " "
- << format(Is64 ? "0x%016" PRIx64 : "0x%08" PRIx64, Start->getTag())
- << " " << format("%-21s", getTypeString(Start->getTag()));
- printValue(O, Start->getTag(), Start->getVal(), Is64, OS);
- OS << "\n";
- }
-
- OS << " Total: " << Total << "\n\n";
- return error_code::success();
-}
-
-ErrorOr<void> dumpELFDynamicTable(ObjectFile *O, raw_ostream &OS) {
- // Little-endian 32-bit
- if (const ELFObjectFile<ELFType<support::little, 4, false> > *ELFObj =
- dyn_cast<ELFObjectFile<ELFType<support::little, 4, false> > >(O))
- return dumpDynamicTable(ELFObj, OS);
-
- // Big-endian 32-bit
- if (const ELFObjectFile<ELFType<support::big, 4, false> > *ELFObj =
- dyn_cast<ELFObjectFile<ELFType<support::big, 4, false> > >(O))
- return dumpDynamicTable(ELFObj, OS);
-
- // Little-endian 64-bit
- if (const ELFObjectFile<ELFType<support::little, 8, true> > *ELFObj =
- dyn_cast<ELFObjectFile<ELFType<support::little, 8, true> > >(O))
- return dumpDynamicTable(ELFObj, OS);
-
- // Big-endian 64-bit
- if (const ELFObjectFile<ELFType<support::big, 8, true> > *ELFObj =
- dyn_cast<ELFObjectFile<ELFType<support::big, 8, true> > >(O))
- return dumpDynamicTable(ELFObj, OS);
- return error_code(object_error::invalid_file_type);
-}
-} // end namespace llvm
diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp
new file mode 100644
index 0000000..3628c3b
--- /dev/null
+++ b/tools/llvm-readobj/ELFDumper.cpp
@@ -0,0 +1,848 @@
+//===-- ELFDumper.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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements the ELF-specific dumper for llvm-readobj.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm-readobj.h"
+#include "Error.h"
+#include "ObjDumper.h"
+#include "StreamWriter.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace ELF;
+
+
+#define LLVM_READOBJ_ENUM_CASE(ns, enum) \
+ case ns::enum: return #enum;
+
+namespace {
+
+template<typename ELFT>
+class ELFDumper : public ObjDumper {
+public:
+ ELFDumper(const ELFObjectFile<ELFT> *Obj, StreamWriter& Writer)
+ : ObjDumper(Writer)
+ , Obj(Obj) { }
+
+ virtual void printFileHeaders() LLVM_OVERRIDE;
+ virtual void printSections() LLVM_OVERRIDE;
+ virtual void printRelocations() LLVM_OVERRIDE;
+ virtual void printSymbols() LLVM_OVERRIDE;
+ virtual void printDynamicSymbols() LLVM_OVERRIDE;
+ virtual void printUnwindInfo() LLVM_OVERRIDE;
+
+ virtual void printDynamicTable() LLVM_OVERRIDE;
+ virtual void printNeededLibraries() LLVM_OVERRIDE;
+ virtual void printProgramHeaders() LLVM_OVERRIDE;
+
+private:
+ typedef ELFObjectFile<ELFT> ELFO;
+ typedef typename ELFO::Elf_Shdr Elf_Shdr;
+ typedef typename ELFO::Elf_Sym Elf_Sym;
+
+ void printSymbol(symbol_iterator SymI, bool IsDynamic = false);
+
+ void printRelocation(section_iterator SecI, relocation_iterator RelI);
+
+ const ELFO *Obj;
+};
+
+} // namespace
+
+
+namespace llvm {
+
+template <class ELFT>
+static error_code createELFDumper(const ELFObjectFile<ELFT> *Obj,
+ StreamWriter &Writer,
+ OwningPtr<ObjDumper> &Result) {
+ Result.reset(new ELFDumper<ELFT>(Obj, Writer));
+ return readobj_error::success;
+}
+
+error_code createELFDumper(const object::ObjectFile *Obj,
+ StreamWriter& Writer,
+ OwningPtr<ObjDumper> &Result) {
+ // Little-endian 32-bit
+ if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
+ return createELFDumper(ELFObj, Writer, Result);
+
+ // Big-endian 32-bit
+ if (const ELF32BEObjectFile *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
+ return createELFDumper(ELFObj, Writer, Result);
+
+ // Little-endian 64-bit
+ if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
+ return createELFDumper(ELFObj, Writer, Result);
+
+ // Big-endian 64-bit
+ if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj))
+ return createELFDumper(ELFObj, Writer, Result);
+
+ return readobj_error::unsupported_obj_file_format;
+}
+
+} // namespace llvm
+
+
+static const EnumEntry<unsigned> ElfClass[] = {
+ { "None", ELF::ELFCLASSNONE },
+ { "32-bit", ELF::ELFCLASS32 },
+ { "64-bit", ELF::ELFCLASS64 },
+};
+
+static const EnumEntry<unsigned> ElfDataEncoding[] = {
+ { "None", ELF::ELFDATANONE },
+ { "LittleEndian", ELF::ELFDATA2LSB },
+ { "BigEndian", ELF::ELFDATA2MSB },
+};
+
+static const EnumEntry<unsigned> ElfObjectFileType[] = {
+ { "None", ELF::ET_NONE },
+ { "Relocatable", ELF::ET_REL },
+ { "Executable", ELF::ET_EXEC },
+ { "SharedObject", ELF::ET_DYN },
+ { "Core", ELF::ET_CORE },
+};
+
+static const EnumEntry<unsigned> ElfOSABI[] = {
+ { "SystemV", ELF::ELFOSABI_NONE },
+ { "HPUX", ELF::ELFOSABI_HPUX },
+ { "NetBSD", ELF::ELFOSABI_NETBSD },
+ { "GNU/Linux", ELF::ELFOSABI_LINUX },
+ { "GNU/Hurd", ELF::ELFOSABI_HURD },
+ { "Solaris", ELF::ELFOSABI_SOLARIS },
+ { "AIX", ELF::ELFOSABI_AIX },
+ { "IRIX", ELF::ELFOSABI_IRIX },
+ { "FreeBSD", ELF::ELFOSABI_FREEBSD },
+ { "TRU64", ELF::ELFOSABI_TRU64 },
+ { "Modesto", ELF::ELFOSABI_MODESTO },
+ { "OpenBSD", ELF::ELFOSABI_OPENBSD },
+ { "OpenVMS", ELF::ELFOSABI_OPENVMS },
+ { "NSK", ELF::ELFOSABI_NSK },
+ { "AROS", ELF::ELFOSABI_AROS },
+ { "FenixOS", ELF::ELFOSABI_FENIXOS },
+ { "C6000_ELFABI", ELF::ELFOSABI_C6000_ELFABI },
+ { "C6000_LINUX" , ELF::ELFOSABI_C6000_LINUX },
+ { "ARM", ELF::ELFOSABI_ARM },
+ { "Standalone" , ELF::ELFOSABI_STANDALONE }
+};
+
+static const EnumEntry<unsigned> ElfMachineType[] = {
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NONE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_M32 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_386 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_88K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_486 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_860 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_S370 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS_RS3_LE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PARISC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VPP500 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARC32PLUS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_960 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PPC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PPC64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_S390 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SPU ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_V800 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_FR20 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RH32 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RCE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARM ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ALPHA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SH ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARCV9 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TRICORE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_300 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_300H ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_H8S ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_500 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_IA_64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS_X ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_COLDFIRE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC12 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MMA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PCP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NCPU ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NDR1 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_STARCORE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ME16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST100 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TINYJ ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_X86_64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PDSP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PDP10 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PDP11 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_FX66 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST9PLUS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST7 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC11 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC08 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC05 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SVX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST19 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VAX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CRIS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_JAVELIN ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_FIREPATH ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ZSP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MMIX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_HUANY ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PRISM ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_AVR ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_FR30 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_D10V ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_D30V ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_V850 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_M32R ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MN10300 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MN10200 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_PJ ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_OPENRISC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC_COMPACT ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_XTENSA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TMM_GPP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NS32K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TPC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SNP1K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ST200 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_IP2K ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MAX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CR ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_F2MC16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MSP430 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_BLACKFIN ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SE_C33 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SEP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARCA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_UNICORE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_EXCESS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_DXP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ALTERA_NIOS2 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CRX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_XGATE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_C166 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_M16C ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_DSPIC30F ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_M32C ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TSK3000 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RS08 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SHARC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG2 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SCORE7 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_DSP24 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE3 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_LATTICEMICO32),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SE_C17 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C6000 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C2000 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C5500 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MMDSP_PLUS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CYPRESS_M8C ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_R32C ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TRIMEDIA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_HEXAGON ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_8051 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_STXP7X ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_NDS32 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG1 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG1X ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MAXQ30 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_XIMO16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MANIK ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CRAYNV2 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_METAG ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_MCST_ELBRUS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CR16 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ETPU ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_SLE9X ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_L10M ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_K10M ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_AARCH64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_AVR32 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_STM8 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TILE64 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEPRO ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CUDA ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEGX ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_CLOUDSHIELD ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_COREA_1ST ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_COREA_2ND ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC_COMPACT2 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_OPEN8 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_RL78 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE5 ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_78KOR ),
+ LLVM_READOBJ_ENUM_ENT(ELF, EM_56800EX )
+};
+
+static const EnumEntry<unsigned> ElfSymbolBindings[] = {
+ { "Local", ELF::STB_LOCAL },
+ { "Global", ELF::STB_GLOBAL },
+ { "Weak", ELF::STB_WEAK }
+};
+
+static const EnumEntry<unsigned> ElfSymbolTypes[] = {
+ { "None", ELF::STT_NOTYPE },
+ { "Object", ELF::STT_OBJECT },
+ { "Function", ELF::STT_FUNC },
+ { "Section", ELF::STT_SECTION },
+ { "File", ELF::STT_FILE },
+ { "Common", ELF::STT_COMMON },
+ { "TLS", ELF::STT_TLS },
+ { "GNU_IFunc", ELF::STT_GNU_IFUNC }
+};
+
+static const char *getElfSectionType(unsigned Arch, unsigned Type) {
+ switch (Arch) {
+ case Triple::arm:
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_EXIDX);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_ATTRIBUTES);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_DEBUGOVERLAY);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_OVERLAYSECTION);
+ }
+ case Triple::hexagon:
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_HEX_ORDERED);
+ }
+ case Triple::x86_64:
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_X86_64_UNWIND);
+ }
+ case Triple::mips:
+ case Triple::mipsel:
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS);
+ }
+ }
+
+ switch (Type) {
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_NULL );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_PROGBITS );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_STRTAB );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_RELA );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_HASH );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNAMIC );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOTE );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOBITS );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_REL );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_SHLIB );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNSYM );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_INIT_ARRAY );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_FINI_ARRAY );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_PREINIT_ARRAY );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GROUP );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_HASH );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verdef );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verneed );
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_versym );
+ default: return "";
+ }
+}
+
+static const EnumEntry<unsigned> ElfSectionFlags[] = {
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_WRITE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_ALLOC ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_EXECINSTR ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_MERGE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_STRINGS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_INFO_LINK ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_LINK_ORDER ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_OS_NONCONFORMING),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_GROUP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_TLS ),
+ LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_CP_SECTION),
+ LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_DP_SECTION),
+ LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP )
+};
+
+static const EnumEntry<unsigned> ElfSegmentTypes[] = {
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_NULL ),
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_LOAD ),
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_DYNAMIC),
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_INTERP ),
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_NOTE ),
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_SHLIB ),
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_PHDR ),
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_TLS ),
+
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_GNU_EH_FRAME),
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_SUNW_EH_FRAME),
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_SUNW_UNWIND),
+
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_GNU_STACK),
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_GNU_RELRO),
+
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_ARM_EXIDX),
+ LLVM_READOBJ_ENUM_ENT(ELF, PT_ARM_UNWIND)
+};
+
+static const EnumEntry<unsigned> ElfSegmentFlags[] = {
+ LLVM_READOBJ_ENUM_ENT(ELF, PF_X),
+ LLVM_READOBJ_ENUM_ENT(ELF, PF_W),
+ LLVM_READOBJ_ENUM_ENT(ELF, PF_R)
+};
+
+
+template<class ELFT>
+void ELFDumper<ELFT>::printFileHeaders() {
+ error_code EC;
+
+ const typename ELFO::Elf_Ehdr *Header = Obj->getElfHeader();
+
+ {
+ DictScope D(W, "ElfHeader");
+ {
+ DictScope D(W, "Ident");
+ W.printBinary("Magic", makeArrayRef(Header->e_ident).slice(ELF::EI_MAG0,
+ 4));
+ W.printEnum ("Class", Header->e_ident[ELF::EI_CLASS],
+ makeArrayRef(ElfClass));
+ W.printEnum ("DataEncoding", Header->e_ident[ELF::EI_DATA],
+ makeArrayRef(ElfDataEncoding));
+ W.printNumber("FileVersion", Header->e_ident[ELF::EI_VERSION]);
+ W.printEnum ("OS/ABI", Header->e_ident[ELF::EI_OSABI],
+ makeArrayRef(ElfOSABI));
+ W.printNumber("ABIVersion", Header->e_ident[ELF::EI_ABIVERSION]);
+ W.printBinary("Unused", makeArrayRef(Header->e_ident).slice(ELF::EI_PAD));
+ }
+
+ W.printEnum ("Type", Header->e_type, makeArrayRef(ElfObjectFileType));
+ W.printEnum ("Machine", Header->e_machine, makeArrayRef(ElfMachineType));
+ W.printNumber("Version", Header->e_version);
+ W.printHex ("Entry", Header->e_entry);
+ W.printHex ("ProgramHeaderOffset", Header->e_phoff);
+ W.printHex ("SectionHeaderOffset", Header->e_shoff);
+ W.printFlags ("Flags", Header->e_flags);
+ W.printNumber("HeaderSize", Header->e_ehsize);
+ W.printNumber("ProgramHeaderEntrySize", Header->e_phentsize);
+ W.printNumber("ProgramHeaderCount", Header->e_phnum);
+ W.printNumber("SectionHeaderEntrySize", Header->e_shentsize);
+ W.printNumber("SectionHeaderCount", Header->e_shnum);
+ W.printNumber("StringTableSectionIndex", Header->e_shstrndx);
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printSections() {
+ ListScope SectionsD(W, "Sections");
+
+ int SectionIndex = -1;
+ error_code EC;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ if (error(EC)) break;
+
+ ++SectionIndex;
+
+ const Elf_Shdr *Section = Obj->getElfSection(SecI);
+ StringRef Name;
+ if (error(SecI->getName(Name)))
+ Name = "";
+
+ DictScope SectionD(W, "Section");
+ W.printNumber("Index", SectionIndex);
+ W.printNumber("Name", Name, Section->sh_name);
+ W.printHex ("Type", getElfSectionType(Obj->getArch(), Section->sh_type),
+ Section->sh_type);
+ W.printFlags ("Flags", Section->sh_flags, makeArrayRef(ElfSectionFlags));
+ W.printHex ("Address", Section->sh_addr);
+ W.printHex ("Offset", Section->sh_offset);
+ W.printNumber("Size", Section->sh_size);
+ W.printNumber("Link", Section->sh_link);
+ W.printNumber("Info", Section->sh_info);
+ W.printNumber("AddressAlignment", Section->sh_addralign);
+ W.printNumber("EntrySize", Section->sh_entsize);
+
+ if (opts::SectionRelocations) {
+ ListScope D(W, "Relocations");
+ for (relocation_iterator RelI = SecI->begin_relocations(),
+ RelE = SecI->end_relocations();
+ RelI != RelE; RelI.increment(EC)) {
+ if (error(EC)) break;
+
+ printRelocation(SecI, RelI);
+ }
+ }
+
+ if (opts::SectionSymbols) {
+ ListScope D(W, "Symbols");
+ for (symbol_iterator SymI = Obj->begin_symbols(),
+ SymE = Obj->end_symbols();
+ SymI != SymE; SymI.increment(EC)) {
+ if (error(EC)) break;
+
+ bool Contained = false;
+ if (SecI->containsSymbol(*SymI, Contained) || !Contained)
+ continue;
+
+ printSymbol(SymI);
+ }
+ }
+
+ if (opts::SectionData) {
+ StringRef Data;
+ if (error(SecI->getContents(Data))) break;
+
+ W.printBinaryBlock("SectionData", Data);
+ }
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printRelocations() {
+ ListScope D(W, "Relocations");
+
+ error_code EC;
+ int SectionNumber = -1;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ if (error(EC)) break;
+
+ ++SectionNumber;
+ StringRef Name;
+ if (error(SecI->getName(Name)))
+ continue;
+
+ bool PrintedGroup = false;
+ for (relocation_iterator RelI = SecI->begin_relocations(),
+ RelE = SecI->end_relocations();
+ RelI != RelE; RelI.increment(EC)) {
+ if (error(EC)) break;
+
+ if (!PrintedGroup) {
+ W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n";
+ W.indent();
+ PrintedGroup = true;
+ }
+
+ printRelocation(SecI, RelI);
+ }
+
+ if (PrintedGroup) {
+ W.unindent();
+ W.startLine() << "}\n";
+ }
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printRelocation(section_iterator Sec,
+ relocation_iterator RelI) {
+ uint64_t Offset;
+ uint64_t RelocType;
+ SmallString<32> RelocName;
+ int64_t Addend;
+ StringRef SymbolName;
+ if (Obj->getElfHeader()->e_type == ELF::ET_REL){
+ if (error(RelI->getOffset(Offset))) return;
+ } else {
+ if (error(RelI->getAddress(Offset))) return;
+ }
+ if (error(RelI->getType(RelocType))) return;
+ if (error(RelI->getTypeName(RelocName))) return;
+ if (error(getELFRelocationAddend(*RelI, Addend))) return;
+ symbol_iterator Symbol = RelI->getSymbol();
+ if (Symbol != Obj->end_symbols() && error(Symbol->getName(SymbolName)))
+ return;
+
+ if (opts::ExpandRelocs) {
+ DictScope Group(W, "Relocation");
+ W.printHex("Offset", Offset);
+ W.printNumber("Type", RelocName, RelocType);
+ W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-");
+ W.printHex("Addend", Addend);
+ } else {
+ raw_ostream& OS = W.startLine();
+ OS << W.hex(Offset)
+ << " " << RelocName
+ << " " << (SymbolName.size() > 0 ? SymbolName : "-")
+ << " " << W.hex(Addend)
+ << "\n";
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printSymbols() {
+ ListScope Group(W, "Symbols");
+
+ error_code EC;
+ for (symbol_iterator SymI = Obj->begin_symbols(), SymE = Obj->end_symbols();
+ SymI != SymE; SymI.increment(EC)) {
+ if (error(EC)) break;
+
+ printSymbol(SymI);
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printDynamicSymbols() {
+ ListScope Group(W, "DynamicSymbols");
+
+ error_code EC;
+ for (symbol_iterator SymI = Obj->begin_dynamic_symbols(),
+ SymE = Obj->end_dynamic_symbols();
+ SymI != SymE; SymI.increment(EC)) {
+ if (error(EC)) break;
+
+ printSymbol(SymI, true);
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printSymbol(symbol_iterator SymI, bool IsDynamic) {
+ error_code EC;
+
+ const Elf_Sym *Symbol = Obj->getElfSymbol(SymI);
+ const Elf_Shdr *Section = Obj->getSection(Symbol);
+
+ StringRef SymbolName;
+ if (SymI->getName(SymbolName))
+ SymbolName = "";
+
+ StringRef SectionName = "";
+ if (Section)
+ Obj->getSectionName(Section, SectionName);
+
+ std::string FullSymbolName(SymbolName);
+ if (IsDynamic) {
+ StringRef Version;
+ bool IsDefault;
+ if (error(Obj->getSymbolVersion(*SymI, Version, IsDefault)))
+ return;
+ if (!Version.empty()) {
+ FullSymbolName += (IsDefault ? "@@" : "@");
+ FullSymbolName += Version;
+ }
+ }
+
+ DictScope D(W, "Symbol");
+ W.printNumber("Name", FullSymbolName, Symbol->st_name);
+ W.printHex ("Value", Symbol->st_value);
+ W.printNumber("Size", Symbol->st_size);
+ W.printEnum ("Binding", Symbol->getBinding(),
+ makeArrayRef(ElfSymbolBindings));
+ W.printEnum ("Type", Symbol->getType(), makeArrayRef(ElfSymbolTypes));
+ W.printNumber("Other", Symbol->st_other);
+ W.printHex ("Section", SectionName, Symbol->st_shndx);
+}
+
+#define LLVM_READOBJ_TYPE_CASE(name) \
+ case DT_##name: return #name
+
+static const char *getTypeString(uint64_t Type) {
+ switch (Type) {
+ LLVM_READOBJ_TYPE_CASE(BIND_NOW);
+ LLVM_READOBJ_TYPE_CASE(DEBUG);
+ LLVM_READOBJ_TYPE_CASE(FINI);
+ LLVM_READOBJ_TYPE_CASE(FINI_ARRAY);
+ LLVM_READOBJ_TYPE_CASE(FINI_ARRAYSZ);
+ LLVM_READOBJ_TYPE_CASE(FLAGS);
+ LLVM_READOBJ_TYPE_CASE(HASH);
+ LLVM_READOBJ_TYPE_CASE(INIT);
+ LLVM_READOBJ_TYPE_CASE(INIT_ARRAY);
+ LLVM_READOBJ_TYPE_CASE(INIT_ARRAYSZ);
+ LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAY);
+ LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAYSZ);
+ LLVM_READOBJ_TYPE_CASE(JMPREL);
+ LLVM_READOBJ_TYPE_CASE(NEEDED);
+ LLVM_READOBJ_TYPE_CASE(NULL);
+ LLVM_READOBJ_TYPE_CASE(PLTGOT);
+ LLVM_READOBJ_TYPE_CASE(PLTREL);
+ LLVM_READOBJ_TYPE_CASE(PLTRELSZ);
+ LLVM_READOBJ_TYPE_CASE(REL);
+ LLVM_READOBJ_TYPE_CASE(RELA);
+ LLVM_READOBJ_TYPE_CASE(RELENT);
+ LLVM_READOBJ_TYPE_CASE(RELSZ);
+ LLVM_READOBJ_TYPE_CASE(RELAENT);
+ LLVM_READOBJ_TYPE_CASE(RELASZ);
+ LLVM_READOBJ_TYPE_CASE(RPATH);
+ LLVM_READOBJ_TYPE_CASE(RUNPATH);
+ LLVM_READOBJ_TYPE_CASE(SONAME);
+ LLVM_READOBJ_TYPE_CASE(STRSZ);
+ LLVM_READOBJ_TYPE_CASE(STRTAB);
+ LLVM_READOBJ_TYPE_CASE(SYMBOLIC);
+ LLVM_READOBJ_TYPE_CASE(SYMENT);
+ LLVM_READOBJ_TYPE_CASE(SYMTAB);
+ LLVM_READOBJ_TYPE_CASE(TEXTREL);
+ default: return "unknown";
+ }
+}
+
+#undef LLVM_READOBJ_TYPE_CASE
+
+template<class ELFT>
+static void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type,
+ uint64_t Value, bool Is64, raw_ostream &OS) {
+ switch (Type) {
+ case DT_PLTREL:
+ if (Value == DT_REL) {
+ OS << "REL";
+ break;
+ } else if (Value == DT_RELA) {
+ OS << "RELA";
+ break;
+ }
+ // Fallthrough.
+ case DT_PLTGOT:
+ case DT_HASH:
+ case DT_STRTAB:
+ case DT_SYMTAB:
+ case DT_RELA:
+ case DT_INIT:
+ case DT_FINI:
+ case DT_REL:
+ case DT_JMPREL:
+ case DT_INIT_ARRAY:
+ case DT_FINI_ARRAY:
+ case DT_PREINIT_ARRAY:
+ case DT_DEBUG:
+ case DT_NULL:
+ OS << format("0x%" PRIX64, Value);
+ break;
+ case DT_PLTRELSZ:
+ case DT_RELASZ:
+ case DT_RELAENT:
+ case DT_STRSZ:
+ case DT_SYMENT:
+ case DT_RELSZ:
+ case DT_RELENT:
+ case DT_INIT_ARRAYSZ:
+ case DT_FINI_ARRAYSZ:
+ case DT_PREINIT_ARRAYSZ:
+ OS << Value << " (bytes)";
+ break;
+ case DT_NEEDED:
+ OS << "SharedLibrary ("
+ << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")";
+ break;
+ case DT_SONAME:
+ OS << "LibrarySoname ("
+ << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")";
+ break;
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printUnwindInfo() {
+ W.startLine() << "UnwindInfo not implemented.\n";
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printDynamicTable() {
+ typedef typename ELFO::Elf_Dyn_iterator EDI;
+ EDI Start = Obj->begin_dynamic_table(),
+ End = Obj->end_dynamic_table(true);
+
+ if (Start == End)
+ return;
+
+ ptrdiff_t Total = std::distance(Start, End);
+ raw_ostream &OS = W.getOStream();
+ W.startLine() << "DynamicSection [ (" << Total << " entries)\n";
+
+ bool Is64 = Obj->getBytesInAddress() == 8;
+
+ W.startLine()
+ << " Tag" << (Is64 ? " " : " ") << "Type"
+ << " " << "Name/Value\n";
+ for (; Start != End; ++Start) {
+ W.startLine()
+ << " "
+ << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Start->getTag())
+ << " " << format("%-21s", getTypeString(Start->getTag()));
+ printValue(Obj, Start->getTag(), Start->getVal(), Is64, OS);
+ OS << "\n";
+ }
+
+ W.startLine() << "]\n";
+}
+
+static bool compareLibraryName(const LibraryRef &L, const LibraryRef &R) {
+ StringRef LPath, RPath;
+ L.getPath(LPath);
+ R.getPath(RPath);
+ return LPath < RPath;
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printNeededLibraries() {
+ ListScope D(W, "NeededLibraries");
+
+ error_code EC;
+
+ typedef std::vector<LibraryRef> LibsTy;
+ LibsTy Libs;
+
+ for (library_iterator I = Obj->begin_libraries_needed(),
+ E = Obj->end_libraries_needed();
+ I != E; I.increment(EC)) {
+ if (EC)
+ report_fatal_error("Needed libraries iteration failed");
+
+ Libs.push_back(*I);
+ }
+
+ std::sort(Libs.begin(), Libs.end(), &compareLibraryName);
+
+ for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end();
+ I != E; ++I) {
+ StringRef Path;
+ I->getPath(Path);
+ outs() << " " << Path << "\n";
+ }
+}
+
+template<class ELFT>
+void ELFDumper<ELFT>::printProgramHeaders() {
+ ListScope L(W, "ProgramHeaders");
+
+ for (typename ELFO::Elf_Phdr_Iter PI = Obj->begin_program_headers(),
+ PE = Obj->end_program_headers();
+ PI != PE; ++PI) {
+ DictScope P(W, "ProgramHeader");
+ W.printEnum ("Type", PI->p_type, makeArrayRef(ElfSegmentTypes));
+ W.printHex ("Offset", PI->p_offset);
+ W.printHex ("VirtualAddress", PI->p_vaddr);
+ W.printHex ("PhysicalAddress", PI->p_paddr);
+ W.printNumber("FileSize", PI->p_filesz);
+ W.printNumber("MemSize", PI->p_memsz);
+ W.printFlags ("Flags", PI->p_flags, makeArrayRef(ElfSegmentFlags));
+ W.printNumber("Alignment", PI->p_align);
+ }
+}
diff --git a/tools/llvm-readobj/Error.cpp b/tools/llvm-readobj/Error.cpp
new file mode 100644
index 0000000..a6c6132
--- /dev/null
+++ b/tools/llvm-readobj/Error.cpp
@@ -0,0 +1,62 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines a new error_category for the llvm-readobj tool.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+namespace {
+class _readobj_error_category : public _do_message {
+public:
+ virtual const char* name() const;
+ virtual std::string message(int ev) const;
+ virtual error_condition default_error_condition(int ev) const;
+};
+} // namespace
+
+const char *_readobj_error_category::name() const {
+ return "llvm.readobj";
+}
+
+std::string _readobj_error_category::message(int ev) const {
+ switch (ev) {
+ case readobj_error::success: return "Success";
+ case readobj_error::file_not_found:
+ return "No such file.";
+ case readobj_error::unsupported_file_format:
+ return "The file was not recognized as a valid object file.";
+ case readobj_error::unrecognized_file_format:
+ return "Unrecognized file type.";
+ case readobj_error::unsupported_obj_file_format:
+ return "Unsupported object file format.";
+ case readobj_error::unknown_symbol:
+ return "Unknown symbol.";
+ default:
+ llvm_unreachable("An enumerator of readobj_error does not have a message "
+ "defined.");
+ }
+}
+
+error_condition _readobj_error_category::default_error_condition(int ev) const {
+ if (ev == readobj_error::success)
+ return errc::success;
+ return errc::invalid_argument;
+}
+
+namespace llvm {
+const error_category &readobj_category() {
+ static _readobj_error_category o;
+ return o;
+}
+} // namespace llvm
diff --git a/tools/llvm-readobj/Error.h b/tools/llvm-readobj/Error.h
new file mode 100644
index 0000000..cf68da8
--- /dev/null
+++ b/tools/llvm-readobj/Error.h
@@ -0,0 +1,48 @@
+//===- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This declares a new error_category for the llvm-readobj tool.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_READOBJ_ERROR_H
+#define LLVM_READOBJ_ERROR_H
+
+#include "llvm/Support/system_error.h"
+
+namespace llvm {
+
+const error_category &readobj_category();
+
+struct readobj_error {
+ enum _ {
+ success = 0,
+ file_not_found,
+ unsupported_file_format,
+ unrecognized_file_format,
+ unsupported_obj_file_format,
+ unknown_symbol
+ };
+ _ v_;
+
+ readobj_error(_ v) : v_(v) {}
+ explicit readobj_error(int v) : v_(_(v)) {}
+ operator int() const {return v_;}
+};
+
+inline error_code make_error_code(readobj_error e) {
+ return error_code(static_cast<int>(e), readobj_category());
+}
+
+template <> struct is_error_code_enum<readobj_error> : true_type { };
+template <> struct is_error_code_enum<readobj_error::_> : true_type { };
+
+} // namespace llvm
+
+#endif
diff --git a/tools/llvm-readobj/LLVMBuild.txt b/tools/llvm-readobj/LLVMBuild.txt
index c9f934f..e75f195 100644
--- a/tools/llvm-readobj/LLVMBuild.txt
+++ b/tools/llvm-readobj/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-readobj
parent = Tools
-required_libraries = Archive BitReader Object
+required_libraries = all-targets BitReader Object
diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp
new file mode 100644
index 0000000..8df6fd6
--- /dev/null
+++ b/tools/llvm-readobj/MachODumper.cpp
@@ -0,0 +1,433 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the MachO-specific dumper for llvm-readobj.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-readobj.h"
+#include "Error.h"
+#include "ObjDumper.h"
+#include "StreamWriter.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/Casting.h"
+
+using namespace llvm;
+using namespace object;
+
+namespace {
+
+class MachODumper : public ObjDumper {
+public:
+ MachODumper(const MachOObjectFile *Obj, StreamWriter& Writer)
+ : ObjDumper(Writer)
+ , Obj(Obj) { }
+
+ virtual void printFileHeaders() LLVM_OVERRIDE;
+ virtual void printSections() LLVM_OVERRIDE;
+ virtual void printRelocations() LLVM_OVERRIDE;
+ virtual void printSymbols() LLVM_OVERRIDE;
+ virtual void printDynamicSymbols() LLVM_OVERRIDE;
+ virtual void printUnwindInfo() LLVM_OVERRIDE;
+
+private:
+ void printSymbol(symbol_iterator SymI);
+
+ void printRelocation(section_iterator SecI, relocation_iterator RelI);
+
+ void printRelocation(const MachOObjectFile *Obj,
+ section_iterator SecI, relocation_iterator RelI);
+
+ void printSections(const MachOObjectFile *Obj);
+
+ const MachOObjectFile *Obj;
+};
+
+} // namespace
+
+
+namespace llvm {
+
+error_code createMachODumper(const object::ObjectFile *Obj,
+ StreamWriter& Writer,
+ OwningPtr<ObjDumper> &Result) {
+ const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj);
+ if (!MachOObj)
+ return readobj_error::unsupported_obj_file_format;
+
+ Result.reset(new MachODumper(MachOObj, Writer));
+ return readobj_error::success;
+}
+
+} // namespace llvm
+
+
+static const EnumEntry<unsigned> MachOSectionTypes[] = {
+ { "Regular" , 0x00 },
+ { "ZeroFill" , 0x01 },
+ { "CStringLiterals" , 0x02 },
+ { "4ByteLiterals" , 0x03 },
+ { "8ByteLiterals" , 0x04 },
+ { "LiteralPointers" , 0x05 },
+ { "NonLazySymbolPointers" , 0x06 },
+ { "LazySymbolPointers" , 0x07 },
+ { "SymbolStubs" , 0x08 },
+ { "ModInitFuncs" , 0x09 },
+ { "ModTermFuncs" , 0x0A },
+ { "Coalesced" , 0x0B },
+ { "GBZeroFill" , 0x0C },
+ { "Interposing" , 0x0D },
+ { "16ByteLiterals" , 0x0E },
+ { "DTraceDOF" , 0x0F },
+ { "LazyDylibSymbolPoints" , 0x10 },
+ { "ThreadLocalRegular" , 0x11 },
+ { "ThreadLocalZerofill" , 0x12 },
+ { "ThreadLocalVariables" , 0x13 },
+ { "ThreadLocalVariablePointers" , 0x14 },
+ { "ThreadLocalInitFunctionPointers", 0x15 }
+};
+
+static const EnumEntry<unsigned> MachOSectionAttributes[] = {
+ { "LocReloc" , 1 << 0 /*S_ATTR_LOC_RELOC */ },
+ { "ExtReloc" , 1 << 1 /*S_ATTR_EXT_RELOC */ },
+ { "SomeInstructions" , 1 << 2 /*S_ATTR_SOME_INSTRUCTIONS */ },
+ { "Debug" , 1 << 17 /*S_ATTR_DEBUG */ },
+ { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ },
+ { "LiveSupport" , 1 << 19 /*S_ATTR_LIVE_SUPPORT */ },
+ { "NoDeadStrip" , 1 << 20 /*S_ATTR_NO_DEAD_STRIP */ },
+ { "StripStaticSyms" , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS */ },
+ { "NoTOC" , 1 << 22 /*S_ATTR_NO_TOC */ },
+ { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS */ },
+};
+
+static const EnumEntry<unsigned> MachOSymbolRefTypes[] = {
+ { "UndefinedNonLazy", 0 },
+ { "ReferenceFlagUndefinedLazy", 1 },
+ { "ReferenceFlagDefined", 2 },
+ { "ReferenceFlagPrivateDefined", 3 },
+ { "ReferenceFlagPrivateUndefinedNonLazy", 4 },
+ { "ReferenceFlagPrivateUndefinedLazy", 5 }
+};
+
+static const EnumEntry<unsigned> MachOSymbolFlags[] = {
+ { "ReferencedDynamically", 0x10 },
+ { "NoDeadStrip", 0x20 },
+ { "WeakRef", 0x40 },
+ { "WeakDef", 0x80 }
+};
+
+static const EnumEntry<unsigned> MachOSymbolTypes[] = {
+ { "Undef", 0x0 },
+ { "External", 0x1 },
+ { "Abs", 0x2 },
+ { "Indirect", 0xA },
+ { "PreboundUndef", 0xC },
+ { "Section", 0xE },
+ { "PrivateExternal", 0x10 }
+};
+
+namespace {
+ enum {
+ N_STAB = 0xE0
+ };
+
+ struct MachOSection {
+ ArrayRef<char> Name;
+ ArrayRef<char> SegmentName;
+ uint64_t Address;
+ uint64_t Size;
+ uint32_t Offset;
+ uint32_t Alignment;
+ uint32_t RelocationTableOffset;
+ uint32_t NumRelocationTableEntries;
+ uint32_t Flags;
+ uint32_t Reserved1;
+ uint32_t Reserved2;
+ };
+
+ struct MachOSymbol {
+ uint32_t StringIndex;
+ uint8_t Type;
+ uint8_t SectionIndex;
+ uint16_t Flags;
+ uint64_t Value;
+ };
+}
+
+static void getSection(const MachOObjectFile *Obj,
+ DataRefImpl Sec,
+ MachOSection &Section) {
+ if (!Obj->is64Bit()) {
+ macho::Section Sect = Obj->getSection(Sec);
+ Section.Address = Sect.Address;
+ Section.Size = Sect.Size;
+ Section.Offset = Sect.Offset;
+ Section.Alignment = Sect.Align;
+ Section.RelocationTableOffset = Sect.RelocationTableOffset;
+ Section.NumRelocationTableEntries = Sect.NumRelocationTableEntries;
+ Section.Flags = Sect.Flags;
+ Section.Reserved1 = Sect.Reserved1;
+ Section.Reserved2 = Sect.Reserved2;
+ return;
+ }
+ macho::Section64 Sect = Obj->getSection64(Sec);
+ Section.Address = Sect.Address;
+ Section.Size = Sect.Size;
+ Section.Offset = Sect.Offset;
+ Section.Alignment = Sect.Align;
+ Section.RelocationTableOffset = Sect.RelocationTableOffset;
+ Section.NumRelocationTableEntries = Sect.NumRelocationTableEntries;
+ Section.Flags = Sect.Flags;
+ Section.Reserved1 = Sect.Reserved1;
+ Section.Reserved2 = Sect.Reserved2;
+}
+
+
+static void getSymbol(const MachOObjectFile *Obj,
+ DataRefImpl DRI,
+ MachOSymbol &Symbol) {
+ if (!Obj->is64Bit()) {
+ macho::SymbolTableEntry Entry = Obj->getSymbolTableEntry(DRI);
+ Symbol.StringIndex = Entry.StringIndex;
+ Symbol.Type = Entry.Type;
+ Symbol.SectionIndex = Entry.SectionIndex;
+ Symbol.Flags = Entry.Flags;
+ Symbol.Value = Entry.Value;
+ return;
+ }
+ macho::Symbol64TableEntry Entry = Obj->getSymbol64TableEntry(DRI);
+ Symbol.StringIndex = Entry.StringIndex;
+ Symbol.Type = Entry.Type;
+ Symbol.SectionIndex = Entry.SectionIndex;
+ Symbol.Flags = Entry.Flags;
+ Symbol.Value = Entry.Value;
+}
+
+void MachODumper::printFileHeaders() {
+ W.startLine() << "FileHeaders not implemented.\n";
+}
+
+void MachODumper::printSections() {
+ return printSections(Obj);
+}
+
+void MachODumper::printSections(const MachOObjectFile *Obj) {
+ ListScope Group(W, "Sections");
+
+ int SectionIndex = -1;
+ error_code EC;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ if (error(EC)) break;
+
+ ++SectionIndex;
+
+ MachOSection Section;
+ getSection(Obj, SecI->getRawDataRefImpl(), Section);
+ DataRefImpl DR = SecI->getRawDataRefImpl();
+
+ StringRef Name;
+ if (error(SecI->getName(Name)))
+ Name = "";
+
+ ArrayRef<char> RawName = Obj->getSectionRawName(DR);
+ StringRef SegmentName = Obj->getSectionFinalSegmentName(DR);
+ ArrayRef<char> RawSegmentName = Obj->getSectionRawFinalSegmentName(DR);
+
+ DictScope SectionD(W, "Section");
+ W.printNumber("Index", SectionIndex);
+ W.printBinary("Name", Name, RawName);
+ W.printBinary("Segment", SegmentName, RawSegmentName);
+ W.printHex ("Address", Section.Address);
+ W.printHex ("Size", Section.Size);
+ W.printNumber("Offset", Section.Offset);
+ W.printNumber("Alignment", Section.Alignment);
+ W.printHex ("RelocationOffset", Section.RelocationTableOffset);
+ W.printNumber("RelocationCount", Section.NumRelocationTableEntries);
+ W.printEnum ("Type", Section.Flags & 0xFF,
+ makeArrayRef(MachOSectionAttributes));
+ W.printFlags ("Attributes", Section.Flags >> 8,
+ makeArrayRef(MachOSectionAttributes));
+ W.printHex ("Reserved1", Section.Reserved1);
+ W.printHex ("Reserved2", Section.Reserved2);
+
+ if (opts::SectionRelocations) {
+ ListScope D(W, "Relocations");
+ for (relocation_iterator RelI = SecI->begin_relocations(),
+ RelE = SecI->end_relocations();
+ RelI != RelE; RelI.increment(EC)) {
+ if (error(EC)) break;
+
+ printRelocation(SecI, RelI);
+ }
+ }
+
+ if (opts::SectionSymbols) {
+ ListScope D(W, "Symbols");
+ for (symbol_iterator SymI = Obj->begin_symbols(),
+ SymE = Obj->end_symbols();
+ SymI != SymE; SymI.increment(EC)) {
+ if (error(EC)) break;
+
+ bool Contained = false;
+ if (SecI->containsSymbol(*SymI, Contained) || !Contained)
+ continue;
+
+ printSymbol(SymI);
+ }
+ }
+
+ if (opts::SectionData) {
+ StringRef Data;
+ if (error(SecI->getContents(Data))) break;
+
+ W.printBinaryBlock("SectionData", Data);
+ }
+ }
+}
+
+void MachODumper::printRelocations() {
+ ListScope D(W, "Relocations");
+
+ error_code EC;
+ for (section_iterator SecI = Obj->begin_sections(),
+ SecE = Obj->end_sections();
+ SecI != SecE; SecI.increment(EC)) {
+ if (error(EC)) break;
+
+ StringRef Name;
+ if (error(SecI->getName(Name)))
+ continue;
+
+ bool PrintedGroup = false;
+ for (relocation_iterator RelI = SecI->begin_relocations(),
+ RelE = SecI->end_relocations();
+ RelI != RelE; RelI.increment(EC)) {
+ if (error(EC)) break;
+
+ if (!PrintedGroup) {
+ W.startLine() << "Section " << Name << " {\n";
+ W.indent();
+ PrintedGroup = true;
+ }
+
+ printRelocation(SecI, RelI);
+ }
+
+ if (PrintedGroup) {
+ W.unindent();
+ W.startLine() << "}\n";
+ }
+ }
+}
+
+void MachODumper::printRelocation(section_iterator SecI,
+ relocation_iterator RelI) {
+ return printRelocation(Obj, SecI, RelI);
+}
+
+void MachODumper::printRelocation(const MachOObjectFile *Obj,
+ section_iterator SecI,
+ relocation_iterator RelI) {
+ uint64_t Offset;
+ SmallString<32> RelocName;
+ StringRef SymbolName;
+ if (error(RelI->getOffset(Offset))) return;
+ if (error(RelI->getTypeName(RelocName))) return;
+ symbol_iterator Symbol = RelI->getSymbol();
+ if (Symbol != Obj->end_symbols() &&
+ error(Symbol->getName(SymbolName)))
+ return;
+
+ DataRefImpl DR = RelI->getRawDataRefImpl();
+ macho::RelocationEntry RE = Obj->getRelocation(DR);
+ bool IsScattered = Obj->isRelocationScattered(RE);
+
+ if (opts::ExpandRelocs) {
+ DictScope Group(W, "Relocation");
+ W.printHex("Offset", Offset);
+ W.printNumber("PCRel", Obj->getAnyRelocationPCRel(RE));
+ W.printNumber("Length", Obj->getAnyRelocationLength(RE));
+ if (IsScattered)
+ W.printString("Extern", StringRef("N/A"));
+ else
+ W.printNumber("Extern", Obj->getPlainRelocationExternal(RE));
+ W.printNumber("Type", RelocName, Obj->getAnyRelocationType(RE));
+ W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-");
+ W.printNumber("Scattered", IsScattered);
+ } else {
+ raw_ostream& OS = W.startLine();
+ OS << W.hex(Offset)
+ << " " << Obj->getAnyRelocationPCRel(RE)
+ << " " << Obj->getAnyRelocationLength(RE);
+ if (IsScattered)
+ OS << " n/a";
+ else
+ OS << " " << Obj->getPlainRelocationExternal(RE);
+ OS << " " << RelocName
+ << " " << IsScattered
+ << " " << (SymbolName.size() > 0 ? SymbolName : "-")
+ << "\n";
+ }
+}
+
+void MachODumper::printSymbols() {
+ ListScope Group(W, "Symbols");
+
+ error_code EC;
+ for (symbol_iterator SymI = Obj->begin_symbols(),
+ SymE = Obj->end_symbols();
+ SymI != SymE; SymI.increment(EC)) {
+ if (error(EC)) break;
+
+ printSymbol(SymI);
+ }
+}
+
+void MachODumper::printDynamicSymbols() {
+ ListScope Group(W, "DynamicSymbols");
+}
+
+void MachODumper::printSymbol(symbol_iterator SymI) {
+ error_code EC;
+
+ StringRef SymbolName;
+ if (SymI->getName(SymbolName))
+ SymbolName = "";
+
+ MachOSymbol Symbol;
+ getSymbol(Obj, SymI->getRawDataRefImpl(), Symbol);
+
+ StringRef SectionName = "";
+ section_iterator SecI(Obj->end_sections());
+ if (!error(SymI->getSection(SecI)) &&
+ SecI != Obj->end_sections())
+ error(SecI->getName(SectionName));
+
+ DictScope D(W, "Symbol");
+ W.printNumber("Name", SymbolName, Symbol.StringIndex);
+ if (Symbol.Type & N_STAB) {
+ W.printHex ("Type", "SymDebugTable", Symbol.Type);
+ } else {
+ W.printEnum("Type", Symbol.Type, makeArrayRef(MachOSymbolTypes));
+ }
+ W.printHex ("Section", SectionName, Symbol.SectionIndex);
+ W.printEnum ("RefType", static_cast<uint16_t>(Symbol.Flags & 0xF),
+ makeArrayRef(MachOSymbolRefTypes));
+ W.printFlags ("Flags", static_cast<uint16_t>(Symbol.Flags & ~0xF),
+ makeArrayRef(MachOSymbolFlags));
+ W.printHex ("Value", Symbol.Value);
+}
+
+void MachODumper::printUnwindInfo() {
+ W.startLine() << "UnwindInfo not implemented.\n";
+}
diff --git a/tools/llvm-readobj/Makefile b/tools/llvm-readobj/Makefile
index a7a7de3..958bd0c 100644
--- a/tools/llvm-readobj/Makefile
+++ b/tools/llvm-readobj/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-readobj
-LINK_COMPONENTS := archive bitreader object
+LINK_COMPONENTS := bitreader object all-targets
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-readobj/ObjDumper.cpp b/tools/llvm-readobj/ObjDumper.cpp
new file mode 100644
index 0000000..61f5117
--- /dev/null
+++ b/tools/llvm-readobj/ObjDumper.cpp
@@ -0,0 +1,33 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements ObjDumper.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ObjDumper.h"
+
+#include "Error.h"
+#include "StreamWriter.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+ObjDumper::ObjDumper(StreamWriter& Writer)
+ : W(Writer) {
+}
+
+ObjDumper::~ObjDumper() {
+}
+
+} // namespace llvm
diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h
new file mode 100644
index 0000000..6918e28
--- /dev/null
+++ b/tools/llvm-readobj/ObjDumper.h
@@ -0,0 +1,61 @@
+//===-- ObjDumper.h -------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_READOBJ_OBJDUMPER_H
+#define LLVM_READOBJ_OBJDUMPER_H
+
+namespace llvm {
+
+namespace object {
+ class ObjectFile;
+}
+
+class error_code;
+
+template<typename T>
+class OwningPtr;
+
+class StreamWriter;
+
+class ObjDumper {
+public:
+ ObjDumper(StreamWriter& Writer);
+ virtual ~ObjDumper();
+
+ virtual void printFileHeaders() = 0;
+ virtual void printSections() = 0;
+ virtual void printRelocations() = 0;
+ virtual void printSymbols() = 0;
+ virtual void printDynamicSymbols() = 0;
+ virtual void printUnwindInfo() = 0;
+
+ // Only implemented for ELF at this time.
+ virtual void printDynamicTable() { }
+ virtual void printNeededLibraries() { }
+ virtual void printProgramHeaders() { }
+
+protected:
+ StreamWriter& W;
+};
+
+error_code createCOFFDumper(const object::ObjectFile *Obj,
+ StreamWriter& Writer,
+ OwningPtr<ObjDumper> &Result);
+
+error_code createELFDumper(const object::ObjectFile *Obj,
+ StreamWriter& Writer,
+ OwningPtr<ObjDumper> &Result);
+
+error_code createMachODumper(const object::ObjectFile *Obj,
+ StreamWriter& Writer,
+ OwningPtr<ObjDumper> &Result);
+
+} // namespace llvm
+
+#endif
diff --git a/tools/llvm-readobj/StreamWriter.cpp b/tools/llvm-readobj/StreamWriter.cpp
new file mode 100644
index 0000000..8718112
--- /dev/null
+++ b/tools/llvm-readobj/StreamWriter.cpp
@@ -0,0 +1,79 @@
+#include "StreamWriter.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Format.h"
+#include <cctype>
+
+using namespace llvm::support;
+
+namespace llvm {
+
+raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value) {
+ uint64_t N = Value.Value;
+ // Zero is a special case.
+ if (N == 0)
+ return OS << "0x0";
+
+ char NumberBuffer[20];
+ char *EndPtr = NumberBuffer + sizeof(NumberBuffer);
+ char *CurPtr = EndPtr;
+
+ while (N) {
+ uintptr_t X = N % 16;
+ *--CurPtr = (X < 10 ? '0' + X : 'A' + X - 10);
+ N /= 16;
+ }
+
+ OS << "0x";
+ return OS.write(CurPtr, EndPtr - CurPtr);
+}
+
+void StreamWriter::printBinaryImpl(StringRef Label, StringRef Str,
+ ArrayRef<uint8_t> Data, bool Block) {
+ if (Data.size() > 16)
+ Block = true;
+
+ if (Block) {
+ startLine() << Label;
+ if (Str.size() > 0)
+ OS << ": " << Str;
+ OS << " (\n";
+ for (size_t addr = 0, end = Data.size(); addr < end; addr += 16) {
+ startLine() << format(" %04" PRIX64 ": ", uint64_t(addr));
+ // Dump line of hex.
+ for (size_t i = 0; i < 16; ++i) {
+ if (i != 0 && i % 4 == 0)
+ OS << ' ';
+ if (addr + i < end)
+ OS << hexdigit((Data[addr + i] >> 4) & 0xF, false)
+ << hexdigit(Data[addr + i] & 0xF, false);
+ else
+ OS << " ";
+ }
+ // Print ascii.
+ OS << " |";
+ for (std::size_t i = 0; i < 16 && addr + i < end; ++i) {
+ if (std::isprint(Data[addr + i] & 0xFF))
+ OS << Data[addr + i];
+ else
+ OS << ".";
+ }
+ OS << "|\n";
+ }
+
+ startLine() << ")\n";
+ } else {
+ startLine() << Label << ":";
+ if (Str.size() > 0)
+ OS << " " << Str;
+ OS << " (";
+ for (size_t i = 0; i < Data.size(); ++i) {
+ if (i > 0)
+ OS << " ";
+
+ OS << format("%02X", static_cast<int>(Data[i]));
+ }
+ OS << ")\n";
+ }
+}
+
+} // namespace llvm
diff --git a/tools/llvm-readobj/StreamWriter.h b/tools/llvm-readobj/StreamWriter.h
new file mode 100644
index 0000000..129f6e7
--- /dev/null
+++ b/tools/llvm-readobj/StreamWriter.h
@@ -0,0 +1,282 @@
+//===-- StreamWriter.h ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_READOBJ_STREAMWRITER_H
+#define LLVM_READOBJ_STREAMWRITER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::support;
+
+namespace llvm {
+
+template<typename T>
+struct EnumEntry {
+ StringRef Name;
+ T Value;
+};
+
+struct HexNumber {
+ // To avoid sign-extension we have to explicitly cast to the appropriate
+ // unsigned type. The overloads are here so that every type that is implicitly
+ // convertible to an integer (including enums and endian helpers) can be used
+ // without requiring type traits or call-site changes.
+ HexNumber(int8_t Value) : Value(static_cast<uint8_t >(Value)) { }
+ HexNumber(int16_t Value) : Value(static_cast<uint16_t>(Value)) { }
+ HexNumber(int32_t Value) : Value(static_cast<uint32_t>(Value)) { }
+ HexNumber(int64_t Value) : Value(static_cast<uint64_t>(Value)) { }
+ HexNumber(uint8_t Value) : Value(Value) { }
+ HexNumber(uint16_t Value) : Value(Value) { }
+ HexNumber(uint32_t Value) : Value(Value) { }
+ HexNumber(uint64_t Value) : Value(Value) { }
+ uint64_t Value;
+};
+
+raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value);
+
+class StreamWriter {
+public:
+ StreamWriter(raw_ostream &OS)
+ : OS(OS)
+ , IndentLevel(0) {
+ }
+
+ void flush() {
+ OS.flush();
+ }
+
+ void indent(int Levels = 1) {
+ IndentLevel += Levels;
+ }
+
+ void unindent(int Levels = 1) {
+ IndentLevel = std::max(0, IndentLevel - Levels);
+ }
+
+ void printIndent() {
+ for (int i = 0; i < IndentLevel; ++i)
+ OS << " ";
+ }
+
+ template<typename T>
+ HexNumber hex(T Value) {
+ return HexNumber(Value);
+ }
+
+ template<typename T, typename TEnum>
+ void printEnum(StringRef Label, T Value,
+ ArrayRef<EnumEntry<TEnum> > EnumValues) {
+ StringRef Name;
+ bool Found = false;
+ for (size_t i = 0; i < EnumValues.size(); ++i) {
+ if (EnumValues[i].Value == Value) {
+ Name = EnumValues[i].Name;
+ Found = true;
+ break;
+ }
+ }
+
+ if (Found) {
+ startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n";
+ } else {
+ startLine() << Label << ": " << hex(Value) << "\n";
+ }
+ }
+
+ template<typename T, typename TFlag>
+ void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag> > Flags,
+ TFlag EnumMask = TFlag(0)) {
+ typedef EnumEntry<TFlag> FlagEntry;
+ typedef SmallVector<FlagEntry, 10> FlagVector;
+ FlagVector SetFlags;
+
+ for (typename ArrayRef<FlagEntry>::const_iterator I = Flags.begin(),
+ E = Flags.end(); I != E; ++I) {
+ if (I->Value == 0)
+ continue;
+
+ bool IsEnum = (I->Value & EnumMask) != 0;
+ if ((!IsEnum && (Value & I->Value) == I->Value) ||
+ (IsEnum && (Value & EnumMask) == I->Value)) {
+ SetFlags.push_back(*I);
+ }
+ }
+
+ std::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>);
+
+ startLine() << Label << " [ (" << hex(Value) << ")\n";
+ for (typename FlagVector::const_iterator I = SetFlags.begin(),
+ E = SetFlags.end();
+ I != E; ++I) {
+ startLine() << " " << I->Name << " (" << hex(I->Value) << ")\n";
+ }
+ startLine() << "]\n";
+ }
+
+ template<typename T>
+ void printFlags(StringRef Label, T Value) {
+ startLine() << Label << " [ (" << hex(Value) << ")\n";
+ uint64_t Flag = 1;
+ uint64_t Curr = Value;
+ while (Curr > 0) {
+ if (Curr & 1)
+ startLine() << " " << hex(Flag) << "\n";
+ Curr >>= 1;
+ Flag <<= 1;
+ }
+ startLine() << "]\n";
+ }
+
+ void printNumber(StringRef Label, uint64_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, uint32_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, uint16_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, uint8_t Value) {
+ startLine() << Label << ": " << unsigned(Value) << "\n";
+ }
+
+ void printNumber(StringRef Label, int64_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, int32_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, int16_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printNumber(StringRef Label, int8_t Value) {
+ startLine() << Label << ": " << int(Value) << "\n";
+ }
+
+ template<typename T>
+ void printHex(StringRef Label, T Value) {
+ startLine() << Label << ": " << hex(Value) << "\n";
+ }
+
+ template<typename T>
+ void printHex(StringRef Label, StringRef Str, T Value) {
+ startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n";
+ }
+
+ void printString(StringRef Label, StringRef Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printString(StringRef Label, const std::string &Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ template<typename T>
+ void printNumber(StringRef Label, StringRef Str, T Value) {
+ startLine() << Label << ": " << Str << " (" << Value << ")\n";
+ }
+
+ void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) {
+ printBinaryImpl(Label, Str, Value, false);
+ }
+
+ void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) {
+ ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
+ printBinaryImpl(Label, Str, V, false);
+ }
+
+ void printBinary(StringRef Label, ArrayRef<uint8_t> Value) {
+ printBinaryImpl(Label, StringRef(), Value, false);
+ }
+
+ void printBinary(StringRef Label, ArrayRef<char> Value) {
+ ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
+ printBinaryImpl(Label, StringRef(), V, false);
+ }
+
+ void printBinary(StringRef Label, StringRef Value) {
+ ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
+ printBinaryImpl(Label, StringRef(), V, false);
+ }
+
+ void printBinaryBlock(StringRef Label, StringRef Value) {
+ ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
+ printBinaryImpl(Label, StringRef(), V, true);
+ }
+
+ raw_ostream& startLine() {
+ printIndent();
+ return OS;
+ }
+
+ raw_ostream& getOStream() {
+ return OS;
+ }
+
+private:
+ template<typename T>
+ static bool flagName(const EnumEntry<T>& lhs, const EnumEntry<T>& rhs) {
+ return lhs.Name < rhs.Name;
+ }
+
+ void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value,
+ bool Block);
+
+ raw_ostream &OS;
+ int IndentLevel;
+};
+
+struct DictScope {
+ DictScope(StreamWriter& W, StringRef N) : W(W) {
+ W.startLine() << N << " {\n";
+ W.indent();
+ }
+
+ ~DictScope() {
+ W.unindent();
+ W.startLine() << "}\n";
+ }
+
+ StreamWriter& W;
+};
+
+struct ListScope {
+ ListScope(StreamWriter& W, StringRef N) : W(W) {
+ W.startLine() << N << " [\n";
+ W.indent();
+ }
+
+ ~ListScope() {
+ W.unindent();
+ W.startLine() << "]\n";
+ }
+
+ StreamWriter& W;
+};
+
+} // namespace llvm
+
+#endif
diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp
index 8f0917f..2e95b6b 100644
--- a/tools/llvm-readobj/llvm-readobj.cpp
+++ b/tools/llvm-readobj/llvm-readobj.cpp
@@ -21,261 +21,273 @@
#include "llvm-readobj.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Analysis/Verifier.h"
-#include "llvm/Object/ELF.h"
+#include "Error.h"
+#include "ObjDumper.h"
+#include "StreamWriter.h"
+
+#include "llvm/Object/Archive.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Debug.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/system_error.h"
-using namespace llvm;
-using namespace llvm::object;
-
-static cl::opt<std::string>
-InputFilename(cl::Positional, cl::desc("<input object>"), cl::init(""));
-
-static void dumpSymbolHeader() {
- outs() << format(" %-32s", (const char*)"Name")
- << format(" %-4s", (const char*)"Type")
- << format(" %-16s", (const char*)"Address")
- << format(" %-16s", (const char*)"Size")
- << format(" %-16s", (const char*)"FileOffset")
- << format(" %-26s", (const char*)"Flags")
- << "\n";
-}
+#include <string>
-static void dumpSectionHeader() {
- outs() << format(" %-24s", (const char*)"Name")
- << format(" %-16s", (const char*)"Address")
- << format(" %-16s", (const char*)"Size")
- << format(" %-8s", (const char*)"Align")
- << format(" %-26s", (const char*)"Flags")
- << "\n";
-}
-static const char *getTypeStr(SymbolRef::Type Type) {
- switch (Type) {
- case SymbolRef::ST_Unknown: return "?";
- case SymbolRef::ST_Data: return "DATA";
- case SymbolRef::ST_Debug: return "DBG";
- case SymbolRef::ST_File: return "FILE";
- case SymbolRef::ST_Function: return "FUNC";
- case SymbolRef::ST_Other: return "-";
- }
- return "INV";
-}
+using namespace llvm;
+using namespace llvm::object;
-static std::string getSymbolFlagStr(uint32_t Flags) {
- std::string result;
- if (Flags & SymbolRef::SF_Undefined)
- result += "undef,";
- if (Flags & SymbolRef::SF_Global)
- result += "global,";
- if (Flags & SymbolRef::SF_Weak)
- result += "weak,";
- if (Flags & SymbolRef::SF_Absolute)
- result += "absolute,";
- if (Flags & SymbolRef::SF_ThreadLocal)
- result += "threadlocal,";
- if (Flags & SymbolRef::SF_Common)
- result += "common,";
- if (Flags & SymbolRef::SF_FormatSpecific)
- result += "formatspecific,";
-
- // Remove trailing comma
- if (result.size() > 0) {
- result.erase(result.size() - 1);
- }
- return result;
+namespace opts {
+ cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input object files>"),
+ cl::ZeroOrMore);
+
+ // -file-headers, -h
+ cl::opt<bool> FileHeaders("file-headers",
+ cl::desc("Display file headers "));
+ cl::alias FileHeadersShort("h",
+ cl::desc("Alias for --file-headers"),
+ cl::aliasopt(FileHeaders));
+
+ // -sections, -s
+ cl::opt<bool> Sections("sections",
+ cl::desc("Display all sections."));
+ cl::alias SectionsShort("s",
+ cl::desc("Alias for --sections"),
+ cl::aliasopt(Sections));
+
+ // -section-relocations, -sr
+ cl::opt<bool> SectionRelocations("section-relocations",
+ cl::desc("Display relocations for each section shown."));
+ cl::alias SectionRelocationsShort("sr",
+ cl::desc("Alias for --section-relocations"),
+ cl::aliasopt(SectionRelocations));
+
+ // -section-symbols, -st
+ cl::opt<bool> SectionSymbols("section-symbols",
+ cl::desc("Display symbols for each section shown."));
+ cl::alias SectionSymbolsShort("st",
+ cl::desc("Alias for --section-symbols"),
+ cl::aliasopt(SectionSymbols));
+
+ // -section-data, -sd
+ cl::opt<bool> SectionData("section-data",
+ cl::desc("Display section data for each section shown."));
+ cl::alias SectionDataShort("sd",
+ cl::desc("Alias for --section-data"),
+ cl::aliasopt(SectionData));
+
+ // -relocations, -r
+ cl::opt<bool> Relocations("relocations",
+ cl::desc("Display the relocation entries in the file"));
+ cl::alias RelocationsShort("r",
+ cl::desc("Alias for --relocations"),
+ cl::aliasopt(Relocations));
+
+ // -symbols, -t
+ cl::opt<bool> Symbols("symbols",
+ cl::desc("Display the symbol table"));
+ cl::alias SymbolsShort("t",
+ cl::desc("Alias for --symbols"),
+ cl::aliasopt(Symbols));
+
+ // -dyn-symbols, -dt
+ cl::opt<bool> DynamicSymbols("dyn-symbols",
+ cl::desc("Display the dynamic symbol table"));
+ cl::alias DynamicSymbolsShort("dt",
+ cl::desc("Alias for --dyn-symbols"),
+ cl::aliasopt(DynamicSymbols));
+
+ // -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
+ cl::opt<bool> DynamicTable("dynamic-table",
+ cl::desc("Display the ELF .dynamic section table"));
+
+ // -needed-libs
+ cl::opt<bool> NeededLibraries("needed-libs",
+ cl::desc("Display the needed libraries"));
+
+ // -program-headers
+ cl::opt<bool> ProgramHeaders("program-headers",
+ cl::desc("Display ELF program headers"));
+
+ // -expand-relocs
+ cl::opt<bool> ExpandRelocs("expand-relocs",
+ cl::desc("Expand each shown relocation to multiple lines"));
+} // namespace opts
+
+namespace llvm {
+
+bool error(error_code EC) {
+ if (!EC)
+ return false;
+
+ outs() << "\nError reading file: " << EC.message() << ".\n";
+ outs().flush();
+ return true;
}
-static void checkError(error_code ec, const char *msg) {
- if (ec)
- report_fatal_error(std::string(msg) + ": " + ec.message());
+bool relocAddressLess(RelocationRef a, RelocationRef b) {
+ uint64_t a_addr, b_addr;
+ if (error(a.getOffset(a_addr))) return false;
+ if (error(b.getOffset(b_addr))) return false;
+ return a_addr < b_addr;
}
-static std::string getSectionFlagStr(const SectionRef &Section) {
- const struct {
- error_code (SectionRef::*MemF)(bool &) const;
- const char *FlagStr, *ErrorStr;
- } Work[] =
- {{ &SectionRef::isText, "text,", "Section.isText() failed" },
- { &SectionRef::isData, "data,", "Section.isData() failed" },
- { &SectionRef::isBSS, "bss,", "Section.isBSS() failed" },
- { &SectionRef::isRequiredForExecution, "required,",
- "Section.isRequiredForExecution() failed" },
- { &SectionRef::isVirtual, "virtual,", "Section.isVirtual() failed" },
- { &SectionRef::isZeroInit, "zeroinit,", "Section.isZeroInit() failed" },
- { &SectionRef::isReadOnlyData, "rodata,",
- "Section.isReadOnlyData() failed" }};
-
- std::string result;
- for (uint32_t I = 0; I < sizeof(Work)/sizeof(*Work); ++I) {
- bool B;
- checkError((Section.*Work[I].MemF)(B), Work[I].ErrorStr);
- if (B)
- result += Work[I].FlagStr;
- }
+} // namespace llvm
- // Remove trailing comma
- if (result.size() > 0) {
- result.erase(result.size() - 1);
- }
- return result;
-}
-static void
-dumpSymbol(const SymbolRef &Sym, const ObjectFile *obj, bool IsDynamic) {
- StringRef Name;
- SymbolRef::Type Type;
- uint32_t Flags;
- uint64_t Address;
- uint64_t Size;
- uint64_t FileOffset;
- checkError(Sym.getName(Name), "SymbolRef.getName() failed");
- checkError(Sym.getAddress(Address), "SymbolRef.getAddress() failed");
- checkError(Sym.getSize(Size), "SymbolRef.getSize() failed");
- checkError(Sym.getFileOffset(FileOffset),
- "SymbolRef.getFileOffset() failed");
- checkError(Sym.getType(Type), "SymbolRef.getType() failed");
- checkError(Sym.getFlags(Flags), "SymbolRef.getFlags() failed");
- std::string FullName = Name;
-
- // If this is a dynamic symbol from an ELF object, append
- // the symbol's version to the name.
- if (IsDynamic && obj->isELF()) {
- StringRef Version;
- bool IsDefault;
- GetELFSymbolVersion(obj, Sym, Version, IsDefault);
- if (!Version.empty()) {
- FullName += (IsDefault ? "@@" : "@");
- FullName += Version;
- }
- }
+static void reportError(StringRef Input, error_code EC) {
+ if (Input == "-")
+ Input = "<stdin>";
- // format() can't handle StringRefs
- outs() << format(" %-32s", FullName.c_str())
- << format(" %-4s", getTypeStr(Type))
- << format(" %16" PRIx64, Address)
- << format(" %16" PRIx64, Size)
- << format(" %16" PRIx64, FileOffset)
- << " " << getSymbolFlagStr(Flags)
- << "\n";
+ errs() << Input << ": " << EC.message() << "\n";
+ errs().flush();
}
-static void dumpStaticSymbol(const SymbolRef &Sym, const ObjectFile *obj) {
- return dumpSymbol(Sym, obj, false);
-}
+static void reportError(StringRef Input, StringRef Message) {
+ if (Input == "-")
+ Input = "<stdin>";
-static void dumpDynamicSymbol(const SymbolRef &Sym, const ObjectFile *obj) {
- return dumpSymbol(Sym, obj, true);
+ errs() << Input << ": " << Message << "\n";
}
-static void dumpSection(const SectionRef &Section, const ObjectFile *obj) {
- StringRef Name;
- checkError(Section.getName(Name), "SectionRef::getName() failed");
- uint64_t Addr, Size, Align;
- checkError(Section.getAddress(Addr), "SectionRef::getAddress() failed");
- checkError(Section.getSize(Size), "SectionRef::getSize() failed");
- checkError(Section.getAlignment(Align), "SectionRef::getAlignment() failed");
- outs() << format(" %-24s", std::string(Name).c_str())
- << format(" %16" PRIx64, Addr)
- << format(" %16" PRIx64, Size)
- << format(" %8" PRIx64, Align)
- << " " << getSectionFlagStr(Section)
- << "\n";
+/// @brief Creates an format-specific object file dumper.
+static error_code createDumper(const ObjectFile *Obj,
+ StreamWriter &Writer,
+ OwningPtr<ObjDumper> &Result) {
+ if (!Obj)
+ return readobj_error::unsupported_file_format;
+
+ if (Obj->isCOFF())
+ return createCOFFDumper(Obj, Writer, Result);
+ if (Obj->isELF())
+ return createELFDumper(Obj, Writer, Result);
+ if (Obj->isMachO())
+ return createMachODumper(Obj, Writer, Result);
+
+ return readobj_error::unsupported_obj_file_format;
}
-static void dumpLibrary(const LibraryRef &lib, const ObjectFile *obj) {
- StringRef path;
- lib.getPath(path);
- outs() << " " << path << "\n";
-}
-template<typename Iterator, typename Func>
-static void dump(const ObjectFile *obj, Func f, Iterator begin, Iterator end,
- const char *errStr) {
- error_code ec;
- uint32_t count = 0;
- Iterator it = begin, ie = end;
- while (it != ie) {
- f(*it, obj);
- it.increment(ec);
- if (ec)
- report_fatal_error(errStr);
- ++count;
+/// @brief Dumps the specified object file.
+static void dumpObject(const ObjectFile *Obj) {
+ StreamWriter Writer(outs());
+ OwningPtr<ObjDumper> Dumper;
+ if (error_code EC = createDumper(Obj, Writer, Dumper)) {
+ reportError(Obj->getFileName(), EC);
+ return;
}
- outs() << " Total: " << count << "\n\n";
-}
-static void dumpHeaders(const ObjectFile *obj) {
- outs() << "File Format : " << obj->getFileFormatName() << "\n";
- outs() << "Arch : "
- << Triple::getArchTypeName((llvm::Triple::ArchType)obj->getArch())
+ outs() << '\n';
+ outs() << "File: " << Obj->getFileName() << "\n";
+ outs() << "Format: " << Obj->getFileFormatName() << "\n";
+ outs() << "Arch: "
+ << Triple::getArchTypeName((llvm::Triple::ArchType)Obj->getArch())
<< "\n";
- outs() << "Address Size: " << (8*obj->getBytesInAddress()) << " bits\n";
- outs() << "Load Name : " << obj->getLoadName() << "\n";
- outs() << "\n";
+ outs() << "AddressSize: " << (8*Obj->getBytesInAddress()) << "bit\n";
+ if (Obj->isELF())
+ outs() << "LoadName: " << Obj->getLoadName() << "\n";
+
+ if (opts::FileHeaders)
+ Dumper->printFileHeaders();
+ if (opts::Sections)
+ Dumper->printSections();
+ if (opts::Relocations)
+ Dumper->printRelocations();
+ if (opts::Symbols)
+ Dumper->printSymbols();
+ if (opts::DynamicSymbols)
+ Dumper->printDynamicSymbols();
+ if (opts::UnwindInfo)
+ Dumper->printUnwindInfo();
+ if (opts::DynamicTable)
+ Dumper->printDynamicTable();
+ if (opts::NeededLibraries)
+ Dumper->printNeededLibraries();
+ if (opts::ProgramHeaders)
+ Dumper->printProgramHeaders();
}
-int main(int argc, char** argv) {
- error_code ec;
- sys::PrintStackTraceOnErrorSignal();
- PrettyStackTraceProgram X(argc, argv);
- cl::ParseCommandLineOptions(argc, argv,
- "LLVM Object Reader\n");
+/// @brief Dumps each object file in \a Arc;
+static void dumpArchive(const Archive *Arc) {
+ for (Archive::child_iterator ArcI = Arc->begin_children(),
+ ArcE = Arc->end_children();
+ ArcI != ArcE; ++ArcI) {
+ OwningPtr<Binary> child;
+ if (error_code EC = ArcI->getAsBinary(child)) {
+ // Ignore non-object files.
+ if (EC != object_error::invalid_file_type)
+ reportError(Arc->getFileName(), EC.message());
+ continue;
+ }
- if (InputFilename.empty()) {
- errs() << "Please specify an input filename\n";
- return 1;
+ if (ObjectFile *Obj = dyn_cast<ObjectFile>(child.get()))
+ dumpObject(Obj);
+ else
+ reportError(Arc->getFileName(), readobj_error::unrecognized_file_format);
}
+}
- // Open the object file
- OwningPtr<MemoryBuffer> File;
- if (MemoryBuffer::getFile(InputFilename, File)) {
- errs() << InputFilename << ": Open failed\n";
- return 1;
+
+/// @brief Opens \a File and dumps it.
+static void dumpInput(StringRef File) {
+ // If file isn't stdin, check that it exists.
+ if (File != "-" && !sys::fs::exists(File)) {
+ reportError(File, readobj_error::file_not_found);
+ return;
}
- OwningPtr<ObjectFile> o(ObjectFile::createObjectFile(File.take()));
- ObjectFile *obj = o.get();
- if (!obj) {
- errs() << InputFilename << ": Object type not recognized\n";
+ // Attempt to open the binary.
+ OwningPtr<Binary> Binary;
+ if (error_code EC = createBinary(File, Binary)) {
+ reportError(File, EC);
+ return;
}
- dumpHeaders(obj);
+ if (Archive *Arc = dyn_cast<Archive>(Binary.get()))
+ dumpArchive(Arc);
+ else if (ObjectFile *Obj = dyn_cast<ObjectFile>(Binary.get()))
+ dumpObject(Obj);
+ else
+ reportError(File, readobj_error::unrecognized_file_format);
+}
- outs() << "Symbols:\n";
- dumpSymbolHeader();
- dump(obj, dumpStaticSymbol, obj->begin_symbols(), obj->end_symbols(),
- "Symbol iteration failed");
- outs() << "Dynamic Symbols:\n";
- dumpSymbolHeader();
- dump(obj, dumpDynamicSymbol, obj->begin_dynamic_symbols(),
- obj->end_dynamic_symbols(), "Symbol iteration failed");
+int main(int argc, const char *argv[]) {
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ llvm_shutdown_obj Y;
- outs() << "Sections:\n";
- dumpSectionHeader();
- dump(obj, &dumpSection, obj->begin_sections(), obj->end_sections(),
- "Section iteration failed");
+ // Initialize targets.
+ llvm::InitializeAllTargetInfos();
- if (obj->isELF()) {
- if (ErrorOr<void> e = dumpELFDynamicTable(obj, outs()))
- ;
- else
- errs() << "InputFilename" << ": " << error_code(e).message() << "\n";
- }
+ // Register the target printer for --version.
+ cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
+
+ cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n");
- outs() << "Libraries needed:\n";
- dump(obj, &dumpLibrary, obj->begin_libraries_needed(),
- obj->end_libraries_needed(), "Needed libraries iteration failed");
+ // Default to stdin if no filename is specified.
+ if (opts::InputFilenames.size() == 0)
+ opts::InputFilenames.push_back("-");
+
+ std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(),
+ dumpInput);
return 0;
}
-
diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h
index cf492b2..3f75610 100644
--- a/tools/llvm-readobj/llvm-readobj.h
+++ b/tools/llvm-readobj/llvm-readobj.h
@@ -1,4 +1,4 @@
-//===- llvm-readobj.h - Dump contents of an Object File -------------------===//
+//===-- llvm-readobj.h ----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -10,13 +10,37 @@
#ifndef LLVM_TOOLS_READ_OBJ_H
#define LLVM_TOOLS_READ_OBJ_H
-#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/CommandLine.h"
+#include <string>
namespace llvm {
-namespace object { class ObjectFile; }
-class raw_ostream;
+ namespace object {
+ class RelocationRef;
+ }
-ErrorOr<void> dumpELFDynamicTable(object::ObjectFile *O, raw_ostream &OS);
-} // end namespace llvm
+ class error_code;
+
+ // Various helper functions.
+ bool error(error_code ec);
+ bool relocAddressLess(object::RelocationRef A,
+ object::RelocationRef B);
+} // namespace llvm
+
+namespace opts {
+ extern llvm::cl::list<std::string> InputFilenames;
+ extern llvm::cl::opt<bool> FileHeaders;
+ extern llvm::cl::opt<bool> Sections;
+ extern llvm::cl::opt<bool> SectionRelocations;
+ extern llvm::cl::opt<bool> SectionSymbols;
+ extern llvm::cl::opt<bool> SectionData;
+ extern llvm::cl::opt<bool> Relocations;
+ extern llvm::cl::opt<bool> Symbols;
+ extern llvm::cl::opt<bool> DynamicSymbols;
+ extern llvm::cl::opt<bool> UnwindInfo;
+ extern llvm::cl::opt<bool> ExpandRelocs;
+} // namespace opts
+
+#define LLVM_READOBJ_ENUM_ENT(ns, enum) \
+ { #enum, ns::enum }
#endif
diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp
index 4d8d345..7f042d2 100644
--- a/tools/llvm-rtdyld/llvm-rtdyld.cpp
+++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp
@@ -17,7 +17,7 @@
#include "llvm/ExecutionEngine/ObjectBuffer.h"
#include "llvm/ExecutionEngine/ObjectImage.h"
#include "llvm/ExecutionEngine/RuntimeDyld.h"
-#include "llvm/Object/MachOObject.h"
+#include "llvm/Object/MachO.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Memory.h"
@@ -69,7 +69,7 @@ public:
return 0;
}
- bool applyPermissions(std::string *ErrMsg) { return false; }
+ bool finalizeMemory(std::string *ErrMsg) { return false; }
// Invalidate instruction cache for sections with execute permissions.
// Some platforms with separate data cache and instruction cache require
@@ -124,8 +124,8 @@ static int printLineInfoForInput() {
InputFileList.push_back("-");
for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) {
// Instantiate a dynamic linker.
- TrivialMemoryManager *MemMgr = new TrivialMemoryManager;
- RuntimeDyld Dyld(MemMgr);
+ TrivialMemoryManager MemMgr;
+ RuntimeDyld Dyld(&MemMgr);
// Load the input memory buffer.
OwningPtr<MemoryBuffer> InputBuffer;
@@ -180,8 +180,8 @@ static int printLineInfoForInput() {
static int executeInput() {
// Instantiate a dynamic linker.
- TrivialMemoryManager *MemMgr = new TrivialMemoryManager;
- RuntimeDyld Dyld(MemMgr);
+ TrivialMemoryManager MemMgr;
+ RuntimeDyld Dyld(&MemMgr);
// If we don't have any input files, read from stdin.
if (!InputFileList.size())
@@ -204,7 +204,7 @@ static int executeInput() {
// Resolve all the relocations we can.
Dyld.resolveRelocations();
// Clear instruction cache before code will be executed.
- MemMgr->invalidateInstructionCache();
+ MemMgr.invalidateInstructionCache();
// FIXME: Error out if there are unresolved relocations.
@@ -214,8 +214,8 @@ static int executeInput() {
return Error("no definition for '" + EntryPoint + "'");
// Invalidate the instruction cache for each loaded function.
- for (unsigned i = 0, e = MemMgr->FunctionMemory.size(); i != e; ++i) {
- sys::MemoryBlock &Data = MemMgr->FunctionMemory[i];
+ for (unsigned i = 0, e = MemMgr.FunctionMemory.size(); i != e; ++i) {
+ sys::MemoryBlock &Data = MemMgr.FunctionMemory[i];
// Make sure the memory is executable.
std::string ErrorStr;
sys::Memory::InvalidateInstructionCache(Data.base(), Data.size());
diff --git a/tools/llvm-shlib/Makefile b/tools/llvm-shlib/Makefile
index 6d6c6e9..1d9053b 100644
--- a/tools/llvm-shlib/Makefile
+++ b/tools/llvm-shlib/Makefile
@@ -51,30 +51,29 @@ ifeq ($(HOST_OS),Darwin)
LLVMLibsOptions := $(LLVMLibsOptions) -all_load
# extra options to override libtool defaults
LLVMLibsOptions := $(LLVMLibsOptions) \
- -Wl,-dead_strip \
- -Wl,-seg1addr -Wl,0xE0000000
+ -Wl,-dead_strip
# Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line
DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/')
ifneq ($(DARWIN_VERS),8)
LLVMLibsOptions := $(LLVMLibsOptions) \
-Wl,-install_name \
- -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)"
+ -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)"
endif
endif
-ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD OpenBSD GNU Bitrig))
+ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU/kFreeBSD OpenBSD GNU Bitrig))
# Include everything from the .a's into the shared library.
LLVMLibsOptions := -Wl,--whole-archive $(LLVMLibsOptions) \
-Wl,--no-whole-archive
endif
-ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU))
+ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU/kFreeBSD GNU))
# Add soname to the library.
LLVMLibsOptions += -Wl,--soname,lib$(LIBRARYNAME)$(SHLIBEXT)
endif
-ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux GNU))
+ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux GNU GNU/kFreeBSD))
# Don't allow unresolved symbols.
LLVMLibsOptions += -Wl,--no-undefined
endif
diff --git a/tools/llvm-stress/Makefile b/tools/llvm-stress/Makefile
index 90d57c3..8767cbe 100644
--- a/tools/llvm-stress/Makefile
+++ b/tools/llvm-stress/Makefile
@@ -10,7 +10,7 @@
LEVEL := ../..
TOOLNAME := llvm-stress
LINK_COMPONENTS := object
-LINK_COMPONENTS := bitreader bitwriter asmparser instrumentation scalaropts ipo
+LINK_COMPONENTS := bitreader bitwriter asmparser irreader instrumentation scalaropts ipo
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
diff --git a/tools/llvm-stress/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp
index fbda1b7..15f7abf 100644
--- a/tools/llvm-stress/llvm-stress.cpp
+++ b/tools/llvm-stress/llvm-stress.cpp
@@ -702,7 +702,7 @@ int main(int argc, char **argv) {
std::string ErrorInfo;
Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo,
- raw_fd_ostream::F_Binary));
+ sys::fs::F_Binary));
if (!ErrorInfo.empty()) {
errs() << ErrorInfo << '\n';
return 1;
diff --git a/tools/llvm-symbolizer/LLVMSymbolize.cpp b/tools/llvm-symbolizer/LLVMSymbolize.cpp
index 86ea34b..0346fb2 100644
--- a/tools/llvm-symbolizer/LLVMSymbolize.cpp
+++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp
@@ -12,8 +12,10 @@
//===----------------------------------------------------------------------===//
#include "LLVMSymbolize.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include <sstream>
@@ -62,15 +64,23 @@ ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx)
SymbolAddress == UnknownAddressOrSize)
continue;
uint64_t SymbolSize;
- if (error(si->getSize(SymbolSize)) || SymbolSize == UnknownAddressOrSize)
+ // Getting symbol size is linear for Mach-O files, so assume that symbol
+ // occupies the memory range up to the following symbol.
+ if (isa<MachOObjectFile>(Obj))
+ SymbolSize = 0;
+ else if (error(si->getSize(SymbolSize)) ||
+ SymbolSize == UnknownAddressOrSize)
continue;
StringRef SymbolName;
if (error(si->getName(SymbolName)))
continue;
+ // Mach-O symbol table names have leading underscore, skip it.
+ if (Module->isMachO() && SymbolName.size() > 0 && SymbolName[0] == '_')
+ SymbolName = SymbolName.drop_front();
// FIXME: If a function has alias, there are two entries in symbol table
// with same address size. Make sure we choose the correct one.
SymbolMapTy &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
- SymbolDesc SD = { SymbolAddress, SymbolAddress + SymbolSize };
+ SymbolDesc SD = { SymbolAddress, SymbolSize };
M.insert(std::make_pair(SD, SymbolName));
}
}
@@ -79,15 +89,18 @@ bool ModuleInfo::getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
std::string &Name, uint64_t &Addr,
uint64_t &Size) const {
const SymbolMapTy &M = Type == SymbolRef::ST_Function ? Functions : Objects;
- SymbolDesc SD = { Address, Address + 1 };
- SymbolMapTy::const_iterator it = M.find(SD);
- if (it == M.end())
+ if (M.empty())
return false;
- if (Address < it->first.Addr || Address >= it->first.AddrEnd)
+ SymbolDesc SD = { Address, Address };
+ SymbolMapTy::const_iterator it = M.upper_bound(SD);
+ if (it == M.begin())
+ return false;
+ --it;
+ if (it->first.Size != 0 && it->first.Addr + it->first.Size <= Address)
return false;
Name = it->second.str();
Addr = it->first.Addr;
- Size = it->first.AddrEnd - it->first.Addr;
+ Size = it->first.Size;
return true;
}
@@ -177,8 +190,8 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
uint64_t Size = 0;
if (Opts.UseSymbolTable) {
if (ModuleInfo *Info = getOrCreateModuleInfo(ModuleName)) {
- if (Info->symbolizeData(ModuleOffset, Name, Start, Size))
- DemangleName(Name);
+ if (Info->symbolizeData(ModuleOffset, Name, Start, Size) && Opts.Demangle)
+ Name = DemangleName(Name);
}
}
std::stringstream ss;
@@ -186,21 +199,14 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
return ss.str();
}
-// Returns true if the object endianness is known.
-static bool getObjectEndianness(const ObjectFile *Obj, bool &IsLittleEndian) {
- // FIXME: Implement this when libLLVMObject allows to do it easily.
- IsLittleEndian = true;
- return true;
-}
-
-static ObjectFile *getObjectFile(const std::string &Path) {
- OwningPtr<MemoryBuffer> Buff;
- if (error_code ec = MemoryBuffer::getFile(Path, Buff))
- error(ec);
- return ObjectFile::createObjectFile(Buff.take());
+void LLVMSymbolizer::flush() {
+ DeleteContainerSeconds(Modules);
+ DeleteContainerPointers(ParsedBinariesAndObjects);
+ BinaryForPath.clear();
+ ObjectFileForArch.clear();
}
-static std::string getDarwinDWARFResourceForModule(const std::string &Path) {
+static std::string getDarwinDWARFResourceForPath(const std::string &Path) {
StringRef Basename = sys::path::filename(Path);
const std::string &DSymDirectory = Path + ".dSYM";
SmallString<16> ResourceName = StringRef(DSymDirectory);
@@ -209,36 +215,89 @@ static std::string getDarwinDWARFResourceForModule(const std::string &Path) {
return ResourceName.str();
}
+LLVMSymbolizer::BinaryPair
+LLVMSymbolizer::getOrCreateBinary(const std::string &Path) {
+ BinaryMapTy::iterator I = BinaryForPath.find(Path);
+ if (I != BinaryForPath.end())
+ return I->second;
+ Binary *Bin = 0;
+ Binary *DbgBin = 0;
+ OwningPtr<Binary> ParsedBinary;
+ OwningPtr<Binary> ParsedDbgBinary;
+ if (!error(createBinary(Path, ParsedBinary))) {
+ // Check if it's a universal binary.
+ Bin = ParsedBinary.take();
+ ParsedBinariesAndObjects.push_back(Bin);
+ if (Bin->isMachO() || Bin->isMachOUniversalBinary()) {
+ // On Darwin we may find DWARF in separate object file in
+ // resource directory.
+ const std::string &ResourcePath =
+ getDarwinDWARFResourceForPath(Path);
+ bool ResourceFileExists = false;
+ if (!sys::fs::exists(ResourcePath, ResourceFileExists) &&
+ ResourceFileExists &&
+ !error(createBinary(ResourcePath, ParsedDbgBinary))) {
+ DbgBin = ParsedDbgBinary.take();
+ ParsedBinariesAndObjects.push_back(DbgBin);
+ }
+ }
+ }
+ if (DbgBin == 0)
+ DbgBin = Bin;
+ BinaryPair Res = std::make_pair(Bin, DbgBin);
+ BinaryForPath[Path] = Res;
+ return Res;
+}
+
+ObjectFile *
+LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, const std::string &ArchName) {
+ if (Bin == 0)
+ return 0;
+ ObjectFile *Res = 0;
+ if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) {
+ ObjectFileForArchMapTy::iterator I = ObjectFileForArch.find(
+ std::make_pair(UB, ArchName));
+ if (I != ObjectFileForArch.end())
+ return I->second;
+ OwningPtr<ObjectFile> ParsedObj;
+ if (!UB->getObjectForArch(Triple(ArchName).getArch(), ParsedObj)) {
+ Res = ParsedObj.take();
+ ParsedBinariesAndObjects.push_back(Res);
+ }
+ ObjectFileForArch[std::make_pair(UB, ArchName)] = Res;
+ } else if (Bin->isObject()) {
+ Res = cast<ObjectFile>(Bin);
+ }
+ return Res;
+}
+
ModuleInfo *
LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
ModuleMapTy::iterator I = Modules.find(ModuleName);
if (I != Modules.end())
return I->second;
+ std::string BinaryName = ModuleName;
+ std::string ArchName = Opts.DefaultArch;
+ size_t ColonPos = ModuleName.find_last_of(':');
+ // Verify that substring after colon form a valid arch name.
+ if (ColonPos != std::string::npos) {
+ std::string ArchStr = ModuleName.substr(ColonPos + 1);
+ if (Triple(ArchStr).getArch() != Triple::UnknownArch) {
+ BinaryName = ModuleName.substr(0, ColonPos);
+ ArchName = ArchStr;
+ }
+ }
+ BinaryPair Binaries = getOrCreateBinary(BinaryName);
+ ObjectFile *Obj = getObjectFileFromBinary(Binaries.first, ArchName);
+ ObjectFile *DbgObj = getObjectFileFromBinary(Binaries.second, ArchName);
- ObjectFile *Obj = getObjectFile(ModuleName);
if (Obj == 0) {
- // Module name doesn't point to a valid object file.
+ // Failed to find valid object file.
Modules.insert(make_pair(ModuleName, (ModuleInfo *)0));
return 0;
}
-
- DIContext *Context = 0;
- bool IsLittleEndian;
- if (getObjectEndianness(Obj, IsLittleEndian)) {
- // On Darwin we may find DWARF in separate object file in
- // resource directory.
- ObjectFile *DbgObj = Obj;
- if (isa<MachOObjectFile>(Obj)) {
- const std::string &ResourceName =
- getDarwinDWARFResourceForModule(ModuleName);
- ObjectFile *ResourceObj = getObjectFile(ResourceName);
- if (ResourceObj != 0)
- DbgObj = ResourceObj;
- }
- Context = DIContext::getDWARFContext(DbgObj);
- assert(Context);
- }
-
+ DIContext *Context = DIContext::getDWARFContext(DbgObj);
+ assert(Context);
ModuleInfo *Info = new ModuleInfo(Obj, Context);
Modules.insert(make_pair(ModuleName, Info));
return Info;
@@ -253,7 +312,8 @@ std::string LLVMSymbolizer::printDILineInfo(DILineInfo LineInfo) const {
std::string FunctionName = LineInfo.getFunctionName();
if (FunctionName == kDILineInfoBadString)
FunctionName = kBadString;
- DemangleName(FunctionName);
+ else if (Opts.Demangle)
+ FunctionName = DemangleName(FunctionName);
Result << FunctionName << "\n";
}
std::string Filename = LineInfo.getFileName();
@@ -270,16 +330,17 @@ extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer,
size_t *length, int *status);
#endif
-void LLVMSymbolizer::DemangleName(std::string &Name) const {
+std::string LLVMSymbolizer::DemangleName(const std::string &Name) {
#if !defined(_MSC_VER)
- if (!Opts.Demangle)
- return;
int status = 0;
char *DemangledName = __cxa_demangle(Name.c_str(), 0, 0, &status);
if (status != 0)
- return;
- Name = DemangledName;
+ return Name;
+ std::string Result = DemangledName;
free(DemangledName);
+ return Result;
+#else
+ return Name;
#endif
}
diff --git a/tools/llvm-symbolizer/LLVMSymbolize.h b/tools/llvm-symbolizer/LLVMSymbolize.h
index e6220aa..03c765c 100644
--- a/tools/llvm-symbolizer/LLVMSymbolize.h
+++ b/tools/llvm-symbolizer/LLVMSymbolize.h
@@ -14,7 +14,9 @@
#define LLVM_SYMBOLIZE_H
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/MemoryBuffer.h"
#include <map>
@@ -35,14 +37,20 @@ public:
bool PrintFunctions : 1;
bool PrintInlining : 1;
bool Demangle : 1;
+ std::string DefaultArch;
Options(bool UseSymbolTable = true, bool PrintFunctions = true,
- bool PrintInlining = true, bool Demangle = true)
+ bool PrintInlining = true, bool Demangle = true,
+ std::string DefaultArch = "")
: UseSymbolTable(UseSymbolTable), PrintFunctions(PrintFunctions),
- PrintInlining(PrintInlining), Demangle(Demangle) {
+ PrintInlining(PrintInlining), Demangle(Demangle),
+ DefaultArch(DefaultArch) {
}
};
LLVMSymbolizer(const Options &Opts = Options()) : Opts(Opts) {}
+ ~LLVMSymbolizer() {
+ flush();
+ }
// Returns the result of symbolization for module name/offset as
// a string (possibly containing newlines).
@@ -50,13 +58,31 @@ public:
symbolizeCode(const std::string &ModuleName, uint64_t ModuleOffset);
std::string
symbolizeData(const std::string &ModuleName, uint64_t ModuleOffset);
+ void flush();
+ static std::string DemangleName(const std::string &Name);
private:
+ typedef std::pair<Binary*, Binary*> BinaryPair;
+
ModuleInfo *getOrCreateModuleInfo(const std::string &ModuleName);
+ /// \brief Returns pair of pointers to binary and debug binary.
+ BinaryPair getOrCreateBinary(const std::string &Path);
+ /// \brief Returns a parsed object file for a given architecture in a
+ /// universal binary (or the binary itself if it is an object file).
+ ObjectFile *getObjectFileFromBinary(Binary *Bin, const std::string &ArchName);
+
std::string printDILineInfo(DILineInfo LineInfo) const;
- void DemangleName(std::string &Name) const;
+ // Owns all the parsed binaries and object files.
+ SmallVector<Binary*, 4> ParsedBinariesAndObjects;
+ // Owns module info objects.
typedef std::map<std::string, ModuleInfo *> ModuleMapTy;
ModuleMapTy Modules;
+ typedef std::map<std::string, BinaryPair> BinaryMapTy;
+ BinaryMapTy BinaryForPath;
+ typedef std::map<std::pair<MachOUniversalBinary *, std::string>, ObjectFile *>
+ ObjectFileForArchMapTy;
+ ObjectFileForArchMapTy ObjectFileForArch;
+
Options Opts;
static const char kBadString[];
};
@@ -76,14 +102,16 @@ private:
bool getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
std::string &Name, uint64_t &Addr,
uint64_t &Size) const;
- OwningPtr<ObjectFile> Module;
+ ObjectFile *Module;
OwningPtr<DIContext> DebugInfoContext;
struct SymbolDesc {
uint64_t Addr;
- uint64_t AddrEnd;
+ // If size is 0, assume that symbol occupies the whole memory range up to
+ // the following symbol.
+ uint64_t Size;
friend bool operator<(const SymbolDesc &s1, const SymbolDesc &s2) {
- return s1.AddrEnd <= s2.Addr;
+ return s1.Addr < s2.Addr;
}
};
typedef std::map<SymbolDesc, StringRef> SymbolMapTy;
diff --git a/tools/llvm-symbolizer/llvm-symbolizer.cpp b/tools/llvm-symbolizer/llvm-symbolizer.cpp
index d039ec6..c32e949 100644
--- a/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -47,6 +47,10 @@ ClPrintInlining("inlining", cl::init(true),
static cl::opt<bool>
ClDemangle("demangle", cl::init(true), cl::desc("Demangle function names"));
+static cl::opt<std::string> ClDefaultArch("default-arch", cl::init(""),
+ cl::desc("Default architecture "
+ "(for multi-arch objects)"));
+
static bool parseCommand(bool &IsData, std::string &ModuleName,
uint64_t &ModuleOffset) {
const char *kDataCmd = "DATA ";
@@ -70,12 +74,25 @@ static bool parseCommand(bool &IsData, std::string &ModuleName,
// If no cmd, assume it's CODE.
IsData = false;
}
- // FIXME: Handle case when filename is given in quotes.
- if (char *FilePath = strtok(pos, kDelimiters)) {
- ModuleName = FilePath;
- if (char *OffsetStr = strtok((char *)0, kDelimiters))
- ModuleOffsetStr = OffsetStr;
+ // Skip delimiters and parse input filename.
+ pos += strspn(pos, kDelimiters);
+ if (*pos == '"' || *pos == '\'') {
+ char quote = *pos;
+ pos++;
+ char *end = strchr(pos, quote);
+ if (end == 0)
+ return false;
+ ModuleName = std::string(pos, end - pos);
+ pos = end + 1;
+ } else {
+ int name_length = strcspn(pos, kDelimiters);
+ ModuleName = std::string(pos, name_length);
+ pos += name_length;
}
+ // Skip delimiters and parse module offset.
+ pos += strspn(pos, kDelimiters);
+ int offset_length = strcspn(pos, kDelimiters);
+ ModuleOffsetStr = std::string(pos, offset_length);
if (StringRef(ModuleOffsetStr).getAsInteger(0, ModuleOffset))
return false;
return true;
@@ -89,7 +106,7 @@ int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv, "llvm symbolizer for compiler-rt\n");
LLVMSymbolizer::Options Opts(ClUseSymbolTable, ClPrintFunctions,
- ClPrintInlining, ClDemangle);
+ ClPrintInlining, ClDemangle, ClDefaultArch);
LLVMSymbolizer Symbolizer(Opts);
bool IsData = false;
diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp
index cf7ffe2..758227d 100644
--- a/tools/lto/LTOCodeGenerator.cpp
+++ b/tools/lto/LTOCodeGenerator.cpp
@@ -24,12 +24,14 @@
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
+#include "llvm/InitializePasses.h"
#include "llvm/Linker.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -44,6 +46,7 @@
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/ObjCARC.h"
using namespace llvm;
static cl::opt<bool>
@@ -68,76 +71,107 @@ const char* LTOCodeGenerator::getVersionString() {
LTOCodeGenerator::LTOCodeGenerator()
: _context(getGlobalContext()),
- _linker("LinkTimeOptimizer", "ld-temp.o", _context), _target(NULL),
+ _linker(new Module("ld-temp.o", _context)), _target(NULL),
_emitDwarfDebugInfo(false), _scopeRestrictionsDone(false),
_codeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC),
_nativeObjectFile(NULL) {
InitializeAllTargets();
InitializeAllTargetMCs();
InitializeAllAsmPrinters();
+ initializeLTOPasses();
}
LTOCodeGenerator::~LTOCodeGenerator() {
delete _target;
delete _nativeObjectFile;
+ delete _linker.getModule();
for (std::vector<char*>::iterator I = _codegenOptions.begin(),
E = _codegenOptions.end(); I != E; ++I)
free(*I);
}
+// Initialize LTO passes. Please keep this funciton in sync with
+// PassManagerBuilder::populateLTOPassManager(), and make sure all LTO
+// passes are initialized.
+//
+void LTOCodeGenerator::initializeLTOPasses() {
+ PassRegistry &R = *PassRegistry::getPassRegistry();
+
+ initializeInternalizePassPass(R);
+ initializeIPSCCPPass(R);
+ initializeGlobalOptPass(R);
+ initializeConstantMergePass(R);
+ initializeDAHPass(R);
+ initializeInstCombinerPass(R);
+ initializeSimpleInlinerPass(R);
+ initializePruneEHPass(R);
+ initializeGlobalDCEPass(R);
+ initializeArgPromotionPass(R);
+ initializeJumpThreadingPass(R);
+ initializeSROAPass(R);
+ initializeSROA_DTPass(R);
+ initializeSROA_SSAUpPass(R);
+ initializeFunctionAttrsPass(R);
+ initializeGlobalsModRefPass(R);
+ initializeLICMPass(R);
+ initializeGVNPass(R);
+ initializeMemCpyOptPass(R);
+ initializeDCEPass(R);
+ initializeCFGSimplifyPassPass(R);
+}
+
bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& errMsg) {
- bool ret = _linker.LinkInModule(mod->getLLVVMModule(), &errMsg);
+ bool ret = _linker.linkInModule(mod->getLLVVMModule(), &errMsg);
const std::vector<const char*> &undefs = mod->getAsmUndefinedRefs();
for (int i = 0, e = undefs.size(); i != e; ++i)
_asmUndefinedRefs[undefs[i]] = 1;
- return ret;
+ return !ret;
}
-bool LTOCodeGenerator::setDebugInfo(lto_debug_model debug,
- std::string& errMsg) {
+void LTOCodeGenerator::setDebugInfo(lto_debug_model debug) {
switch (debug) {
case LTO_DEBUG_MODEL_NONE:
_emitDwarfDebugInfo = false;
- return false;
+ return;
case LTO_DEBUG_MODEL_DWARF:
_emitDwarfDebugInfo = true;
- return false;
+ return;
}
llvm_unreachable("Unknown debug format!");
}
-bool LTOCodeGenerator::setCodePICModel(lto_codegen_model model,
- std::string& errMsg) {
+void LTOCodeGenerator::setCodePICModel(lto_codegen_model model) {
switch (model) {
case LTO_CODEGEN_PIC_MODEL_STATIC:
case LTO_CODEGEN_PIC_MODEL_DYNAMIC:
case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC:
_codeModel = model;
- return false;
+ return;
}
llvm_unreachable("Unknown PIC model!");
}
bool LTOCodeGenerator::writeMergedModules(const char *path,
std::string &errMsg) {
- if (determineTarget(errMsg))
- return true;
+ if (!determineTarget(errMsg))
+ return false;
- // mark which symbols can not be internalized
- applyScopeRestrictions();
+ // Run the verifier on the merged modules.
+ PassManager passes;
+ passes.add(createVerifierPass());
+ passes.run(*_linker.getModule());
// create output file
std::string ErrInfo;
- tool_output_file Out(path, ErrInfo,
- raw_fd_ostream::F_Binary);
+ tool_output_file Out(path, ErrInfo, sys::fs::F_Binary);
if (!ErrInfo.empty()) {
errMsg = "could not open bitcode file for writing: ";
errMsg += path;
- return true;
+ return false;
}
// write bitcode to it
@@ -148,52 +182,48 @@ bool LTOCodeGenerator::writeMergedModules(const char *path,
errMsg = "could not write bitcode file: ";
errMsg += path;
Out.os().clear_error();
- return true;
+ return false;
}
Out.keep();
- return false;
+ return true;
}
bool LTOCodeGenerator::compile_to_file(const char** name, std::string& errMsg) {
// make unique temp .o file to put generated object file
- sys::PathWithStatus uniqueObjPath("lto-llvm.o");
- if (uniqueObjPath.createTemporaryFileOnDisk(false, &errMsg)) {
- uniqueObjPath.eraseFromDisk();
- return true;
+ SmallString<128> Filename;
+ int FD;
+ error_code EC = sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filename);
+ if (EC) {
+ errMsg = EC.message();
+ return false;
}
- sys::RemoveFileOnSignal(uniqueObjPath);
// generate object file
- bool genResult = false;
- tool_output_file objFile(uniqueObjPath.c_str(), errMsg);
- if (!errMsg.empty()) {
- uniqueObjPath.eraseFromDisk();
- return true;
- }
+ tool_output_file objFile(Filename.c_str(), FD);
- genResult = this->generateObjectFile(objFile.os(), errMsg);
+ bool genResult = generateObjectFile(objFile.os(), errMsg);
objFile.os().close();
if (objFile.os().has_error()) {
objFile.os().clear_error();
- uniqueObjPath.eraseFromDisk();
- return true;
+ sys::fs::remove(Twine(Filename));
+ return false;
}
objFile.keep();
- if (genResult) {
- uniqueObjPath.eraseFromDisk();
- return true;
+ if (!genResult) {
+ sys::fs::remove(Twine(Filename));
+ return false;
}
- _nativeObjectPath = uniqueObjPath.str();
+ _nativeObjectPath = Filename.c_str();
*name = _nativeObjectPath.c_str();
- return false;
+ return true;
}
const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) {
const char *name;
- if (compile_to_file(&name, errMsg))
+ if (!compile_to_file(&name, errMsg))
return NULL;
// remove old buffer if compile() called twice
@@ -203,13 +233,13 @@ const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) {
OwningPtr<MemoryBuffer> BuffPtr;
if (error_code ec = MemoryBuffer::getFile(name, BuffPtr, -1, false)) {
errMsg = ec.message();
- sys::Path(_nativeObjectPath).eraseFromDisk();
+ sys::fs::remove(_nativeObjectPath);
return NULL;
}
_nativeObjectFile = BuffPtr.take();
// remove temp files
- sys::Path(_nativeObjectPath).eraseFromDisk();
+ sys::fs::remove(_nativeObjectPath);
// return buffer, unless error
if (_nativeObjectFile == NULL)
@@ -218,9 +248,14 @@ const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) {
return _nativeObjectFile->getBufferStart();
}
-bool LTOCodeGenerator::determineTarget(std::string& errMsg) {
+bool LTOCodeGenerator::determineTarget(std::string &errMsg) {
if (_target != NULL)
- return false;
+ return true;
+
+ // if options were requested, set them
+ if (!_codegenOptions.empty())
+ cl::ParseCommandLineOptions(_codegenOptions.size(),
+ const_cast<char **>(&_codegenOptions[0]));
std::string TripleStr = _linker.getModule()->getTargetTriple();
if (TripleStr.empty())
@@ -230,7 +265,7 @@ bool LTOCodeGenerator::determineTarget(std::string& errMsg) {
// create target machine from info for merged modules
const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg);
if (march == NULL)
- return true;
+ return false;
// The relocation model is actually a static member of TargetMachine and
// needs to be set before the TargetMachine is instantiated.
@@ -263,7 +298,7 @@ bool LTOCodeGenerator::determineTarget(std::string& errMsg) {
_target = march->createTargetMachine(TripleStr, _mCpu, FeatureStr, Options,
RelocModel, CodeModel::Default,
CodeGenOpt::Aggressive);
- return false;
+ return true;
}
void LTOCodeGenerator::
@@ -286,9 +321,7 @@ static void findUsedValues(GlobalVariable *LLVMUsed,
SmallPtrSet<GlobalValue*, 8> &UsedValues) {
if (LLVMUsed == 0) return;
- ConstantArray *Inits = dyn_cast<ConstantArray>(LLVMUsed->getInitializer());
- if (Inits == 0) return;
-
+ ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer());
for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i)
if (GlobalValue *GV =
dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts()))
@@ -304,8 +337,8 @@ void LTOCodeGenerator::applyScopeRestrictions() {
passes.add(createVerifierPass());
// mark which symbols can not be internalized
- MCContext Context(*_target->getMCAsmInfo(), *_target->getRegisterInfo(),NULL);
- Mangler mangler(Context, *_target->getDataLayout());
+ MCContext Context(_target->getMCAsmInfo(), _target->getRegisterInfo(), NULL);
+ Mangler mangler(Context, _target);
std::vector<const char*> mustPreserveList;
SmallPtrSet<GlobalValue*, 8> asmUsed;
@@ -325,24 +358,26 @@ void LTOCodeGenerator::applyScopeRestrictions() {
if (LLVMCompilerUsed)
LLVMCompilerUsed->eraseFromParent();
- llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(_context);
- std::vector<Constant*> asmUsed2;
- for (SmallPtrSet<GlobalValue*, 16>::const_iterator i = asmUsed.begin(),
- e = asmUsed.end(); i !=e; ++i) {
- GlobalValue *GV = *i;
- Constant *c = ConstantExpr::getBitCast(GV, i8PTy);
- asmUsed2.push_back(c);
+ if (!asmUsed.empty()) {
+ llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(_context);
+ std::vector<Constant*> asmUsed2;
+ for (SmallPtrSet<GlobalValue*, 16>::const_iterator i = asmUsed.begin(),
+ e = asmUsed.end(); i !=e; ++i) {
+ GlobalValue *GV = *i;
+ Constant *c = ConstantExpr::getBitCast(GV, i8PTy);
+ asmUsed2.push_back(c);
+ }
+
+ llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, asmUsed2.size());
+ LLVMCompilerUsed =
+ new llvm::GlobalVariable(*mergedModule, ATy, false,
+ llvm::GlobalValue::AppendingLinkage,
+ llvm::ConstantArray::get(ATy, asmUsed2),
+ "llvm.compiler.used");
+
+ LLVMCompilerUsed->setSection("llvm.metadata");
}
- llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, asmUsed2.size());
- LLVMCompilerUsed =
- new llvm::GlobalVariable(*mergedModule, ATy, false,
- llvm::GlobalValue::AppendingLinkage,
- llvm::ConstantArray::get(ATy, asmUsed2),
- "llvm.compiler.used");
-
- LLVMCompilerUsed->setSection("llvm.metadata");
-
passes.add(createInternalizePass(mustPreserveList));
// apply scope restrictions
@@ -354,17 +389,12 @@ void LTOCodeGenerator::applyScopeRestrictions() {
/// Optimize merged modules using various IPO passes
bool LTOCodeGenerator::generateObjectFile(raw_ostream &out,
std::string &errMsg) {
- if (this->determineTarget(errMsg))
- return true;
+ if (!this->determineTarget(errMsg))
+ return false;
Module* mergedModule = _linker.getModule();
- // if options were requested, set them
- if (!_codegenOptions.empty())
- cl::ParseCommandLineOptions(_codegenOptions.size(),
- const_cast<char **>(&_codegenOptions[0]));
-
- // mark which symbols can not be internalized
+ // Mark which symbols can not be internalized
this->applyScopeRestrictions();
// Instantiate the pass manager to organize the passes.
@@ -380,12 +410,11 @@ bool LTOCodeGenerator::generateObjectFile(raw_ostream &out,
// Enabling internalize here would use its AllButMain variant. It
// keeps only main if it exists and does nothing for libraries. Instead
// we create the pass ourselves with the symbol list provided by the linker.
- if (!DisableOpt) {
+ if (!DisableOpt)
PassManagerBuilder().populateLTOPassManager(passes,
/*Internalize=*/false,
!DisableInline,
DisableGVNLoadPRE);
- }
// Make sure everything is still good.
passes.add(createVerifierPass());
@@ -397,10 +426,14 @@ bool LTOCodeGenerator::generateObjectFile(raw_ostream &out,
formatted_raw_ostream Out(out);
+ // If the bitcode files contain ARC code and were compiled with optimization,
+ // the ObjCARCContractPass must be run, so do it unconditionally here.
+ codeGenPasses.add(createObjCARCContractPass());
+
if (_target->addPassesToEmitFile(codeGenPasses, Out,
TargetMachine::CGFT_ObjectFile)) {
errMsg = "target file type not supported";
- return true;
+ return false;
}
// Run our queue of passes all at once now, efficiently.
@@ -409,7 +442,7 @@ bool LTOCodeGenerator::generateObjectFile(raw_ostream &out,
// Run the code generator, and write assembly file
codeGenPasses.run(*mergedModule);
- return false; // success
+ return true;
}
/// setCodeGenDebugOptions - Set codegen debugging options to aid in debugging
diff --git a/tools/lto/LTOCodeGenerator.h b/tools/lto/LTOCodeGenerator.h
index 601dbfa..8f37cf0 100644
--- a/tools/lto/LTOCodeGenerator.h
+++ b/tools/lto/LTOCodeGenerator.h
@@ -9,6 +9,27 @@
//
// This file declares the LTOCodeGenerator class.
//
+// LTO compilation consists of three phases: Pre-IPO, IPO and Post-IPO.
+//
+// The Pre-IPO phase compiles source code into bitcode file. The resulting
+// bitcode files, along with object files and libraries, will be fed to the
+// linker to through the IPO and Post-IPO phases. By using obj-file extension,
+// the resulting bitcode file disguises itself as an object file, and therefore
+// obviates the need of writing a special set of the make-rules only for LTO
+// compilation.
+//
+// The IPO phase perform inter-procedural analyses and optimizations, and
+// the Post-IPO consists two sub-phases: intra-procedural scalar optimizations
+// (SOPT), and intra-procedural target-dependent code generator (CG).
+//
+// As of this writing, we don't separate IPO and the Post-IPO SOPT. They
+// are intermingled together, and are driven by a single pass manager (see
+// PassManagerBuilder::populateLTOPassManager()).
+//
+// The "LTOCodeGenerator" is the driver for the IPO and Post-IPO stages.
+// The "CodeGenerator" here is bit confusing. Don't confuse the "CodeGenerator"
+// with the machine specific code generator.
+//
//===----------------------------------------------------------------------===//
#ifndef LTO_CODE_GENERATOR_H
@@ -19,6 +40,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/Linker.h"
#include <string>
+#include <vector>
namespace llvm {
class LLVMContext;
@@ -39,9 +61,11 @@ struct LTOCodeGenerator {
LTOCodeGenerator();
~LTOCodeGenerator();
+ // Merge given module, return true on success.
bool addModule(struct LTOModule*, std::string &errMsg);
- bool setDebugInfo(lto_debug_model, std::string &errMsg);
- bool setCodePICModel(lto_codegen_model, std::string &errMsg);
+
+ void setDebugInfo(lto_debug_model);
+ void setCodePICModel(lto_codegen_model);
void setCpu(const char* mCpu) { _mCpu = mCpu; }
@@ -49,12 +73,38 @@ struct LTOCodeGenerator {
_mustPreserveSymbols[sym] = 1;
}
+ // To pass options to the driver and optimization passes. These options are
+ // not necessarily for debugging purpose (The function name is misleading).
+ // This function should be called before LTOCodeGenerator::compilexxx(),
+ // and LTOCodeGenerator::writeMergedModules().
+ //
+ void setCodeGenDebugOptions(const char *opts);
+
+ // Write the merged module to the file specified by the given path.
+ // Return true on success.
bool writeMergedModules(const char *path, std::string &errMsg);
+
+ // Compile the merged module into a *single* object file; the path to object
+ // file is returned to the caller via argument "name". Return true on
+ // success.
+ //
+ // NOTE that it is up to the linker to remove the intermediate object file.
+ // Do not try to remove the object file in LTOCodeGenerator's destructor
+ // as we don't who (LTOCodeGenerator or the obj file) will last longer.
+ //
bool compile_to_file(const char **name, std::string &errMsg);
+
+ // As with compile_to_file(), this function compiles the merged module into
+ // single object file. Instead of returning the object-file-path to the caller
+ // (linker), it brings the object to a buffer, and return the buffer to the
+ // caller. This function should delete intermediate object file once its content
+ // is brought to memory. Return NULL is the compilation was not successful.
+ //
const void *compile(size_t *length, std::string &errMsg);
- void setCodeGenDebugOptions(const char *opts);
private:
+ void initializeLTOPasses();
+
bool generateObjectFile(llvm::raw_ostream &out, std::string &errMsg);
void applyScopeRestrictions();
void applyRestriction(llvm::GlobalValue &GV,
diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp
index ff67769..e89733f 100644
--- a/tools/lto/LTOModule.cpp
+++ b/tools/lto/LTOModule.cpp
@@ -29,6 +29,7 @@
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Host.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
@@ -49,11 +50,6 @@ DisableFPElim("disable-fp-elim",
cl::init(false));
static cl::opt<bool>
-DisableFPElimNonLeaf("disable-non-leaf-fp-elim",
- cl::desc("Disable frame pointer elimination optimization for non-leaf funcs"),
- cl::init(false));
-
-static cl::opt<bool>
EnableUnsafeFPMath("enable-unsafe-fp-math",
cl::desc("Enable optimizations that may decrease FP precision"),
cl::init(false));
@@ -125,11 +121,6 @@ OverrideStackAlignment("stack-alignment",
cl::desc("Override default stack alignment"),
cl::init(0));
-static cl::opt<bool>
-EnableRealignStack("realign-stack",
- cl::desc("Realign stack if needed"),
- cl::init(true));
-
static cl::opt<std::string>
TrapFuncName("trap-func", cl::Hidden,
cl::desc("Emit a call to trap function rather than a trap instruction"),
@@ -150,25 +141,23 @@ UseInitArray("use-init-array",
cl::desc("Use .init_array instead of .ctors."),
cl::init(false));
-static cl::opt<unsigned>
-SSPBufferSize("stack-protector-buffer-size", cl::init(8),
- cl::desc("Lower bound for a buffer to be considered for "
- "stack protection"));
-
LTOModule::LTOModule(llvm::Module *m, llvm::TargetMachine *t)
: _module(m), _target(t),
- _context(*_target->getMCAsmInfo(), *_target->getRegisterInfo(), NULL),
- _mangler(_context, *_target->getDataLayout()) {}
+ _context(_target->getMCAsmInfo(), _target->getRegisterInfo(), NULL),
+ _mangler(_context, t) {}
/// isBitcodeFile - Returns 'true' if the file (or memory contents) is LLVM
/// bitcode.
bool LTOModule::isBitcodeFile(const void *mem, size_t length) {
- return llvm::sys::IdentifyFileType((const char*)mem, length)
- == llvm::sys::Bitcode_FileType;
+ return sys::fs::identify_magic(StringRef((const char *)mem, length)) ==
+ sys::fs::file_magic::bitcode;
}
bool LTOModule::isBitcodeFile(const char *path) {
- return llvm::sys::Path(path).isBitcodeFile();
+ sys::fs::file_magic type;
+ if (sys::fs::identify_magic(path, type))
+ return false;
+ return type == sys::fs::file_magic::bitcode;
}
/// isBitcodeFileForTarget - Returns 'true' if the file (or memory contents) is
@@ -210,17 +199,16 @@ LTOModule *LTOModule::makeLTOModule(const char *path, std::string &errMsg) {
LTOModule *LTOModule::makeLTOModule(int fd, const char *path,
size_t size, std::string &errMsg) {
- return makeLTOModule(fd, path, size, size, 0, errMsg);
+ return makeLTOModule(fd, path, size, 0, errMsg);
}
LTOModule *LTOModule::makeLTOModule(int fd, const char *path,
- size_t file_size,
size_t map_size,
off_t offset,
std::string &errMsg) {
OwningPtr<MemoryBuffer> buffer;
- if (error_code ec = MemoryBuffer::getOpenFile(fd, path, buffer, file_size,
- map_size, offset, false)) {
+ if (error_code ec =
+ MemoryBuffer::getOpenFileSlice(fd, path, buffer, map_size, offset)) {
errMsg = ec.message();
return NULL;
}
@@ -238,7 +226,6 @@ LTOModule *LTOModule::makeLTOModule(const void *mem, size_t length,
void LTOModule::getTargetOptions(TargetOptions &Options) {
Options.LessPreciseFPMADOption = EnableFPMAD;
Options.NoFramePointerElim = DisableFPElim;
- Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf;
Options.AllowFPOpFusion = FuseFPOps;
Options.UnsafeFPMath = EnableUnsafeFPMath;
Options.NoInfsFPMath = EnableNoInfsFPMath;
@@ -252,12 +239,10 @@ void LTOModule::getTargetOptions(TargetOptions &Options) {
Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt;
Options.DisableTailCalls = DisableTailCalls;
Options.StackAlignmentOverride = OverrideStackAlignment;
- Options.RealignStack = EnableRealignStack;
Options.TrapFuncName = TrapFuncName;
Options.PositionIndependentExecutable = EnablePIE;
Options.EnableSegmentedStacks = SegmentedStacks;
Options.UseInitArray = UseInitArray;
- Options.SSPBufferSize = SSPBufferSize;
}
LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer,
@@ -487,7 +472,7 @@ void LTOModule::addDefinedSymbol(const GlobalValue *def, bool isFunction) {
// set alignment part log2() can have rounding errors
uint32_t align = def->getAlignment();
- uint32_t attr = align ? CountTrailingZeros_32(def->getAlignment()) : 0;
+ uint32_t attr = align ? countTrailingZeros(def->getAlignment()) : 0;
// set permissions part
if (isFunction) {
@@ -743,7 +728,7 @@ namespace {
AddValueSymbols(Inst.getOperand(i).getExpr());
}
virtual void EmitLabel(MCSymbol *Symbol) {
- Symbol->setSection(*getCurrentSection());
+ Symbol->setSection(*getCurrentSection().first);
markDefined(*Symbol);
}
virtual void EmitDebugLabel(MCSymbol *Symbol) {
@@ -771,7 +756,8 @@ namespace {
virtual void EmitBundleUnlock() {}
// Noop calls.
- virtual void ChangeSection(const MCSection *Section) {}
+ virtual void ChangeSection(const MCSection *Section,
+ const MCExpr *Subsection) {}
virtual void InitToTextSection() {}
virtual void InitSections() {}
virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {}
@@ -787,9 +773,8 @@ namespace {
unsigned ByteAlignment) {}
virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol,
uint64_t Size, unsigned ByteAlignment) {}
- virtual void EmitBytes(StringRef Data, unsigned AddrSpace) {}
- virtual void EmitValueImpl(const MCExpr *Value, unsigned Size,
- unsigned AddrSpace) {}
+ virtual void EmitBytes(StringRef Data) {}
+ virtual void EmitValueImpl(const MCExpr *Value, unsigned Size) {}
virtual void EmitULEB128Value(const MCExpr *Value) {}
virtual void EmitSLEB128Value(const MCExpr *Value) {}
virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value,
diff --git a/tools/lto/LTOModule.h b/tools/lto/LTOModule.h
index 83f3a7d..902e9c5 100644
--- a/tools/lto/LTOModule.h
+++ b/tools/lto/LTOModule.h
@@ -82,7 +82,6 @@ public:
static LTOModule *makeLTOModule(int fd, const char *path,
size_t size, std::string &errMsg);
static LTOModule *makeLTOModule(int fd, const char *path,
- size_t file_size,
size_t map_size,
off_t offset,
std::string& errMsg);
diff --git a/tools/lto/Makefile b/tools/lto/Makefile
index ab2e16e..56c67df 100644
--- a/tools/lto/Makefile
+++ b/tools/lto/Makefile
@@ -39,15 +39,14 @@ ifeq ($(HOST_OS),Darwin)
endif
# extra options to override libtool defaults
LLVMLibsOptions := $(LLVMLibsOptions) \
- -Wl,-dead_strip \
- -Wl,-seg1addr -Wl,0xE0000000
+ -Wl,-dead_strip
# Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line
DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/')
ifneq ($(DARWIN_VERS),8)
LLVMLibsOptions := $(LLVMLibsOptions) \
-Wl,-install_name \
- -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)"
+ -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)"
endif
# If we're doing an Apple-style build, add the LTO object path.
diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp
index 11ad532..db7147c 100644
--- a/tools/lto/lto.cpp
+++ b/tools/lto/lto.cpp
@@ -78,8 +78,7 @@ lto_module_t lto_module_create_from_fd_at_offset(int fd, const char *path,
size_t file_size,
size_t map_size,
off_t offset) {
- return LTOModule::makeLTOModule(fd, path, file_size, map_size,
- offset, sLastErrorString);
+ return LTOModule::makeLTOModule(fd, path, map_size, offset, sLastErrorString);
}
/// lto_module_create_from_memory - Loads an object file from memory. Returns
@@ -141,20 +140,22 @@ void lto_codegen_dispose(lto_code_gen_t cg) {
/// which code will be generated. Returns true on error (check
/// lto_get_error_message() for details).
bool lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod) {
- return cg->addModule(mod, sLastErrorString);
+ return !cg->addModule(mod, sLastErrorString);
}
/// lto_codegen_set_debug_model - Sets what if any format of debug info should
/// be generated. Returns true on error (check lto_get_error_message() for
/// details).
bool lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model debug) {
- return cg->setDebugInfo(debug, sLastErrorString);
+ cg->setDebugInfo(debug);
+ return false;
}
/// lto_codegen_set_pic_model - Sets what code model to generated. Returns true
/// on error (check lto_get_error_message() for details).
bool lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model model) {
- return cg->setCodePICModel(model, sLastErrorString);
+ cg->setCodePICModel(model);
+ return false;
}
/// lto_codegen_set_cpu - Sets the cpu to generate code for.
@@ -186,7 +187,7 @@ void lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg,
/// that contains the merged contents of all modules added so far. Returns true
/// on error (check lto_get_error_message() for details).
bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char *path) {
- return cg->writeMergedModules(path, sLastErrorString);
+ return !cg->writeMergedModules(path, sLastErrorString);
}
/// lto_codegen_compile - Generates code for all added modules into one native
@@ -203,7 +204,7 @@ const void *lto_codegen_compile(lto_code_gen_t cg, size_t *length) {
/// native object file. The name of the file is written to name. Returns true on
/// error.
bool lto_codegen_compile_to_file(lto_code_gen_t cg, const char **name) {
- return cg->compile_to_file(name, sLastErrorString);
+ return !cg->compile_to_file(name, sLastErrorString);
}
/// lto_codegen_debug_options - Used to pass extra options to the code
diff --git a/tools/macho-dump/macho-dump.cpp b/tools/macho-dump/macho-dump.cpp
index 3bd3ecc..897a785 100644
--- a/tools/macho-dump/macho-dump.cpp
+++ b/tools/macho-dump/macho-dump.cpp
@@ -11,9 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Object/MachOObject.h"
+#include "llvm/Object/MachO.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ManagedStatic.h"
@@ -66,7 +67,8 @@ static void DumpSegmentCommandData(StringRef Name,
outs() << " ('flags', " << Flags << ")\n";
}
-static int DumpSectionData(MachOObject &Obj, unsigned Index, StringRef Name,
+static int DumpSectionData(const MachOObjectFile &Obj, unsigned Index,
+ StringRef Name,
StringRef SegmentName, uint64_t Address,
uint64_t Size, uint32_t Offset,
uint32_t Align, uint32_t RelocationTableOffset,
@@ -92,26 +94,22 @@ static int DumpSectionData(MachOObject &Obj, unsigned Index, StringRef Name,
outs() << " ),\n";
// Dump the relocation entries.
- int Res = 0;
outs() << " ('_relocations', [\n";
- for (unsigned i = 0; i != NumRelocationTableEntries; ++i) {
- InMemoryStruct<macho::RelocationEntry> RE;
- Obj.ReadRelocationEntry(RelocationTableOffset, i, RE);
- if (!RE) {
- Res = Error("unable to read relocation table entry '" + Twine(i) + "'");
- break;
- }
-
- outs() << " # Relocation " << i << "\n";
- outs() << " (('word-0', " << format("0x%x", RE->Word0) << "),\n";
- outs() << " ('word-1', " << format("0x%x", RE->Word1) << ")),\n";
+ unsigned RelNum = 0;
+ error_code EC;
+ for (relocation_iterator I = Obj.getSectionRelBegin(Index),
+ E = Obj.getSectionRelEnd(Index); I != E; I.increment(EC), ++RelNum) {
+ macho::RelocationEntry RE = Obj.getRelocation(I->getRawDataRefImpl());
+ outs() << " # Relocation " << RelNum << "\n";
+ outs() << " (('word-0', " << format("0x%x", RE.Word0) << "),\n";
+ outs() << " ('word-1', " << format("0x%x", RE.Word1) << ")),\n";
}
outs() << " ])\n";
// Dump the section data, if requested.
if (ShowSectionData) {
outs() << " ('_section_data', '";
- StringRef Data = Obj.getData(Offset, Size);
+ StringRef Data = Obj.getData().substr(Offset, Size);
for (unsigned i = 0; i != Data.size(); ++i) {
if (i && (i % 4) == 0)
outs() << ' ';
@@ -121,208 +119,162 @@ static int DumpSectionData(MachOObject &Obj, unsigned Index, StringRef Name,
outs() << "')\n";
}
- return Res;
+ return 0;
}
-static int DumpSegmentCommand(MachOObject &Obj,
- const MachOObject::LoadCommandInfo &LCI) {
- InMemoryStruct<macho::SegmentLoadCommand> SLC;
- Obj.ReadSegmentLoadCommand(LCI, SLC);
- if (!SLC)
- return Error("unable to read segment load command");
+static int DumpSegmentCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &LCI) {
+ macho::SegmentLoadCommand SLC = Obj.getSegmentLoadCommand(LCI);
- DumpSegmentCommandData(StringRef(SLC->Name, 16), SLC->VMAddress,
- SLC->VMSize, SLC->FileOffset, SLC->FileSize,
- SLC->MaxVMProtection, SLC->InitialVMProtection,
- SLC->NumSections, SLC->Flags);
+ DumpSegmentCommandData(StringRef(SLC.Name, 16), SLC.VMAddress,
+ SLC.VMSize, SLC.FileOffset, SLC.FileSize,
+ SLC.MaxVMProtection, SLC.InitialVMProtection,
+ SLC.NumSections, SLC.Flags);
// Dump the sections.
- int Res = 0;
outs() << " ('sections', [\n";
- for (unsigned i = 0; i != SLC->NumSections; ++i) {
- InMemoryStruct<macho::Section> Sect;
- Obj.ReadSection(LCI, i, Sect);
- if (!SLC) {
- Res = Error("unable to read section '" + Twine(i) + "'");
- break;
- }
-
- if ((Res = DumpSectionData(Obj, i, StringRef(Sect->Name, 16),
- StringRef(Sect->SegmentName, 16), Sect->Address,
- Sect->Size, Sect->Offset, Sect->Align,
- Sect->RelocationTableOffset,
- Sect->NumRelocationTableEntries, Sect->Flags,
- Sect->Reserved1, Sect->Reserved2)))
- break;
+ for (unsigned i = 0; i != SLC.NumSections; ++i) {
+ macho::Section Sect = Obj.getSection(LCI, i);
+ DumpSectionData(Obj, i, StringRef(Sect.Name, 16),
+ StringRef(Sect.SegmentName, 16), Sect.Address,
+ Sect.Size, Sect.Offset, Sect.Align,
+ Sect.RelocationTableOffset,
+ Sect.NumRelocationTableEntries, Sect.Flags,
+ Sect.Reserved1, Sect.Reserved2);
}
outs() << " ])\n";
- return Res;
+ return 0;
}
-static int DumpSegment64Command(MachOObject &Obj,
- const MachOObject::LoadCommandInfo &LCI) {
- InMemoryStruct<macho::Segment64LoadCommand> SLC;
- Obj.ReadSegment64LoadCommand(LCI, SLC);
- if (!SLC)
- return Error("unable to read segment load command");
-
- DumpSegmentCommandData(StringRef(SLC->Name, 16), SLC->VMAddress,
- SLC->VMSize, SLC->FileOffset, SLC->FileSize,
- SLC->MaxVMProtection, SLC->InitialVMProtection,
- SLC->NumSections, SLC->Flags);
+static int DumpSegment64Command(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &LCI) {
+ macho::Segment64LoadCommand SLC = Obj.getSegment64LoadCommand(LCI);
+ DumpSegmentCommandData(StringRef(SLC.Name, 16), SLC.VMAddress,
+ SLC.VMSize, SLC.FileOffset, SLC.FileSize,
+ SLC.MaxVMProtection, SLC.InitialVMProtection,
+ SLC.NumSections, SLC.Flags);
// Dump the sections.
- int Res = 0;
outs() << " ('sections', [\n";
- for (unsigned i = 0; i != SLC->NumSections; ++i) {
- InMemoryStruct<macho::Section64> Sect;
- Obj.ReadSection64(LCI, i, Sect);
- if (!SLC) {
- Res = Error("unable to read section '" + Twine(i) + "'");
- break;
- }
-
- if ((Res = DumpSectionData(Obj, i, StringRef(Sect->Name, 16),
- StringRef(Sect->SegmentName, 16), Sect->Address,
- Sect->Size, Sect->Offset, Sect->Align,
- Sect->RelocationTableOffset,
- Sect->NumRelocationTableEntries, Sect->Flags,
- Sect->Reserved1, Sect->Reserved2,
- Sect->Reserved3)))
- break;
+ for (unsigned i = 0; i != SLC.NumSections; ++i) {
+ macho::Section64 Sect = Obj.getSection64(LCI, i);
+
+ DumpSectionData(Obj, i, StringRef(Sect.Name, 16),
+ StringRef(Sect.SegmentName, 16), Sect.Address,
+ Sect.Size, Sect.Offset, Sect.Align,
+ Sect.RelocationTableOffset,
+ Sect.NumRelocationTableEntries, Sect.Flags,
+ Sect.Reserved1, Sect.Reserved2,
+ Sect.Reserved3);
}
outs() << " ])\n";
- return Res;
+ return 0;
}
-static void DumpSymbolTableEntryData(MachOObject &Obj,
+static void DumpSymbolTableEntryData(const MachOObjectFile &Obj,
unsigned Index, uint32_t StringIndex,
uint8_t Type, uint8_t SectionIndex,
- uint16_t Flags, uint64_t Value) {
+ uint16_t Flags, uint64_t Value,
+ StringRef StringTable) {
+ const char *Name = &StringTable.data()[StringIndex];
outs() << " # Symbol " << Index << "\n";
outs() << " (('n_strx', " << StringIndex << ")\n";
outs() << " ('n_type', " << format("0x%x", Type) << ")\n";
outs() << " ('n_sect', " << uint32_t(SectionIndex) << ")\n";
outs() << " ('n_desc', " << Flags << ")\n";
outs() << " ('n_value', " << Value << ")\n";
- outs() << " ('_string', '" << Obj.getStringAtIndex(StringIndex) << "')\n";
+ outs() << " ('_string', '" << Name << "')\n";
outs() << " ),\n";
}
-static int DumpSymtabCommand(MachOObject &Obj,
- const MachOObject::LoadCommandInfo &LCI) {
- InMemoryStruct<macho::SymtabLoadCommand> SLC;
- Obj.ReadSymtabLoadCommand(LCI, SLC);
- if (!SLC)
- return Error("unable to read segment load command");
-
- outs() << " ('symoff', " << SLC->SymbolTableOffset << ")\n";
- outs() << " ('nsyms', " << SLC->NumSymbolTableEntries << ")\n";
- outs() << " ('stroff', " << SLC->StringTableOffset << ")\n";
- outs() << " ('strsize', " << SLC->StringTableSize << ")\n";
+static int DumpSymtabCommand(const MachOObjectFile &Obj) {
+ macho::SymtabLoadCommand SLC = Obj.getSymtabLoadCommand();
- // Cache the string table data.
- Obj.RegisterStringTable(*SLC);
+ outs() << " ('symoff', " << SLC.SymbolTableOffset << ")\n";
+ outs() << " ('nsyms', " << SLC.NumSymbolTableEntries << ")\n";
+ outs() << " ('stroff', " << SLC.StringTableOffset << ")\n";
+ outs() << " ('strsize', " << SLC.StringTableSize << ")\n";
// Dump the string data.
outs() << " ('_string_data', '";
- outs().write_escaped(Obj.getStringTableData(),
+ StringRef StringTable = Obj.getStringTableData();
+ outs().write_escaped(StringTable,
/*UseHexEscapes=*/true) << "')\n";
// Dump the symbol table.
- int Res = 0;
outs() << " ('_symbols', [\n";
- for (unsigned i = 0; i != SLC->NumSymbolTableEntries; ++i) {
+ error_code EC;
+ unsigned SymNum = 0;
+ for (symbol_iterator I = Obj.begin_symbols(), E = Obj.end_symbols(); I != E;
+ I.increment(EC), ++SymNum) {
+ DataRefImpl DRI = I->getRawDataRefImpl();
if (Obj.is64Bit()) {
- InMemoryStruct<macho::Symbol64TableEntry> STE;
- Obj.ReadSymbol64TableEntry(SLC->SymbolTableOffset, i, STE);
- if (!STE) {
- Res = Error("unable to read symbol: '" + Twine(i) + "'");
- break;
- }
-
- DumpSymbolTableEntryData(Obj, i, STE->StringIndex, STE->Type,
- STE->SectionIndex, STE->Flags, STE->Value);
+ macho::Symbol64TableEntry STE = Obj.getSymbol64TableEntry(DRI);
+ DumpSymbolTableEntryData(Obj, SymNum, STE.StringIndex, STE.Type,
+ STE.SectionIndex, STE.Flags, STE.Value,
+ StringTable);
} else {
- InMemoryStruct<macho::SymbolTableEntry> STE;
- Obj.ReadSymbolTableEntry(SLC->SymbolTableOffset, i, STE);
- if (!SLC) {
- Res = Error("unable to read symbol: '" + Twine(i) + "'");
- break;
- }
-
- DumpSymbolTableEntryData(Obj, i, STE->StringIndex, STE->Type,
- STE->SectionIndex, STE->Flags, STE->Value);
+ macho::SymbolTableEntry STE = Obj.getSymbolTableEntry(DRI);
+ DumpSymbolTableEntryData(Obj, SymNum, STE.StringIndex, STE.Type,
+ STE.SectionIndex, STE.Flags, STE.Value,
+ StringTable);
}
}
outs() << " ])\n";
- return Res;
+ return 0;
}
-static int DumpDysymtabCommand(MachOObject &Obj,
- const MachOObject::LoadCommandInfo &LCI) {
- InMemoryStruct<macho::DysymtabLoadCommand> DLC;
- Obj.ReadDysymtabLoadCommand(LCI, DLC);
- if (!DLC)
- return Error("unable to read segment load command");
-
- outs() << " ('ilocalsym', " << DLC->LocalSymbolsIndex << ")\n";
- outs() << " ('nlocalsym', " << DLC->NumLocalSymbols << ")\n";
- outs() << " ('iextdefsym', " << DLC->ExternalSymbolsIndex << ")\n";
- outs() << " ('nextdefsym', " << DLC->NumExternalSymbols << ")\n";
- outs() << " ('iundefsym', " << DLC->UndefinedSymbolsIndex << ")\n";
- outs() << " ('nundefsym', " << DLC->NumUndefinedSymbols << ")\n";
- outs() << " ('tocoff', " << DLC->TOCOffset << ")\n";
- outs() << " ('ntoc', " << DLC->NumTOCEntries << ")\n";
- outs() << " ('modtaboff', " << DLC->ModuleTableOffset << ")\n";
- outs() << " ('nmodtab', " << DLC->NumModuleTableEntries << ")\n";
- outs() << " ('extrefsymoff', " << DLC->ReferenceSymbolTableOffset << ")\n";
+static int DumpDysymtabCommand(const MachOObjectFile &Obj) {
+ macho::DysymtabLoadCommand DLC = Obj.getDysymtabLoadCommand();
+
+ outs() << " ('ilocalsym', " << DLC.LocalSymbolsIndex << ")\n";
+ outs() << " ('nlocalsym', " << DLC.NumLocalSymbols << ")\n";
+ outs() << " ('iextdefsym', " << DLC.ExternalSymbolsIndex << ")\n";
+ outs() << " ('nextdefsym', " << DLC.NumExternalSymbols << ")\n";
+ outs() << " ('iundefsym', " << DLC.UndefinedSymbolsIndex << ")\n";
+ outs() << " ('nundefsym', " << DLC.NumUndefinedSymbols << ")\n";
+ outs() << " ('tocoff', " << DLC.TOCOffset << ")\n";
+ outs() << " ('ntoc', " << DLC.NumTOCEntries << ")\n";
+ outs() << " ('modtaboff', " << DLC.ModuleTableOffset << ")\n";
+ outs() << " ('nmodtab', " << DLC.NumModuleTableEntries << ")\n";
+ outs() << " ('extrefsymoff', " << DLC.ReferenceSymbolTableOffset << ")\n";
outs() << " ('nextrefsyms', "
- << DLC->NumReferencedSymbolTableEntries << ")\n";
- outs() << " ('indirectsymoff', " << DLC->IndirectSymbolTableOffset << ")\n";
+ << DLC.NumReferencedSymbolTableEntries << ")\n";
+ outs() << " ('indirectsymoff', " << DLC.IndirectSymbolTableOffset << ")\n";
outs() << " ('nindirectsyms', "
- << DLC->NumIndirectSymbolTableEntries << ")\n";
- outs() << " ('extreloff', " << DLC->ExternalRelocationTableOffset << ")\n";
- outs() << " ('nextrel', " << DLC->NumExternalRelocationTableEntries << ")\n";
- outs() << " ('locreloff', " << DLC->LocalRelocationTableOffset << ")\n";
- outs() << " ('nlocrel', " << DLC->NumLocalRelocationTableEntries << ")\n";
+ << DLC.NumIndirectSymbolTableEntries << ")\n";
+ outs() << " ('extreloff', " << DLC.ExternalRelocationTableOffset << ")\n";
+ outs() << " ('nextrel', " << DLC.NumExternalRelocationTableEntries << ")\n";
+ outs() << " ('locreloff', " << DLC.LocalRelocationTableOffset << ")\n";
+ outs() << " ('nlocrel', " << DLC.NumLocalRelocationTableEntries << ")\n";
// Dump the indirect symbol table.
- int Res = 0;
outs() << " ('_indirect_symbols', [\n";
- for (unsigned i = 0; i != DLC->NumIndirectSymbolTableEntries; ++i) {
- InMemoryStruct<macho::IndirectSymbolTableEntry> ISTE;
- Obj.ReadIndirectSymbolTableEntry(*DLC, i, ISTE);
- if (!ISTE) {
- Res = Error("unable to read segment load command");
- break;
- }
-
+ for (unsigned i = 0; i != DLC.NumIndirectSymbolTableEntries; ++i) {
+ macho::IndirectSymbolTableEntry ISTE =
+ Obj.getIndirectSymbolTableEntry(DLC, i);
outs() << " # Indirect Symbol " << i << "\n";
outs() << " (('symbol_index', "
- << format("0x%x", ISTE->Index) << "),),\n";
+ << format("0x%x", ISTE.Index) << "),),\n";
}
outs() << " ])\n";
- return Res;
+ return 0;
}
-static int DumpLinkeditDataCommand(MachOObject &Obj,
- const MachOObject::LoadCommandInfo &LCI) {
- InMemoryStruct<macho::LinkeditDataLoadCommand> LLC;
- Obj.ReadLinkeditDataLoadCommand(LCI, LLC);
- if (!LLC)
- return Error("unable to read segment load command");
-
- outs() << " ('dataoff', " << LLC->DataOffset << ")\n"
- << " ('datasize', " << LLC->DataSize << ")\n"
+static int
+DumpLinkeditDataCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &LCI) {
+ macho::LinkeditDataLoadCommand LLC = Obj.getLinkeditDataLoadCommand(LCI);
+ outs() << " ('dataoff', " << LLC.DataOffset << ")\n"
+ << " ('datasize', " << LLC.DataSize << ")\n"
<< " ('_addresses', [\n";
SmallVector<uint64_t, 8> Addresses;
- Obj.ReadULEB128s(LLC->DataOffset, Addresses);
+ Obj.ReadULEB128s(LLC.DataOffset, Addresses);
for (unsigned i = 0, e = Addresses.size(); i != e; ++i)
outs() << " # Address " << i << '\n'
<< " ('address', " << format("0x%x", Addresses[i]) << "),\n";
@@ -332,28 +284,22 @@ static int DumpLinkeditDataCommand(MachOObject &Obj,
return 0;
}
-static int DumpDataInCodeDataCommand(MachOObject &Obj,
- const MachOObject::LoadCommandInfo &LCI) {
- InMemoryStruct<macho::LinkeditDataLoadCommand> LLC;
- Obj.ReadLinkeditDataLoadCommand(LCI, LLC);
- if (!LLC)
- return Error("unable to read data-in-code load command");
-
- outs() << " ('dataoff', " << LLC->DataOffset << ")\n"
- << " ('datasize', " << LLC->DataSize << ")\n"
+static int
+DumpDataInCodeDataCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &LCI) {
+ macho::LinkeditDataLoadCommand LLC = Obj.getLinkeditDataLoadCommand(LCI);
+ outs() << " ('dataoff', " << LLC.DataOffset << ")\n"
+ << " ('datasize', " << LLC.DataSize << ")\n"
<< " ('_data_regions', [\n";
-
- unsigned NumRegions = LLC->DataSize / 8;
+ unsigned NumRegions = LLC.DataSize / sizeof(macho::DataInCodeTableEntry);
for (unsigned i = 0; i < NumRegions; ++i) {
- InMemoryStruct<macho::DataInCodeTableEntry> DICE;
- Obj.ReadDataInCodeTableEntry(LLC->DataOffset, i, DICE);
- if (!DICE)
- return Error("unable to read DataInCodeTableEntry");
+ macho::DataInCodeTableEntry DICE =
+ Obj.getDataInCodeTableEntry(LLC.DataOffset, i);
outs() << " # DICE " << i << "\n"
- << " ('offset', " << DICE->Offset << ")\n"
- << " ('length', " << DICE->Length << ")\n"
- << " ('kind', " << DICE->Kind << ")\n";
+ << " ('offset', " << DICE.Offset << ")\n"
+ << " ('length', " << DICE.Length << ")\n"
+ << " ('kind', " << DICE.Kind << ")\n";
}
outs() <<" ])\n";
@@ -361,99 +307,111 @@ static int DumpDataInCodeDataCommand(MachOObject &Obj,
return 0;
}
-static int DumpLinkerOptionsCommand(MachOObject &Obj,
- const MachOObject::LoadCommandInfo &LCI) {
- InMemoryStruct<macho::LinkerOptionsLoadCommand> LOLC;
- Obj.ReadLinkerOptionsLoadCommand(LCI, LOLC);
- if (!LOLC)
- return Error("unable to read linker options load command");
-
- outs() << " ('count', " << LOLC->Count << ")\n"
- << " ('_strings', [\n";
-
- uint64_t DataSize = LOLC->Size - sizeof(macho::LinkerOptionsLoadCommand);
- StringRef Data = Obj.getData(
- LCI.Offset + sizeof(macho::LinkerOptionsLoadCommand), DataSize);
- for (unsigned i = 0; i != LOLC->Count; ++i) {
- std::pair<StringRef,StringRef> Split = Data.split('\0');
- outs() << "\t\"";
- outs().write_escaped(Split.first);
- outs() << "\",\n";
- Data = Split.second;
- }
- outs() <<" ])\n";
+static int
+DumpLinkerOptionsCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &LCI) {
+ macho::LinkerOptionsLoadCommand LOLC = Obj.getLinkerOptionsLoadCommand(LCI);
+ outs() << " ('count', " << LOLC.Count << ")\n"
+ << " ('_strings', [\n";
+
+ uint64_t DataSize = LOLC.Size - sizeof(macho::LinkerOptionsLoadCommand);
+ const char *P = LCI.Ptr + sizeof(macho::LinkerOptionsLoadCommand);
+ StringRef Data(P, DataSize);
+ for (unsigned i = 0; i != LOLC.Count; ++i) {
+ std::pair<StringRef,StringRef> Split = Data.split('\0');
+ outs() << "\t\"";
+ outs().write_escaped(Split.first);
+ outs() << "\",\n";
+ Data = Split.second;
+ }
+ outs() <<" ])\n";
return 0;
}
-
-static int DumpLoadCommand(MachOObject &Obj, unsigned Index) {
- const MachOObject::LoadCommandInfo &LCI = Obj.getLoadCommandInfo(Index);
- int Res = 0;
-
- outs() << " # Load Command " << Index << "\n"
- << " (('command', " << LCI.Command.Type << ")\n"
- << " ('size', " << LCI.Command.Size << ")\n";
- switch (LCI.Command.Type) {
+static int DumpLoadCommand(const MachOObjectFile &Obj,
+ MachOObjectFile::LoadCommandInfo &LCI) {
+ switch (LCI.C.Type) {
case macho::LCT_Segment:
- Res = DumpSegmentCommand(Obj, LCI);
- break;
+ return DumpSegmentCommand(Obj, LCI);
case macho::LCT_Segment64:
- Res = DumpSegment64Command(Obj, LCI);
- break;
+ return DumpSegment64Command(Obj, LCI);
case macho::LCT_Symtab:
- Res = DumpSymtabCommand(Obj, LCI);
- break;
+ return DumpSymtabCommand(Obj);
case macho::LCT_Dysymtab:
- Res = DumpDysymtabCommand(Obj, LCI);
- break;
+ return DumpDysymtabCommand(Obj);
case macho::LCT_CodeSignature:
case macho::LCT_SegmentSplitInfo:
case macho::LCT_FunctionStarts:
- Res = DumpLinkeditDataCommand(Obj, LCI);
- break;
+ return DumpLinkeditDataCommand(Obj, LCI);
case macho::LCT_DataInCode:
- Res = DumpDataInCodeDataCommand(Obj, LCI);
- break;
+ return DumpDataInCodeDataCommand(Obj, LCI);
case macho::LCT_LinkerOptions:
- Res = DumpLinkerOptionsCommand(Obj, LCI);
- break;
+ return DumpLinkerOptionsCommand(Obj, LCI);
default:
- Warning("unknown load command: " + Twine(LCI.Command.Type));
- break;
+ Warning("unknown load command: " + Twine(LCI.C.Type));
+ return 0;
}
- outs() << " ),\n";
+}
+
+static int DumpLoadCommand(const MachOObjectFile &Obj, unsigned Index,
+ MachOObjectFile::LoadCommandInfo &LCI) {
+ outs() << " # Load Command " << Index << "\n"
+ << " (('command', " << LCI.C.Type << ")\n"
+ << " ('size', " << LCI.C.Size << ")\n";
+ int Res = DumpLoadCommand(Obj, LCI);
+ outs() << " ),\n";
return Res;
}
+static void printHeader(const MachOObjectFile *Obj,
+ const macho::Header &Header) {
+ outs() << "('cputype', " << Header.CPUType << ")\n";
+ outs() << "('cpusubtype', " << Header.CPUSubtype << ")\n";
+ outs() << "('filetype', " << Header.FileType << ")\n";
+ outs() << "('num_load_commands', " << Header.NumLoadCommands << ")\n";
+ outs() << "('load_commands_size', " << Header.SizeOfLoadCommands << ")\n";
+ outs() << "('flag', " << Header.Flags << ")\n";
+
+ // Print extended header if 64-bit.
+ if (Obj->is64Bit()) {
+ macho::Header64Ext Header64Ext = Obj->getHeader64Ext();
+ outs() << "('reserved', " << Header64Ext.Reserved << ")\n";
+ }
+}
+
int main(int argc, char **argv) {
ProgramName = argv[0];
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
cl::ParseCommandLineOptions(argc, argv, "llvm Mach-O dumping tool\n");
- // Load the input file.
- std::string ErrorStr;
- OwningPtr<MemoryBuffer> InputBuffer;
- if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFile, InputBuffer))
- return Error("unable to read input: '" + ec.message() + "'");
+ OwningPtr<Binary> Binary;
+ if (error_code EC = createBinary(InputFile, Binary))
+ return Error("unable to read input: '" + EC.message() + "'");
- // Construct the Mach-O wrapper object.
- OwningPtr<MachOObject> InputObject(
- MachOObject::LoadFromBuffer(InputBuffer.take(), &ErrorStr));
+ const MachOObjectFile *InputObject = dyn_cast<MachOObjectFile>(Binary.get());
if (!InputObject)
- return Error("unable to load object: '" + ErrorStr + "'");
+ return Error("Not a MachO object");
// Print the header
- InputObject->printHeader(outs());
+ macho::Header Header = InputObject->getHeader();
+ printHeader(InputObject, Header);
// Print the load commands.
int Res = 0;
+ MachOObjectFile::LoadCommandInfo Command =
+ InputObject->getFirstLoadCommandInfo();
outs() << "('load_commands', [\n";
- for (unsigned i = 0; i != InputObject->getHeader().NumLoadCommands; ++i)
- if ((Res = DumpLoadCommand(*InputObject, i)))
+ for (unsigned i = 0; ; ++i) {
+ if (DumpLoadCommand(*InputObject, i, Command))
break;
+
+ if (i == Header.NumLoadCommands - 1)
+ break;
+ Command = InputObject->getNextLoadCommandInfo(Command);
+ }
outs() << "])\n";
return Res;
diff --git a/tools/obj2yaml/CMakeLists.txt b/tools/obj2yaml/CMakeLists.txt
new file mode 100644
index 0000000..6b39193
--- /dev/null
+++ b/tools/obj2yaml/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(LLVM_LINK_COMPONENTS object)
+
+add_llvm_utility(obj2yaml
+ obj2yaml.cpp coff2yaml.cpp
+ )
+
+target_link_libraries(obj2yaml LLVMSupport)
diff --git a/tools/llvm-ranlib/Makefile b/tools/obj2yaml/Makefile
index cca9501..95f393d 100644
--- a/tools/llvm-ranlib/Makefile
+++ b/tools/obj2yaml/Makefile
@@ -1,17 +1,20 @@
-##===- tools/llvm-ranlib/Makefile --------------------------*- Makefile -*-===##
-#
+##===- utils/obj2yaml/Makefile ----------------------------*- Makefile -*-===##
+#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
-#
+#
##===----------------------------------------------------------------------===##
-LEVEL := ../..
-TOOLNAME := llvm-ranlib
-LINK_COMPONENTS := archive
+LEVEL = ../..
+TOOLNAME = obj2yaml
+LINK_COMPONENTS := object
# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS := 1
+TOOL_NO_EXPORTS = 1
+
+# Don't install this utility
+NO_INSTALL = 1
include $(LEVEL)/Makefile.common
diff --git a/tools/obj2yaml/coff2yaml.cpp b/tools/obj2yaml/coff2yaml.cpp
new file mode 100644
index 0000000..1e28c4e
--- /dev/null
+++ b/tools/obj2yaml/coff2yaml.cpp
@@ -0,0 +1,120 @@
+//===------ utils/obj2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "obj2yaml.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/COFFYAML.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace llvm;
+
+namespace {
+
+class COFFDumper {
+ const object::COFFObjectFile &Obj;
+ COFFYAML::Object YAMLObj;
+ void dumpHeader(const object::coff_file_header *Header);
+ void dumpSections(unsigned numSections);
+ void dumpSymbols(unsigned numSymbols);
+
+public:
+ COFFDumper(const object::COFFObjectFile &Obj);
+ COFFYAML::Object &getYAMLObj();
+};
+
+}
+
+static void check(error_code ec) {
+ if (ec)
+ report_fatal_error(ec.message());
+}
+
+COFFDumper::COFFDumper(const object::COFFObjectFile &Obj) : Obj(Obj) {
+ const object::coff_file_header *Header;
+ check(Obj.getCOFFHeader(Header));
+ dumpHeader(Header);
+ dumpSections(Header->NumberOfSections);
+ dumpSymbols(Header->NumberOfSymbols);
+}
+
+void COFFDumper::dumpHeader(const object::coff_file_header *Header) {
+ YAMLObj.Header.Machine = Header->Machine;
+ YAMLObj.Header.Characteristics = Header->Characteristics;
+}
+
+void COFFDumper::dumpSections(unsigned NumSections) {
+ std::vector<COFFYAML::Section> &Sections = YAMLObj.Sections;
+ error_code ec;
+ for (object::section_iterator iter = Obj.begin_sections();
+ iter != Obj.end_sections(); iter.increment(ec)) {
+ check(ec);
+ const object::coff_section *Sect = Obj.getCOFFSection(iter);
+ COFFYAML::Section Sec;
+ Sec.Name = Sect->Name; // FIXME: check the null termination!
+ uint32_t Characteristics = Sect->Characteristics;
+ Sec.Header.Characteristics = Characteristics;
+ Sec.Alignment = 1 << (((Characteristics >> 20) & 0xf) - 1);
+
+ ArrayRef<uint8_t> sectionData;
+ Obj.getSectionContents(Sect, sectionData);
+ Sec.SectionData = object::yaml::BinaryRef(sectionData);
+
+ std::vector<COFFYAML::Relocation> Relocations;
+ for (object::relocation_iterator rIter = iter->begin_relocations();
+ rIter != iter->end_relocations(); rIter.increment(ec)) {
+ const object::coff_relocation *reloc = Obj.getCOFFRelocation(rIter);
+ COFFYAML::Relocation Rel;
+ object::symbol_iterator Sym = rIter->getSymbol();
+ StringRef Name;
+ Sym->getName(Rel.SymbolName);
+ Rel.VirtualAddress = reloc->VirtualAddress;
+ Rel.Type = reloc->Type;
+ Relocations.push_back(Rel);
+ }
+ Sec.Relocations = Relocations;
+ Sections.push_back(Sec);
+ }
+}
+
+void COFFDumper::dumpSymbols(unsigned NumSymbols) {
+ error_code ec;
+ std::vector<COFFYAML::Symbol> &Symbols = YAMLObj.Symbols;
+ for (object::symbol_iterator iter = Obj.begin_symbols();
+ iter != Obj.end_symbols(); iter.increment(ec)) {
+ check(ec);
+ const object::coff_symbol *Symbol = Obj.getCOFFSymbol(iter);
+ COFFYAML::Symbol Sym;
+ Obj.getSymbolName(Symbol, Sym.Name);
+ Sym.SimpleType = COFF::SymbolBaseType(Symbol->getBaseType());
+ Sym.ComplexType = COFF::SymbolComplexType(Symbol->getComplexType());
+ Sym.Header.StorageClass = Symbol->StorageClass;
+ Sym.Header.Value = Symbol->Value;
+ Sym.Header.SectionNumber = Symbol->SectionNumber;
+ Sym.Header.NumberOfAuxSymbols = Symbol->NumberOfAuxSymbols;
+ Sym.AuxiliaryData = object::yaml::BinaryRef(Obj.getSymbolAuxData(Symbol));
+ Symbols.push_back(Sym);
+ }
+}
+
+COFFYAML::Object &COFFDumper::getYAMLObj() {
+ return YAMLObj;
+}
+
+error_code coff2yaml(raw_ostream &Out, MemoryBuffer *Buff) {
+ error_code ec;
+ object::COFFObjectFile Obj(Buff, ec);
+ check(ec);
+ COFFDumper Dumper(Obj);
+
+ yaml::Output Yout(Out);
+ Yout << Dumper.getYAMLObj();
+
+ return object::object_error::success;
+}
diff --git a/tools/obj2yaml/obj2yaml.cpp b/tools/obj2yaml/obj2yaml.cpp
new file mode 100644
index 0000000..8d128b3
--- /dev/null
+++ b/tools/obj2yaml/obj2yaml.cpp
@@ -0,0 +1,54 @@
+//===------ utils/obj2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "obj2yaml.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+
+using namespace llvm;
+
+namespace {
+enum ObjectFileType {
+ coff
+};
+}
+
+cl::opt<ObjectFileType> InputFormat(
+ cl::desc("Choose input format"),
+ cl::values(clEnumVal(coff, "process COFF object files"), clEnumValEnd));
+
+cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input file>"),
+ cl::init("-"));
+
+int main(int argc, char *argv[]) {
+ cl::ParseCommandLineOptions(argc, argv);
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ // Process the input file
+ OwningPtr<MemoryBuffer> buf;
+
+ // TODO: If this is an archive, then burst it and dump each entry
+ if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, buf)) {
+ errs() << "Error: '" << ec.message() << "' opening file '" << InputFilename
+ << "'\n";
+ } else {
+ ec = coff2yaml(outs(), buf.take());
+ if (ec)
+ errs() << "Error: " << ec.message() << " dumping COFF file\n";
+ }
+
+ return 0;
+}
diff --git a/tools/obj2yaml/obj2yaml.h b/tools/obj2yaml/obj2yaml.h
new file mode 100644
index 0000000..bde82e6
--- /dev/null
+++ b/tools/obj2yaml/obj2yaml.h
@@ -0,0 +1,22 @@
+//===------ utils/obj2yaml.hpp - obj2yaml conversion tool -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// This file declares some helper routines, and also the format-specific
+// writers. To add a new format, add the declaration here, and, in a separate
+// source file, implement it.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_OBJ2YAML_H
+#define LLVM_TOOLS_OBJ2YAML_H
+
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+
+llvm::error_code coff2yaml(llvm::raw_ostream &Out, llvm::MemoryBuffer *TheObj);
+
+#endif
diff --git a/tools/opt/CMakeLists.txt b/tools/opt/CMakeLists.txt
index cf5e5a8..9195911 100644
--- a/tools/opt/CMakeLists.txt
+++ b/tools/opt/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser bitwriter instrumentation scalaropts objcarcopts ipo vectorize)
+set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser bitwriter irreader instrumentation scalaropts objcarcopts ipo vectorize)
add_llvm_tool(opt
AnalysisWrappers.cpp
@@ -6,3 +6,4 @@ add_llvm_tool(opt
PrintSCC.cpp
opt.cpp
)
+set_target_properties(opt PROPERTIES ENABLE_EXPORTS 1)
diff --git a/tools/opt/LLVMBuild.txt b/tools/opt/LLVMBuild.txt
index a866d12..77b9446 100644
--- a/tools/opt/LLVMBuild.txt
+++ b/tools/opt/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = opt
parent = Tools
-required_libraries = AsmParser BitReader BitWriter IPO Instrumentation Scalar ObjCARC all-targets
+required_libraries = AsmParser BitReader BitWriter IRReader IPO Instrumentation Scalar ObjCARC all-targets
diff --git a/tools/opt/Makefile b/tools/opt/Makefile
index 79ed815..a451005 100644
--- a/tools/opt/Makefile
+++ b/tools/opt/Makefile
@@ -9,6 +9,6 @@
LEVEL := ../..
TOOLNAME := opt
-LINK_COMPONENTS := bitreader bitwriter asmparser instrumentation scalaropts objcarcopts ipo vectorize all-targets
+LINK_COMPONENTS := bitreader bitwriter asmparser irreader instrumentation scalaropts objcarcopts ipo vectorize all-targets
include $(LEVEL)/Makefile.common
diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp
index 81a2de2..37637ca 100644
--- a/tools/opt/opt.cpp
+++ b/tools/opt/opt.cpp
@@ -26,17 +26,18 @@
#include "llvm/DebugInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Module.h"
+#include "llvm/IRReader/IRReader.h"
#include "llvm/LinkAllIR.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/PassManager.h"
#include "llvm/Support/Debug.h"
-#include "llvm/Support/IRReader.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PassNameParser.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
@@ -388,8 +389,11 @@ struct BreakpointPrinter : public ModulePass {
for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) {
std::string Name;
DISubprogram SP(NMD->getOperand(i));
- if (SP.Verify())
- getContextName(SP.getContext(), Name);
+ assert((!SP || SP.isSubprogram()) &&
+ "A MDNode in llvm.dbg.sp should be null or a DISubprogram.");
+ if (!SP)
+ continue;
+ getContextName(SP.getContext(), Name);
Name = Name + SP.getDisplayName().str();
if (!Name.empty() && Processed.insert(Name)) {
Out << Name << "\n";
@@ -444,7 +448,6 @@ static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM,
}
Builder.DisableUnitAtATime = !UnitAtATime;
Builder.DisableUnrollLoops = OptLevel == 0;
- Builder.DisableSimplifyLibCalls = DisableSimplifyLibCalls;
Builder.populateFunctionPassManager(FPM);
Builder.populateModulePassManager(MPM);
@@ -464,7 +467,6 @@ static void AddStandardCompilePasses(PassManagerBase &PM) {
if (!DisableInline)
Builder.Inliner = createFunctionInliningPass();
Builder.OptLevel = 3;
- Builder.DisableSimplifyLibCalls = DisableSimplifyLibCalls;
Builder.populateModulePassManager(PM);
}
@@ -489,7 +491,6 @@ static TargetOptions GetTargetOptions() {
TargetOptions Options;
Options.LessPreciseFPMADOption = EnableFPMAD;
Options.NoFramePointerElim = DisableFPElim;
- Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf;
Options.AllowFPOpFusion = FuseFPOps;
Options.UnsafeFPMath = EnableUnsafeFPMath;
Options.NoInfsFPMath = EnableNoInfsFPMath;
@@ -503,12 +504,10 @@ static TargetOptions GetTargetOptions() {
Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt;
Options.DisableTailCalls = DisableTailCalls;
Options.StackAlignmentOverride = OverrideStackAlignment;
- Options.RealignStack = EnableRealignStack;
Options.TrapFuncName = TrapFuncName;
Options.PositionIndependentExecutable = EnablePIE;
Options.EnableSegmentedStacks = SegmentedStacks;
Options.UseInitArray = UseInitArray;
- Options.SSPBufferSize = SSPBufferSize;
return Options;
}
@@ -566,6 +565,7 @@ int main(int argc, char **argv) {
// Initialize passes
PassRegistry &Registry = *PassRegistry::getPassRegistry();
initializeCore(Registry);
+ initializeDebugIRPass(Registry);
initializeScalarOpts(Registry);
initializeObjCARCOpts(Registry);
initializeVectorization(Registry);
@@ -588,7 +588,7 @@ int main(int argc, char **argv) {
SMDiagnostic Err;
// Load the input module...
- std::auto_ptr<Module> M;
+ OwningPtr<Module> M;
M.reset(ParseIRFile(InputFilename, Err, Context));
if (M.get() == 0) {
@@ -613,7 +613,7 @@ int main(int argc, char **argv) {
std::string ErrorInfo;
Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo,
- raw_fd_ostream::F_Binary));
+ sys::fs::F_Binary));
if (!ErrorInfo.empty()) {
errs() << ErrorInfo << '\n';
return 1;
@@ -655,7 +655,7 @@ int main(int argc, char **argv) {
TargetMachine *Machine = 0;
if (ModuleTriple.getArch())
Machine = GetTargetMachine(Triple(ModuleTriple));
- std::auto_ptr<TargetMachine> TM(Machine);
+ OwningPtr<TargetMachine> TM(Machine);
// Add internal analysis passes from the target machine.
if (TM.get())
@@ -666,6 +666,9 @@ int main(int argc, char **argv) {
FPasses.reset(new FunctionPassManager(M.get()));
if (TD)
FPasses->add(new DataLayout(*TD));
+ if (TM.get())
+ TM->addAnalysisPasses(*FPasses);
+
}
if (PrintBreakpoints) {
@@ -676,7 +679,7 @@ int main(int argc, char **argv) {
std::string ErrorInfo;
Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo,
- raw_fd_ostream::F_Binary));
+ sys::fs::F_Binary));
if (!ErrorInfo.empty()) {
errs() << ErrorInfo << '\n';
return 1;
diff --git a/tools/yaml2obj/CMakeLists.txt b/tools/yaml2obj/CMakeLists.txt
new file mode 100644
index 0000000..8d9d652
--- /dev/null
+++ b/tools/yaml2obj/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(LLVM_LINK_COMPONENTS object)
+
+add_llvm_utility(yaml2obj
+ yaml2obj.cpp
+ yaml2coff.cpp
+ yaml2elf.cpp
+ )
+
+target_link_libraries(yaml2obj LLVMSupport)
diff --git a/tools/yaml2obj/Makefile b/tools/yaml2obj/Makefile
new file mode 100644
index 0000000..8801795
--- /dev/null
+++ b/tools/yaml2obj/Makefile
@@ -0,0 +1,20 @@
+##===- utils/yaml2obj/Makefile ----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+TOOLNAME = yaml2obj
+LINK_COMPONENTS := object
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+# Don't install this utility
+NO_INSTALL = 1
+
+include $(LEVEL)/Makefile.common
diff --git a/tools/yaml2obj/yaml2coff.cpp b/tools/yaml2obj/yaml2coff.cpp
new file mode 100644
index 0000000..11aae0e
--- /dev/null
+++ b/tools/yaml2obj/yaml2coff.cpp
@@ -0,0 +1,288 @@
+//===- yaml2coff - Convert YAML to a COFF object file ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief The COFF component of yaml2obj.
+///
+//===----------------------------------------------------------------------===//
+
+#include "yaml2obj.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Object/COFFYAML.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
+#include <vector>
+
+using namespace llvm;
+
+/// This parses a yaml stream that represents a COFF object file.
+/// See docs/yaml2obj for the yaml scheema.
+struct COFFParser {
+ COFFParser(COFFYAML::Object &Obj) : Obj(Obj) {
+ // A COFF string table always starts with a 4 byte size field. Offsets into
+ // it include this size, so allocate it now.
+ StringTable.append(4, 0);
+ }
+
+ bool parseSections() {
+ for (std::vector<COFFYAML::Section>::iterator i = Obj.Sections.begin(),
+ e = Obj.Sections.end(); i != e; ++i) {
+ COFFYAML::Section &Sec = *i;
+
+ // If the name is less than 8 bytes, store it in place, otherwise
+ // store it in the string table.
+ StringRef Name = Sec.Name;
+
+ if (Name.size() <= COFF::NameSize) {
+ std::copy(Name.begin(), Name.end(), Sec.Header.Name);
+ } else {
+ // Add string to the string table and format the index for output.
+ unsigned Index = getStringIndex(Name);
+ std::string str = utostr(Index);
+ if (str.size() > 7) {
+ errs() << "String table got too large";
+ return false;
+ }
+ Sec.Header.Name[0] = '/';
+ std::copy(str.begin(), str.end(), Sec.Header.Name + 1);
+ }
+
+ Sec.Header.Characteristics |= (Log2_32(Sec.Alignment) + 1) << 20;
+ }
+ return true;
+ }
+
+ bool parseSymbols() {
+ for (std::vector<COFFYAML::Symbol>::iterator i = Obj.Symbols.begin(),
+ e = Obj.Symbols.end(); i != e; ++i) {
+ COFFYAML::Symbol &Sym = *i;
+
+ // If the name is less than 8 bytes, store it in place, otherwise
+ // store it in the string table.
+ StringRef Name = Sym.Name;
+ if (Name.size() <= COFF::NameSize) {
+ std::copy(Name.begin(), Name.end(), Sym.Header.Name);
+ } else {
+ // Add string to the string table and format the index for output.
+ unsigned Index = getStringIndex(Name);
+ *reinterpret_cast<support::aligned_ulittle32_t*>(
+ Sym.Header.Name + 4) = Index;
+ }
+
+ Sym.Header.Type = Sym.SimpleType;
+ Sym.Header.Type |= Sym.ComplexType << COFF::SCT_COMPLEX_TYPE_SHIFT;
+ }
+ return true;
+ }
+
+ bool parse() {
+ if (!parseSections())
+ return false;
+ if (!parseSymbols())
+ return false;
+ return true;
+ }
+
+ unsigned getStringIndex(StringRef Str) {
+ StringMap<unsigned>::iterator i = StringTableMap.find(Str);
+ if (i == StringTableMap.end()) {
+ unsigned Index = StringTable.size();
+ StringTable.append(Str.begin(), Str.end());
+ StringTable.push_back(0);
+ StringTableMap[Str] = Index;
+ return Index;
+ }
+ return i->second;
+ }
+
+ COFFYAML::Object &Obj;
+
+ StringMap<unsigned> StringTableMap;
+ std::string StringTable;
+};
+
+// Take a CP and assign addresses and sizes to everything. Returns false if the
+// layout is not valid to do.
+static bool layoutCOFF(COFFParser &CP) {
+ uint32_t SectionTableStart = 0;
+ uint32_t SectionTableSize = 0;
+
+ // The section table starts immediately after the header, including the
+ // optional header.
+ SectionTableStart = sizeof(COFF::header) + CP.Obj.Header.SizeOfOptionalHeader;
+ SectionTableSize = sizeof(COFF::section) * CP.Obj.Sections.size();
+
+ uint32_t CurrentSectionDataOffset = SectionTableStart + SectionTableSize;
+
+ // Assign each section data address consecutively.
+ for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(),
+ e = CP.Obj.Sections.end();
+ i != e; ++i) {
+ if (i->SectionData.binary_size() > 0) {
+ i->Header.SizeOfRawData = i->SectionData.binary_size();
+ i->Header.PointerToRawData = CurrentSectionDataOffset;
+ CurrentSectionDataOffset += i->Header.SizeOfRawData;
+ if (!i->Relocations.empty()) {
+ i->Header.PointerToRelocations = CurrentSectionDataOffset;
+ i->Header.NumberOfRelocations = i->Relocations.size();
+ CurrentSectionDataOffset += i->Header.NumberOfRelocations *
+ COFF::RelocationSize;
+ }
+ // TODO: Handle alignment.
+ } else {
+ i->Header.SizeOfRawData = 0;
+ i->Header.PointerToRawData = 0;
+ }
+ }
+
+ uint32_t SymbolTableStart = CurrentSectionDataOffset;
+
+ // Calculate number of symbols.
+ uint32_t NumberOfSymbols = 0;
+ for (std::vector<COFFYAML::Symbol>::iterator i = CP.Obj.Symbols.begin(),
+ e = CP.Obj.Symbols.end();
+ i != e; ++i) {
+ unsigned AuxBytes = i->AuxiliaryData.binary_size();
+ if (AuxBytes % COFF::SymbolSize != 0) {
+ errs() << "AuxiliaryData size not a multiple of symbol size!\n";
+ return false;
+ }
+ i->Header.NumberOfAuxSymbols = AuxBytes / COFF::SymbolSize;
+ NumberOfSymbols += 1 + i->Header.NumberOfAuxSymbols;
+ }
+
+ // Store all the allocated start addresses in the header.
+ CP.Obj.Header.NumberOfSections = CP.Obj.Sections.size();
+ CP.Obj.Header.NumberOfSymbols = NumberOfSymbols;
+ CP.Obj.Header.PointerToSymbolTable = SymbolTableStart;
+
+ *reinterpret_cast<support::ulittle32_t *>(&CP.StringTable[0])
+ = CP.StringTable.size();
+
+ return true;
+}
+
+template <typename value_type>
+struct binary_le_impl {
+ value_type Value;
+ binary_le_impl(value_type V) : Value(V) {}
+};
+
+template <typename value_type>
+raw_ostream &operator <<( raw_ostream &OS
+ , const binary_le_impl<value_type> &BLE) {
+ char Buffer[sizeof(BLE.Value)];
+ support::endian::write<value_type, support::little, support::unaligned>(
+ Buffer, BLE.Value);
+ OS.write(Buffer, sizeof(BLE.Value));
+ return OS;
+}
+
+template <typename value_type>
+binary_le_impl<value_type> binary_le(value_type V) {
+ return binary_le_impl<value_type>(V);
+}
+
+bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
+ OS << binary_le(CP.Obj.Header.Machine)
+ << binary_le(CP.Obj.Header.NumberOfSections)
+ << binary_le(CP.Obj.Header.TimeDateStamp)
+ << binary_le(CP.Obj.Header.PointerToSymbolTable)
+ << binary_le(CP.Obj.Header.NumberOfSymbols)
+ << binary_le(CP.Obj.Header.SizeOfOptionalHeader)
+ << binary_le(CP.Obj.Header.Characteristics);
+
+ // Output section table.
+ for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(),
+ e = CP.Obj.Sections.end();
+ i != e; ++i) {
+ OS.write(i->Header.Name, COFF::NameSize);
+ OS << binary_le(i->Header.VirtualSize)
+ << binary_le(i->Header.VirtualAddress)
+ << binary_le(i->Header.SizeOfRawData)
+ << binary_le(i->Header.PointerToRawData)
+ << binary_le(i->Header.PointerToRelocations)
+ << binary_le(i->Header.PointerToLineNumbers)
+ << binary_le(i->Header.NumberOfRelocations)
+ << binary_le(i->Header.NumberOfLineNumbers)
+ << binary_le(i->Header.Characteristics);
+ }
+
+ unsigned CurSymbol = 0;
+ StringMap<unsigned> SymbolTableIndexMap;
+ for (std::vector<COFFYAML::Symbol>::iterator I = CP.Obj.Symbols.begin(),
+ E = CP.Obj.Symbols.end();
+ I != E; ++I) {
+ SymbolTableIndexMap[I->Name] = CurSymbol;
+ CurSymbol += 1 + I->Header.NumberOfAuxSymbols;
+ }
+
+ // Output section data.
+ for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(),
+ e = CP.Obj.Sections.end();
+ i != e; ++i) {
+ i->SectionData.writeAsBinary(OS);
+ for (unsigned I2 = 0, E2 = i->Relocations.size(); I2 != E2; ++I2) {
+ const COFFYAML::Relocation &R = i->Relocations[I2];
+ uint32_t SymbolTableIndex = SymbolTableIndexMap[R.SymbolName];
+ OS << binary_le(R.VirtualAddress)
+ << binary_le(SymbolTableIndex)
+ << binary_le(R.Type);
+ }
+ }
+
+ // Output symbol table.
+
+ for (std::vector<COFFYAML::Symbol>::const_iterator i = CP.Obj.Symbols.begin(),
+ e = CP.Obj.Symbols.end();
+ i != e; ++i) {
+ OS.write(i->Header.Name, COFF::NameSize);
+ OS << binary_le(i->Header.Value)
+ << binary_le(i->Header.SectionNumber)
+ << binary_le(i->Header.Type)
+ << binary_le(i->Header.StorageClass)
+ << binary_le(i->Header.NumberOfAuxSymbols);
+ i->AuxiliaryData.writeAsBinary(OS);
+ }
+
+ // Output string table.
+ OS.write(&CP.StringTable[0], CP.StringTable.size());
+ return true;
+}
+
+int yaml2coff(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) {
+ yaml::Input YIn(Buf->getBuffer());
+ COFFYAML::Object Doc;
+ YIn >> Doc;
+ if (YIn.error()) {
+ errs() << "yaml2obj: Failed to parse YAML file!\n";
+ return 1;
+ }
+
+ COFFParser CP(Doc);
+ if (!CP.parse()) {
+ errs() << "yaml2obj: Failed to parse YAML file!\n";
+ return 1;
+ }
+
+ if (!layoutCOFF(CP)) {
+ errs() << "yaml2obj: Failed to layout COFF file!\n";
+ return 1;
+ }
+ if (!writeCOFF(CP, Out)) {
+ errs() << "yaml2obj: Failed to write COFF file!\n";
+ return 1;
+ }
+ return 0;
+}
diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp
new file mode 100644
index 0000000..61252a4
--- /dev/null
+++ b/tools/yaml2obj/yaml2elf.cpp
@@ -0,0 +1,398 @@
+//===- yaml2elf - Convert YAML to a ELF object file -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief The ELF component of yaml2obj.
+///
+//===----------------------------------------------------------------------===//
+
+#include "yaml2obj.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Object/ELFYAML.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+// There is similar code in yaml2coff, but with some slight COFF-specific
+// variations like different initial state. Might be able to deduplicate
+// some day, but also want to make sure that the Mach-O use case is served.
+//
+// This class has a deliberately small interface, since a lot of
+// implementation variation is possible.
+//
+// TODO: Use an ordered container with a suffix-based comparison in order
+// to deduplicate suffixes. std::map<> with a custom comparator is likely
+// to be the simplest implementation, but a suffix trie could be more
+// suitable for the job.
+namespace {
+class StringTableBuilder {
+ /// \brief Indices of strings currently present in `Buf`.
+ StringMap<unsigned> StringIndices;
+ /// \brief The contents of the string table as we build it.
+ std::string Buf;
+public:
+ StringTableBuilder() {
+ Buf.push_back('\0');
+ }
+ /// \returns Index of string in string table.
+ unsigned addString(StringRef S) {
+ StringMapEntry<unsigned> &Entry = StringIndices.GetOrCreateValue(S);
+ unsigned &I = Entry.getValue();
+ if (I != 0)
+ return I;
+ I = Buf.size();
+ Buf.append(S.begin(), S.end());
+ Buf.push_back('\0');
+ return I;
+ }
+ size_t size() const {
+ return Buf.size();
+ }
+ void writeToStream(raw_ostream &OS) {
+ OS.write(Buf.data(), Buf.size());
+ }
+};
+} // end anonymous namespace
+
+// This class is used to build up a contiguous binary blob while keeping
+// track of an offset in the output (which notionally begins at
+// `InitialOffset`).
+namespace {
+class ContiguousBlobAccumulator {
+ const uint64_t InitialOffset;
+ SmallVector<char, 128> Buf;
+ raw_svector_ostream OS;
+
+ /// \returns The new offset.
+ uint64_t padToAlignment(unsigned Align) {
+ uint64_t CurrentOffset = InitialOffset + OS.tell();
+ uint64_t AlignedOffset = RoundUpToAlignment(CurrentOffset, Align);
+ for (; CurrentOffset != AlignedOffset; ++CurrentOffset)
+ OS.write('\0');
+ return AlignedOffset; // == CurrentOffset;
+ }
+
+public:
+ ContiguousBlobAccumulator(uint64_t InitialOffset_)
+ : InitialOffset(InitialOffset_), Buf(), OS(Buf) {}
+ template <class Integer>
+ raw_ostream &getOSAndAlignedOffset(Integer &Offset, unsigned Align = 16) {
+ Offset = padToAlignment(Align);
+ return OS;
+ }
+ void writeBlobToStream(raw_ostream &Out) { Out << OS.str(); }
+};
+} // end anonymous namespace
+
+// Used to keep track of section names, so that in the YAML file sections
+// can be referenced by name instead of by index.
+namespace {
+class SectionNameToIdxMap {
+ StringMap<int> Map;
+public:
+ /// \returns true if name is already present in the map.
+ bool addName(StringRef SecName, unsigned i) {
+ StringMapEntry<int> &Entry = Map.GetOrCreateValue(SecName, -1);
+ if (Entry.getValue() != -1)
+ return true;
+ Entry.setValue((int)i);
+ return false;
+ }
+ /// \returns true if name is not present in the map
+ bool lookupSection(StringRef SecName, unsigned &Idx) const {
+ StringMap<int>::const_iterator I = Map.find(SecName);
+ if (I == Map.end())
+ return true;
+ Idx = I->getValue();
+ return false;
+ }
+};
+} // end anonymous namespace
+
+template <class T>
+static size_t vectorDataSize(const std::vector<T> &Vec) {
+ return Vec.size() * sizeof(T);
+}
+
+template <class T>
+static void writeVectorData(raw_ostream &OS, const std::vector<T> &Vec) {
+ OS.write((const char *)Vec.data(), vectorDataSize(Vec));
+}
+
+template <class T>
+static void zero(T &Obj) {
+ memset(&Obj, 0, sizeof(Obj));
+}
+
+/// \brief Create a string table in `SHeader`, which we assume is already
+/// zero'd.
+template <class Elf_Shdr>
+static void createStringTableSectionHeader(Elf_Shdr &SHeader,
+ StringTableBuilder &STB,
+ ContiguousBlobAccumulator &CBA) {
+ SHeader.sh_type = ELF::SHT_STRTAB;
+ STB.writeToStream(CBA.getOSAndAlignedOffset(SHeader.sh_offset));
+ SHeader.sh_size = STB.size();
+ SHeader.sh_addralign = 1;
+}
+
+namespace {
+/// \brief "Single point of truth" for the ELF file construction.
+/// TODO: This class still has a ways to go before it is truly a "single
+/// point of truth".
+template <class ELFT>
+class ELFState {
+ /// \brief The future ".strtab" section.
+ StringTableBuilder DotStrtab;
+ /// \brief The section number of the ".strtab" section.
+ unsigned DotStrtabSecNo;
+ /// \brief The accumulated contents of all sections so far.
+ ContiguousBlobAccumulator &SectionContentAccum;
+ typedef typename object::ELFObjectFile<ELFT>::Elf_Ehdr Elf_Ehdr;
+ /// \brief The ELF file header.
+ Elf_Ehdr &Header;
+
+ SectionNameToIdxMap &SN2I;
+
+public:
+
+ ELFState(Elf_Ehdr &Header_, ContiguousBlobAccumulator &Accum,
+ unsigned DotStrtabSecNo_, SectionNameToIdxMap &SN2I_)
+ : DotStrtab(), DotStrtabSecNo(DotStrtabSecNo_),
+ SectionContentAccum(Accum), Header(Header_), SN2I(SN2I_) {}
+
+ unsigned getDotStrTabSecNo() const { return DotStrtabSecNo; }
+ StringTableBuilder &getStringTable() { return DotStrtab; }
+ ContiguousBlobAccumulator &getSectionContentAccum() {
+ return SectionContentAccum;
+ }
+ SectionNameToIdxMap &getSN2I() { return SN2I; }
+};
+} // end anonymous namespace
+
+// FIXME: At this point it is fairly clear that we need to refactor these
+// static functions into methods of a class sharing some typedefs. These
+// ELF type names are insane.
+template <class ELFT>
+static void
+addSymbols(const std::vector<ELFYAML::Symbol> &Symbols, ELFState<ELFT> &State,
+ std::vector<typename object::ELFObjectFile<ELFT>::Elf_Sym> &Syms,
+ unsigned SymbolBinding) {
+ typedef typename object::ELFObjectFile<ELFT>::Elf_Sym Elf_Sym;
+ for (unsigned i = 0, e = Symbols.size(); i != e; ++i) {
+ const ELFYAML::Symbol &Sym = Symbols[i];
+ Elf_Sym Symbol;
+ zero(Symbol);
+ if (!Sym.Name.empty())
+ Symbol.st_name = State.getStringTable().addString(Sym.Name);
+ Symbol.setBindingAndType(SymbolBinding, Sym.Type);
+ if (!Sym.Section.empty()) {
+ unsigned Index;
+ if (State.getSN2I().lookupSection(Sym.Section, Index)) {
+ errs() << "error: Unknown section referenced: '" << Sym.Section
+ << "' by YAML symbol " << Sym.Name << ".\n";
+ exit(1);
+ }
+ Symbol.st_shndx = Index;
+ } // else Symbol.st_shndex == SHN_UNDEF (== 0), since it was zero'd earlier.
+ Symbol.st_value = Sym.Value;
+ Symbol.st_size = Sym.Size;
+ Syms.push_back(Symbol);
+ }
+}
+
+template <class ELFT>
+static void handleSymtabSectionHeader(
+ const ELFYAML::LocalGlobalWeakSymbols &Symbols, ELFState<ELFT> &State,
+ typename object::ELFObjectFile<ELFT>::Elf_Shdr &SHeader) {
+
+ typedef typename object::ELFObjectFile<ELFT>::Elf_Sym Elf_Sym;
+ SHeader.sh_type = ELF::SHT_SYMTAB;
+ SHeader.sh_link = State.getDotStrTabSecNo();
+ // One greater than symbol table index of the last local symbol.
+ SHeader.sh_info = Symbols.Local.size() + 1;
+ SHeader.sh_entsize = sizeof(Elf_Sym);
+
+ std::vector<Elf_Sym> Syms;
+ {
+ // Ensure STN_UNDEF is present
+ Elf_Sym Sym;
+ zero(Sym);
+ Syms.push_back(Sym);
+ }
+ addSymbols(Symbols.Local, State, Syms, ELF::STB_LOCAL);
+ addSymbols(Symbols.Global, State, Syms, ELF::STB_GLOBAL);
+ addSymbols(Symbols.Weak, State, Syms, ELF::STB_WEAK);
+
+ ContiguousBlobAccumulator &CBA = State.getSectionContentAccum();
+ writeVectorData(CBA.getOSAndAlignedOffset(SHeader.sh_offset), Syms);
+ SHeader.sh_size = vectorDataSize(Syms);
+}
+
+template <class ELFT>
+static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) {
+ using namespace llvm::ELF;
+ typedef typename object::ELFObjectFile<ELFT>::Elf_Ehdr Elf_Ehdr;
+ typedef typename object::ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr;
+
+ const ELFYAML::FileHeader &Hdr = Doc.Header;
+
+ Elf_Ehdr Header;
+ zero(Header);
+ Header.e_ident[EI_MAG0] = 0x7f;
+ Header.e_ident[EI_MAG1] = 'E';
+ Header.e_ident[EI_MAG2] = 'L';
+ Header.e_ident[EI_MAG3] = 'F';
+ Header.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
+ bool IsLittleEndian = ELFT::TargetEndianness == support::little;
+ Header.e_ident[EI_DATA] = IsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB;
+ Header.e_ident[EI_VERSION] = EV_CURRENT;
+ Header.e_ident[EI_OSABI] = Hdr.OSABI;
+ Header.e_ident[EI_ABIVERSION] = 0;
+ Header.e_type = Hdr.Type;
+ Header.e_machine = Hdr.Machine;
+ Header.e_version = EV_CURRENT;
+ Header.e_entry = Hdr.Entry;
+ Header.e_ehsize = sizeof(Elf_Ehdr);
+
+ // TODO: Flesh out section header support.
+ // TODO: Program headers.
+
+ Header.e_shentsize = sizeof(Elf_Shdr);
+ // Immediately following the ELF header.
+ Header.e_shoff = sizeof(Header);
+ const std::vector<ELFYAML::Section> &Sections = Doc.Sections;
+ // "+ 4" for
+ // - SHT_NULL entry (placed first, i.e. 0'th entry)
+ // - symbol table (.symtab) (placed third to last)
+ // - string table (.strtab) (placed second to last)
+ // - section header string table. (placed last)
+ Header.e_shnum = Sections.size() + 4;
+ // Place section header string table last.
+ Header.e_shstrndx = Header.e_shnum - 1;
+ const unsigned DotStrtabSecNo = Header.e_shnum - 2;
+
+ // XXX: This offset is tightly coupled with the order that we write
+ // things to `OS`.
+ const size_t SectionContentBeginOffset =
+ Header.e_ehsize + Header.e_shentsize * Header.e_shnum;
+ ContiguousBlobAccumulator CBA(SectionContentBeginOffset);
+ SectionNameToIdxMap SN2I;
+ for (unsigned i = 0, e = Sections.size(); i != e; ++i) {
+ StringRef Name = Sections[i].Name;
+ if (Name.empty())
+ continue;
+ // "+ 1" to take into account the SHT_NULL entry.
+ if (SN2I.addName(Name, i + 1)) {
+ errs() << "error: Repeated section name: '" << Name
+ << "' at YAML section number " << i << ".\n";
+ return 1;
+ }
+ }
+
+ ELFState<ELFT> State(Header, CBA, DotStrtabSecNo, SN2I);
+
+ StringTableBuilder SHStrTab;
+ std::vector<Elf_Shdr> SHeaders;
+ {
+ // Ensure SHN_UNDEF entry is present. An all-zero section header is a
+ // valid SHN_UNDEF entry since SHT_NULL == 0.
+ Elf_Shdr SHdr;
+ zero(SHdr);
+ SHeaders.push_back(SHdr);
+ }
+ for (unsigned i = 0, e = Sections.size(); i != e; ++i) {
+ const ELFYAML::Section &Sec = Sections[i];
+ Elf_Shdr SHeader;
+ zero(SHeader);
+ SHeader.sh_name = SHStrTab.addString(Sec.Name);
+ SHeader.sh_type = Sec.Type;
+ SHeader.sh_flags = Sec.Flags;
+ SHeader.sh_addr = Sec.Address;
+
+ Sec.Content.writeAsBinary(CBA.getOSAndAlignedOffset(SHeader.sh_offset));
+ SHeader.sh_size = Sec.Content.binary_size();
+
+ if (!Sec.Link.empty()) {
+ unsigned Index;
+ if (SN2I.lookupSection(Sec.Link, Index)) {
+ errs() << "error: Unknown section referenced: '" << Sec.Link
+ << "' at YAML section number " << i << ".\n";
+ return 1;
+ }
+ SHeader.sh_link = Index;
+ }
+ SHeader.sh_info = 0;
+ SHeader.sh_addralign = Sec.AddressAlign;
+ SHeader.sh_entsize = 0;
+ SHeaders.push_back(SHeader);
+ }
+
+ // .symtab section.
+ Elf_Shdr SymtabSHeader;
+ zero(SymtabSHeader);
+ SymtabSHeader.sh_name = SHStrTab.addString(StringRef(".symtab"));
+ handleSymtabSectionHeader<ELFT>(Doc.Symbols, State, SymtabSHeader);
+ SHeaders.push_back(SymtabSHeader);
+
+ // .strtab string table header.
+ Elf_Shdr DotStrTabSHeader;
+ zero(DotStrTabSHeader);
+ DotStrTabSHeader.sh_name = SHStrTab.addString(StringRef(".strtab"));
+ createStringTableSectionHeader(DotStrTabSHeader, State.getStringTable(), CBA);
+ SHeaders.push_back(DotStrTabSHeader);
+
+ // Section header string table header.
+ Elf_Shdr SHStrTabSHeader;
+ zero(SHStrTabSHeader);
+ createStringTableSectionHeader(SHStrTabSHeader, SHStrTab, CBA);
+ SHeaders.push_back(SHStrTabSHeader);
+
+ OS.write((const char *)&Header, sizeof(Header));
+ writeVectorData(OS, SHeaders);
+ CBA.writeBlobToStream(OS);
+ return 0;
+}
+
+static bool is64Bit(const ELFYAML::Object &Doc) {
+ return Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64);
+}
+
+static bool isLittleEndian(const ELFYAML::Object &Doc) {
+ return Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB);
+}
+
+int yaml2elf(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) {
+ yaml::Input YIn(Buf->getBuffer());
+ ELFYAML::Object Doc;
+ YIn >> Doc;
+ if (YIn.error()) {
+ errs() << "yaml2obj: Failed to parse YAML file!\n";
+ return 1;
+ }
+ using object::ELFType;
+ typedef ELFType<support::little, 8, true> LE64;
+ typedef ELFType<support::big, 8, true> BE64;
+ typedef ELFType<support::little, 4, false> LE32;
+ typedef ELFType<support::big, 4, false> BE32;
+ if (is64Bit(Doc)) {
+ if (isLittleEndian(Doc))
+ return writeELF<LE64>(outs(), Doc);
+ else
+ return writeELF<BE64>(outs(), Doc);
+ } else {
+ if (isLittleEndian(Doc))
+ return writeELF<LE32>(outs(), Doc);
+ else
+ return writeELF<BE32>(outs(), Doc);
+ }
+}
diff --git a/tools/yaml2obj/yaml2obj.cpp b/tools/yaml2obj/yaml2obj.cpp
new file mode 100644
index 0000000..6d1107c
--- /dev/null
+++ b/tools/yaml2obj/yaml2obj.cpp
@@ -0,0 +1,71 @@
+//===- yaml2obj - Convert YAML to a binary object file --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This program takes a YAML description of an object file and outputs the
+// binary equivalent.
+//
+// This is used for writing tests that require binary files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "yaml2obj.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+
+using namespace llvm;
+
+static cl::opt<std::string>
+ Input(cl::Positional, cl::desc("<input>"), cl::init("-"));
+
+// TODO: The "right" way to tell what kind of object file a given YAML file
+// corresponds to is to look at YAML "tags" (e.g. `!Foo`). Then, different
+// tags (`!ELF`, `!COFF`, etc.) would be used to discriminate between them.
+// Interpreting the tags is needed eventually for when writing test cases,
+// so that we can e.g. have `!Archive` contain a sequence of `!ELF`, and
+// just Do The Right Thing. However, interpreting these tags and acting on
+// them appropriately requires some work in the YAML parser and the YAMLIO
+// library.
+enum YAMLObjectFormat {
+ YOF_COFF,
+ YOF_ELF
+};
+
+cl::opt<YAMLObjectFormat> Format(
+ "format",
+ cl::desc("Interpret input as this type of object file"),
+ cl::values(
+ clEnumValN(YOF_COFF, "coff", "COFF object file format"),
+ clEnumValN(YOF_ELF, "elf", "ELF object file format"),
+ clEnumValEnd));
+
+
+int main(int argc, char **argv) {
+ cl::ParseCommandLineOptions(argc, argv);
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ OwningPtr<MemoryBuffer> Buf;
+ if (MemoryBuffer::getFileOrSTDIN(Input, Buf))
+ return 1;
+ if (Format == YOF_COFF) {
+ return yaml2coff(outs(), Buf.get());
+ } else if (Format == YOF_ELF) {
+ return yaml2elf(outs(), Buf.get());
+ } else {
+ errs() << "Not yet implemented\n";
+ return 1;
+ }
+}
diff --git a/tools/yaml2obj/yaml2obj.h b/tools/yaml2obj/yaml2obj.h
new file mode 100644
index 0000000..095435c
--- /dev/null
+++ b/tools/yaml2obj/yaml2obj.h
@@ -0,0 +1,22 @@
+//===--- yaml2obj.h - -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief Common declarations for yaml2obj
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_YAML2OBJ_H
+#define LLVM_TOOLS_YAML2OBJ_H
+
+namespace llvm {
+ class raw_ostream;
+ class MemoryBuffer;
+}
+int yaml2coff(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf);
+int yaml2elf(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf);
+
+#endif