Commit a12aeb05 authored by Gideon Müller's avatar Gideon Müller

Initial Source upload

parent 2201c624
cmake_minimum_required(VERSION 2.8.8)
project(f2h)
#set(LLVM_SRC_DIR "/usr/local/llvm")
#set(LLVM_BIN_DIR "/usr/local/llvm/bin")
#set(LLVM_DIR "/usr/local/llvm/lib/")
#message(STATUS "LLVM DIR: ${LLVM_SRC_DIR}")
#find_package(LLVM)
set(LLVM_PATH /usr/local/llvm)
link_directories(${LLVM_PATH}/lib)
include_directories(${LLVM_PATH}/include/)
add_definitions(
-D__STDC_LIMIT_MACROS
-D__STDC_CONSTANT_MACROS
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -std=c++11")
add_library(LLVM SHARED IMPORTED "/usr/local/llvm/lib")
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
# Set your project compile flags.
# E.g. if using the C++ header files
# you will need to enable C++11 support
# for your compiler.
#include_directories(${LLVM_INCLUDE_DIRS})
#add_definitions(${LLVM_DEFINITIONS})
# Now build our tools
add_executable(f2h
# llvm-dwarfdump.cpp
main.cpp
CommonBlock.hpp
CommonBlock.cpp
Subprogram.hpp
Subprogram.cpp
Variable.hpp
Variable.cpp
)
set_property(TARGET f2h PROPERTY CXX_STANDARD 11)
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
endif()
# Find the libraries that correspond to the LLVM components
# that we wish to use
#llvm_map_components_to_libnames(llvm_libs debuginfodwarf object support)
# Link against LLVM libraries
#target_link_libraries(f2h LLVM${llvm_libs})
target_link_libraries(f2h
LLVMX86AsmParser # MC, MCParser, Support, X86Desc, X86Info
LLVMX86Desc # MC, Support, X86AsmPrinter, X86Info
LLVMX86AsmPrinter # MC, Support, X86Utils
LLVMX86Info # MC, Support, Target
LLVMX86Utils # Core, Support
LLVMipo
LLVMScalarOpts
LLVMInstCombine
LLVMTransformUtils
LLVMipa
LLVMAnalysis
LLVMTarget
LLVMOption # Support
LLVMMCParser # MC, Support
LLVMMC # Object, Support
LLVMObject # BitReader, Core, Support
LLVMBitReader # Core, Support
LLVMCore # Support
LLVMSupport
)
#include "CommonBlock.hpp"
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Dwarf.h"
#include <sstream>
using namespace llvm;
llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const CommonBlock &cb)
{
o << "common block " << cb.name_ << '\n';
for (auto &v : cb.vars_)
{
o << " " << v->cDeclaration();
}
return o;
}
CommonBlock::CommonMap CommonBlock::map_;
CommonBlock::Handle
CommonBlock::extractAndAdd(const DWARFDebugInfoEntryMinimal *die, DWARFCompileUnit *cu)
{
std::string commonName = die->getName(cu, llvm::DINameKind::ShortName);
auto fit = CommonBlock::map_.find(commonName);
if (fit == CommonBlock::map_.end()) {
CommonBlock::Handle cb(CommonBlock::extract(die, cu));
CommonBlock::map_.insert(std::make_pair(commonName, cb));
return cb;
} else {
return fit->second;
}
}
CommonBlock::Handle CommonBlock::extract(const DWARFDebugInfoEntryMinimal *die, DWARFCompileUnit *cu)
{
CommonBlock::Handle r(new CommonBlock());
if (die->getTag() != dwarf::DW_TAG_common_block) {
throw std::runtime_error("DIE is not a common block");
}
// names
r->name_ = die->getName(cu, DINameKind::ShortName);
r->linkageName_ = die->getName(cu, DINameKind::LinkageName);
auto debugInfoData = cu->getDebugInfoExtractor();
auto offset = die->getOffset();
assert(debugInfoData.isValidOffset(offset));
auto abbrCode = debugInfoData.getULEB128(&offset);
assert(abbrCode);
// children of common are the variables it contains
auto child = die->getFirstChild();
while (child && !child->isNULL()) {
auto var = Variable::extract(Variable::COMMON_BLOCK_MEMBER, child, cu);
r->vars_.push_back(std::move(var));
child = child->getSibling();
}
r->insertPadding();
return r;
}
void CommonBlock::insertPadding()
{
assert(vars_[0]->location_ == 0);
size_t loc = 0, padCount=1;
auto it = vars_.begin();
loc += (*it)->elementSize() * (*it)->elementCount();
++it;
while (it != vars_.end()) {
ptrdiff_t pad = (*it)->location_ - loc;
assert(pad >= 0);
if (pad) {
std::stringstream ss;
ss << "pad" << padCount++;
Variable::Handle padVar(new Variable());
padVar->location_ = loc;
padVar->elementSize_ = 1;
padVar->type_ = dwarf::DW_ATE_unsigned;
padVar->name_ = ss.str();
padVar->context_ = Variable::COMMON_BLOCK_MEMBER;
if (pad > 1) {
padVar->dims_.push_back(Variable::Dimension(std::make_pair(0, pad-1)));
}
it = vars_.insert(it, std::move(padVar));
++it;
loc += pad;
}
loc += (*it)->elementSize() * (*it)->elementCount();
++it;
}
}
std::string CommonBlock::cDeclaration() const
{
std::stringstream ss;
ss << "extern struct { \n";
for (auto &v : vars_)
{
ss << " " << v->cDeclaration() << ";" << std::endl;
}
ss << "} " << linkageName_ << ";" << std::endl;
return ss.str();
}
#ifndef CommonBlock_hpp
#define CommonBlock_hpp
#include <string>
#include <vector>
#include <unordered_map>
#include <memory>
#include "Variable.hpp"
namespace llvm {
class DWARFDebugInfoEntryMinimal;
class DWARFCompileUnit;
}
class CommonBlock
{
public:
using Handle = std::shared_ptr<CommonBlock>;
using CommonMap = std::unordered_map<std::string, Handle>;
/**
* Extracts the common common block definition from the dwarf data
* and stores it in the map. If the map already contains a common
* block with the same name, then this method assumes they are
* identical and does nothing.
*/
static Handle extractAndAdd(const llvm::DWARFDebugInfoEntryMinimal *die, llvm::DWARFCompileUnit *cu);
/// Contains all common blocks added so far and indexed by name.
static CommonMap map_;
/// \return C declaration for this common block.
std::string cDeclaration() const;
private:
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CommonBlock &);
static Handle extract(const llvm::DWARFDebugInfoEntryMinimal *die, llvm::DWARFCompileUnit *cu);
void insertPadding();
std::string name_;
std::string linkageName_;
std::vector<Variable::Handle> vars_;
};
#endif
#include "Subprogram.hpp"
#include "CommonBlock.hpp"
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Dwarf.h"
#include <sstream>
using namespace llvm;
Subprogram::Subprogram() : unsupported_(true)
{
}
Subprogram::~Subprogram()
{
}
Subprogram::Handle Subprogram::extract(const llvm::DWARFDebugInfoEntryMinimal *die, llvm::DWARFCompileUnit *cu)
{
Handle r(new Subprogram());
r->name_ = die->getName(cu, DINameKind::ShortName);
r->linkageName_ = die->getName(cu, DINameKind::LinkageName);
// ignore main
if (!r->name_.compare("main")) {
r->unsupported_ = true;
return r;
}
int stringParamCount = 0;
auto child = die->getFirstChild();
while (child && !child->isNULL()) {
auto tag = child->getTag();
if (tag == dwarf::DW_TAG_common_block) {
try {
CommonBlock::extractAndAdd(child, cu);
} catch (std::runtime_error &ex) {
errs() << "skipping common block in " << r->name_ << " because " << ex.what() << "\n";
}
}
else if (tag == dwarf::DW_TAG_formal_parameter) {
try {
Variable::Handle h = Variable::extract(Variable::PARAMETER, child, cu);
// if there is a parameter named __result, then it is an out parameter for
// the return value of a function. I still haven't figured out how this works
// so best to skip this function
if (!h->name_.compare("__result")) {
errs() << "function " << r->name_ << " appears to return an array or string which is not supported yet, skipping...\n";
break;
}
// if this argument is a string, then there will be a hidden argument at the end for its length
if (h->isString()) {
++stringParamCount;
}
r->args_.push_back(std::move(h));
} catch (std::runtime_error &ex) {
errs() << "extract subrountine " << r->name_ << " failed on parameter: " << ex.what() << "\n";
throw ex;
}
}
// need to check the local variables because that is the only way to identify
// a function that returns a value
else if (tag == dwarf::DW_TAG_variable) {
r->extractReturn(child, cu);
}
child = child->getSibling();
}
// mark parameters at the end of the argument list as string lengths
auto rit = r->args_.rbegin();
while (stringParamCount > 0) {
rit->get()->context_ = Variable::STRING_LEN_PARAMETER;
--stringParamCount;
++rit;
}
r->unsupported_ = false;
return r;
}
std::string Subprogram::cDeclaration() const
{
std::stringstream ss;
int line = 1;
if (unsupported_) {
ss << "// function " << name_ << " is not supported yet\n";
} else {
// return type
if (returnVal_) {
ss << returnVal_->cType() << " ";
} else {
ss << "void ";
}
// name
ss << linkageName_ << "( ";
// arguments
size_t narg = args_.size();
for (size_t i=0; i<narg; ++i) {
auto &arg = args_[i];
if (i>0) {
ss << ", ";
if (ss.tellp() > line * 100) {
ss << std::endl << " ";
++line;
}
}
try {
ss << arg->cDeclaration();
} catch (std::runtime_error &ex) {
errs() << "Subprogram::cDeclaration--argument cDecl failed: " << ex.what() << "\n";
errs() << "Skipping " << name_ << "\n";
throw ex;
}
}
ss << " );";
}
return ss.str();
}
void Subprogram::extractReturn(const llvm::DWARFDebugInfoEntryMinimal *die, llvm::DWARFCompileUnit *cu)
{
std::string resultName = "__result_" + name_;
const char *varName = die->getName(cu, DINameKind::ShortName);
if (varName && !resultName.compare(varName)) {
returnVal_ = Variable::extract(Variable::PARAMETER, die, cu);
}
}
\ No newline at end of file
#ifndef Subprogram_hpp
#define Subprogram_hpp
#include <string>
#include <vector>
#include <unordered_map>
#include <memory>
#include "Variable.hpp"
namespace llvm {
class DWARFDebugInfoEntryMinimal;
class DWARFCompileUnit;
}
class Subprogram
{
public:
using Handle = std::shared_ptr<Subprogram>;
Subprogram();
~Subprogram();
/**
* Extract information about the subprogram from dwarf data.
* Any referenced common blocks are added to the static map.
*/
static Handle extract(const llvm::DWARFDebugInfoEntryMinimal *die, llvm::DWARFCompileUnit *cu);
std::string cDeclaration() const;
std::string name_;
std::string linkageName_;
std::vector<Variable::Handle> args_;
Variable::Handle returnVal_;
bool unsupported_;
void extractReturn(const llvm::DWARFDebugInfoEntryMinimal *die, llvm::DWARFCompileUnit *cu);
};
#endif
This diff is collapsed.
#ifndef Variable_hpp_
#define Variable_hpp_
#include <string>
#include <utility>
#include <vector>
#include <llvm/Support/Dwarf.h>
#include <llvm/ADT/Optional.h>
#include "llvm/Support/raw_ostream.h"
namespace llvm {
class DWARFDebugInfoEntryMinimal;
class DWARFCompileUnit;
}
class Variable
{
public:
/// lower bound, upper bound
using Dimension = llvm::Optional<std::pair<ptrdiff_t, ptrdiff_t> >;
using Handle = std::unique_ptr<Variable>;
enum Context {
PARAMETER,
STRING_LEN_PARAMETER,
COMMON_BLOCK_MEMBER
};
Variable();
virtual ~Variable();
std::string cDeclaration() const;
std::string cType() const {
return dwarfToCType(type_, elementSize());
}
size_t elementCount() const;
size_t elementSize() const { return elementSize_; }
static std::string dwarfToCType(llvm::dwarf::TypeKind, size_t elementSize);
static Handle extract(Context context,
const llvm::DWARFDebugInfoEntryMinimal *die,
llvm::DWARFCompileUnit *cu);
/**
* All common block members should have the location attribute stored as a
* block1 with the first byte being the op-code for an absolute address followed
* by an 8 byte address.
* Local variables and parameters will have a location attribute with a different
* form and cause this routine to throw an exception. Location is only needed for
* common block members to determine padding.
*/
void extractLocation(const llvm::DWARFDebugInfoEntryMinimal *die,
llvm::DWARFCompileUnit *cu);
void extractType(const llvm::DWARFDebugInfoEntryMinimal *die,
llvm::DWARFCompileUnit *cu);
void extractArrayDims(const llvm::DWARFDebugInfoEntryMinimal *die,
llvm::DWARFCompileUnit *cu);
bool isString() const { return (type_ == llvm::dwarf::DW_ATE_signed_char ||
type_ == llvm::dwarf::DW_ATE_unsigned_char); }
Context context_;
llvm::dwarf::TypeKind type_;
uint64_t elementSize_;
uint64_t location_;
std::string name_;
std::vector<Dimension> dims_;
bool isConst_;
};
llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const Variable &var);
#endif
//===-- llvm-dwarfdump.cpp - Debug info dumping utility for llvm ----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This program is a utility that works like "dwarfdump".
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/RelocVisitor.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.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/raw_ostream.h"
#include <algorithm>
#include <cstring>
#include <list>
#include <string>
#include <system_error>
using namespace llvm;
using namespace object;
static cl::list<std::string>
InputFilenames(cl::Positional, cl::desc("<input object files>"),
cl::ZeroOrMore);
static cl::opt<DIDumpType>
DumpType("debug-dump", cl::init(DIDT_All),
cl::desc("Dump of debug sections:"),
cl::values(
clEnumValN(DIDT_All, "all", "Dump all debug sections"),
clEnumValN(DIDT_Abbrev, "abbrev", ".debug_abbrev"),
clEnumValN(DIDT_AbbrevDwo, "abbrev.dwo", ".debug_abbrev.dwo"),
clEnumValN(DIDT_AppleNames, "apple_names", ".apple_names"),
clEnumValN(DIDT_AppleTypes, "apple_types", ".apple_types"),
clEnumValN(DIDT_AppleNamespaces, "apple_namespaces", ".apple_namespaces"),
clEnumValN(DIDT_AppleObjC, "apple_objc", ".apple_objc"),
clEnumValN(DIDT_Aranges, "aranges", ".debug_aranges"),
clEnumValN(DIDT_Info, "info", ".debug_info"),
clEnumValN(DIDT_InfoDwo, "info.dwo", ".debug_info.dwo"),
clEnumValN(DIDT_Types, "types", ".debug_types"),
clEnumValN(DIDT_TypesDwo, "types.dwo", ".debug_types.dwo"),
clEnumValN(DIDT_Line, "line", ".debug_line"),
clEnumValN(DIDT_LineDwo, "line.dwo", ".debug_line.dwo"),
clEnumValN(DIDT_Loc, "loc", ".debug_loc"),
clEnumValN(DIDT_LocDwo, "loc.dwo", ".debug_loc.dwo"),
clEnumValN(DIDT_Frames, "frames", ".debug_frame"),
clEnumValN(DIDT_Ranges, "ranges", ".debug_ranges"),
clEnumValN(DIDT_Pubnames, "pubnames", ".debug_pubnames"),
clEnumValN(DIDT_Pubtypes, "pubtypes", ".debug_pubtypes"),
clEnumValN(DIDT_GnuPubnames, "gnu_pubnames", ".debug_gnu_pubnames"),
clEnumValN(DIDT_GnuPubtypes, "gnu_pubtypes", ".debug_gnu_pubtypes"),
clEnumValN(DIDT_Str, "str", ".debug_str"),
clEnumValN(DIDT_StrDwo, "str.dwo", ".debug_str.dwo"),
clEnumValN(DIDT_StrOffsetsDwo, "str_offsets.dwo", ".debug_str_offsets.dwo"),
clEnumValEnd));
static void error(StringRef Filename, std::error_code EC) {
if (!EC)
return;
errs() << Filename << ": " << EC.message() << "\n";
exit(1);
}
static void DumpObjectFile(ObjectFile &Obj, Twine Filename) {
std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(Obj));
outs() << Filename.str() << ":\tfile format " << Obj.getFileFormatName()
<< "\n\n";
// Dump the complete DWARF structure.
DICtx->dump(outs(), DumpType);
}
static void DumpInput(StringRef Filename) {
ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
MemoryBuffer::getFileOrSTDIN(Filename);
error(Filename, BuffOrErr.getError());
std::unique_ptr<MemoryBuffer> Buff = std::move(BuffOrErr.get());
ErrorOr<std::unique_ptr<Binary>> BinOrErr =
object::createBinary(Buff->getMemBufferRef());
error(Filename, BinOrErr.getError());
if (auto *Obj = dyn_cast<ObjectFile>(BinOrErr->get()))
DumpObjectFile(*Obj, Filename);
else if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get()))
for (auto &ObjForArch : Fat->objects()) {
auto MachOOrErr = ObjForArch.getAsObjectFile();
error(Filename, MachOOrErr.getError());
DumpObjectFile(**MachOOrErr,
Filename + " (" + ObjForArch.getArchTypeName() + ")");
}
}
int main(int argc, char **argv) {
// Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal();
PrettyStackTraceProgram X(argc, argv);
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
cl::ParseCommandLineOptions(argc, argv, "llvm dwarf dumper\n");
// Defaults to a.out if no filenames specified.
if (InputFilenames.size() == 0)
InputFilenames.push_back("a.out");
std::for_each(InputFilenames.begin(), InputFilenames.end(), DumpInput);
return EXIT_SUCCESS;
}
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
//#include "llvm/DebugInfo/DIContext.h"
//#include "llvm/DebugInfo/DWARF/DWARFContext.h"
//#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/RelocVisitor.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.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/raw_ostream.h"
#include "llvm/Support/Dwarf.h"
#include <algorithm>
#include <cstring>
#include <list>
#include <string>
#include <system_error>
#include <iostream>
#include <fstream>
#include "Variable.hpp"
#include "CommonBlock.hpp"
#include "Subprogram.hpp"
using namespace llvm;
using namespace object;
static cl::list<std::string>
InputFilenames(cl::Positional, cl::desc("<input object files>"),
cl::ZeroOrMore);
static cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
cl::init("-"), cl::desc("Output file"));
static cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
cl::aliasopt(OutputFilename));
static std::ostream *outputStream(&std::cout);
static int ReturnValue = EXIT_SUCCESS;
static bool error(StringRef Filename, std::error_code EC) {
if (!EC)
return false;
errs() << Filename << ": " << EC.message() << "\n";