#include "llvm/Debugger/Debugger.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Debugger/InferiorProcess.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/StringExtras.h"
#include <cstdlib>
#include <memory>
using namespace llvm;
Debugger::Debugger() : Environment(0), Program(0), Process(0) {
}
Debugger::~Debugger() {
try {
killProgram();
} catch (const char *) {
} catch (const std::string &) {
}
unloadProgram();
}
std::string Debugger::getProgramPath() const {
return Program ? Program->getModuleIdentifier() : "";
}
static Module *
getMaterializedModuleProvider(const std::string &Filename) {
std::auto_ptr<MemoryBuffer> Buffer;
Buffer.reset(MemoryBuffer::getFileOrSTDIN(Filename.c_str()));
if (Buffer.get())
return ParseBitcodeFile(Buffer.get());
return 0;
}
void Debugger::loadProgram(const std::string &Filename) {
if ((Program = getMaterializedModuleProvider(Filename)) ||
(Program = getMaterializedModuleProvider(Filename+".bc")))
return;
if (const char *PathS = getenv("PATH")) {
std::string Path = PathS;
std::string Directory = getToken(Path, ":");
while (!Directory.empty()) {
if ((Program = getMaterializedModuleProvider(Directory +"/"+ Filename)) ||
(Program = getMaterializedModuleProvider(Directory +"/"+ Filename
+ ".bc")))
return;
Directory = getToken(Path, ":");
}
}
throw "Could not find program '" + Filename + "'!";
}
void Debugger::unloadProgram() {
if (!isProgramLoaded()) return;
killProgram();
delete Program;
Program = 0;
}
void Debugger::createProgram() {
if (!isProgramLoaded())
throw "Cannot start program: none is loaded.";
killProgram();
std::vector<std::string> Args(ProgramArguments);
Args.insert(Args.begin(), getProgramPath());
Process = InferiorProcess::create(Program, Args, Environment);
}
InferiorProcess *
InferiorProcess::create(Module *M, const std::vector<std::string> &Arguments,
const char * const *envp) {
throw"No supported binding to inferior processes (debugger not implemented).";
}
void Debugger::killProgram() {
try {
delete Process;
} catch (...) {
Process = 0;
throw;
}
Process = 0;
}
void Debugger::stepProgram() {
assert(isProgramRunning() && "Cannot step if the program isn't running!");
try {
Process->stepProgram();
} catch (InferiorProcessDead &IPD) {
killProgram();
throw NonErrorException("The program stopped with exit code " +
itostr(IPD.getExitCode()));
} catch (...) {
killProgram();
throw;
}
}
void Debugger::nextProgram() {
assert(isProgramRunning() && "Cannot next if the program isn't running!");
try {
void *CurrentFrame = Process->getPreviousFrame(0);
void *ParentFrame = Process->getPreviousFrame(CurrentFrame);
Process->stepProgram();
void *NewFrame = Process->getPreviousFrame(0);
if (NewFrame != CurrentFrame) {
void *NewParentFrame = Process->getPreviousFrame(NewFrame);
if (ParentFrame != NewParentFrame) {
if (CurrentFrame == NewParentFrame)
Process->finishProgram(NewFrame);
}
}
} catch (InferiorProcessDead &IPD) {
killProgram();
throw NonErrorException("The program stopped with exit code " +
itostr(IPD.getExitCode()));
} catch (...) {
killProgram();
throw;
}
}
void Debugger::finishProgram(void *Frame) {
assert(isProgramRunning() && "Cannot cont if the program isn't running!");
try {
Process->finishProgram(Frame);
} catch (InferiorProcessDead &IPD) {
killProgram();
throw NonErrorException("The program stopped with exit code " +
itostr(IPD.getExitCode()));
} catch (...) {
killProgram();
throw;
}
}
void Debugger::contProgram() {
assert(isProgramRunning() && "Cannot cont if the program isn't running!");
try {
Process->contProgram();
} catch (InferiorProcessDead &IPD) {
killProgram();
throw NonErrorException("The program stopped with exit code " +
itostr(IPD.getExitCode()));
} catch (...) {
killProgram();
throw;
}
}