From 4575dcb5873af0163f871196b92a77928fbb5c8e Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Mon, 5 Jan 2004 05:23:38 +0000 Subject: [PATCH] Initial implementation of some source-level debugging stuff git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@10684 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Debugger/Debugger.h | 169 ++++++++++++++++ include/llvm/Debugger/InferiorProcess.h | 138 +++++++++++++ include/llvm/Debugger/ProgramInfo.h | 245 ++++++++++++++++++++++++ include/llvm/Debugger/RuntimeInfo.h | 141 ++++++++++++++ include/llvm/Debugger/SourceFile.h | 95 +++++++++ include/llvm/Debugger/SourceLanguage.h | 99 ++++++++++ 6 files changed, 887 insertions(+) create mode 100644 include/llvm/Debugger/Debugger.h create mode 100644 include/llvm/Debugger/InferiorProcess.h create mode 100644 include/llvm/Debugger/ProgramInfo.h create mode 100644 include/llvm/Debugger/RuntimeInfo.h create mode 100644 include/llvm/Debugger/SourceFile.h create mode 100644 include/llvm/Debugger/SourceLanguage.h diff --git a/include/llvm/Debugger/Debugger.h b/include/llvm/Debugger/Debugger.h new file mode 100644 index 00000000000..b1115daca6a --- /dev/null +++ b/include/llvm/Debugger/Debugger.h @@ -0,0 +1,169 @@ +//===- Debugger.h - LLVM debugger library interface -------------*- C++ -*-===// +// +// 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 defines the LLVM source-level debugger library interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGGER_DEBUGGER_H +#define LLVM_DEBUGGER_DEBUGGER_H + +#include +#include + +namespace llvm { + class Module; + class InferiorProcess; + + /// Debugger class - This class implements the LLVM source-level debugger. + /// This allows clients to handle the user IO processing without having to + /// worry about how the debugger itself works. + /// + class Debugger { + // State the debugger needs when starting and stopping the program. + std::vector ProgramArguments; + + // The environment to run the program with. This should eventually be + // changed to vector of strings when we allow the user to edit the + // environment. + const char * const *Environment; + + // Program - The currently loaded program, or null if none is loaded. + Module *Program; + + // Process - The currently executing inferior process. + InferiorProcess *Process; + + Debugger(const Debugger &); // DO NOT IMPLEMENT + void operator=(const Debugger &); // DO NOT IMPLEMENT + public: + Debugger(); + ~Debugger(); + + //===------------------------------------------------------------------===// + // Methods for manipulating and inspecting the execution environment. + // + + /// initializeEnvironment - Specify the environment the program should run + /// with. This is used to initialize the environment of the program to the + /// environment of the debugger. + void initializeEnvironment(const char *const *envp) { + Environment = envp; + } + + /// setWorkingDirectory - Specify the working directory for the program to + /// be started from. + void setWorkingDirectory(const std::string &Dir) { + // FIXME: implement + } + + template + void setProgramArguments(It I, It E) { + ProgramArguments.assign(I, E); + } + + + //===------------------------------------------------------------------===// + // Methods for manipulating and inspecting the program currently loaded. + // + + /// isProgramLoaded - Return true if there is a program currently loaded. + /// + bool isProgramLoaded() const { return Program != 0; } + + /// getProgram - Return the LLVM module corresponding to the program. + /// + Module *getProgram() const { return Program; } + + /// getProgramPath - Get the path of the currently loaded program, or an + /// empty string if none is loaded. + std::string getProgramPath() const; + + /// 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 loadProgram(const std::string &Path); + + /// 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 unloadProgram(); + + //===------------------------------------------------------------------===// + // Methods for manipulating and inspecting the program currently running. + // + // If the program is running, and the debugger is active, then we know that + // the program has stopped. This being the case, we can inspect the + // program, ask it for its source location, set breakpoints, etc. + // + + /// isProgramRunning - Return true if a program is loaded and has a + /// currently active instance. + bool isProgramRunning() const { return Process != 0; } + + /// getRunningProcess - If there is no program running, throw an exception. + /// Otherwise return the running process so that it can be inspected by the + /// debugger. + const InferiorProcess &getRunningProcess() const { + if (Process == 0) throw "No process running."; + return *Process; + } + + /// 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 createProgram(); + + /// 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. + /// If something horrible happens when killing the program, an exception + /// gets thrown. + void killProgram(); + + + //===------------------------------------------------------------------===// + // Methods for continuing execution. These methods continue the execution + // of the program by some amount. If the program is successfully stopped, + // execution returns, otherwise an exception is thrown. + // + // NOTE: These methods should always be used in preference to directly + // accessing the Dbg object, because these will delete the Process object if + // the process unexpectedly dies. + // + + /// stepProgram - Implement the 'step' command, continuing execution until + /// the next possible stop point. + void stepProgram(); + + /// nextProgram - Implement the 'next' command, continuing execution until + /// the next possible stop point that is in the current function. + void nextProgram(); + + /// finishProgram - Implement the 'finish' command, continuing execution + /// until the specified frame ID returns. + void finishProgram(void *Frame); + + /// contProgram - Implement the 'cont' command, continuing execution until + /// the next breakpoint is encountered. + void contProgram(); + }; + + class NonErrorException { + std::string Message; + public: + NonErrorException(const std::string &M) : Message(M) {} + const std::string &getMessage() const { return Message; } + }; + +} // end namespace llvm + +#endif diff --git a/include/llvm/Debugger/InferiorProcess.h b/include/llvm/Debugger/InferiorProcess.h new file mode 100644 index 00000000000..c3f388654ae --- /dev/null +++ b/include/llvm/Debugger/InferiorProcess.h @@ -0,0 +1,138 @@ +//===- InferiorProcess.h - Represent the program being debugged -*- C++ -*-===// +// +// 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 defines the InferiorProcess class, which is used to represent, +// inspect, and manipulate a process under the control of the LLVM debugger. +// +// This is an abstract class which should allow various different types of +// implementations. Initially we implement a unix specific debugger backend +// that does not require code generator support, but we could eventually use +// code generator support with ptrace, support windows based targets, supported +// remote targets, etc. +// +// If the inferior process unexpectedly dies, an attempt to communicate with it +// will cause an InferiorProcessDead exception to be thrown, indicating the exit +// code of the process. When this occurs, no methods on the InferiorProcess +// class should be called except for the destructor. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGGER_INFERIORPROCESS_H +#define LLVM_DEBUGGER_INFERIORPROCESS_H + +#include +#include + +namespace llvm { + class Module; + class GlobalVariable; + + /// InferiorProcessDead exception - This class is thrown by methods that + /// communicate with the interior process if the process unexpectedly exits or + /// dies. The instance variable indicates what the exit code of the process + /// was, or -1 if unknown. + class InferiorProcessDead { + int ExitCode; + public: + InferiorProcessDead(int EC) : ExitCode(EC) {} + int getExitCode() const { return ExitCode; } + }; + + /// InferiorProcess class - This class represents the process being debugged + /// by the debugger. Objects of this class should not be stack allocated, + /// because the destructor can throw exceptions. + /// + class InferiorProcess { + Module *M; + protected: + InferiorProcess(Module *m) : M(m) {} + public: + /// create - Create an inferior process of the specified module, and + /// stop it at the first opportunity. If there is a problem starting the + /// program (for example, it has no main), throw an exception. + static InferiorProcess *create(Module *M, + const std::vector &Arguments, + const char * const *envp); + + // InferiorProcess destructor - Kill the current process. If something + // terrible happens, we throw an exception from the destructor. + virtual ~InferiorProcess() {} + + //===------------------------------------------------------------------===// + // Status methods - These methods return information about the currently + // stopped process. + // + + /// getStatus - Return a status message that is specific to the current type + /// of inferior process that is created. This can return things like the + /// PID of the inferior or other potentially interesting things. + virtual std::string getStatus() const { + return ""; + } + + //===------------------------------------------------------------------===// + // Methods for inspecting the call stack. + // + + /// getPreviousFrame - Given the descriptor for the current stack frame, + /// return the descriptor for the caller frame. This returns null when it + /// runs out of frames. If Frame is null, the initial frame should be + /// returned. + virtual void *getPreviousFrame(void *Frame) const = 0; + + /// getSubprogramDesc - Return the subprogram descriptor for the current + /// stack frame. + virtual const GlobalVariable *getSubprogramDesc(void *Frame) const = 0; + + /// getFrameLocation - This method returns the source location where each + /// stack frame is stopped. + virtual void getFrameLocation(void *Frame, unsigned &LineNo, + unsigned &ColNo, + const GlobalVariable *&SourceDesc) const = 0; + + //===------------------------------------------------------------------===// + // Methods for manipulating breakpoints. + // + + /// addBreakpoint - This method adds a breakpoint at the specified line, + /// column, and source file, and returns a unique identifier for it. + /// + /// It is up to the debugger to determine whether or not there is actually a + /// stop-point that corresponds with the specified location. + virtual unsigned addBreakpoint(unsigned LineNo, unsigned ColNo, + const GlobalVariable *SourceDesc) = 0; + + /// removeBreakpoint - This deletes the breakpoint with the specified ID + /// number. + virtual void removeBreakpoint(unsigned ID) = 0; + + + //===------------------------------------------------------------------===// + // Execution methods - These methods cause the program to continue execution + // by some amount. If the program successfully stops, this returns. + // Otherwise, if the program unexpectedly terminates, an InferiorProcessDead + // exception is thrown. + // + + /// stepProgram - Implement the 'step' command, continuing execution until + /// the next possible stop point. + virtual void stepProgram() = 0; + + /// finishProgram - Implement the 'finish' command, continuing execution + /// until the current function returns. + virtual void finishProgram(void *Frame) = 0; + + /// contProgram - Implement the 'cont' command, continuing execution until + /// a breakpoint is encountered. + virtual void contProgram() = 0; + }; +} // end namespace llvm + +#endif + diff --git a/include/llvm/Debugger/ProgramInfo.h b/include/llvm/Debugger/ProgramInfo.h new file mode 100644 index 00000000000..0807d8ca5b6 --- /dev/null +++ b/include/llvm/Debugger/ProgramInfo.h @@ -0,0 +1,245 @@ +//===- ProgramInfo.h - Information about the loaded program -----*- C++ -*-===// +// +// 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 defines various pieces of information about the currently loaded +// program. One instance of this object is created every time a program is +// loaded, and destroyed every time it is unloaded. +// +// The various pieces of information gathered about the source program are all +// designed to be extended by various SourceLanguage implementations. This +// allows source languages to keep any extended information that they support in +// the derived class portions of the class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGGER_PROGRAMINFO_H +#define LLVM_DEBUGGER_PROGRAMINFO_H + +#include +#include +#include + +namespace llvm { + class GlobalVariable; + class Module; + class SourceFile; + class SourceLanguage; + class ProgramInfo; + + /// SourceLanguageCache - SourceLanguage implementations are allowed to cache + /// stuff in the ProgramInfo object. The only requirement we have on these + /// instances is that they are destroyable. + struct SourceLanguageCache { + virtual ~SourceLanguageCache() {} + }; + + /// SourceFileInfo - One instance of this structure is created for each + /// source file in the program. + /// + class SourceFileInfo { + /// BaseName - The filename of the source file. + std::string BaseName; + + /// Directory - The working directory of this source file when it was + /// compiled. + std::string Directory; + + /// Version - The version of the LLVM debug information that this file was + /// compiled with. + unsigned Version; + + /// Language - The source language that the file was compiled with. This + /// pointer is never null. + /// + const SourceLanguage *Language; + + /// Descriptor - The LLVM Global Variable which describes the source file. + /// + const GlobalVariable *Descriptor; + + /// SourceText - The body of this source file, or null if it has not yet + /// been loaded. + mutable SourceFile *SourceText; + public: + SourceFileInfo(const GlobalVariable *Desc, const SourceLanguage &Lang); + ~SourceFileInfo(); + + const std::string &getBaseName() const { return BaseName; } + const std::string &getDirectory() const { return Directory; } + unsigned getDebugVersion() const { return Version; } + const GlobalVariable *getDescriptor() const { return Descriptor; } + SourceFile &getSourceText() const; + + const SourceLanguage &getLanguage() const { return *Language; } + }; + + + /// SourceFunctionInfo - An instance of this class is used to represent each + /// source function in the program. + /// + class SourceFunctionInfo { + /// Name - This contains an abstract name that is potentially useful to the + /// end-user. If there is no explicit support for the current language, + /// then this string is used to identify the function. + std::string Name; + + /// Descriptor - The descriptor for this function. + /// + const GlobalVariable *Descriptor; + + /// SourceFile - The file that this function is defined in. + /// + const SourceFileInfo *SourceFile; + + /// LineNo, ColNo - The location of the first stop-point in the function. + /// These are computed on demand. + mutable unsigned LineNo, ColNo; + + public: + SourceFunctionInfo(ProgramInfo &PI, const GlobalVariable *Desc); + virtual ~SourceFunctionInfo() {} + + /// getSymbolicName - Return a human-readable symbolic name to identify the + /// function (for example, in stack traces). + virtual std::string getSymbolicName() const { return Name; } + + /// getDescriptor - This returns the descriptor for the function. + /// + const GlobalVariable *getDescriptor() const { return Descriptor; } + + /// getSourceFile - This returns the source file that defines the function. + /// + const SourceFileInfo &getSourceFile() const { return *SourceFile; } + + /// getSourceLocation - This method returns the location of the first + /// stopping point in the function. If the body of the function cannot be + /// found, this returns zeros for both values. + void getSourceLocation(unsigned &LineNo, unsigned &ColNo) const; + }; + + + /// ProgramInfo - This object contains information about the loaded program. + /// When a new program is loaded, an instance of this class is created. When + /// the program is unloaded, the instance is destroyed. This object basically + /// manages the lazy computation of information useful for the debugger. + class ProgramInfo { + Module *M; + + /// ProgramTimeStamp - This is the timestamp of the executable file that we + /// currently have loaded into the debugger. + unsigned long long ProgramTimeStamp; + + /// SourceFiles - This map is used to transform source file descriptors into + /// their corresponding SourceFileInfo objects. This mapping owns the + /// memory for the SourceFileInfo objects. + /// + bool SourceFilesIsComplete; + std::map SourceFiles; + + /// SourceFileIndex - Mapping from source file basenames to the information + /// about the file. Note that there can be filename collisions, so this is + /// a multimap. This map is populated incrementally as the user interacts + /// with the program, through the getSourceFileFromDesc method. If ALL of + /// the source files are needed, the getSourceFiles() method scans the + /// entire program looking for them. + /// + std::multimap SourceFileIndex; + + /// SourceFunctions - This map contains entries functions in the source + /// program. If SourceFunctionsIsComplete is true, then this is ALL of the + /// functions in the program are in this map. + bool SourceFunctionsIsComplete; + std::map SourceFunctions; + + /// LanguageCaches - Each source language is permitted to keep a per-program + /// cache of information specific to whatever it needs. This vector is + /// effectively a small map from the languages that are active in the + /// program to their caches. This can be accessed by the language by the + /// "getLanguageCache" method. + std::vector > LanguageCaches; + public: + ProgramInfo(Module *m); + ~ProgramInfo(); + + /// getProgramTimeStamp - Return the time-stamp of the program when it was + /// loaded. + unsigned long long getProgramTimeStamp() const { return ProgramTimeStamp; } + + //===------------------------------------------------------------------===// + // Interfaces to the source code files that make up the program. + // + + /// 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 &getSourceFile(const GlobalVariable *Desc); + + /// 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. + /// + /// If the source file hasn't been discovered yet in the program, this + /// method might have to index the whole program by calling the + /// getSourceFiles() method. + /// + const SourceFileInfo &getSourceFile(const std::string &Filename); + + /// getSourceFiles - Index all of the source files 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 & + getSourceFiles(bool RequiresCompleteMap = true); + + //===------------------------------------------------------------------===// + // Interfaces to the functions that make up the program. + // + + /// getFunction - Return source 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 &getFunction(const GlobalVariable *Desc); + + /// 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 & + getSourceFunctions(bool RequiresCompleteMap = true); + + /// addSourceFunctionsRead - Return true if the source functions map is + /// complete: that is, all functions in the program have been read in. + bool allSourceFunctionsRead() const { return SourceFunctionsIsComplete; } + + /// getLanguageCache - This method is used to build per-program caches of + /// information, such as the functions or types visible to the program. + /// This can be used by SourceLanguage implementations because it requires + /// an accessible ::CacheType typedef, where is the C++ type of the + /// source-language subclass. + template + typename SL::CacheType &getLanguageCache(const SL *L) { + for (unsigned i = 0, e = LanguageCaches.size(); i != e; ++i) + if (LanguageCaches[i].first == L) + return *(typename SL::CacheType*)LanguageCaches[i].second; + typename SL::CacheType *NewCache = L->createSourceLanguageCache(*this); + LanguageCaches.push_back(std::make_pair(L, NewCache)); + return *NewCache; + } + }; + +} // end namespace llvm + +#endif diff --git a/include/llvm/Debugger/RuntimeInfo.h b/include/llvm/Debugger/RuntimeInfo.h new file mode 100644 index 00000000000..360b923e55d --- /dev/null +++ b/include/llvm/Debugger/RuntimeInfo.h @@ -0,0 +1,141 @@ +//===- RuntimeInfo.h - Information about running program --------*- C++ -*-===// +// +// 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 defines classes that capture various pieces of information about +// the currently executing, but stopped, program. One instance of this object +// is created every time a program is stopped, and destroyed every time it +// starts running again. This object's main goal is to make access to runtime +// information easy and efficient, by caching information as requested. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGGER_RUNTIMEINFO_H +#define LLVM_DEBUGGER_RUNTIMEINFO_H + +#include + +namespace llvm { + class ProgramInfo; + class RuntimeInfo; + class InferiorProcess; + class GlobalVariable; + class SourceFileInfo; + + /// StackFrame - One instance of this structure is created for each stack + /// frame that is active in the program. + /// + class StackFrame { + RuntimeInfo &RI; + void *FrameID; + const GlobalVariable *FunctionDesc; + + /// LineNo, ColNo, FileInfo - This information indicates WHERE in the source + /// code for the program the stack frame is located. + unsigned LineNo, ColNo; + const SourceFileInfo *SourceInfo; + public: + StackFrame(RuntimeInfo &RI, void *ParentFrameID); + + StackFrame &operator=(const StackFrame &RHS) { + FrameID = RHS.FrameID; + FunctionDesc = RHS.FunctionDesc; + return *this; + } + + /// getFrameID - return the low-level opaque frame ID of this stack frame. + /// + void *getFrameID() const { return FrameID; } + + /// getFunctionDesc - Return the descriptor for the function that contains + /// this stack frame, or null if it is unknown. + /// + const GlobalVariable *getFunctionDesc(); + + /// getSourceLocation - Return the source location that this stack frame is + /// sitting at. + void getSourceLocation(unsigned &LineNo, unsigned &ColNo, + const SourceFileInfo *&SourceInfo); + }; + + + /// RuntimeInfo - This class collects information about the currently running + /// process. It is created whenever the program stops execution for the + /// debugger, and destroyed whenver execution continues. + class RuntimeInfo { + /// ProgInfo - This object contains static information about the program. + /// + ProgramInfo *ProgInfo; + + /// IP - This object contains information about the actual inferior process + /// that we are communicating with and aggregating information from. + const InferiorProcess &IP; + + /// CallStack - This caches information about the current stack trace of the + /// program. This is lazily computed as needed. + std::vector CallStack; + + /// CurrentFrame - The user can traverse the stack frame with the + /// up/down/frame family of commands. This index indicates the current + /// stack frame. + unsigned CurrentFrame; + + public: + RuntimeInfo(ProgramInfo *PI, const InferiorProcess &ip) + : ProgInfo(PI), IP(ip), CurrentFrame(0) { + // Make sure that the top of stack has been materialized. If this throws + // an exception, something is seriously wrong and the RuntimeInfo object + // would be unusable anyway. + getStackFrame(0); + } + + ProgramInfo &getProgramInfo() { return *ProgInfo; } + const InferiorProcess &getInferiorProcess() const { return IP; } + + //===------------------------------------------------------------------===// + // Methods for inspecting the call stack of the program. + // + + /// getStackFrame - Materialize the specified stack frame and return it. If + /// the specified ID is off of the bottom of the stack, throw an exception + /// indicating the problem. + StackFrame &getStackFrame(unsigned ID) { + if (ID >= CallStack.size()) + materializeFrame(ID); + return CallStack[ID]; + } + + /// getCurrentFrame - Return the current stack frame object that the user is + /// inspecting. + StackFrame &getCurrentFrame() { + assert(CallStack.size() > CurrentFrame && + "Must have materialized frame before making it current!"); + return CallStack[CurrentFrame]; + } + + /// getCurrentFrameIdx - Return the current frame the user is inspecting. + /// + unsigned getCurrentFrameIdx() const { return CurrentFrame; } + + /// setCurrentFrameIdx - Set the current frame index to the specified value. + /// Note that the specified frame must have been materialized with + /// getStackFrame before it can be made current. + void setCurrentFrameIdx(unsigned Idx) { + assert(Idx < CallStack.size() && + "Must materialize frame before making it current!"); + CurrentFrame = Idx; + } + private: + /// 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 materializeFrame(unsigned ID); + }; +} + +#endif diff --git a/include/llvm/Debugger/SourceFile.h b/include/llvm/Debugger/SourceFile.h new file mode 100644 index 00000000000..86a7f36b10a --- /dev/null +++ b/include/llvm/Debugger/SourceFile.h @@ -0,0 +1,95 @@ +//===- SourceFile.h - Class to represent a source code file -----*- C++ -*-===// +// +// 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 defines the SourceFile class which is used to represent a single +// file of source code in the program, caching data from the file to make access +// efficient. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGGER_SOURCEFILE_H +#define LLVM_DEBUGGER_SOURCEFILE_H + +#include +#include + +namespace llvm { + class GlobalVariable; + + class SourceFile { + /// Filename - This is the full path of the file that is loaded. + /// + std::string Filename; + + /// Descriptor - The debugging descriptor for this source file. If there + /// are multiple descriptors for the same file, this is just the first one + /// encountered. + /// + const GlobalVariable *Descriptor; + + /// FileStart, FileEnd - These pointers point to the start and end of the + /// file data for this file. If there was an error loading the file, these + /// pointers will both be null. + const char *FileStart, *FileEnd; + + /// LineOffset - This vector contains a mapping from source line numbers to + /// their offsets in the file. This data is computed lazily, the first time + /// it is asked for. If there are zero elements allocated in this vector, + /// then it has not yet been computed. + mutable std::vector LineOffset; + + public: + /// SourceFile constructor - Read in the specified source file if it exists, + /// but do not build the LineOffsets table until it is requested. This will + /// NOT throw an exception if the file is not found, if there is an error + /// reading it, or if the user cancels the operation. Instead, it will just + /// be an empty source file. + SourceFile(const std::string &fn, const GlobalVariable *Desc) + : Filename(fn), Descriptor(Desc), FileStart(0), FileEnd(0) { + readFile(); + } + ~SourceFile() { + delete[] FileStart; + } + + /// getDescriptor - Return the debugging decriptor for this source file. + /// + const GlobalVariable *getDescriptor() const { return Descriptor; } + + /// getFilename - Return the fully resolved path that this file was loaded + /// from. + const std::string &getFilename() const { return Filename; } + + /// 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. This also strips off + /// any newlines from the end of the line, to ease formatting of the text. + void getSourceLine(unsigned LineNo, const char *&LineStart, + const char *&LineEnd) const; + + /// getNumLines - Return the number of lines the source file contains. + /// + unsigned getNumLines() const { + if (LineOffset.empty()) calculateLineOffsets(); + return LineOffset.size(); + } + + private: + /// readFile - Load Filename into FileStart and FileEnd. + /// + void readFile(); + + /// calculateLineOffsets - Compute the LineOffset vector for the current + /// file. + void calculateLineOffsets() const; + }; +} // end namespace llvm + +#endif diff --git a/include/llvm/Debugger/SourceLanguage.h b/include/llvm/Debugger/SourceLanguage.h new file mode 100644 index 00000000000..798e0fb49c8 --- /dev/null +++ b/include/llvm/Debugger/SourceLanguage.h @@ -0,0 +1,99 @@ +//===- SourceLanguage.h - Interact with source languages --------*- C++ -*-===// +// +// 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 defines the abstract SourceLanguage interface, which is used by the +// LLVM debugger to parse source-language expressions and render program objects +// into a human readable string. In general, these classes perform all of the +// analysis and interpretation of the language-specific debugger information. +// +// This interface is designed to be completely stateless, so all methods are +// const. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGGER_SOURCELANGUAGE_H +#define LLVM_DEBUGGER_SOURCELANGUAGE_H + +#include + +namespace llvm { + class GlobalVariable; + class SourceFileInfo; + class SourceFunctionInfo; + class ProgramInfo; + class RuntimeInfo; + + struct SourceLanguage { + virtual ~SourceLanguage() {} + + /// getSourceLanguageName - This method is used to implement the 'show + /// language' command in the debugger. + virtual const char *getSourceLanguageName() const = 0; + + //===------------------------------------------------------------------===// + // Methods used to implement debugger hooks. + // + + /// printInfo - Implementing this method allows the debugger to use + /// language-specific 'info' extensions, e.g., 'info selectors' for objc. + /// This method should return true if the specified string is recognized. + /// + virtual bool printInfo(const std::string &What) const { + return false; + } + + /// 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 { + return 0; + } + + + //===------------------------------------------------------------------===// + // Methods used to parse various pieces of program information. + // + + /// createSourceFileInfo - This method can be implemented by the front-end + /// if it needs to keep track of information beyond what the debugger + /// requires. + virtual SourceFileInfo * + createSourceFileInfo(const GlobalVariable *Desc, ProgramInfo &PI) const; + + /// createSourceFunctionInfo - This method can be implemented by the derived + /// SourceLanguage if it needs to keep track of more information than the + /// SourceFunctionInfo has. + virtual SourceFunctionInfo * + createSourceFunctionInfo(const GlobalVariable *Desc, ProgramInfo &PI) const; + + + //===------------------------------------------------------------------===// + // Static methods used to get instances of various source languages. + // + + /// get - This method returns a source-language instance for the specified + /// Dwarf 3 language identifier. If the language is unknown, an object is + /// returned that can support some minimal operations, but is not terribly + /// bright. + static const SourceLanguage &get(unsigned ID); + + /// get*Instance() - These methods return specific instances of languages. + /// + static const SourceLanguage &getCFamilyInstance(); + static const SourceLanguage &getCPlusPlusInstance(); + static const SourceLanguage &getUnknownLanguageInstance(); + }; +} + +#endif