diff options
Diffstat (limited to 'lib/Debugger')
-rw-r--r-- | lib/Debugger/CMakeLists.txt | 10 | ||||
-rw-r--r-- | lib/Debugger/Debugger.cpp | 230 | ||||
-rw-r--r-- | lib/Debugger/Makefile | 16 | ||||
-rw-r--r-- | lib/Debugger/ProgramInfo.cpp | 377 | ||||
-rw-r--r-- | lib/Debugger/README.txt | 7 | ||||
-rw-r--r-- | lib/Debugger/RuntimeInfo.cpp | 69 | ||||
-rw-r--r-- | lib/Debugger/SourceFile.cpp | 82 | ||||
-rw-r--r-- | lib/Debugger/SourceLanguage-CFamily.cpp | 28 | ||||
-rw-r--r-- | lib/Debugger/SourceLanguage-CPlusPlus.cpp | 27 | ||||
-rw-r--r-- | lib/Debugger/SourceLanguage-Unknown.cpp | 138 | ||||
-rw-r--r-- | lib/Debugger/SourceLanguage.cpp | 54 |
11 files changed, 1038 insertions, 0 deletions
diff --git a/lib/Debugger/CMakeLists.txt b/lib/Debugger/CMakeLists.txt new file mode 100644 index 0000000..d2508cf --- /dev/null +++ b/lib/Debugger/CMakeLists.txt @@ -0,0 +1,10 @@ +add_llvm_library(LLVMDebugger + Debugger.cpp + ProgramInfo.cpp + RuntimeInfo.cpp + SourceFile.cpp + SourceLanguage-CFamily.cpp + SourceLanguage-CPlusPlus.cpp + SourceLanguage-Unknown.cpp + SourceLanguage.cpp + ) diff --git a/lib/Debugger/Debugger.cpp b/lib/Debugger/Debugger.cpp new file mode 100644 index 0000000..b12d90a --- /dev/null +++ b/lib/Debugger/Debugger.cpp @@ -0,0 +1,230 @@ +//===-- Debugger.cpp - LLVM debugger library implementation ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file 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/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 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) { + std::auto_ptr<MemoryBuffer> Buffer; + Buffer.reset(MemoryBuffer::getFileOrSTDIN(Filename.c_str())); + if (Buffer.get()) + return ParseBitcodeFile(Buffer.get()); + return 0; +} + +/// 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; + } +} diff --git a/lib/Debugger/Makefile b/lib/Debugger/Makefile new file mode 100644 index 0000000..8290e30 --- /dev/null +++ b/lib/Debugger/Makefile @@ -0,0 +1,16 @@ +##===- lib/Debugger/Makefile -------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +LIBRARYNAME = LLVMDebugger +EXTRA_DIST = README.txt +REQUIRES_EH := 1 +BUILD_ARCHIVE = 1 + +include $(LEVEL)/Makefile.common diff --git a/lib/Debugger/ProgramInfo.cpp b/lib/Debugger/ProgramInfo.cpp new file mode 100644 index 0000000..125ff55 --- /dev/null +++ b/lib/Debugger/ProgramInfo.cpp @@ -0,0 +1,377 @@ +//===-- ProgramInfo.cpp - Compute and cache info about a program ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the ProgramInfo and related classes, by sorting through +// the loaded Module. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Debugger/ProgramInfo.h" +#include "llvm/Constants.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Intrinsics.h" +#include "llvm/IntrinsicInst.h" +#include "llvm/Instructions.h" +#include "llvm/Module.h" +#include "llvm/Debugger/SourceFile.h" +#include "llvm/Debugger/SourceLanguage.h" +#include "llvm/Support/SlowOperationInformer.h" +#include "llvm/Support/Streams.h" +#include "llvm/ADT/STLExtras.h" +using namespace llvm; + +/// getGlobalVariablesUsing - Return all of the global variables which have the +/// specified value in their initializer somewhere. +static void getGlobalVariablesUsing(Value *V, + std::vector<GlobalVariable*> &Found) { + for (Value::use_iterator I = V->use_begin(), E = V->use_end(); I != E; ++I) { + if (GlobalVariable *GV = dyn_cast<GlobalVariable>(*I)) + Found.push_back(GV); + else if (Constant *C = dyn_cast<Constant>(*I)) + getGlobalVariablesUsing(C, Found); + } +} + +/// getNextStopPoint - Follow the def-use chains of the specified LLVM value, +/// traversing the use chains until we get to a stoppoint. When we do, return +/// the source location of the stoppoint. If we don't find a stoppoint, return +/// null. +static const GlobalVariable *getNextStopPoint(const Value *V, unsigned &LineNo, + unsigned &ColNo) { + // The use-def chains can fork. As such, we pick the lowest numbered one we + // find. + const GlobalVariable *LastDesc = 0; + unsigned LastLineNo = ~0; + unsigned LastColNo = ~0; + + for (Value::use_const_iterator UI = V->use_begin(), E = V->use_end(); + UI != E; ++UI) { + bool ShouldRecurse = true; + if (cast<Instruction>(*UI)->getOpcode() == Instruction::PHI) { + // Infinite loops == bad, ignore PHI nodes. + ShouldRecurse = false; + } else if (const CallInst *CI = dyn_cast<CallInst>(*UI)) { + + // If we found a stop point, check to see if it is earlier than what we + // already have. If so, remember it. + if (CI->getCalledFunction()) + if (const DbgStopPointInst *SPI = dyn_cast<DbgStopPointInst>(CI)) { + unsigned CurLineNo = SPI->getLine(); + unsigned CurColNo = SPI->getColumn(); + const GlobalVariable *CurDesc = 0; + const Value *Op = SPI->getContext(); + + if ((CurDesc = dyn_cast<GlobalVariable>(Op)) && + (LineNo < LastLineNo || + (LineNo == LastLineNo && ColNo < LastColNo))) { + LastDesc = CurDesc; + LastLineNo = CurLineNo; + LastColNo = CurColNo; + } + ShouldRecurse = false; + } + } + + // If this is not a phi node or a stopping point, recursively scan the users + // of this instruction to skip over region.begin's and the like. + if (ShouldRecurse) { + unsigned CurLineNo, CurColNo; + if (const GlobalVariable *GV = getNextStopPoint(*UI, CurLineNo,CurColNo)){ + if (LineNo < LastLineNo || (LineNo == LastLineNo && ColNo < LastColNo)){ + LastDesc = GV; + LastLineNo = CurLineNo; + LastColNo = CurColNo; + } + } + } + } + + if (LastDesc) { + LineNo = LastLineNo != ~0U ? LastLineNo : 0; + ColNo = LastColNo != ~0U ? LastColNo : 0; + } + return LastDesc; +} + + +//===----------------------------------------------------------------------===// +// SourceFileInfo implementation +// + +SourceFileInfo::SourceFileInfo(const GlobalVariable *Desc, + const SourceLanguage &Lang) + : Language(&Lang), Descriptor(Desc) { + Version = 0; + SourceText = 0; + + if (Desc && Desc->hasInitializer()) + if (ConstantStruct *CS = dyn_cast<ConstantStruct>(Desc->getInitializer())) + if (CS->getNumOperands() > 4) { + if (ConstantInt *CUI = dyn_cast<ConstantInt>(CS->getOperand(1))) + Version = CUI->getZExtValue(); + + if (!GetConstantStringInfo(CS->getOperand(3), BaseName)) + BaseName = ""; + if (!GetConstantStringInfo(CS->getOperand(4), Directory)) + Directory = ""; + } +} + +SourceFileInfo::~SourceFileInfo() { + delete SourceText; +} + +SourceFile &SourceFileInfo::getSourceText() const { + // FIXME: this should take into account the source search directories! + if (SourceText == 0) { // Read the file in if we haven't already. + sys::Path tmpPath; + if (!Directory.empty()) + tmpPath.set(Directory); + tmpPath.appendComponent(BaseName); + if (tmpPath.canRead()) + SourceText = new SourceFile(tmpPath.toString(), Descriptor); + else + SourceText = new SourceFile(BaseName, Descriptor); + } + return *SourceText; +} + + +//===----------------------------------------------------------------------===// +// SourceFunctionInfo implementation +// +SourceFunctionInfo::SourceFunctionInfo(ProgramInfo &PI, + const GlobalVariable *Desc) + : Descriptor(Desc) { + LineNo = ColNo = 0; + if (Desc && Desc->hasInitializer()) + if (ConstantStruct *CS = dyn_cast<ConstantStruct>(Desc->getInitializer())) + if (CS->getNumOperands() > 2) { + // Entry #1 is the file descriptor. + if (const GlobalVariable *GV = + dyn_cast<GlobalVariable>(CS->getOperand(1))) + SourceFile = &PI.getSourceFile(GV); + + // Entry #2 is the function name. + if (!GetConstantStringInfo(CS->getOperand(2), Name)) + Name = ""; + } +} + +/// getSourceLocation - This method returns the location of the first stopping +/// point in the function. +void SourceFunctionInfo::getSourceLocation(unsigned &RetLineNo, + unsigned &RetColNo) const { + // If we haven't computed this yet... + if (!LineNo) { + // Look at all of the users of the function descriptor, looking for calls to + // %llvm.dbg.func.start. + for (Value::use_const_iterator UI = Descriptor->use_begin(), + E = Descriptor->use_end(); UI != E; ++UI) + if (const CallInst *CI = dyn_cast<CallInst>(*UI)) + if (const Function *F = CI->getCalledFunction()) + if (F->getIntrinsicID() == Intrinsic::dbg_func_start) { + // We found the start of the function. Check to see if there are + // any stop points on the use-list of the function start. + const GlobalVariable *SD = getNextStopPoint(CI, LineNo, ColNo); + if (SD) { // We found the first stop point! + // This is just a sanity check. + if (getSourceFile().getDescriptor() != SD) + cout << "WARNING: first line of function is not in the" + << " file that the function descriptor claims it is in.\n"; + break; + } + } + } + RetLineNo = LineNo; RetColNo = ColNo; +} + +//===----------------------------------------------------------------------===// +// ProgramInfo implementation +// + +ProgramInfo::ProgramInfo(Module *m) : M(m), ProgramTimeStamp(0,0) { + assert(M && "Cannot create program information with a null module!"); + sys::PathWithStatus ModPath(M->getModuleIdentifier()); + const sys::FileStatus *Stat = ModPath.getFileStatus(); + if (Stat) + ProgramTimeStamp = Stat->getTimestamp(); + + SourceFilesIsComplete = false; + SourceFunctionsIsComplete = false; +} + +ProgramInfo::~ProgramInfo() { + // Delete cached information about source program objects... + for (std::map<const GlobalVariable*, SourceFileInfo*>::iterator + I = SourceFiles.begin(), E = SourceFiles.end(); I != E; ++I) + delete I->second; + for (std::map<const GlobalVariable*, SourceFunctionInfo*>::iterator + I = SourceFunctions.begin(), E = SourceFunctions.end(); I != E; ++I) + delete I->second; + + // Delete the source language caches. + for (unsigned i = 0, e = LanguageCaches.size(); i != e; ++i) + delete LanguageCaches[i].second; +} + + +//===----------------------------------------------------------------------===// +// SourceFileInfo tracking... +// + +/// getSourceFile - Return source file information for the specified source file +/// descriptor object, adding it to the collection as needed. This method +/// always succeeds (is unambiguous), and is always efficient. +/// +const SourceFileInfo & +ProgramInfo::getSourceFile(const GlobalVariable *Desc) { + SourceFileInfo *&Result = SourceFiles[Desc]; + if (Result) return *Result; + + // Figure out what language this source file comes from... + unsigned LangID = 0; // Zero is unknown language + if (Desc && Desc->hasInitializer()) + if (ConstantStruct *CS = dyn_cast<ConstantStruct>(Desc->getInitializer())) + if (CS->getNumOperands() > 2) + if (ConstantInt *CUI = dyn_cast<ConstantInt>(CS->getOperand(2))) + LangID = CUI->getZExtValue(); + + const SourceLanguage &Lang = SourceLanguage::get(LangID); + SourceFileInfo *New = Lang.createSourceFileInfo(Desc, *this); + + // FIXME: this should check to see if there is already a Filename/WorkingDir + // pair that matches this one. If so, we shouldn't create the duplicate! + // + SourceFileIndex.insert(std::make_pair(New->getBaseName(), New)); + return *(Result = New); +} + + +/// getSourceFiles - Index all of the source files in the program and return +/// a mapping of it. This information is lazily computed the first time +/// that it is requested. Since this information can take a long time to +/// compute, the user is given a chance to cancel it. If this occurs, an +/// exception is thrown. +const std::map<const GlobalVariable*, SourceFileInfo*> & +ProgramInfo::getSourceFiles(bool RequiresCompleteMap) { + // If we have a fully populated map, or if the client doesn't need one, just + // return what we have. + if (SourceFilesIsComplete || !RequiresCompleteMap) + return SourceFiles; + + // Ok, all of the source file descriptors (compile_unit in dwarf terms), + // should be on the use list of the llvm.dbg.translation_units global. + // + GlobalVariable *Units = + M->getGlobalVariable("llvm.dbg.translation_units", + StructType::get(std::vector<const Type*>())); + if (Units == 0) + throw "Program contains no debugging information!"; + + std::vector<GlobalVariable*> TranslationUnits; + getGlobalVariablesUsing(Units, TranslationUnits); + + SlowOperationInformer SOI("building source files index"); + + // Loop over all of the translation units found, building the SourceFiles + // mapping. + for (unsigned i = 0, e = TranslationUnits.size(); i != e; ++i) { + getSourceFile(TranslationUnits[i]); + if (SOI.progress(i+1, e)) + throw "While building source files index, operation cancelled."; + } + + // Ok, if we got this far, then we indexed the whole program. + SourceFilesIsComplete = true; + return SourceFiles; +} + +/// getSourceFile - Look up the file with the specified name. If there is +/// more than one match for the specified filename, prompt the user to pick +/// one. If there is no source file that matches the specified name, throw +/// an exception indicating that we can't find the file. Otherwise, return +/// the file information for that file. +const SourceFileInfo &ProgramInfo::getSourceFile(const std::string &Filename) { + std::multimap<std::string, SourceFileInfo*>::const_iterator Start, End; + getSourceFiles(); + tie(Start, End) = SourceFileIndex.equal_range(Filename); + + if (Start == End) throw "Could not find source file '" + Filename + "'!"; + const SourceFileInfo &SFI = *Start->second; + ++Start; + if (Start == End) return SFI; + + throw "FIXME: Multiple source files with the same name not implemented!"; +} + + +//===----------------------------------------------------------------------===// +// SourceFunctionInfo tracking... +// + + +/// getFunction - Return function information for the specified function +/// descriptor object, adding it to the collection as needed. This method +/// always succeeds (is unambiguous), and is always efficient. +/// +const SourceFunctionInfo & +ProgramInfo::getFunction(const GlobalVariable *Desc) { + SourceFunctionInfo *&Result = SourceFunctions[Desc]; + if (Result) return *Result; + + // Figure out what language this function comes from... + const GlobalVariable *SourceFileDesc = 0; + if (Desc && Desc->hasInitializer()) + if (ConstantStruct *CS = dyn_cast<ConstantStruct>(Desc->getInitializer())) + if (CS->getNumOperands() > 0) + if (const GlobalVariable *GV = + dyn_cast<GlobalVariable>(CS->getOperand(1))) + SourceFileDesc = GV; + + const SourceLanguage &Lang = getSourceFile(SourceFileDesc).getLanguage(); + return *(Result = Lang.createSourceFunctionInfo(Desc, *this)); +} + + +// getSourceFunctions - Index all of the functions in the program and return +// them. This information is lazily computed the first time that it is +// requested. Since this information can take a long time to compute, the user +// is given a chance to cancel it. If this occurs, an exception is thrown. +const std::map<const GlobalVariable*, SourceFunctionInfo*> & +ProgramInfo::getSourceFunctions(bool RequiresCompleteMap) { + if (SourceFunctionsIsComplete || !RequiresCompleteMap) + return SourceFunctions; + + // Ok, all of the source function descriptors (subprogram in dwarf terms), + // should be on the use list of the llvm.dbg.translation_units global. + // + GlobalVariable *Units = + M->getGlobalVariable("llvm.dbg.globals", + StructType::get(std::vector<const Type*>())); + if (Units == 0) + throw "Program contains no debugging information!"; + + std::vector<GlobalVariable*> Functions; + getGlobalVariablesUsing(Units, Functions); + + SlowOperationInformer SOI("building functions index"); + + // Loop over all of the functions found, building the SourceFunctions mapping. + for (unsigned i = 0, e = Functions.size(); i != e; ++i) { + getFunction(Functions[i]); + if (SOI.progress(i+1, e)) + throw "While functions index, operation cancelled."; + } + + // Ok, if we got this far, then we indexed the whole program. + SourceFunctionsIsComplete = true; + return SourceFunctions; +} diff --git a/lib/Debugger/README.txt b/lib/Debugger/README.txt new file mode 100644 index 0000000..89935c5 --- /dev/null +++ b/lib/Debugger/README.txt @@ -0,0 +1,7 @@ +//===-- llvm/lib/Debugger/ - LLVM Debugger interfaces ---------------------===// + +This directory contains the implementation of the LLVM debugger backend. This +directory builds into a library which can be used by various debugger +front-ends to debug LLVM programs. The current command line LLVM debugger, +llvm-db is currently the only client of this library, but others could be +built, to provide a GUI front-end for example. diff --git a/lib/Debugger/RuntimeInfo.cpp b/lib/Debugger/RuntimeInfo.cpp new file mode 100644 index 0000000..2f0ff72 --- /dev/null +++ b/lib/Debugger/RuntimeInfo.cpp @@ -0,0 +1,69 @@ +//===-- RuntimeInfo.cpp - Compute and cache info about running program ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the RuntimeInfo and related classes, by querying and +// cachine information from the running inferior process. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Debugger/InferiorProcess.h" +#include "llvm/Debugger/ProgramInfo.h" +#include "llvm/Debugger/RuntimeInfo.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// StackFrame class implementation + +StackFrame::StackFrame(RuntimeInfo &ri, void *ParentFrameID) + : RI(ri), SourceInfo(0) { + FrameID = RI.getInferiorProcess().getPreviousFrame(ParentFrameID); + if (FrameID == 0) throw "Stack frame does not exist!"; + + // Compute lazily as needed. + FunctionDesc = 0; +} + +const GlobalVariable *StackFrame::getFunctionDesc() { + if (FunctionDesc == 0) + FunctionDesc = RI.getInferiorProcess().getSubprogramDesc(FrameID); + return FunctionDesc; +} + +/// getSourceLocation - Return the source location that this stack frame is +/// sitting at. +void StackFrame::getSourceLocation(unsigned &lineNo, unsigned &colNo, + const SourceFileInfo *&sourceInfo) { + if (SourceInfo == 0) { + const GlobalVariable *SourceDesc = 0; + RI.getInferiorProcess().getFrameLocation(FrameID, LineNo,ColNo, SourceDesc); + SourceInfo = &RI.getProgramInfo().getSourceFile(SourceDesc); + } + + lineNo = LineNo; + colNo = ColNo; + sourceInfo = SourceInfo; +} + +//===----------------------------------------------------------------------===// +// RuntimeInfo class implementation + +/// materializeFrame - Create and process all frames up to and including the +/// specified frame number. This throws an exception if the specified frame +/// ID is nonexistant. +void RuntimeInfo::materializeFrame(unsigned ID) { + assert(ID >= CallStack.size() && "no need to materialize this frame!"); + void *CurFrame = 0; + if (!CallStack.empty()) + CurFrame = CallStack.back().getFrameID(); + + while (CallStack.size() <= ID) { + CallStack.push_back(StackFrame(*this, CurFrame)); + CurFrame = CallStack.back().getFrameID(); + } +} diff --git a/lib/Debugger/SourceFile.cpp b/lib/Debugger/SourceFile.cpp new file mode 100644 index 0000000..03c60f8 --- /dev/null +++ b/lib/Debugger/SourceFile.cpp @@ -0,0 +1,82 @@ +//===-- SourceFile.cpp - SourceFile implementation for the debugger -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SourceFile class for the LLVM debugger. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Debugger/SourceFile.h" +#include "llvm/Support/MemoryBuffer.h" +#include <cassert> +using namespace llvm; + +static const char EmptyFile = 0; + +SourceFile::SourceFile(const std::string &fn, const GlobalVariable *Desc) + : Filename(fn), Descriptor(Desc) { + File.reset(MemoryBuffer::getFileOrSTDIN(fn)); + + // On error, return an empty buffer. + if (File == 0) + File.reset(MemoryBuffer::getMemBuffer(&EmptyFile, &EmptyFile)); +} + +SourceFile::~SourceFile() { +} + + +/// calculateLineOffsets - Compute the LineOffset vector for the current file. +/// +void SourceFile::calculateLineOffsets() const { + assert(LineOffset.empty() && "Line offsets already computed!"); + const char *BufPtr = File->getBufferStart(); + const char *FileStart = BufPtr; + const char *FileEnd = File->getBufferEnd(); + do { + LineOffset.push_back(BufPtr-FileStart); + + // Scan until we get to a newline. + while (BufPtr != FileEnd && *BufPtr != '\n' && *BufPtr != '\r') + ++BufPtr; + + if (BufPtr != FileEnd) { + ++BufPtr; // Skip over the \n or \r + if (BufPtr[-1] == '\r' && BufPtr != FileEnd && BufPtr[0] == '\n') + ++BufPtr; // Skip over dos/windows style \r\n's + } + } while (BufPtr != FileEnd); +} + + +/// getSourceLine - Given a line number, return the start and end of the line +/// in the file. If the line number is invalid, or if the file could not be +/// loaded, null pointers are returned for the start and end of the file. Note +/// that line numbers start with 0, not 1. +void SourceFile::getSourceLine(unsigned LineNo, const char *&LineStart, + const char *&LineEnd) const { + LineStart = LineEnd = 0; + if (LineOffset.empty()) calculateLineOffsets(); + + // Asking for an out-of-range line number? + if (LineNo >= LineOffset.size()) return; + + // Otherwise, they are asking for a valid line, which we can fulfill. + LineStart = File->getBufferStart()+LineOffset[LineNo]; + + if (LineNo+1 < LineOffset.size()) + LineEnd = File->getBufferStart()+LineOffset[LineNo+1]; + else + LineEnd = File->getBufferEnd(); + + // If the line ended with a newline, strip it off. + while (LineEnd != LineStart && (LineEnd[-1] == '\n' || LineEnd[-1] == '\r')) + --LineEnd; + + assert(LineEnd >= LineStart && "We somehow got our pointers swizzled!"); +} diff --git a/lib/Debugger/SourceLanguage-CFamily.cpp b/lib/Debugger/SourceLanguage-CFamily.cpp new file mode 100644 index 0000000..f329db4 --- /dev/null +++ b/lib/Debugger/SourceLanguage-CFamily.cpp @@ -0,0 +1,28 @@ +//===-- SourceLanguage-CFamily.cpp - C family SourceLanguage impl ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SourceLanguage class for the C family of languages +// (K&R C, C89, C99, etc). +// +//===----------------------------------------------------------------------===// + +#include "llvm/Debugger/SourceLanguage.h" +using namespace llvm; + +#if 0 +namespace { + struct CSL : public SourceLanguage { + } TheCSourceLanguageInstance; +} +#endif + +const SourceLanguage &SourceLanguage::getCFamilyInstance() { + return get(0); // We don't have an implementation for C yet fall back on + // generic +} diff --git a/lib/Debugger/SourceLanguage-CPlusPlus.cpp b/lib/Debugger/SourceLanguage-CPlusPlus.cpp new file mode 100644 index 0000000..ce94ff4 --- /dev/null +++ b/lib/Debugger/SourceLanguage-CPlusPlus.cpp @@ -0,0 +1,27 @@ +//===-- SourceLanguage-CPlusPlus.cpp - C++ SourceLanguage impl ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SourceLanguage class for the C++ language. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Debugger/SourceLanguage.h" +using namespace llvm; + +#if 0 +namespace { + struct CPPSL : public SourceLanguage { + } TheCPlusPlusLanguageInstance; +} +#endif + +const SourceLanguage &SourceLanguage::getCPlusPlusInstance() { + return get(0); // We don't have an implementation for C yet fall back on + // generic +} diff --git a/lib/Debugger/SourceLanguage-Unknown.cpp b/lib/Debugger/SourceLanguage-Unknown.cpp new file mode 100644 index 0000000..b806fc7 --- /dev/null +++ b/lib/Debugger/SourceLanguage-Unknown.cpp @@ -0,0 +1,138 @@ +//===-- SourceLanguage-Unknown.cpp - Implement itf for unknown languages --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// If the LLVM debugger does not have a module for a particular language, it +// falls back on using this one to perform the source-language interface. This +// interface is not wonderful, but it gets the job done. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Debugger/SourceLanguage.h" +#include "llvm/Debugger/ProgramInfo.h" +#include "llvm/Support/Streams.h" +#include <cassert> +#include <ostream> +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Implement the SourceLanguage cache for the Unknown language. +// + +namespace { + /// SLUCache - This cache allows for efficient lookup of source functions by + /// name. + /// + struct SLUCache : public SourceLanguageCache { + ProgramInfo &PI; + std::multimap<std::string, SourceFunctionInfo*> FunctionMap; + public: + SLUCache(ProgramInfo &pi); + + typedef std::multimap<std::string, SourceFunctionInfo*>::const_iterator + fm_iterator; + + std::pair<fm_iterator, fm_iterator> + getFunction(const std::string &Name) const { + return FunctionMap.equal_range(Name); + } + + SourceFunctionInfo *addSourceFunction(SourceFunctionInfo *SF) { + FunctionMap.insert(std::make_pair(SF->getSymbolicName(), SF)); + return SF; + } + }; +} + +SLUCache::SLUCache(ProgramInfo &pi) : PI(pi) { +} + + +//===----------------------------------------------------------------------===// +// Implement SourceLanguageUnknown class, which is used to handle unrecognized +// languages. +// + +namespace { + static struct SLU : public SourceLanguage { + //===------------------------------------------------------------------===// + // Implement the miscellaneous methods... + // + virtual const char *getSourceLanguageName() const { + return "unknown"; + } + + /// lookupFunction - Given a textual function name, return the + /// SourceFunctionInfo descriptor for that function, or null if it cannot be + /// found. If the program is currently running, the RuntimeInfo object + /// provides information about the current evaluation context, otherwise it + /// will be null. + /// + virtual SourceFunctionInfo *lookupFunction(const std::string &FunctionName, + ProgramInfo &PI, + RuntimeInfo *RI = 0) const; + + //===------------------------------------------------------------------===// + // We do use a cache for information... + // + typedef SLUCache CacheType; + SLUCache *createSourceLanguageCache(ProgramInfo &PI) const { + return new SLUCache(PI); + } + + /// createSourceFunctionInfo - Create the new object and inform the cache of + /// the new function. + virtual SourceFunctionInfo * + createSourceFunctionInfo(const GlobalVariable *Desc, ProgramInfo &PI) const; + + } TheUnknownSourceLanguageInstance; +} + +const SourceLanguage &SourceLanguage::getUnknownLanguageInstance() { + return TheUnknownSourceLanguageInstance; +} + + +SourceFunctionInfo * +SLU::createSourceFunctionInfo(const GlobalVariable *Desc, + ProgramInfo &PI) const { + SourceFunctionInfo *Result = new SourceFunctionInfo(PI, Desc); + return PI.getLanguageCache(this).addSourceFunction(Result); +} + + +/// lookupFunction - Given a textual function name, return the +/// SourceFunctionInfo descriptor for that function, or null if it cannot be +/// found. If the program is currently running, the RuntimeInfo object +/// provides information about the current evaluation context, otherwise it will +/// be null. +/// +SourceFunctionInfo *SLU::lookupFunction(const std::string &FunctionName, + ProgramInfo &PI, RuntimeInfo *RI) const{ + SLUCache &Cache = PI.getLanguageCache(this); + std::pair<SLUCache::fm_iterator, SLUCache::fm_iterator> IP + = Cache.getFunction(FunctionName); + + if (IP.first == IP.second) { + if (PI.allSourceFunctionsRead()) + return 0; // Nothing found + + // Otherwise, we might be able to find the function if we read all of them + // in. Do so now. + PI.getSourceFunctions(); + assert(PI.allSourceFunctionsRead() && "Didn't read in all functions?"); + return lookupFunction(FunctionName, PI, RI); + } + + SourceFunctionInfo *Found = IP.first->second; + ++IP.first; + if (IP.first != IP.second) + cout << "Whoa, found multiple functions with the same name. I should" + << " ask the user which one to use: FIXME!\n"; + return Found; +} diff --git a/lib/Debugger/SourceLanguage.cpp b/lib/Debugger/SourceLanguage.cpp new file mode 100644 index 0000000..4fcc38b --- /dev/null +++ b/lib/Debugger/SourceLanguage.cpp @@ -0,0 +1,54 @@ +//===-- SourceLanguage.cpp - Implement the SourceLanguage class -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SourceLanguage class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Debugger/SourceLanguage.h" +#include "llvm/Debugger/ProgramInfo.h" +using namespace llvm; + +const SourceLanguage &SourceLanguage::get(unsigned ID) { + switch (ID) { + case 1: // DW_LANG_C89 + case 2: // DW_LANG_C + case 12: // DW_LANG_C99 + return getCFamilyInstance(); + + case 4: // DW_LANG_C_plus_plus + return getCPlusPlusInstance(); + + case 3: // DW_LANG_Ada83 + case 5: // DW_LANG_Cobol74 + case 6: // DW_LANG_Cobol85 + case 7: // DW_LANG_Fortran77 + case 8: // DW_LANG_Fortran90 + case 9: // DW_LANG_Pascal83 + case 10: // DW_LANG_Modula2 + case 11: // DW_LANG_Java + case 13: // DW_LANG_Ada95 + case 14: // DW_LANG_Fortran95 + default: + return getUnknownLanguageInstance(); + } +} + + +SourceFileInfo * +SourceLanguage::createSourceFileInfo(const GlobalVariable *Desc, + ProgramInfo &PI) const { + return new SourceFileInfo(Desc, *this); +} + +SourceFunctionInfo * +SourceLanguage::createSourceFunctionInfo(const GlobalVariable *Desc, + ProgramInfo &PI) const { + return new SourceFunctionInfo(PI, Desc); +} |