1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2016, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 #include "Architecture.h" 8 9 #include <new> 10 11 #include <AutoDeleter.h> 12 #include <AutoLocker.h> 13 14 #include "CfaContext.h" 15 #include "CpuState.h" 16 #include "FunctionInstance.h" 17 #include "Image.h" 18 #include "ImageDebugInfo.h" 19 #include "ImageDebugInfoProvider.h" 20 #include "Register.h" 21 #include "RegisterMap.h" 22 #include "SpecificImageDebugInfo.h" 23 #include "StackTrace.h" 24 #include "Team.h" 25 26 27 Architecture::Architecture(TeamMemory* teamMemory, uint8 addressSize, 28 size_t debugCpuStateSize, bool bigEndian) 29 : 30 fTeamMemory(teamMemory), 31 fAddressSize(addressSize), 32 fDebugCpuStateSize(debugCpuStateSize), 33 fBigEndian(bigEndian) 34 { 35 } 36 37 38 Architecture::~Architecture() 39 { 40 } 41 42 43 status_t 44 Architecture::Init() 45 { 46 return B_OK; 47 } 48 49 50 status_t 51 Architecture::InitRegisterRules(CfaContext& context) const 52 { 53 // Init the initial register rules. The DWARF 3 specs on the 54 // matter: "The default rule for all columns before 55 // interpretation of the initial instructions is the undefined 56 // rule. However, an ABI authoring body or a compilation system 57 // authoring body may specify an alternate default value for any 58 // or all columns." 59 // GCC's assumes the "same value" rule for all callee preserved 60 // registers. We set them respectively. 61 // the stack pointer is initialized to 62 // CFA offset 0 by default. 63 const Register* registers = Registers(); 64 RegisterMap* toDwarf = NULL; 65 status_t result = GetDwarfRegisterMaps(&toDwarf, NULL); 66 if (result != B_OK) 67 return result; 68 69 BReference<RegisterMap> toDwarfMapReference(toDwarf, true); 70 for (int32 i = 0; i < CountRegisters(); i++) { 71 int32 dwarfReg = toDwarf->MapRegisterIndex(i); 72 if (dwarfReg < 0 || dwarfReg > CountRegisters() - 1) 73 continue; 74 75 // TODO: on CPUs that have a return address register 76 // a default rule should be set up to use that to 77 // extract the instruction pointer 78 switch (registers[i].Type()) { 79 case REGISTER_TYPE_STACK_POINTER: 80 { 81 context.RegisterRule(dwarfReg)->SetToValueOffset(0); 82 break; 83 } 84 default: 85 { 86 context.RegisterRule(dwarfReg)->SetToSameValue(); 87 break; 88 } 89 } 90 } 91 92 return result; 93 } 94 95 96 status_t 97 Architecture::CreateStackTrace(Team* team, 98 ImageDebugInfoProvider* imageInfoProvider, CpuState* cpuState, 99 StackTrace*& _stackTrace, ReturnValueInfoList* returnValueInfos, 100 int32 maxStackDepth, bool useExistingTrace, bool getFullFrameInfo) 101 { 102 BReference<CpuState> cpuStateReference(cpuState); 103 104 StackTrace* stackTrace = NULL; 105 ObjectDeleter<StackTrace> stackTraceDeleter; 106 StackFrame* nextFrame = NULL; 107 108 if (useExistingTrace) 109 stackTrace = _stackTrace; 110 else { 111 // create the object 112 stackTrace = new(std::nothrow) StackTrace; 113 if (stackTrace == NULL) 114 return B_NO_MEMORY; 115 stackTraceDeleter.SetTo(stackTrace); 116 } 117 118 // if we're passed an already existing partial stack trace, 119 // attempt to continue building it from where it left off. 120 if (stackTrace->CountFrames() > 0) { 121 nextFrame = stackTrace->FrameAt(stackTrace->CountFrames() - 1); 122 cpuState = nextFrame->PreviousCpuState(); 123 } 124 125 while (cpuState != NULL) { 126 // get the instruction pointer 127 target_addr_t instructionPointer = cpuState->InstructionPointer(); 128 129 // get the image for the instruction pointer 130 AutoLocker<Team> teamLocker(team); 131 Image* image = team->ImageByAddress(instructionPointer); 132 BReference<Image> imageReference(image); 133 teamLocker.Unlock(); 134 135 // get the image debug info 136 ImageDebugInfo* imageDebugInfo = NULL; 137 if (image != NULL) 138 imageInfoProvider->GetImageDebugInfo(image, imageDebugInfo); 139 BReference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo, 140 true); 141 142 // get the function 143 teamLocker.Lock(); 144 FunctionInstance* function = NULL; 145 FunctionDebugInfo* functionDebugInfo = NULL; 146 if (imageDebugInfo != NULL) { 147 function = imageDebugInfo->FunctionAtAddress(instructionPointer); 148 if (function != NULL) 149 functionDebugInfo = function->GetFunctionDebugInfo(); 150 } 151 BReference<FunctionInstance> functionReference(function); 152 teamLocker.Unlock(); 153 154 // If the CPU state's instruction pointer is actually the return address 155 // of the next frame, we let the architecture fix that. 156 if (nextFrame != NULL 157 && nextFrame->ReturnAddress() == cpuState->InstructionPointer()) { 158 UpdateStackFrameCpuState(nextFrame, image, 159 functionDebugInfo, cpuState); 160 } 161 162 // create the frame using the debug info 163 StackFrame* frame = NULL; 164 CpuState* previousCpuState = NULL; 165 if (function != NULL) { 166 status_t error = functionDebugInfo->GetSpecificImageDebugInfo() 167 ->CreateFrame(image, function, cpuState, getFullFrameInfo, 168 nextFrame == NULL 169 ? returnValueInfos : NULL, frame, 170 previousCpuState); 171 if (error != B_OK && error != B_UNSUPPORTED) 172 break; 173 } 174 175 // If we have no frame yet, let the architecture create it. 176 if (frame == NULL) { 177 status_t error = CreateStackFrame(image, functionDebugInfo, 178 cpuState, nextFrame == NULL, frame, previousCpuState); 179 if (error != B_OK) 180 break; 181 } 182 183 cpuStateReference.SetTo(previousCpuState, true); 184 185 frame->SetImage(image); 186 frame->SetFunction(function); 187 188 if (!stackTrace->AddFrame(frame)) { 189 delete frame; 190 return B_NO_MEMORY; 191 } 192 193 nextFrame = frame; 194 cpuState = previousCpuState; 195 if (--maxStackDepth == 0) 196 break; 197 } 198 199 if (stackTrace->CountFrames() == 0) 200 return B_ERROR; 201 202 stackTraceDeleter.Detach(); 203 _stackTrace = stackTrace; 204 return B_OK; 205 } 206