| //===-- Debugger.cpp - LLVM debugger library implementation ---------------===// | 
 | // | 
 | //                     The LLVM Compiler Infrastructure | 
 | // | 
 | // This file was developed by the LLVM research group and is distributed under | 
 | // the University of Illinois Open Source License. See LICENSE.TXT for details. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // This file contains the main implementation of the LLVM debugger library. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "llvm/Debugger/Debugger.h" | 
 | #include "llvm/Module.h" | 
 | #include "llvm/ModuleProvider.h" | 
 | #include "llvm/Bytecode/Reader.h" | 
 | #include "llvm/Debugger/InferiorProcess.h" | 
 | #include "llvm/ADT/StringExtras.h" | 
 | #include <memory> | 
 | using namespace llvm; | 
 |  | 
 | /// Debugger constructor - Initialize the debugger to its initial, empty, state. | 
 | /// | 
 | Debugger::Debugger() : Environment(0), Program(0), Process(0) { | 
 | } | 
 |  | 
 | Debugger::~Debugger() { | 
 |   // Killing the program could throw an exception.  We don't want to progagate | 
 |   // the exception out of our destructor though. | 
 |   try { | 
 |     killProgram(); | 
 |   } catch (const char *) { | 
 |   } catch (const std::string &) { | 
 |   } | 
 |  | 
 |   unloadProgram(); | 
 | } | 
 |  | 
 | /// getProgramPath - Get the path of the currently loaded program, or an | 
 | /// empty string if none is loaded. | 
 | std::string Debugger::getProgramPath() const { | 
 |   return Program ? Program->getModuleIdentifier() : ""; | 
 | } | 
 |  | 
 | static Module * | 
 | getMaterializedModuleProvider(const std::string &Filename) { | 
 |   return ParseBytecodeFile(Filename); | 
 | } | 
 |  | 
 | /// loadProgram - If a program is currently loaded, unload it.  Then search | 
 | /// the PATH for the specified program, loading it when found.  If the | 
 | /// specified program cannot be found, an exception is thrown to indicate the | 
 | /// error. | 
 | void Debugger::loadProgram(const std::string &Filename) { | 
 |   if ((Program = getMaterializedModuleProvider(Filename)) || | 
 |       (Program = getMaterializedModuleProvider(Filename+".bc"))) | 
 |     return;   // Successfully loaded the program. | 
 |  | 
 |   // Search the program path for the file... | 
 |   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;   // Successfully loaded the program. | 
 |  | 
 |       Directory = getToken(Path, ":"); | 
 |     } | 
 |   } | 
 |  | 
 |   throw "Could not find program '" + Filename + "'!"; | 
 | } | 
 |  | 
 | /// unloadProgram - If a program is running, kill it, then unload all traces | 
 | /// of the current program.  If no program is loaded, this method silently | 
 | /// succeeds. | 
 | void Debugger::unloadProgram() { | 
 |   if (!isProgramLoaded()) return; | 
 |   killProgram(); | 
 |   delete Program; | 
 |   Program = 0; | 
 | } | 
 |  | 
 |  | 
 | /// createProgram - Create an instance of the currently loaded program, | 
 | /// killing off any existing one.  This creates the program and stops it at | 
 | /// the first possible moment.  If there is no program loaded or if there is a | 
 | /// problem starting the program, this method throws an exception. | 
 | void Debugger::createProgram() { | 
 |   if (!isProgramLoaded()) | 
 |     throw "Cannot start program: none is loaded."; | 
 |  | 
 |   // Kill any existing program. | 
 |   killProgram(); | 
 |  | 
 |   // Add argv[0] to the arguments vector.. | 
 |   std::vector<std::string> Args(ProgramArguments); | 
 |   Args.insert(Args.begin(), getProgramPath()); | 
 |  | 
 |   // Start the new program... this could throw if the program cannot be started. | 
 |   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)."; | 
 | } | 
 |  | 
 | /// killProgram - If the program is currently executing, kill off the | 
 | /// process and free up any state related to the currently running program.  If | 
 | /// there is no program currently running, this just silently succeeds. | 
 | void Debugger::killProgram() { | 
 |   // The destructor takes care of the dirty work. | 
 |   try { | 
 |     delete Process; | 
 |   } catch (...) { | 
 |     Process = 0; | 
 |     throw; | 
 |   } | 
 |   Process = 0; | 
 | } | 
 |  | 
 | /// stepProgram - Implement the 'step' command, continuing execution until | 
 | /// the next possible stop point. | 
 | 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; | 
 |   } | 
 | } | 
 |  | 
 | /// nextProgram - Implement the 'next' command, continuing execution until | 
 | /// the next possible stop point that is in the current function. | 
 | void Debugger::nextProgram() { | 
 |   assert(isProgramRunning() && "Cannot next if the program isn't running!"); | 
 |   try { | 
 |     // This should step the process.  If the process enters a function, then it | 
 |     // should 'finish' it.  However, figuring this out is tricky.  In | 
 |     // particular, the program can do any of: | 
 |     //  0. Not change current frame. | 
 |     //  1. Entering or exiting a region within the current function | 
 |     //     (which changes the frame ID, but which we shouldn't 'finish') | 
 |     //  2. Exiting the current function (which changes the frame ID) | 
 |     //  3. Entering a function (which should be 'finish'ed) | 
 |     // For this reason, we have to be very careful about when we decide to do | 
 |     // the 'finish'. | 
 |  | 
 |     // Get the current frame, but don't trust it.  It could change... | 
 |     void *CurrentFrame = Process->getPreviousFrame(0); | 
 |  | 
 |     // Don't trust the current frame: get the caller frame. | 
 |     void *ParentFrame  = Process->getPreviousFrame(CurrentFrame); | 
 |  | 
 |     // Ok, we have some information, run the program one step. | 
 |     Process->stepProgram(); | 
 |  | 
 |     // Where is the new frame?  The most common case, by far is that it has not | 
 |     // been modified (Case #0), in which case we don't need to do anything more. | 
 |     void *NewFrame = Process->getPreviousFrame(0); | 
 |     if (NewFrame != CurrentFrame) { | 
 |       // Ok, the frame changed.  If we are case #1, then the parent frame will | 
 |       // be identical. | 
 |       void *NewParentFrame = Process->getPreviousFrame(NewFrame); | 
 |       if (ParentFrame != NewParentFrame) { | 
 |         // Ok, now we know we aren't case #0 or #1.  Check to see if we entered | 
 |         // a new function.  If so, the parent frame will be "CurrentFrame". | 
 |         if (CurrentFrame == NewParentFrame) | 
 |           Process->finishProgram(NewFrame); | 
 |       } | 
 |     } | 
 |  | 
 |   } catch (InferiorProcessDead &IPD) { | 
 |     killProgram(); | 
 |     throw NonErrorException("The program stopped with exit code " + | 
 |                             itostr(IPD.getExitCode())); | 
 |   } catch (...) { | 
 |     killProgram(); | 
 |     throw; | 
 |   } | 
 | } | 
 |  | 
 | /// finishProgram - Implement the 'finish' command, continuing execution | 
 | /// until the specified frame ID returns. | 
 | 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; | 
 |   } | 
 | } | 
 |  | 
 | /// contProgram - Implement the 'cont' command, continuing execution until | 
 | /// the next breakpoint is encountered. | 
 | 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; | 
 |   } | 
 | } |