1 /* 2 * Copyright 2012, Rene Gollent, rene@gollent.com. 3 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include "DwarfStackFrameDebugInfo.h" 9 10 #include <new> 11 12 #include "Architecture.h" 13 #include "CompilationUnit.h" 14 #include "CpuState.h" 15 #include "DebugInfoEntries.h" 16 #include "Dwarf.h" 17 #include "DwarfFile.h" 18 #include "DwarfTargetInterface.h" 19 #include "DwarfTypeFactory.h" 20 #include "DwarfUtils.h" 21 #include "DwarfTypes.h" 22 #include "FunctionID.h" 23 #include "FunctionParameterID.h" 24 #include "GlobalTypeLookup.h" 25 #include "LocalVariableID.h" 26 #include "Register.h" 27 #include "RegisterMap.h" 28 #include "ReturnValueID.h" 29 #include "StringUtils.h" 30 #include "Tracing.h" 31 #include "ValueLocation.h" 32 #include "Variable.h" 33 34 35 // #pragma mark - DwarfFunctionParameterID 36 37 38 struct DwarfStackFrameDebugInfo::DwarfFunctionParameterID 39 : public FunctionParameterID { 40 41 DwarfFunctionParameterID(FunctionID* functionID, const BString& name) 42 : 43 fFunctionID(functionID), 44 fName(name) 45 { 46 fFunctionID->AcquireReference(); 47 } 48 49 virtual ~DwarfFunctionParameterID() 50 { 51 fFunctionID->ReleaseReference(); 52 } 53 54 virtual bool operator==(const ObjectID& other) const 55 { 56 const DwarfFunctionParameterID* parameterID 57 = dynamic_cast<const DwarfFunctionParameterID*>(&other); 58 return parameterID != NULL && *fFunctionID == *parameterID->fFunctionID 59 && fName == parameterID->fName; 60 } 61 62 protected: 63 virtual uint32 ComputeHashValue() const 64 { 65 uint32 hash = fFunctionID->HashValue(); 66 return hash * 19 + StringUtils::HashValue(fName); 67 } 68 69 private: 70 FunctionID* fFunctionID; 71 const BString fName; 72 }; 73 74 75 // #pragma mark - DwarfLocalVariableID 76 77 78 struct DwarfStackFrameDebugInfo::DwarfLocalVariableID : public LocalVariableID { 79 80 DwarfLocalVariableID(FunctionID* functionID, const BString& name, 81 int32 line, int32 column) 82 : 83 fFunctionID(functionID), 84 fName(name), 85 fLine(line), 86 fColumn(column) 87 { 88 fFunctionID->AcquireReference(); 89 } 90 91 virtual ~DwarfLocalVariableID() 92 { 93 fFunctionID->ReleaseReference(); 94 } 95 96 virtual bool operator==(const ObjectID& other) const 97 { 98 const DwarfLocalVariableID* otherID 99 = dynamic_cast<const DwarfLocalVariableID*>(&other); 100 return otherID != NULL && *fFunctionID == *otherID->fFunctionID 101 && fName == otherID->fName && fLine == otherID->fLine 102 && fColumn == otherID->fColumn; 103 } 104 105 protected: 106 virtual uint32 ComputeHashValue() const 107 { 108 uint32 hash = fFunctionID->HashValue(); 109 hash = hash * 19 + StringUtils::HashValue(fName); 110 hash = hash * 19 + fLine; 111 hash = hash * 19 + fColumn; 112 return hash; 113 } 114 115 private: 116 FunctionID* fFunctionID; 117 const BString fName; 118 int32 fLine; 119 int32 fColumn; 120 }; 121 122 123 // #pragma mark - DwarfReturnValueID 124 125 126 struct DwarfStackFrameDebugInfo::DwarfReturnValueID 127 : public ReturnValueID { 128 129 DwarfReturnValueID(FunctionID* functionID) 130 : 131 fFunctionID(functionID), 132 fName("(returned)") 133 { 134 fFunctionID->AcquireReference(); 135 } 136 137 virtual ~DwarfReturnValueID() 138 { 139 fFunctionID->ReleaseReference(); 140 } 141 142 virtual bool operator==(const ObjectID& other) const 143 { 144 const DwarfReturnValueID* returnValueID 145 = dynamic_cast<const DwarfReturnValueID*>(&other); 146 return returnValueID != NULL 147 && *fFunctionID == *returnValueID->fFunctionID 148 && fName == returnValueID->fName; 149 } 150 151 protected: 152 virtual uint32 ComputeHashValue() const 153 { 154 uint32 hash = fFunctionID->HashValue(); 155 return hash * 25 + StringUtils::HashValue(fName); 156 } 157 158 private: 159 FunctionID* fFunctionID; 160 const BString fName; 161 }; 162 163 164 // #pragma mark - DwarfStackFrameDebugInfo 165 166 167 DwarfStackFrameDebugInfo::DwarfStackFrameDebugInfo(Architecture* architecture, 168 image_id imageID, DwarfFile* file, CompilationUnit* compilationUnit, 169 DIESubprogram* subprogramEntry, GlobalTypeLookup* typeLookup, 170 GlobalTypeCache* typeCache, target_addr_t instructionPointer, 171 target_addr_t framePointer, target_addr_t relocationDelta, 172 DwarfTargetInterface* targetInterface, RegisterMap* fromDwarfRegisterMap) 173 : 174 StackFrameDebugInfo(), 175 fTypeContext(new(std::nothrow) DwarfTypeContext(architecture, imageID, file, 176 compilationUnit, subprogramEntry, instructionPointer, framePointer, 177 relocationDelta, targetInterface, fromDwarfRegisterMap)), 178 fTypeLookup(typeLookup), 179 fTypeCache(typeCache) 180 { 181 fTypeCache->AcquireReference(); 182 } 183 184 185 DwarfStackFrameDebugInfo::~DwarfStackFrameDebugInfo() 186 { 187 fTypeCache->ReleaseReference(); 188 189 if (fTypeContext != NULL) 190 fTypeContext->ReleaseReference(); 191 192 delete fTypeFactory; 193 } 194 195 196 status_t 197 DwarfStackFrameDebugInfo::Init() 198 { 199 if (fTypeContext == NULL) 200 return B_NO_MEMORY; 201 202 // create a type context without dependency to the stack frame 203 DwarfTypeContext* typeContext = new(std::nothrow) DwarfTypeContext( 204 fTypeContext->GetArchitecture(), fTypeContext->ImageID(), 205 fTypeContext->File(), fTypeContext->GetCompilationUnit(), NULL, 0, 0, 206 fTypeContext->RelocationDelta(), fTypeContext->TargetInterface(), 207 fTypeContext->FromDwarfRegisterMap()); 208 if (typeContext == NULL) 209 return B_NO_MEMORY; 210 BReference<DwarfTypeContext> typeContextReference(typeContext, true); 211 212 // create the type factory 213 fTypeFactory = new(std::nothrow) DwarfTypeFactory(typeContext, fTypeLookup, 214 fTypeCache); 215 if (fTypeFactory == NULL) 216 return B_NO_MEMORY; 217 218 return B_OK; 219 } 220 221 222 status_t 223 DwarfStackFrameDebugInfo::CreateParameter(FunctionID* functionID, 224 DIEFormalParameter* parameterEntry, Variable*& _parameter) 225 { 226 // get the name 227 BString name; 228 DwarfUtils::GetDIEName(parameterEntry, name); 229 230 TRACE_LOCALS("DwarfStackFrameDebugInfo::CreateParameter(DIE: %p): name: " 231 "\"%s\"\n", parameterEntry, name.String()); 232 233 // create the ID 234 DwarfFunctionParameterID* id = new(std::nothrow) DwarfFunctionParameterID( 235 functionID, name); 236 if (id == NULL) 237 return B_NO_MEMORY; 238 BReference<DwarfFunctionParameterID> idReference(id, true); 239 240 // create the variable 241 return _CreateVariable(id, name, _GetDIEType(parameterEntry), 242 parameterEntry->GetLocationDescription(), _parameter); 243 } 244 245 246 status_t 247 DwarfStackFrameDebugInfo::CreateLocalVariable(FunctionID* functionID, 248 DIEVariable* variableEntry, Variable*& _variable) 249 { 250 // get the name 251 BString name; 252 DwarfUtils::GetDIEName(variableEntry, name); 253 254 TRACE_LOCALS("DwarfStackFrameDebugInfo::CreateLocalVariable(DIE: %p): " 255 "name: \"%s\"\n", variableEntry, name.String()); 256 257 // get the declaration location 258 int32 line = -1; 259 int32 column = -1; 260 const char* file; 261 const char* directory; 262 DwarfUtils::GetDeclarationLocation(fTypeContext->File(), variableEntry, 263 directory, file, line, column); 264 // TODO: If the declaration location is unavailable, we should probably 265 // add a component to the ID to make it unique nonetheless (the name 266 // might not suffice). 267 268 // create the ID 269 DwarfLocalVariableID* id = new(std::nothrow) DwarfLocalVariableID( 270 functionID, name, line, column); 271 if (id == NULL) 272 return B_NO_MEMORY; 273 BReference<DwarfLocalVariableID> idReference(id, true); 274 275 // create the variable 276 return _CreateVariable(id, name, _GetDIEType(variableEntry), 277 variableEntry->GetLocationDescription(), _variable); 278 } 279 280 281 status_t 282 DwarfStackFrameDebugInfo::CreateReturnValue(FunctionID* functionID, 283 DIEType* returnType, ValueLocation* location, CpuState* state, 284 Variable*& _variable) 285 { 286 if (returnType == NULL) 287 return B_BAD_VALUE; 288 289 // create the type 290 DwarfType* type; 291 status_t error = fTypeFactory->CreateType(returnType, type); 292 if (error != B_OK) 293 return error; 294 BReference<DwarfType> typeReference(type, true); 295 296 DwarfReturnValueID* id = new(std::nothrow) DwarfReturnValueID( 297 functionID); 298 if (id == NULL) 299 return B_NO_MEMORY; 300 301 BString name; 302 name.SetToFormat("%s returned", functionID->FunctionName().String()); 303 304 Variable* variable = new(std::nothrow) Variable(id, name, 305 type, location, state); 306 if (variable == NULL) 307 return B_NO_MEMORY; 308 309 _variable = variable; 310 311 return B_OK; 312 } 313 314 315 status_t 316 DwarfStackFrameDebugInfo::_CreateVariable(ObjectID* id, const BString& name, 317 DIEType* typeEntry, LocationDescription* locationDescription, 318 Variable*& _variable) 319 { 320 if (typeEntry == NULL) 321 return B_BAD_VALUE; 322 323 // create the type 324 DwarfType* type; 325 status_t error = fTypeFactory->CreateType(typeEntry, type); 326 if (error != B_OK) 327 return error; 328 BReference<DwarfType> typeReference(type, true); 329 330 // get the location, if possible 331 ValueLocation* location = new(std::nothrow) ValueLocation( 332 fTypeContext->GetArchitecture()->IsBigEndian()); 333 if (location == NULL) 334 return B_NO_MEMORY; 335 BReference<ValueLocation> locationReference(location, true); 336 337 if (locationDescription->IsValid()) { 338 status_t error = type->ResolveLocation(fTypeContext, 339 locationDescription, 0, false, *location); 340 if (error != B_OK) 341 return error; 342 343 TRACE_LOCALS_ONLY(location->Dump()); 344 } 345 346 // create the variable 347 Variable* variable = new(std::nothrow) Variable(id, name, type, location); 348 if (variable == NULL) 349 return B_NO_MEMORY; 350 351 _variable = variable; 352 return B_OK; 353 } 354 355 356 template<typename EntryType> 357 /*static*/ DIEType* 358 DwarfStackFrameDebugInfo::_GetDIEType(EntryType* entry) 359 { 360 if (DIEType* typeEntry = entry->GetType()) 361 return typeEntry; 362 363 if (EntryType* abstractOrigin = dynamic_cast<EntryType*>( 364 entry->AbstractOrigin())) { 365 entry = abstractOrigin; 366 if (DIEType* typeEntry = entry->GetType()) 367 return typeEntry; 368 } 369 370 if (EntryType* specification = dynamic_cast<EntryType*>( 371 entry->Specification())) { 372 entry = specification; 373 if (DIEType* typeEntry = entry->GetType()) 374 return typeEntry; 375 } 376 377 return NULL; 378 } 379