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