#include "JITRegistrar.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/MutexGuard.h"
using namespace llvm;
extern "C" {
typedef enum {
JIT_NOACTION = 0,
JIT_REGISTER_FN,
JIT_UNREGISTER_FN
} jit_actions_t;
struct jit_code_entry {
struct jit_code_entry *next_entry;
struct jit_code_entry *prev_entry;
const char *symfile_addr;
uint64_t symfile_size;
};
struct jit_descriptor {
uint32_t version;
uint32_t action_flag;
struct jit_code_entry *relevant_entry;
struct jit_code_entry *first_entry;
};
struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { }
}
namespace {
typedef llvm::DenseMap< const char*,
std::pair<std::size_t, jit_code_entry*> >
RegisteredObjectBufferMap;
class GDBJITRegistrar : public JITRegistrar {
RegisteredObjectBufferMap ObjectBufferMap;
public:
GDBJITRegistrar() : ObjectBufferMap() {}
virtual ~GDBJITRegistrar();
void registerObject(const ObjectBuffer &Object);
bool deregisterObject(const ObjectBuffer &Object);
private:
void deregisterObjectInternal(RegisteredObjectBufferMap::iterator I);
};
llvm::sys::Mutex JITDebugLock;
void NotifyDebugger(jit_code_entry* JITCodeEntry) {
llvm::MutexGuard locked(JITDebugLock);
__jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
JITCodeEntry->prev_entry = NULL;
jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry;
JITCodeEntry->next_entry = NextEntry;
if (NextEntry != NULL) {
NextEntry->prev_entry = JITCodeEntry;
}
__jit_debug_descriptor.first_entry = JITCodeEntry;
__jit_debug_descriptor.relevant_entry = JITCodeEntry;
__jit_debug_register_code();
}
GDBJITRegistrar::~GDBJITRegistrar() {
for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), E = ObjectBufferMap.end();
I != E; ++I) {
deregisterObjectInternal(I);
}
ObjectBufferMap.clear();
}
void GDBJITRegistrar::registerObject(const ObjectBuffer &Object) {
const char *Buffer = Object.getBufferStart();
size_t Size = Object.getBufferSize();
assert(Buffer && "Attempt to register a null object with a debugger.");
assert(ObjectBufferMap.find(Buffer) == ObjectBufferMap.end() &&
"Second attempt to perform debug registration.");
jit_code_entry* JITCodeEntry = new jit_code_entry();
if (JITCodeEntry == 0) {
llvm::report_fatal_error(
"Allocation failed when registering a JIT entry!\n");
}
else {
JITCodeEntry->symfile_addr = Buffer;
JITCodeEntry->symfile_size = Size;
ObjectBufferMap[Buffer] = std::make_pair(Size, JITCodeEntry);
NotifyDebugger(JITCodeEntry);
}
}
bool GDBJITRegistrar::deregisterObject(const ObjectBuffer& Object) {
const char *Buffer = Object.getBufferStart();
RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(Buffer);
if (I != ObjectBufferMap.end()) {
deregisterObjectInternal(I);
ObjectBufferMap.erase(I);
return true;
}
return false;
}
void GDBJITRegistrar::deregisterObjectInternal(
RegisteredObjectBufferMap::iterator I) {
jit_code_entry*& JITCodeEntry = I->second.second;
{
llvm::MutexGuard locked(JITDebugLock);
__jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
jit_code_entry* PrevEntry = JITCodeEntry->prev_entry;
jit_code_entry* NextEntry = JITCodeEntry->next_entry;
if (NextEntry) {
NextEntry->prev_entry = PrevEntry;
}
if (PrevEntry) {
PrevEntry->next_entry = NextEntry;
}
else {
assert(__jit_debug_descriptor.first_entry == JITCodeEntry);
__jit_debug_descriptor.first_entry = NextEntry;
}
__jit_debug_descriptor.relevant_entry = JITCodeEntry;
__jit_debug_register_code();
}
delete JITCodeEntry;
JITCodeEntry = NULL;
}
}
namespace llvm {
JITRegistrar& JITRegistrar::getGDBRegistrar() {
static GDBJITRegistrar* sRegistrar = NULL;
if (sRegistrar == NULL) {
llvm::MutexGuard locked(JITDebugLock);
if (sRegistrar == NULL) {
sRegistrar = new GDBJITRegistrar;
}
}
return *sRegistrar;
}
}