1/* 2 * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. 3 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Copyright 2011-2012, Rene Gollent, rene@gollent.com. 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9#include "ArchitectureX8664.h" 10 11#include <new> 12 13#include <String.h> 14 15#include <AutoDeleter.h> 16 17#include "CfaContext.h" 18#include "CpuStateX8664.h" 19#include "DisassembledCode.h" 20#include "FunctionDebugInfo.h" 21#include "InstructionInfo.h" 22#include "NoOpStackFrameDebugInfo.h" 23#include "RegisterMap.h" 24#include "StackFrame.h" 25#include "Statement.h" 26#include "TeamMemory.h" 27#include "X86AssemblyLanguage.h" 28 29#include "disasm/DisassemblerX8664.h" 30 31 32static const int32 kFromDwarfRegisters[] = { 33 X86_64_REGISTER_RAX, 34 X86_64_REGISTER_RDX, 35 X86_64_REGISTER_RCX, 36 X86_64_REGISTER_RBX, 37 X86_64_REGISTER_RSI, 38 X86_64_REGISTER_RDI, 39 X86_64_REGISTER_RBP, 40 X86_64_REGISTER_RSP, 41 X86_64_REGISTER_R8, 42 X86_64_REGISTER_R9, 43 X86_64_REGISTER_R10, 44 X86_64_REGISTER_R11, 45 X86_64_REGISTER_R12, 46 X86_64_REGISTER_R13, 47 X86_64_REGISTER_R14, 48 X86_64_REGISTER_R15, 49 X86_64_REGISTER_RIP, 50 -1, -1, -1, -1, -1, -1, -1, -1, // xmm0-xmm7 51 -1, -1, -1, -1, -1, -1, -1, -1, // xmm8-xmm15 52 -1, -1, -1, -1, -1, -1, -1, -1, // st0-st7 53 -1, -1, -1, -1, -1, -1, -1, -1, // mm0-mm7 54 -1, // rflags 55 X86_64_REGISTER_ES, 56 X86_64_REGISTER_CS, 57 X86_64_REGISTER_SS, 58 X86_64_REGISTER_DS, 59 X86_64_REGISTER_FS, 60 X86_64_REGISTER_GS, 61}; 62 63static const int32 kFromDwarfRegisterCount = sizeof(kFromDwarfRegisters) / 4; 64 65 66// #pragma mark - ToDwarfRegisterMap 67 68 69struct ArchitectureX8664::ToDwarfRegisterMap : RegisterMap { 70 ToDwarfRegisterMap() 71 { 72 // init the index array from the reverse map 73 memset(fIndices, -1, sizeof(fIndices)); 74 for (int32 i = 0; i < kFromDwarfRegisterCount; i++) { 75 if (kFromDwarfRegisters[i] >= 0) 76 fIndices[kFromDwarfRegisters[i]] = i; 77 } 78 } 79 80 virtual int32 CountRegisters() const 81 { 82 return X86_64_REGISTER_COUNT; 83 } 84 85 virtual int32 MapRegisterIndex(int32 index) const 86 { 87 return index >= 0 && index < X86_64_REGISTER_COUNT ? fIndices[index] : -1; 88 } 89 90private: 91 int32 fIndices[X86_64_REGISTER_COUNT]; 92}; 93 94 95// #pragma mark - FromDwarfRegisterMap 96 97 98struct ArchitectureX8664::FromDwarfRegisterMap : RegisterMap { 99 virtual int32 CountRegisters() const 100 { 101 return kFromDwarfRegisterCount; 102 } 103 104 virtual int32 MapRegisterIndex(int32 index) const 105 { 106 return index >= 0 && index < kFromDwarfRegisterCount 107 ? kFromDwarfRegisters[index] : -1; 108 } 109}; 110 111 112// #pragma mark - ArchitectureX8664 113 114 115ArchitectureX8664::ArchitectureX8664(TeamMemory* teamMemory) 116 : 117 Architecture(teamMemory, 8, false), 118 fAssemblyLanguage(NULL), 119 fToDwarfRegisterMap(NULL), 120 fFromDwarfRegisterMap(NULL) 121{ 122} 123 124 125ArchitectureX8664::~ArchitectureX8664() 126{ 127 if (fToDwarfRegisterMap != NULL) 128 fToDwarfRegisterMap->ReleaseReference(); 129 if (fFromDwarfRegisterMap != NULL) 130 fFromDwarfRegisterMap->ReleaseReference(); 131 if (fAssemblyLanguage != NULL) 132 fAssemblyLanguage->ReleaseReference(); 133} 134 135 136status_t 137ArchitectureX8664::Init() 138{ 139 fAssemblyLanguage = new(std::nothrow) X86AssemblyLanguage; 140 if (fAssemblyLanguage == NULL) 141 return B_NO_MEMORY; 142 143 try { 144 _AddIntegerRegister(X86_64_REGISTER_RIP, "rip", B_UINT64_TYPE, 145 REGISTER_TYPE_INSTRUCTION_POINTER, false); 146 _AddIntegerRegister(X86_64_REGISTER_RSP, "rsp", B_UINT64_TYPE, 147 REGISTER_TYPE_STACK_POINTER, true); 148 _AddIntegerRegister(X86_64_REGISTER_RBP, "rbp", B_UINT64_TYPE, 149 REGISTER_TYPE_GENERAL_PURPOSE, true); 150 151 _AddIntegerRegister(X86_64_REGISTER_RAX, "rax", B_UINT64_TYPE, 152 REGISTER_TYPE_GENERAL_PURPOSE, false); 153 _AddIntegerRegister(X86_64_REGISTER_RBX, "rbx", B_UINT64_TYPE, 154 REGISTER_TYPE_GENERAL_PURPOSE, true); 155 _AddIntegerRegister(X86_64_REGISTER_RCX, "rcx", B_UINT64_TYPE, 156 REGISTER_TYPE_GENERAL_PURPOSE, false); 157 _AddIntegerRegister(X86_64_REGISTER_RDX, "rdx", B_UINT64_TYPE, 158 REGISTER_TYPE_GENERAL_PURPOSE, false); 159 160 _AddIntegerRegister(X86_64_REGISTER_RSI, "rsi", B_UINT64_TYPE, 161 REGISTER_TYPE_GENERAL_PURPOSE, false); 162 _AddIntegerRegister(X86_64_REGISTER_RDI, "rdi", B_UINT64_TYPE, 163 REGISTER_TYPE_GENERAL_PURPOSE, false); 164 165 _AddIntegerRegister(X86_64_REGISTER_R8, "r8", B_UINT64_TYPE, 166 REGISTER_TYPE_GENERAL_PURPOSE, false); 167 _AddIntegerRegister(X86_64_REGISTER_R9, "r9", B_UINT64_TYPE, 168 REGISTER_TYPE_GENERAL_PURPOSE, false); 169 _AddIntegerRegister(X86_64_REGISTER_R10, "r10", B_UINT64_TYPE, 170 REGISTER_TYPE_GENERAL_PURPOSE, false); 171 _AddIntegerRegister(X86_64_REGISTER_R11, "r11", B_UINT64_TYPE, 172 REGISTER_TYPE_GENERAL_PURPOSE, false); 173 _AddIntegerRegister(X86_64_REGISTER_R12, "r12", B_UINT64_TYPE, 174 REGISTER_TYPE_GENERAL_PURPOSE, true); 175 _AddIntegerRegister(X86_64_REGISTER_R13, "r13", B_UINT64_TYPE, 176 REGISTER_TYPE_GENERAL_PURPOSE, true); 177 _AddIntegerRegister(X86_64_REGISTER_R14, "r14", B_UINT64_TYPE, 178 REGISTER_TYPE_GENERAL_PURPOSE, true); 179 _AddIntegerRegister(X86_64_REGISTER_R15, "r15", B_UINT64_TYPE, 180 REGISTER_TYPE_GENERAL_PURPOSE, true); 181 182 _AddIntegerRegister(X86_64_REGISTER_CS, "cs", B_UINT16_TYPE, 183 REGISTER_TYPE_SPECIAL_PURPOSE, true); 184 _AddIntegerRegister(X86_64_REGISTER_DS, "ds", B_UINT16_TYPE, 185 REGISTER_TYPE_SPECIAL_PURPOSE, true); 186 _AddIntegerRegister(X86_64_REGISTER_ES, "es", B_UINT16_TYPE, 187 REGISTER_TYPE_SPECIAL_PURPOSE, true); 188 _AddIntegerRegister(X86_64_REGISTER_FS, "fs", B_UINT16_TYPE, 189 REGISTER_TYPE_SPECIAL_PURPOSE, true); 190 _AddIntegerRegister(X86_64_REGISTER_GS, "gs", B_UINT16_TYPE, 191 REGISTER_TYPE_SPECIAL_PURPOSE, true); 192 _AddIntegerRegister(X86_64_REGISTER_SS, "ss", B_UINT16_TYPE, 193 REGISTER_TYPE_SPECIAL_PURPOSE, true); 194 } catch (std::bad_alloc) { 195 return B_NO_MEMORY; 196 } 197 198 fToDwarfRegisterMap = new(std::nothrow) ToDwarfRegisterMap; 199 fFromDwarfRegisterMap = new(std::nothrow) FromDwarfRegisterMap; 200 201 if (fToDwarfRegisterMap == NULL || fFromDwarfRegisterMap == NULL) 202 return B_NO_MEMORY; 203 204 return B_OK; 205} 206 207 208int32 209ArchitectureX8664::StackGrowthDirection() const 210{ 211 return STACK_GROWTH_DIRECTION_NEGATIVE; 212} 213 214 215int32 216ArchitectureX8664::CountRegisters() const 217{ 218 return fRegisters.Count(); 219} 220 221 222const Register* 223ArchitectureX8664::Registers() const 224{ 225 return fRegisters.Elements(); 226} 227 228 229status_t 230ArchitectureX8664::InitRegisterRules(CfaContext& context) const 231{ 232 status_t error = Architecture::InitRegisterRules(context); 233 if (error != B_OK) 234 return error; 235 236 // set up rule for RIP register 237 context.RegisterRule(fToDwarfRegisterMap->MapRegisterIndex( 238 X86_64_REGISTER_RIP))->SetToLocationOffset(0); 239 240 return B_OK; 241} 242 243 244status_t 245ArchitectureX8664::GetDwarfRegisterMaps(RegisterMap** _toDwarf, 246 RegisterMap** _fromDwarf) const 247{ 248 if (_toDwarf != NULL) { 249 *_toDwarf = fToDwarfRegisterMap; 250 fToDwarfRegisterMap->AcquireReference(); 251 } 252 253 if (_fromDwarf != NULL) { 254 *_fromDwarf = fFromDwarfRegisterMap; 255 fFromDwarfRegisterMap->AcquireReference(); 256 } 257 258 return B_OK; 259} 260 261 262status_t 263ArchitectureX8664::CreateCpuState(CpuState*& _state) 264{ 265 CpuStateX8664* state = new(std::nothrow) CpuStateX8664; 266 if (state == NULL) 267 return B_NO_MEMORY; 268 269 _state = state; 270 return B_OK; 271} 272 273 274status_t 275ArchitectureX8664::CreateCpuState(const void* cpuStateData, size_t size, 276 CpuState*& _state) 277{ 278 if (size != sizeof(x86_64_debug_cpu_state)) 279 return B_BAD_VALUE; 280 281 CpuStateX8664* state = new(std::nothrow) CpuStateX8664( 282 *(const x86_64_debug_cpu_state*)cpuStateData); 283 if (state == NULL) 284 return B_NO_MEMORY; 285 286 _state = state; 287 return B_OK; 288} 289 290 291status_t 292ArchitectureX8664::CreateStackFrame(Image* image, FunctionDebugInfo* function, 293 CpuState* _cpuState, bool isTopFrame, StackFrame*& _frame, 294 CpuState*& _previousCpuState) 295{ 296 fprintf(stderr, "ArchitectureX8664::CreateStackFrame: TODO\n"); 297 return B_UNSUPPORTED; 298} 299 300 301void 302ArchitectureX8664::UpdateStackFrameCpuState(const StackFrame* frame, 303 Image* previousImage, FunctionDebugInfo* previousFunction, 304 CpuState* previousCpuState) 305{ 306 // This is not a top frame, so we want to offset rip to the previous 307 // (calling) instruction. 308 CpuStateX8664* cpuState = dynamic_cast<CpuStateX8664*>(previousCpuState); 309 310 // get rip 311 uint64 rip = cpuState->IntRegisterValue(X86_64_REGISTER_RIP); 312 if (previousFunction == NULL || rip <= previousFunction->Address()) 313 return; 314 target_addr_t functionAddress = previousFunction->Address(); 315 316 // allocate a buffer for the function code to disassemble 317 size_t bufferSize = rip - functionAddress; 318 void* buffer = malloc(bufferSize); 319 if (buffer == NULL) 320 return; 321 MemoryDeleter bufferDeleter(buffer); 322 323 // read the code 324 ssize_t bytesRead = fTeamMemory->ReadMemory(functionAddress, buffer, 325 bufferSize); 326 if (bytesRead != (ssize_t)bufferSize) 327 return; 328 329 // disassemble to get the previous instruction 330 DisassemblerX8664 disassembler; 331 target_addr_t instructionAddress; 332 target_size_t instructionSize; 333 if (disassembler.Init(functionAddress, buffer, bufferSize) == B_OK 334 && disassembler.GetPreviousInstruction(rip, instructionAddress, 335 instructionSize) == B_OK) { 336 rip -= instructionSize; 337 cpuState->SetIntRegister(X86_64_REGISTER_RIP, rip); 338 } 339} 340 341 342status_t 343ArchitectureX8664::ReadValueFromMemory(target_addr_t address, uint32 valueType, 344 BVariant& _value) const 345{ 346 uint8 buffer[64]; 347 size_t size = BVariant::SizeOfType(valueType); 348 if (size == 0 || size > sizeof(buffer)) 349 return B_BAD_VALUE; 350 351 ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, size); 352 if (bytesRead < 0) 353 return bytesRead; 354 if ((size_t)bytesRead != size) 355 return B_ERROR; 356 357 // TODO: We need to swap endianess, if the host is big endian! 358 359 switch (valueType) { 360 case B_INT8_TYPE: 361 _value.SetTo(*(int8*)buffer); 362 return B_OK; 363 case B_UINT8_TYPE: 364 _value.SetTo(*(uint8*)buffer); 365 return B_OK; 366 case B_INT16_TYPE: 367 _value.SetTo(*(int16*)buffer); 368 return B_OK; 369 case B_UINT16_TYPE: 370 _value.SetTo(*(uint16*)buffer); 371 return B_OK; 372 case B_INT32_TYPE: 373 _value.SetTo(*(int32*)buffer); 374 return B_OK; 375 case B_UINT32_TYPE: 376 _value.SetTo(*(uint32*)buffer); 377 return B_OK; 378 case B_INT64_TYPE: 379 _value.SetTo(*(int64*)buffer); 380 return B_OK; 381 case B_UINT64_TYPE: 382 _value.SetTo(*(uint64*)buffer); 383 return B_OK; 384 case B_FLOAT_TYPE: 385 _value.SetTo(*(float*)buffer); 386 // TODO: float on the host might work differently! 387 return B_OK; 388 case B_DOUBLE_TYPE: 389 _value.SetTo(*(double*)buffer); 390 // TODO: double on the host might work differently! 391 return B_OK; 392 default: 393 return B_BAD_VALUE; 394 } 395} 396 397 398status_t 399ArchitectureX8664::ReadValueFromMemory(target_addr_t addressSpace, 400 target_addr_t address, uint32 valueType, BVariant& _value) const 401{ 402 // n/a on this architecture 403 return B_BAD_VALUE; 404} 405 406 407status_t 408ArchitectureX8664::DisassembleCode(FunctionDebugInfo* function, 409 const void* buffer, size_t bufferSize, DisassembledCode*& _sourceCode) 410{ 411 DisassembledCode* source = new(std::nothrow) DisassembledCode( 412 fAssemblyLanguage); 413 if (source == NULL) 414 return B_NO_MEMORY; 415 BReference<DisassembledCode> sourceReference(source, true); 416 417 // init disassembler 418 DisassemblerX8664 disassembler; 419 status_t error = disassembler.Init(function->Address(), buffer, bufferSize); 420 if (error != B_OK) 421 return error; 422 423 // add a function name line 424 BString functionName(function->PrettyName()); 425 if (!source->AddCommentLine((functionName << ':').String())) 426 return B_NO_MEMORY; 427 428 // disassemble the instructions 429 BString line; 430 target_addr_t instructionAddress; 431 target_size_t instructionSize; 432 bool breakpointAllowed; 433 while (disassembler.GetNextInstruction(line, instructionAddress, 434 instructionSize, breakpointAllowed) == B_OK) { 435// TODO: Respect breakpointAllowed! 436 if (!source->AddInstructionLine(line, instructionAddress, 437 instructionSize)) { 438 return B_NO_MEMORY; 439 } 440 } 441 442 _sourceCode = sourceReference.Detach(); 443 return B_OK; 444} 445 446 447status_t 448ArchitectureX8664::GetStatement(FunctionDebugInfo* function, 449 target_addr_t address, Statement*& _statement) 450{ 451// TODO: This is not architecture dependent anymore! 452 // get the instruction info 453 InstructionInfo info; 454 status_t error = GetInstructionInfo(address, info, NULL); 455 if (error != B_OK) 456 return error; 457 458 // create a statement 459 ContiguousStatement* statement = new(std::nothrow) ContiguousStatement( 460 SourceLocation(-1), TargetAddressRange(info.Address(), info.Size())); 461 if (statement == NULL) 462 return B_NO_MEMORY; 463 464 _statement = statement; 465 return B_OK; 466} 467 468 469status_t 470ArchitectureX8664::GetInstructionInfo(target_addr_t address, 471 InstructionInfo& _info, CpuState* state) 472{ 473 // read the code - maximum x86{-64} instruction size = 15 bytes 474 uint8 buffer[16]; 475 ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, 476 sizeof(buffer)); 477 if (bytesRead < 0) 478 return bytesRead; 479 480 // init disassembler 481 DisassemblerX8664 disassembler; 482 status_t error = disassembler.Init(address, buffer, bytesRead); 483 if (error != B_OK) 484 return error; 485 486 return disassembler.GetNextInstructionInfo(_info, state); 487} 488 489 490status_t 491ArchitectureX8664::GetWatchpointDebugCapabilities(int32& _maxRegisterCount, 492 int32& _maxBytesPerRegister, uint8& _watchpointCapabilityFlags) 493{ 494 // Have 4 debug registers, 1 is required for breakpoint support, which 495 // leaves 3 available for watchpoints. 496 _maxRegisterCount = 3; 497 _maxBytesPerRegister = 8; 498 499 // x86 only supports write and read/write watchpoints. 500 _watchpointCapabilityFlags = WATCHPOINT_CAPABILITY_FLAG_WRITE 501 | WATCHPOINT_CAPABILITY_FLAG_READ_WRITE; 502 503 return B_OK; 504} 505 506 507status_t 508ArchitectureX8664::GetReturnAddressLocation(StackFrame* frame, 509 target_size_t valueSize, ValueLocation*& _location) { 510 return B_NOT_SUPPORTED; 511} 512 513 514void 515ArchitectureX8664::_AddRegister(int32 index, const char* name, 516 uint32 bitSize, uint32 valueType, register_type type, bool calleePreserved) 517{ 518 if (!fRegisters.Add(Register(index, name, bitSize, valueType, type, 519 calleePreserved))) { 520 throw std::bad_alloc(); 521 } 522} 523 524 525void 526ArchitectureX8664::_AddIntegerRegister(int32 index, const char* name, 527 uint32 valueType, register_type type, bool calleePreserved) 528{ 529 _AddRegister(index, name, 8 * BVariant::SizeOfType(valueType), valueType, 530 type, calleePreserved); 531} 532