Jim Laskey | 6af5681 | 2006-01-04 13:36:38 +0000 | [diff] [blame] | 1 | //===-- llvm/CodeGen/MachineDebugInfo.cpp -----------------------*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file was developed by James M. Laskey and is distributed under |
| 6 | // the University of Illinois Open Source License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
Jim Laskey | 6af5681 | 2006-01-04 13:36:38 +0000 | [diff] [blame] | 9 | |
| 10 | #include "llvm/CodeGen/MachineDebugInfo.h" |
| 11 | |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 12 | #include "llvm/Constants.h" |
| 13 | #include "llvm/DerivedTypes.h" |
| 14 | #include "llvm/Intrinsics.h" |
| 15 | #include "llvm/Instructions.h" |
| 16 | #include "llvm/Module.h" |
| 17 | #include "llvm/Support/Dwarf.h" |
| 18 | |
Jim Laskey | 6af5681 | 2006-01-04 13:36:38 +0000 | [diff] [blame] | 19 | using namespace llvm; |
| 20 | |
| 21 | // Handle the Pass registration stuff necessary to use TargetData's. |
| 22 | namespace { |
Jim Laskey | b2efb85 | 2006-01-04 22:28:25 +0000 | [diff] [blame] | 23 | RegisterPass<MachineDebugInfo> X("machinedebuginfo", "Debug Information"); |
| 24 | } |
Jim Laskey | 063e765 | 2006-01-17 17:31:53 +0000 | [diff] [blame] | 25 | |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 26 | //===----------------------------------------------------------------------===// |
| 27 | |
| 28 | /// getGlobalVariablesUsing - Return all of the global variables which have the |
| 29 | /// specified value in their initializer somewhere. |
| 30 | static void |
| 31 | getGlobalVariablesUsing(Value *V, std::vector<GlobalVariable*> &Result) { |
| 32 | // Scan though value users. |
| 33 | for (Value::use_iterator I = V->use_begin(), E = V->use_end(); I != E; ++I) { |
| 34 | if (GlobalVariable *GV = dyn_cast<GlobalVariable>(*I)) { |
| 35 | // If the user is a global variable then add to result. |
| 36 | Result.push_back(GV); |
| 37 | } else if (Constant *C = dyn_cast<Constant>(*I)) { |
| 38 | // If the user is a constant variable then scan its users |
| 39 | getGlobalVariablesUsing(C, Result); |
| 40 | } |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | /// getGlobalVariablesUsing - Return all of the global variables that use the |
| 45 | /// named global variable. |
| 46 | static std::vector<GlobalVariable*> |
| 47 | getGlobalVariablesUsing(Module &M, const std::string &RootName) { |
| 48 | std::vector<GlobalVariable*> Result; // Global variables matching criteria. |
| 49 | |
| 50 | // Get the global variable root. |
| 51 | GlobalVariable *UseRoot = M.getGlobalVariable(RootName, |
| 52 | StructType::get(std::vector<const Type*>())); |
| 53 | |
| 54 | // If present and linkonce then scan for users. |
| 55 | if (UseRoot && UseRoot->hasLinkOnceLinkage()) { |
| 56 | getGlobalVariablesUsing(UseRoot, Result); |
| 57 | } |
| 58 | |
| 59 | return Result; |
| 60 | } |
| 61 | |
| 62 | /// getStringValue - Turn an LLVM constant pointer that eventually points to a |
| 63 | /// global into a string value. Return an empty string if we can't do it. |
| 64 | /// |
Chris Lattner | 22760af | 2006-01-27 17:31:30 +0000 | [diff] [blame] | 65 | static const std::string getStringValue(Value *V, unsigned Offset = 0) { |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 66 | if (GlobalVariable *GV = dyn_cast<GlobalVariable>(V)) { |
| 67 | if (GV->hasInitializer() && isa<ConstantArray>(GV->getInitializer())) { |
| 68 | ConstantArray *Init = cast<ConstantArray>(GV->getInitializer()); |
| 69 | if (Init->isString()) { |
| 70 | std::string Result = Init->getAsString(); |
| 71 | if (Offset < Result.size()) { |
| 72 | // If we are pointing INTO The string, erase the beginning... |
| 73 | Result.erase(Result.begin(), Result.begin()+Offset); |
| 74 | |
| 75 | // Take off the null terminator, and any string fragments after it. |
| 76 | std::string::size_type NullPos = Result.find_first_of((char)0); |
| 77 | if (NullPos != std::string::npos) |
| 78 | Result.erase(Result.begin()+NullPos, Result.end()); |
| 79 | return Result; |
| 80 | } |
| 81 | } |
| 82 | } |
| 83 | } else if (Constant *C = dyn_cast<Constant>(V)) { |
| 84 | if (GlobalValue *GV = dyn_cast<GlobalValue>(C)) |
| 85 | return getStringValue(GV, Offset); |
| 86 | else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) { |
| 87 | if (CE->getOpcode() == Instruction::GetElementPtr) { |
| 88 | // Turn a gep into the specified offset. |
| 89 | if (CE->getNumOperands() == 3 && |
| 90 | cast<Constant>(CE->getOperand(1))->isNullValue() && |
| 91 | isa<ConstantInt>(CE->getOperand(2))) { |
| 92 | return getStringValue(CE->getOperand(0), |
| 93 | Offset+cast<ConstantInt>(CE->getOperand(2))->getRawValue()); |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | } |
| 98 | return ""; |
| 99 | } |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 100 | |
| 101 | /// getGlobalValue - Return either a direct or cast Global value. |
| 102 | /// |
| 103 | static GlobalVariable *getGlobalValue(Value *V) { |
| 104 | if (GlobalVariable *GV = dyn_cast<GlobalVariable>(V)) { |
| 105 | return GV; |
| 106 | } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) { |
| 107 | return CE->getOpcode() == Instruction::Cast ? dyn_cast<GlobalVariable>(V) |
| 108 | : NULL; |
| 109 | } |
| 110 | return NULL; |
| 111 | } |
| 112 | |
Jim Laskey | b2efb85 | 2006-01-04 22:28:25 +0000 | [diff] [blame] | 113 | |
Jim Laskey | 063e765 | 2006-01-17 17:31:53 +0000 | [diff] [blame] | 114 | //===----------------------------------------------------------------------===// |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 115 | |
| 116 | DebugInfoWrapper::DebugInfoWrapper(GlobalVariable *G) |
| 117 | : GV(G) |
| 118 | , IC(dyn_cast<ConstantStruct>(GV->getInitializer())) { |
| 119 | assert(IC && "llvm.db.global is missing structured constant"); |
| 120 | } |
| 121 | |
| 122 | //===----------------------------------------------------------------------===// |
| 123 | |
| 124 | CompileUnitWrapper::CompileUnitWrapper(GlobalVariable *G) |
| 125 | : DebugInfoWrapper(G) |
| 126 | { |
| 127 | // FIXME - should probably ease up on the number of operands (version.) |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 128 | assert(IC->getNumOperands() == N_op && |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 129 | "Compile unit does not have correct number of operands"); |
| 130 | } |
| 131 | |
| 132 | /// getTag - Return the compile unit's tag number. Currently should be |
| 133 | /// DW_TAG_variable. |
| 134 | unsigned CompileUnitWrapper::getTag() const { |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 135 | return cast<ConstantUInt>(IC->getOperand(Tag_op))->getValue(); |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 136 | } |
| 137 | |
| 138 | /// isCorrectDebugVersion - Return true if is the correct llvm debug version. |
| 139 | /// Currently the value is 0 (zero.) If the value is is not correct then |
| 140 | /// ignore all debug information. |
| 141 | bool CompileUnitWrapper::isCorrectDebugVersion() const { |
Jim Laskey | 1a05851 | 2006-01-27 15:46:54 +0000 | [diff] [blame] | 142 | return cast<ConstantUInt>(IC->getOperand(Version_op))->getValue() == 0; |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | /// getLanguage - Return the compile unit's language number (ex. DW_LANG_C89.) |
| 146 | /// |
| 147 | unsigned CompileUnitWrapper::getLanguage() const { |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 148 | return cast<ConstantUInt>(IC->getOperand(Language_op))->getValue(); |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 149 | } |
| 150 | |
| 151 | /// getFileName - Return the compile unit's file name. |
| 152 | /// |
| 153 | const std::string CompileUnitWrapper::getFileName() const { |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 154 | return getStringValue(IC->getOperand(FileName_op)); |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 155 | } |
| 156 | |
| 157 | /// getDirectory - Return the compile unit's file directory. |
| 158 | /// |
| 159 | const std::string CompileUnitWrapper::getDirectory() const { |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 160 | return getStringValue(IC->getOperand(Directory_op)); |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 161 | } |
| 162 | |
| 163 | /// getProducer - Return the compile unit's generator name. |
| 164 | /// |
| 165 | const std::string CompileUnitWrapper::getProducer() const { |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 166 | return getStringValue(IC->getOperand(Producer_op)); |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 167 | } |
| 168 | |
| 169 | //===----------------------------------------------------------------------===// |
| 170 | |
| 171 | GlobalWrapper::GlobalWrapper(GlobalVariable *G) |
| 172 | : DebugInfoWrapper(G) |
| 173 | { |
| 174 | // FIXME - should probably ease up on the number of operands (version.) |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 175 | assert(IC->getNumOperands() == N_op && |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 176 | "Global does not have correct number of operands"); |
| 177 | } |
| 178 | |
| 179 | /// getTag - Return the global's tag number. Currently should be |
| 180 | /// DW_TAG_variable or DW_TAG_subprogram. |
| 181 | unsigned GlobalWrapper::getTag() const { |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 182 | return cast<ConstantUInt>(IC->getOperand(Tag_op))->getValue(); |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 183 | } |
| 184 | |
| 185 | /// getContext - Return the "lldb.compile_unit" context global. |
| 186 | /// |
| 187 | GlobalVariable *GlobalWrapper::getContext() const { |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 188 | return getGlobalValue(IC->getOperand(Context_op)); |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 189 | } |
| 190 | |
| 191 | /// getName - Return the name of the global. |
| 192 | /// |
| 193 | const std::string GlobalWrapper::getName() const { |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 194 | return getStringValue(IC->getOperand(Name_op)); |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 195 | } |
| 196 | |
| 197 | /// getType - Return the type of the global. |
| 198 | /// |
| 199 | const GlobalVariable *GlobalWrapper::getType() const { |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 200 | return getGlobalValue(IC->getOperand(Type_op)); |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 201 | } |
| 202 | |
| 203 | /// isStatic - Return true if the global is static. |
| 204 | /// |
| 205 | bool GlobalWrapper::isStatic() const { |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 206 | return cast<ConstantBool>(IC->getOperand(Static_op))->getValue(); |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 207 | } |
| 208 | |
| 209 | /// isDefinition - Return true if the global is a definition. |
| 210 | /// |
| 211 | bool GlobalWrapper::isDefinition() const { |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 212 | return dyn_cast<ConstantBool>(IC->getOperand(Definition_op))->getValue(); |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 213 | } |
| 214 | |
| 215 | /// getGlobalVariable - Return the global variable (tag == DW_TAG_variable.) |
| 216 | /// |
| 217 | GlobalVariable *GlobalWrapper::getGlobalVariable() const { |
Jim Laskey | d8f77ba | 2006-01-27 15:20:54 +0000 | [diff] [blame] | 218 | return getGlobalValue(IC->getOperand(GlobalVariable_op)); |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 219 | } |
| 220 | |
| 221 | //===----------------------------------------------------------------------===// |
| 222 | |
| 223 | |
| 224 | MachineDebugInfo::MachineDebugInfo() |
| 225 | : CompileUnits() |
| 226 | , Directories() |
| 227 | , SourceFiles() |
| 228 | , Lines() |
| 229 | { |
| 230 | |
| 231 | } |
| 232 | MachineDebugInfo::~MachineDebugInfo() { |
| 233 | |
| 234 | } |
| 235 | |
Jim Laskey | b2efb85 | 2006-01-04 22:28:25 +0000 | [diff] [blame] | 236 | /// doInitialization - Initialize the debug state for a new module. |
| 237 | /// |
| 238 | bool MachineDebugInfo::doInitialization() { |
| 239 | return false; |
Jim Laskey | 6af5681 | 2006-01-04 13:36:38 +0000 | [diff] [blame] | 240 | } |
| 241 | |
Jim Laskey | b2efb85 | 2006-01-04 22:28:25 +0000 | [diff] [blame] | 242 | /// doFinalization - Tear down the debug state after completion of a module. |
| 243 | /// |
| 244 | bool MachineDebugInfo::doFinalization() { |
| 245 | return false; |
| 246 | } |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 247 | |
| 248 | /// AnalyzeModule - Scan the module for global debug information. |
| 249 | /// |
| 250 | void MachineDebugInfo::AnalyzeModule(Module &M) { |
| 251 | SetupCompileUnits(M); |
| 252 | } |
| 253 | |
| 254 | /// SetupCompileUnits - Set up the unique vector of compile units. |
| 255 | /// |
| 256 | void MachineDebugInfo::SetupCompileUnits(Module &M) { |
| 257 | // Get vector of all debug compile units. |
| 258 | std::vector<GlobalVariable*> Globals = |
| 259 | getGlobalVariablesUsing(M, "llvm.dbg.translation_units"); |
| 260 | |
| 261 | // Scan all compile unit globals. |
| 262 | for (unsigned i = 0, N = Globals.size(); i < N; ++i) { |
| 263 | // Create wrapper for compile unit. |
| 264 | CompileUnitWrapper CUI(Globals[i]); |
| 265 | // Add to result. |
| 266 | if (CUI.isCorrectDebugVersion()) CompileUnits.insert(CUI); |
| 267 | } |
| 268 | |
| 269 | // If there any bad compile units then suppress debug information |
| 270 | if (CompileUnits.size() != Globals.size()) CompileUnits.reset(); |
| 271 | } |
| 272 | |
Jim Laskey | 6e87c0e | 2006-01-26 21:22:49 +0000 | [diff] [blame] | 273 | /// getCompileUnits - Return a vector of debug compile units. |
| 274 | /// |
| 275 | const UniqueVector<CompileUnitWrapper> MachineDebugInfo::getCompileUnits()const{ |
| 276 | return CompileUnits; |
| 277 | } |
| 278 | |
Jim Laskey | b3e789a | 2006-01-26 20:21:46 +0000 | [diff] [blame] | 279 | /// getGlobalVariables - Return a vector of debug global variables. |
| 280 | /// |
| 281 | std::vector<GlobalWrapper> MachineDebugInfo::getGlobalVariables(Module &M) { |
| 282 | // Get vector of all debug global objects. |
| 283 | std::vector<GlobalVariable*> Globals = |
| 284 | getGlobalVariablesUsing(M, "llvm.dbg.globals"); |
| 285 | |
| 286 | // Accumulation of global variables. |
| 287 | std::vector<GlobalWrapper> GlobalVariables; |
| 288 | |
| 289 | // FIXME - skip until globals have new format |
| 290 | #if 0 |
| 291 | // Scan all globals. |
| 292 | for (unsigned i = 0, N = Globals.size(); i < N; ++i) { |
| 293 | // Create wrapper for global. |
| 294 | GlobalWrapper GW(Globals[i]); |
| 295 | // If the global is a variable then add to result. |
| 296 | if (GW.getTag() == DW_TAG_variable) GlobalVariables.push_back(GW); |
| 297 | } |
| 298 | #endif |
| 299 | |
| 300 | return GlobalVariables; |
| 301 | } |
| 302 | |