Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Use LLVM's disassembler for non X86 platforms

  • Loading branch information...
commit b79cb11949bd3731f24d23153b4cdcc3ad381720 1 parent 589f1b0
@dbussink dbussink authored
View
111 vm/llvm/disassembler.cpp
@@ -0,0 +1,111 @@
+#include "vm/config.h"
+#include "llvm/disassembler.hpp"
+#if RBX_LLVM_API_VER == 208
+#include <llvm/System/Host.h>
+#elif RBX_LLVM_API_VER == 209
+#include <llvm/Support/Host.h>
+#endif
+#include <llvm/Instructions.h>
+#include <llvm/Target/TargetRegistry.h>
+#include <llvm/Target/TargetSelect.h>
+#include <llvm/Target/TargetInstrInfo.h>
+#include <llvm/Target/TargetInstrDesc.h>
+#include <llvm/MC/MCInstPrinter.h>
+#include <llvm/MC/MCAsmInfo.h>
+#include <llvm/MC/MCInst.h>
+#include <llvm/Support/raw_ostream.h>
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+#include <dlfcn.h>
+
+namespace rubinius {
+
+ JITDisassembler::JITDisassembler(void* buffer, size_t size)
+ : asm_info(0)
+ , disassembler(0)
+ , memory_object(0)
+ {
+ std::string host = llvm::sys::getHostTriple();
+ std::string error;
+ llvm::InitializeNativeTargetAsmPrinter();
+ llvm::InitializeAllDisassemblers();
+ target = llvm::TargetRegistry::lookupTarget(host, error);
+ target_machine = target->createTargetMachine(host, error);
+ asm_info = target_machine->getMCAsmInfo();
+ if(asm_info) {
+ disassembler = target->createMCDisassembler();
+ memory_object = new JITMemoryObject((const uint8_t*)buffer, (uint64_t) size);
+ }
+ }
+
+ JITDisassembler::~JITDisassembler() {
+ if(memory_object) delete memory_object;
+ if(disassembler) delete disassembler;
+ if(target_machine) delete target_machine;
+ }
+
+ std::string JITDisassembler::print_machine_code() {
+
+ std::ostringstream output;
+ output << std::hex;
+
+ if(!asm_info) {
+ return std::string("Can't create assembly information for target");
+ }
+
+ llvm::MCInstPrinter* printer = target->createMCInstPrinter(asm_info->getAssemblerDialect(), *asm_info);
+ if(!printer) {
+ return std::string("No instruction printer for target");
+ }
+
+ uint64_t instruction_pointer = 0;
+ uint64_t instruction_offset = memory_object->getOffset();
+ uint64_t instruction_count = memory_object->getExtent();
+
+ const llvm::TargetInstrInfo* inst_info = target_machine->getInstrInfo();
+
+ while(instruction_pointer < instruction_count) {
+ std::string tmp;
+ llvm::raw_string_ostream out(tmp);
+ llvm::MCInst instruction;
+ uint64_t instruction_size;
+ uint64_t instruction_position = instruction_offset + instruction_pointer;
+ if(disassembler->getInstruction(instruction, instruction_size,
+ *memory_object, instruction_pointer,
+ llvm::nulls())) {
+ printer->printInst(&instruction, out);
+
+ output << "0x" << instruction_position << " ";
+ output << std::setw(30) << std::left << out.str();
+
+ const llvm::TargetInstrDesc &inst_descr = inst_info->get(instruction.getOpcode());
+
+ for(uint8_t i = 0; i < instruction.getNumOperands(); ++i) {
+ llvm::MCOperand& op = instruction.getOperand(i);
+ if(op.isImm()) {
+ uint64_t val = op.getImm();
+ // If it's a branch we want to add the complete location
+ // as an easier way to see where we are jumping to.
+ if(inst_descr.isBranch()) {
+ output << "; 0x" << instruction_position + instruction_size + val;
+ }
+ // Check whether it might be a immediate that references
+ // a specific method for a jump later or in this call instruction.
+ Dl_info info;
+ if(dladdr((void*)val, &info)) {
+ output << "; " << info.dli_sname;
+ }
+ }
+ }
+ output << std::endl;
+ instruction_pointer += instruction_size;
+ } else {
+ break;
+ }
+ }
+
+ return output.str();
+ }
+
+}
View
84 vm/llvm/disassembler.hpp
@@ -0,0 +1,84 @@
+#ifndef VM_LLVM_DISASSEMBLER_HPP
+#define VM_LLVM_DISASSEMBLER_HPP
+
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+
+#include <llvm/Target/TargetRegistry.h>
+#include <llvm/Target/TargetMachine.h>
+#include <llvm/MC/MCAsmInfo.h>
+#include <llvm/MC/MCDisassembler.h>
+#include <llvm/Support/MemoryObject.h>
+
+namespace rubinius {
+
+ class JITMemoryObject: public llvm::MemoryObject {
+
+ public:
+
+ JITMemoryObject(const uint8_t* buffer, uint64_t size)
+ : buffer_(buffer)
+ , size_(size)
+ {}
+
+ uint64_t getOffset() const {
+ return (uint64_t) buffer_;
+ }
+
+ uint64_t getBase() const {
+ return 0;
+ }
+
+ uint64_t getExtent() const {
+ return size_;
+ }
+
+ int readByte(uint64_t addr, uint8_t *byte) const {
+ if(addr >= size_) {
+ return -1;
+ }
+ *byte = buffer_[addr];
+ return 0;
+ }
+
+ int readBytes(uint64_t offset, uint64_t size, uint8_t* buffer, uint64_t* copied) const {
+ // Cannot read passed the maximum buffer size
+ if(offset >= size_) {
+ return -1;
+ }
+ // If the offset + requested size is bigger than the
+ // requested size, we clamp it at the maximum size from the offset.
+ if((offset + size) > size_) {
+ size = size_ - offset;
+ }
+ memcpy(buffer, buffer_ + offset, size);
+ if(copied) {
+ *copied = size;
+ }
+ return 0;
+ }
+
+ private:
+ const uint8_t* buffer_;
+ uint64_t size_;
+
+ };
+
+ class JITDisassembler {
+ public:
+ JITDisassembler(void* buffer, size_t size);
+ ~JITDisassembler();
+ std::string print_machine_code();
+ private:
+
+ const llvm::Target* target;
+ const llvm::TargetMachine* target_machine;
+ const llvm::MCAsmInfo* asm_info;
+ llvm::MCDisassembler* disassembler;
+ const JITMemoryObject* memory_object;
+ };
+
+}
+
+#endif
View
4 vm/llvm/jit_runtime.cpp
@@ -14,6 +14,10 @@
namespace rubinius {
namespace jit {
+ RuntimeDataHolder::~RuntimeDataHolder() {
+ runtime_data_.clear();
+ }
+
void RuntimeDataHolder::cleanup(STATE, CodeManager* cm) {
LLVMState* ls = cm->shared()->llvm_state;
assert(ls);
View
2  vm/llvm/jit_runtime.hpp
@@ -106,6 +106,8 @@ namespace rubinius {
, native_size_(0)
{}
+ ~RuntimeDataHolder();
+
virtual void cleanup(VM* vm, CodeManager* cm);
virtual const char* kind() {
View
13 vm/llvm/state.cpp
@@ -7,6 +7,7 @@
#include "llvm/jit_block.hpp"
#include "llvm/method_info.hpp"
#include "llvm/background_compile_request.hpp"
+#include "llvm/disassembler.hpp"
#include "llvm/jit_context.hpp"
#include "vm/config.h"
@@ -629,6 +630,9 @@ namespace rubinius {
LLVMState::~LLVMState() {
shared_.remove_managed_thread(this);
shared_.om->del_aux_barrier(0, &write_barrier_);
+ delete passes_;
+ delete module_;
+ delete background_thread_;
}
bool LLVMState::debug_p() {
@@ -977,6 +981,8 @@ namespace rubinius {
}
void LLVMState::show_machine_code(void* buffer, size_t size) {
+
+#if defined(IS_X86) || defined(IS_X8664)
#ifndef RBX_WINDOWS
ud_t ud;
@@ -1033,6 +1039,13 @@ namespace rubinius {
std::cout << "\n";
}
#endif // !RBX_WINDOWS
+
+#else
+ JITDisassembler disassembler(buffer, size);
+ std::string output = disassembler.print_machine_code();
+ std::cout << output;
+#endif // !IS_X86
+
}
}
View
11 vm/shared_state.cpp
@@ -16,6 +16,10 @@
#include "agent.hpp"
#include "world_state.hpp"
+#ifdef ENABLE_LLVM
+#include "llvm/state.hpp"
+#endif
+
namespace rubinius {
SharedState::SharedState(Environment* env, Configuration& config, ConfigParser& cp)
@@ -51,6 +55,13 @@ namespace rubinius {
if(!initialized_) return;
// std::cerr << "Time waiting: " << world_->time_waiting() << "\n";
+
+#ifdef ENABLE_LLVM
+ if(llvm_state) {
+ delete llvm_state;
+ }
+#endif
+
delete tool_broker_;
delete world_;
delete ic_registry_;
Please sign in to comment.
Something went wrong with that request. Please try again.