1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | #include <cstdarg> |
6 | #include <cstdlib> |
7 | #include "sosplugin.h" |
8 | #include <string.h> |
9 | #include <string> |
10 | |
11 | #define CONVERT_FROM_SIGN_EXTENDED(offset) ((ULONG_PTR)(offset)) |
12 | |
13 | ULONG g_currentThreadIndex = -1; |
14 | ULONG g_currentThreadSystemId = -1; |
15 | char *g_coreclrDirectory; |
16 | |
17 | LLDBServices::LLDBServices(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject, lldb::SBProcess *process, lldb::SBThread *thread) : |
18 | m_ref(1), |
19 | m_debugger(debugger), |
20 | m_returnObject(returnObject), |
21 | m_currentProcess(process), |
22 | m_currentThread(thread) |
23 | { |
24 | returnObject.SetStatus(lldb::eReturnStatusSuccessFinishResult); |
25 | } |
26 | |
27 | LLDBServices::~LLDBServices() |
28 | { |
29 | } |
30 | |
31 | //---------------------------------------------------------------------------- |
32 | // IUnknown |
33 | //---------------------------------------------------------------------------- |
34 | |
35 | HRESULT |
36 | LLDBServices::QueryInterface( |
37 | REFIID InterfaceId, |
38 | PVOID* Interface |
39 | ) |
40 | { |
41 | if (InterfaceId == __uuidof(IUnknown) || |
42 | InterfaceId == __uuidof(ILLDBServices)) |
43 | { |
44 | *Interface = (ILLDBServices*)this; |
45 | AddRef(); |
46 | return S_OK; |
47 | } |
48 | else |
49 | { |
50 | *Interface = NULL; |
51 | return E_NOINTERFACE; |
52 | } |
53 | } |
54 | |
55 | ULONG |
56 | LLDBServices::AddRef() |
57 | { |
58 | LONG ref = InterlockedIncrement(&m_ref); |
59 | return ref; |
60 | } |
61 | |
62 | ULONG |
63 | LLDBServices::Release() |
64 | { |
65 | LONG ref = InterlockedDecrement(&m_ref); |
66 | if (ref == 0) |
67 | { |
68 | delete this; |
69 | } |
70 | return ref; |
71 | } |
72 | |
73 | //---------------------------------------------------------------------------- |
74 | // ILLDBServices |
75 | //---------------------------------------------------------------------------- |
76 | |
77 | PCSTR |
78 | LLDBServices::GetCoreClrDirectory() |
79 | { |
80 | return g_coreclrDirectory; |
81 | } |
82 | |
83 | DWORD_PTR |
84 | LLDBServices::GetExpression( |
85 | PCSTR exp) |
86 | { |
87 | if (exp == nullptr) |
88 | { |
89 | return 0; |
90 | } |
91 | |
92 | lldb::SBFrame frame = GetCurrentFrame(); |
93 | if (!frame.IsValid()) |
94 | { |
95 | return 0; |
96 | } |
97 | |
98 | DWORD_PTR result = 0; |
99 | lldb::SBError error; |
100 | std::string str; |
101 | |
102 | // To be compatible with windbg/dbgeng, we need to emulate the default |
103 | // hex radix (because sos prints addresses and other hex values without |
104 | // the 0x) by first prepending 0x and if that fails use the actual |
105 | // undecorated expression. |
106 | str.append("0x" ); |
107 | str.append(exp); |
108 | |
109 | result = GetExpression(frame, error, str.c_str()); |
110 | if (error.Fail()) |
111 | { |
112 | result = GetExpression(frame, error, exp); |
113 | } |
114 | |
115 | return result; |
116 | } |
117 | |
118 | // Internal function |
119 | DWORD_PTR |
120 | LLDBServices::GetExpression( |
121 | /* const */ lldb::SBFrame& frame, |
122 | lldb::SBError& error, |
123 | PCSTR exp) |
124 | { |
125 | DWORD_PTR result = 0; |
126 | |
127 | lldb::SBValue value = frame.EvaluateExpression(exp, lldb::eNoDynamicValues); |
128 | if (value.IsValid()) |
129 | { |
130 | result = value.GetValueAsUnsigned(error); |
131 | } |
132 | |
133 | return result; |
134 | } |
135 | |
136 | // |
137 | // lldb doesn't have a way or API to unwind an arbitrary context (IP, SP) |
138 | // and return the next frame so we have to stick with the native frames |
139 | // lldb has found and find the closest frame to the incoming context SP. |
140 | // |
141 | HRESULT |
142 | LLDBServices::VirtualUnwind( |
143 | DWORD threadID, |
144 | ULONG32 contextSize, |
145 | PBYTE context) |
146 | { |
147 | lldb::SBProcess process; |
148 | lldb::SBThread thread; |
149 | |
150 | if (context == NULL || contextSize < sizeof(DT_CONTEXT)) |
151 | { |
152 | return E_INVALIDARG; |
153 | } |
154 | |
155 | process = GetCurrentProcess(); |
156 | if (!process.IsValid()) |
157 | { |
158 | return E_FAIL; |
159 | } |
160 | |
161 | thread = process.GetThreadByID(threadID); |
162 | if (!thread.IsValid()) |
163 | { |
164 | return E_FAIL; |
165 | } |
166 | |
167 | DT_CONTEXT *dtcontext = (DT_CONTEXT*)context; |
168 | lldb::SBFrame frameFound; |
169 | |
170 | #ifdef DBG_TARGET_AMD64 |
171 | DWORD64 spToFind = dtcontext->Rsp; |
172 | #elif DBG_TARGET_X86 |
173 | DWORD spToFind = dtcontext->Esp; |
174 | #elif DBG_TARGET_ARM |
175 | DWORD spToFind = dtcontext->Sp; |
176 | #elif DBG_TARGET_ARM64 |
177 | DWORD64 spToFind = dtcontext->Sp; |
178 | #else |
179 | #error "spToFind undefined for this platform" |
180 | #endif |
181 | |
182 | int numFrames = thread.GetNumFrames(); |
183 | for (int i = 0; i < numFrames; i++) |
184 | { |
185 | lldb::SBFrame frame = thread.GetFrameAtIndex(i); |
186 | if (!frame.IsValid()) |
187 | { |
188 | break; |
189 | } |
190 | lldb::addr_t sp = frame.GetSP(); |
191 | |
192 | if ((i + 1) < numFrames) |
193 | { |
194 | lldb::SBFrame frameNext = thread.GetFrameAtIndex(i + 1); |
195 | if (frameNext.IsValid()) |
196 | { |
197 | lldb::addr_t spNext = frameNext.GetSP(); |
198 | |
199 | // An exact match of the current frame's SP would be nice |
200 | // but sometimes the incoming context is between lldb frames |
201 | if (spToFind >= sp && spToFind < spNext) |
202 | { |
203 | frameFound = frameNext; |
204 | break; |
205 | } |
206 | } |
207 | } |
208 | } |
209 | |
210 | if (!frameFound.IsValid()) |
211 | { |
212 | return E_FAIL; |
213 | } |
214 | |
215 | GetContextFromFrame(frameFound, dtcontext); |
216 | |
217 | return S_OK; |
218 | } |
219 | |
220 | bool |
221 | ExceptionBreakpointCallback( |
222 | void *baton, |
223 | lldb::SBProcess &process, |
224 | lldb::SBThread &thread, |
225 | lldb::SBBreakpointLocation &location) |
226 | { |
227 | lldb::SBDebugger debugger = process.GetTarget().GetDebugger(); |
228 | |
229 | // Send the normal and error output to stdout/stderr since we |
230 | // don't have a return object from the command interpreter. |
231 | lldb::SBCommandReturnObject result; |
232 | result.SetImmediateOutputFile(stdout); |
233 | result.SetImmediateErrorFile(stderr); |
234 | |
235 | // Save the process and thread to be used by the current process/thread |
236 | // helper functions. |
237 | LLDBServices* client = new LLDBServices(debugger, result, &process, &thread); |
238 | return ((PFN_EXCEPTION_CALLBACK)baton)(client) == S_OK; |
239 | } |
240 | |
241 | lldb::SBBreakpoint g_exceptionbp; |
242 | |
243 | HRESULT |
244 | LLDBServices::SetExceptionCallback( |
245 | PFN_EXCEPTION_CALLBACK callback) |
246 | { |
247 | if (!g_exceptionbp.IsValid()) |
248 | { |
249 | lldb::SBTarget target = m_debugger.GetSelectedTarget(); |
250 | if (!target.IsValid()) |
251 | { |
252 | return E_FAIL; |
253 | } |
254 | lldb::SBBreakpoint exceptionbp = target.BreakpointCreateForException(lldb::LanguageType::eLanguageTypeC_plus_plus, false, true); |
255 | if (!exceptionbp.IsValid()) |
256 | { |
257 | return E_FAIL; |
258 | } |
259 | #ifdef FLAGS_ANONYMOUS_ENUM |
260 | exceptionbp.AddName("DoNotDeleteOrDisable" ); |
261 | #endif |
262 | exceptionbp.SetCallback(ExceptionBreakpointCallback, (void *)callback); |
263 | g_exceptionbp = exceptionbp; |
264 | } |
265 | return S_OK; |
266 | } |
267 | |
268 | HRESULT |
269 | LLDBServices::ClearExceptionCallback() |
270 | { |
271 | if (g_exceptionbp.IsValid()) |
272 | { |
273 | lldb::SBTarget target = m_debugger.GetSelectedTarget(); |
274 | if (!target.IsValid()) |
275 | { |
276 | return E_FAIL; |
277 | } |
278 | target.BreakpointDelete(g_exceptionbp.GetID()); |
279 | g_exceptionbp = lldb::SBBreakpoint(); |
280 | } |
281 | return S_OK; |
282 | } |
283 | |
284 | //---------------------------------------------------------------------------- |
285 | // IDebugControl2 |
286 | //---------------------------------------------------------------------------- |
287 | |
288 | // Checks for a user interrupt, such a Ctrl-C |
289 | // or stop button. |
290 | // This method is reentrant. |
291 | HRESULT |
292 | LLDBServices::GetInterrupt() |
293 | { |
294 | return E_FAIL; |
295 | } |
296 | |
297 | // Sends output through clients |
298 | // output callbacks if the mask is allowed |
299 | // by the current output control mask and |
300 | // according to the output distribution |
301 | // settings. |
302 | HRESULT |
303 | LLDBServices::Output( |
304 | ULONG mask, |
305 | PCSTR format, |
306 | ...) |
307 | { |
308 | va_list args; |
309 | va_start (args, format); |
310 | HRESULT result = OutputVaList(mask, format, args); |
311 | va_end (args); |
312 | return result; |
313 | } |
314 | |
315 | HRESULT |
316 | LLDBServices::OutputVaList( |
317 | ULONG mask, |
318 | PCSTR format, |
319 | va_list args) |
320 | { |
321 | HRESULT result = S_OK; |
322 | char str[1024]; |
323 | |
324 | va_list args_copy; |
325 | va_copy (args_copy, args); |
326 | |
327 | // Try and format our string into a fixed buffer first and see if it fits |
328 | size_t length = ::vsnprintf(str, sizeof(str), format, args); |
329 | if (length < sizeof(str)) |
330 | { |
331 | OutputString(mask, str); |
332 | } |
333 | else |
334 | { |
335 | // Our stack buffer wasn't big enough to contain the entire formatted |
336 | // string, so lets let vasprintf create the string for us! |
337 | char *str_ptr = nullptr; |
338 | length = ::vasprintf(&str_ptr, format, args_copy); |
339 | if (str_ptr) |
340 | { |
341 | OutputString(mask, str_ptr); |
342 | ::free (str_ptr); |
343 | } |
344 | else |
345 | { |
346 | result = E_FAIL; |
347 | } |
348 | } |
349 | |
350 | va_end (args_copy); |
351 | |
352 | return result; |
353 | } |
354 | |
355 | // The following methods allow direct control |
356 | // over the distribution of the given output |
357 | // for situations where something other than |
358 | // the default is desired. These methods require |
359 | // extra work in the engine so they should |
360 | // only be used when necessary. |
361 | HRESULT |
362 | LLDBServices::ControlledOutput( |
363 | ULONG outputControl, |
364 | ULONG mask, |
365 | PCSTR format, |
366 | ...) |
367 | { |
368 | va_list args; |
369 | va_start (args, format); |
370 | HRESULT result = ControlledOutputVaList(outputControl, mask, format, args); |
371 | va_end (args); |
372 | return result; |
373 | } |
374 | |
375 | HRESULT |
376 | LLDBServices::ControlledOutputVaList( |
377 | ULONG outputControl, |
378 | ULONG mask, |
379 | PCSTR format, |
380 | va_list args) |
381 | { |
382 | return OutputVaList(mask, format, args); |
383 | } |
384 | |
385 | // Returns information about the debuggee such |
386 | // as user vs. kernel, dump vs. live, etc. |
387 | HRESULT |
388 | LLDBServices::GetDebuggeeType( |
389 | PULONG debugClass, |
390 | PULONG qualifier) |
391 | { |
392 | *debugClass = DEBUG_CLASS_USER_WINDOWS; |
393 | *qualifier = 0; |
394 | return S_OK; |
395 | } |
396 | |
397 | // Returns the page size for the currently executing |
398 | // processor context. The page size may vary between |
399 | // processor types. |
400 | HRESULT |
401 | LLDBServices::GetPageSize( |
402 | PULONG size) |
403 | { |
404 | *size = 4096; |
405 | return S_OK; |
406 | } |
407 | |
408 | HRESULT |
409 | LLDBServices::GetExecutingProcessorType( |
410 | PULONG type) |
411 | { |
412 | #ifdef DBG_TARGET_AMD64 |
413 | *type = IMAGE_FILE_MACHINE_AMD64; |
414 | #elif DBG_TARGET_ARM |
415 | *type = IMAGE_FILE_MACHINE_ARMNT; |
416 | #elif DBG_TARGET_ARM64 |
417 | *type = IMAGE_FILE_MACHINE_ARM64; |
418 | #elif DBG_TARGET_X86 |
419 | *type = IMAGE_FILE_MACHINE_I386; |
420 | #else |
421 | #error "Unsupported target" |
422 | #endif |
423 | return S_OK; |
424 | } |
425 | |
426 | HRESULT |
427 | LLDBServices::Execute( |
428 | ULONG outputControl, |
429 | PCSTR command, |
430 | ULONG flags) |
431 | { |
432 | lldb::SBCommandInterpreter interpreter = m_debugger.GetCommandInterpreter(); |
433 | |
434 | lldb::SBCommandReturnObject result; |
435 | lldb::ReturnStatus status = interpreter.HandleCommand(command, result); |
436 | |
437 | return status <= lldb::eReturnStatusSuccessContinuingResult ? S_OK : E_FAIL; |
438 | } |
439 | |
440 | // PAL raise exception function and exception record pointer variable name |
441 | // See coreclr\src\pal\src\exception\seh-unwind.cpp for the details. This |
442 | // function depends on RtlpRaisException not being inlined or optimized. |
443 | #define FUNCTION_NAME "RtlpRaiseException" |
444 | #define VARIABLE_NAME "ExceptionRecord" |
445 | |
446 | HRESULT |
447 | LLDBServices::GetLastEventInformation( |
448 | PULONG type, |
449 | PULONG processId, |
450 | PULONG threadId, |
451 | PVOID , |
452 | ULONG , |
453 | PULONG , |
454 | PSTR description, |
455 | ULONG descriptionSize, |
456 | PULONG descriptionUsed) |
457 | { |
458 | if (extraInformationSize < sizeof(DEBUG_LAST_EVENT_INFO_EXCEPTION) || |
459 | type == NULL || processId == NULL || threadId == NULL || extraInformationUsed == NULL) |
460 | { |
461 | return E_INVALIDARG; |
462 | } |
463 | |
464 | *type = DEBUG_EVENT_EXCEPTION; |
465 | *processId = 0; |
466 | *threadId = 0; |
467 | *extraInformationUsed = sizeof(DEBUG_LAST_EVENT_INFO_EXCEPTION); |
468 | |
469 | DEBUG_LAST_EVENT_INFO_EXCEPTION *pdle = (DEBUG_LAST_EVENT_INFO_EXCEPTION *)extraInformation; |
470 | pdle->FirstChance = 1; |
471 | |
472 | lldb::SBProcess process = GetCurrentProcess(); |
473 | if (!process.IsValid()) |
474 | { |
475 | return E_FAIL; |
476 | } |
477 | lldb::SBThread thread = GetCurrentThread(); |
478 | if (!thread.IsValid()) |
479 | { |
480 | return E_FAIL; |
481 | } |
482 | |
483 | *processId = process.GetProcessID(); |
484 | *threadId = thread.GetThreadID(); |
485 | |
486 | // Enumerate each stack frame at the special "throw" |
487 | // breakpoint and find the raise exception function |
488 | // with the exception record parameter. |
489 | int numFrames = thread.GetNumFrames(); |
490 | for (int i = 0; i < numFrames; i++) |
491 | { |
492 | lldb::SBFrame frame = thread.GetFrameAtIndex(i); |
493 | if (!frame.IsValid()) |
494 | { |
495 | break; |
496 | } |
497 | |
498 | const char *functionName = frame.GetFunctionName(); |
499 | if (functionName == NULL || strncmp(functionName, FUNCTION_NAME, sizeof(FUNCTION_NAME) - 1) != 0) |
500 | { |
501 | continue; |
502 | } |
503 | |
504 | lldb::SBValue exValue = frame.FindVariable(VARIABLE_NAME); |
505 | if (!exValue.IsValid()) |
506 | { |
507 | break; |
508 | } |
509 | |
510 | lldb::SBError error; |
511 | ULONG64 pExceptionRecord = exValue.GetValueAsUnsigned(error); |
512 | if (error.Fail()) |
513 | { |
514 | break; |
515 | } |
516 | |
517 | process.ReadMemory(pExceptionRecord, &pdle->ExceptionRecord, sizeof(pdle->ExceptionRecord), error); |
518 | if (error.Fail()) |
519 | { |
520 | break; |
521 | } |
522 | |
523 | return S_OK; |
524 | } |
525 | |
526 | return E_FAIL; |
527 | } |
528 | |
529 | HRESULT |
530 | LLDBServices::Disassemble( |
531 | ULONG64 offset, |
532 | ULONG flags, |
533 | PSTR buffer, |
534 | ULONG bufferSize, |
535 | PULONG disassemblySize, |
536 | PULONG64 endOffset) |
537 | { |
538 | lldb::SBInstruction instruction; |
539 | lldb::SBInstructionList list; |
540 | lldb::SBTarget target; |
541 | lldb::SBAddress address; |
542 | lldb::SBError error; |
543 | lldb::SBData data; |
544 | std::string str; |
545 | HRESULT hr = S_OK; |
546 | ULONG size = 0; |
547 | uint8_t byte; |
548 | int cch; |
549 | |
550 | // lldb doesn't expect sign-extended address |
551 | offset = CONVERT_FROM_SIGN_EXTENDED(offset); |
552 | |
553 | if (buffer == NULL) |
554 | { |
555 | hr = E_INVALIDARG; |
556 | goto exit; |
557 | } |
558 | *buffer = 0; |
559 | |
560 | target = m_debugger.GetSelectedTarget(); |
561 | if (!target.IsValid()) |
562 | { |
563 | hr = E_INVALIDARG; |
564 | goto exit; |
565 | } |
566 | address = target.ResolveLoadAddress(offset); |
567 | if (!address.IsValid()) |
568 | { |
569 | hr = E_INVALIDARG; |
570 | goto exit; |
571 | } |
572 | list = target.ReadInstructions(address, 1, "intel" ); |
573 | if (!list.IsValid()) |
574 | { |
575 | hr = E_FAIL; |
576 | goto exit; |
577 | } |
578 | instruction = list.GetInstructionAtIndex(0); |
579 | if (!instruction.IsValid()) |
580 | { |
581 | hr = E_FAIL; |
582 | goto exit; |
583 | } |
584 | cch = snprintf(buffer, bufferSize, "%016llx " , (unsigned long long)offset); |
585 | buffer += cch; |
586 | bufferSize -= cch; |
587 | |
588 | size = instruction.GetByteSize(); |
589 | data = instruction.GetData(target); |
590 | for (int i = 0; i < size && bufferSize > 0; i++) |
591 | { |
592 | byte = data.GetUnsignedInt8(error, i); |
593 | if (error.Fail()) |
594 | { |
595 | hr = E_FAIL; |
596 | goto exit; |
597 | } |
598 | cch = snprintf(buffer, bufferSize, "%02x" , byte); |
599 | buffer += cch; |
600 | bufferSize -= cch; |
601 | } |
602 | // Pad the data bytes to 16 chars |
603 | cch = size * 2; |
604 | while (bufferSize > 0) |
605 | { |
606 | *buffer++ = ' '; |
607 | bufferSize--; |
608 | if (++cch >= 21) |
609 | break; |
610 | } |
611 | |
612 | cch = snprintf(buffer, bufferSize, "%s" , instruction.GetMnemonic(target)); |
613 | buffer += cch; |
614 | bufferSize -= cch; |
615 | |
616 | // Pad the mnemonic to 8 chars |
617 | while (bufferSize > 0) |
618 | { |
619 | *buffer++ = ' '; |
620 | bufferSize--; |
621 | if (++cch >= 8) |
622 | break; |
623 | } |
624 | snprintf(buffer, bufferSize, "%s\n" , instruction.GetOperands(target)); |
625 | |
626 | exit: |
627 | if (disassemblySize != NULL) |
628 | { |
629 | *disassemblySize = size; |
630 | } |
631 | if (endOffset != NULL) |
632 | { |
633 | *endOffset = offset + size; |
634 | } |
635 | return hr; |
636 | } |
637 | |
638 | // Internal output string function |
639 | void |
640 | LLDBServices::OutputString( |
641 | ULONG mask, |
642 | PCSTR str) |
643 | { |
644 | if (mask == DEBUG_OUTPUT_ERROR) |
645 | { |
646 | m_returnObject.SetStatus(lldb::eReturnStatusFailed); |
647 | } |
648 | // Can not use AppendMessage or AppendWarning because they add a newline. SetError |
649 | // can not be used for DEBUG_OUTPUT_ERROR mask because it caches the error strings |
650 | // seperately from the normal output so error/normal texts are not intermixed |
651 | // correctly. |
652 | m_returnObject.Printf("%s" , str); |
653 | } |
654 | |
655 | //---------------------------------------------------------------------------- |
656 | // IDebugControl4 |
657 | //---------------------------------------------------------------------------- |
658 | |
659 | HRESULT |
660 | LLDBServices::GetContextStackTrace( |
661 | PVOID startContext, |
662 | ULONG startContextSize, |
663 | PDEBUG_STACK_FRAME frames, |
664 | ULONG framesSize, |
665 | PVOID frameContexts, |
666 | ULONG frameContextsSize, |
667 | ULONG frameContextsEntrySize, |
668 | PULONG framesFilled) |
669 | { |
670 | DT_CONTEXT *currentContext = (DT_CONTEXT*)frameContexts; |
671 | PDEBUG_STACK_FRAME currentFrame = frames; |
672 | lldb::SBThread thread; |
673 | lldb::SBFrame frame; |
674 | ULONG cFrames = 0; |
675 | HRESULT hr = S_OK; |
676 | |
677 | // Doesn't support a starting context |
678 | if (startContext != NULL || frames == NULL || frameContexts == NULL || frameContextsEntrySize != sizeof(DT_CONTEXT)) |
679 | { |
680 | hr = E_INVALIDARG; |
681 | goto exit; |
682 | } |
683 | |
684 | thread = GetCurrentThread(); |
685 | if (!thread.IsValid()) |
686 | { |
687 | hr = E_FAIL; |
688 | goto exit; |
689 | } |
690 | |
691 | frame = thread.GetFrameAtIndex(0); |
692 | for (int i = 0; i < thread.GetNumFrames(); i++) |
693 | { |
694 | if (!frame.IsValid() || (cFrames > framesSize) || ((char *)currentContext > ((char *)frameContexts + frameContextsSize))) |
695 | { |
696 | break; |
697 | } |
698 | lldb::SBFrame framePrevious; |
699 | lldb::SBFrame frameNext; |
700 | |
701 | currentFrame->InstructionOffset = frame.GetPC(); |
702 | currentFrame->StackOffset = frame.GetSP(); |
703 | |
704 | currentFrame->FuncTableEntry = 0; |
705 | currentFrame->Params[0] = 0; |
706 | currentFrame->Params[1] = 0; |
707 | currentFrame->Params[2] = 0; |
708 | currentFrame->Params[3] = 0; |
709 | currentFrame->Virtual = i == 0 ? TRUE : FALSE; |
710 | currentFrame->FrameNumber = frame.GetFrameID(); |
711 | |
712 | frameNext = thread.GetFrameAtIndex(i + 1); |
713 | if (frameNext.IsValid()) |
714 | { |
715 | currentFrame->ReturnOffset = frameNext.GetPC(); |
716 | } |
717 | |
718 | if (framePrevious.IsValid()) |
719 | { |
720 | currentFrame->FrameOffset = framePrevious.GetSP(); |
721 | } |
722 | else |
723 | { |
724 | currentFrame->FrameOffset = frame.GetSP(); |
725 | } |
726 | |
727 | GetContextFromFrame(frame, currentContext); |
728 | |
729 | framePrevious = frame; |
730 | frame = frameNext; |
731 | currentContext++; |
732 | currentFrame++; |
733 | cFrames++; |
734 | } |
735 | |
736 | exit: |
737 | if (framesFilled != NULL) |
738 | { |
739 | *framesFilled = cFrames; |
740 | } |
741 | return hr; |
742 | } |
743 | |
744 | //---------------------------------------------------------------------------- |
745 | // IDebugDataSpaces |
746 | //---------------------------------------------------------------------------- |
747 | |
748 | HRESULT |
749 | LLDBServices::ReadVirtual( |
750 | ULONG64 offset, |
751 | PVOID buffer, |
752 | ULONG bufferSize, |
753 | PULONG bytesRead) |
754 | { |
755 | lldb::SBError error; |
756 | size_t read = 0; |
757 | |
758 | // lldb doesn't expect sign-extended address |
759 | offset = CONVERT_FROM_SIGN_EXTENDED(offset); |
760 | |
761 | lldb::SBProcess process = GetCurrentProcess(); |
762 | if (!process.IsValid()) |
763 | { |
764 | goto exit; |
765 | } |
766 | |
767 | read = process.ReadMemory(offset, buffer, bufferSize, error); |
768 | |
769 | exit: |
770 | if (bytesRead) |
771 | { |
772 | *bytesRead = read; |
773 | } |
774 | return error.Success() || (read != 0) ? S_OK : E_FAIL; |
775 | } |
776 | |
777 | HRESULT |
778 | LLDBServices::WriteVirtual( |
779 | ULONG64 offset, |
780 | PVOID buffer, |
781 | ULONG bufferSize, |
782 | PULONG bytesWritten) |
783 | { |
784 | lldb::SBError error; |
785 | size_t written = 0; |
786 | |
787 | // lldb doesn't expect sign-extended address |
788 | offset = CONVERT_FROM_SIGN_EXTENDED(offset); |
789 | |
790 | lldb::SBProcess process = GetCurrentProcess(); |
791 | if (!process.IsValid()) |
792 | { |
793 | goto exit; |
794 | } |
795 | |
796 | written = process.WriteMemory(offset, buffer, bufferSize, error); |
797 | |
798 | exit: |
799 | if (bytesWritten) |
800 | { |
801 | *bytesWritten = written; |
802 | } |
803 | return error.Success() || (written != 0) ? S_OK : E_FAIL; |
804 | } |
805 | |
806 | //---------------------------------------------------------------------------- |
807 | // IDebugSymbols |
808 | //---------------------------------------------------------------------------- |
809 | |
810 | HRESULT |
811 | LLDBServices::GetSymbolOptions( |
812 | PULONG options) |
813 | { |
814 | *options = SYMOPT_LOAD_LINES; |
815 | return S_OK; |
816 | } |
817 | |
818 | HRESULT |
819 | LLDBServices::GetNameByOffset( |
820 | ULONG64 offset, |
821 | PSTR nameBuffer, |
822 | ULONG nameBufferSize, |
823 | PULONG nameSize, |
824 | PULONG64 displacement) |
825 | { |
826 | ULONG64 disp = DEBUG_INVALID_OFFSET; |
827 | HRESULT hr = S_OK; |
828 | |
829 | lldb::SBTarget target; |
830 | lldb::SBAddress address; |
831 | lldb::SBModule module; |
832 | lldb::SBFileSpec file; |
833 | lldb::SBSymbol symbol; |
834 | std::string str; |
835 | |
836 | // lldb doesn't expect sign-extended address |
837 | offset = CONVERT_FROM_SIGN_EXTENDED(offset); |
838 | |
839 | target = m_debugger.GetSelectedTarget(); |
840 | if (!target.IsValid()) |
841 | { |
842 | hr = E_FAIL; |
843 | goto exit; |
844 | } |
845 | |
846 | address = target.ResolveLoadAddress(offset); |
847 | if (!address.IsValid()) |
848 | { |
849 | hr = E_INVALIDARG; |
850 | goto exit; |
851 | } |
852 | |
853 | module = address.GetModule(); |
854 | if (!module.IsValid()) |
855 | { |
856 | hr = E_FAIL; |
857 | goto exit; |
858 | } |
859 | |
860 | file = module.GetFileSpec(); |
861 | if (file.IsValid()) |
862 | { |
863 | str.append(file.GetFilename()); |
864 | } |
865 | |
866 | symbol = address.GetSymbol(); |
867 | if (symbol.IsValid()) |
868 | { |
869 | lldb::SBAddress startAddress = symbol.GetStartAddress(); |
870 | disp = address.GetOffset() - startAddress.GetOffset(); |
871 | |
872 | const char *name = symbol.GetName(); |
873 | if (name) |
874 | { |
875 | if (file.IsValid()) |
876 | { |
877 | str.append("!" ); |
878 | } |
879 | str.append(name); |
880 | } |
881 | } |
882 | |
883 | str.append(1, '\0'); |
884 | |
885 | exit: |
886 | if (nameSize) |
887 | { |
888 | *nameSize = str.length(); |
889 | } |
890 | if (nameBuffer) |
891 | { |
892 | str.copy(nameBuffer, nameBufferSize); |
893 | } |
894 | if (displacement) |
895 | { |
896 | *displacement = disp; |
897 | } |
898 | return hr; |
899 | } |
900 | |
901 | HRESULT |
902 | LLDBServices::GetNumberModules( |
903 | PULONG loaded, |
904 | PULONG unloaded) |
905 | { |
906 | ULONG numModules = 0; |
907 | HRESULT hr = S_OK; |
908 | |
909 | lldb::SBTarget target = m_debugger.GetSelectedTarget(); |
910 | if (!target.IsValid()) |
911 | { |
912 | hr = E_FAIL; |
913 | goto exit; |
914 | } |
915 | |
916 | numModules = target.GetNumModules(); |
917 | |
918 | exit: |
919 | if (loaded) |
920 | { |
921 | *loaded = numModules; |
922 | } |
923 | if (unloaded) |
924 | { |
925 | *unloaded = 0; |
926 | } |
927 | return hr; |
928 | } |
929 | |
930 | HRESULT LLDBServices::GetModuleByIndex( |
931 | ULONG index, |
932 | PULONG64 base) |
933 | { |
934 | ULONG64 moduleBase = UINT64_MAX; |
935 | |
936 | lldb::SBTarget target; |
937 | lldb::SBModule module; |
938 | |
939 | target = m_debugger.GetSelectedTarget(); |
940 | if (!target.IsValid()) |
941 | { |
942 | goto exit; |
943 | } |
944 | |
945 | module = target.GetModuleAtIndex(index); |
946 | if (!module.IsValid()) |
947 | { |
948 | goto exit; |
949 | } |
950 | |
951 | moduleBase = GetModuleBase(target, module); |
952 | |
953 | exit: |
954 | if (base) |
955 | { |
956 | *base = moduleBase; |
957 | } |
958 | return moduleBase == UINT64_MAX ? E_FAIL : S_OK; |
959 | } |
960 | |
961 | HRESULT |
962 | LLDBServices::GetModuleByModuleName( |
963 | PCSTR name, |
964 | ULONG startIndex, |
965 | PULONG index, |
966 | PULONG64 base) |
967 | { |
968 | ULONG64 moduleBase = UINT64_MAX; |
969 | ULONG moduleIndex = UINT32_MAX; |
970 | |
971 | lldb::SBTarget target; |
972 | lldb::SBModule module; |
973 | lldb::SBFileSpec fileSpec; |
974 | fileSpec.SetFilename(name); |
975 | |
976 | target = m_debugger.GetSelectedTarget(); |
977 | if (!target.IsValid()) |
978 | { |
979 | goto exit; |
980 | } |
981 | |
982 | module = target.FindModule(fileSpec); |
983 | if (!module.IsValid()) |
984 | { |
985 | goto exit; |
986 | } |
987 | |
988 | moduleBase = GetModuleBase(target, module); |
989 | |
990 | if (index) |
991 | { |
992 | int numModules = target.GetNumModules(); |
993 | for (int mi = startIndex; mi < numModules; mi++) |
994 | { |
995 | lldb::SBModule mod = target.GetModuleAtIndex(mi); |
996 | if (module == mod) |
997 | { |
998 | moduleIndex = mi; |
999 | break; |
1000 | } |
1001 | } |
1002 | } |
1003 | |
1004 | exit: |
1005 | if (index) |
1006 | { |
1007 | *index = moduleIndex; |
1008 | } |
1009 | if (base) |
1010 | { |
1011 | *base = moduleBase; |
1012 | } |
1013 | return moduleBase == UINT64_MAX ? E_FAIL : S_OK; |
1014 | } |
1015 | |
1016 | HRESULT |
1017 | LLDBServices::GetModuleByOffset( |
1018 | ULONG64 offset, |
1019 | ULONG startIndex, |
1020 | PULONG index, |
1021 | PULONG64 base) |
1022 | { |
1023 | ULONG64 moduleBase = UINT64_MAX; |
1024 | ULONG moduleIndex = UINT32_MAX; |
1025 | |
1026 | lldb::SBTarget target; |
1027 | int numModules; |
1028 | |
1029 | // lldb doesn't expect sign-extended address |
1030 | offset = CONVERT_FROM_SIGN_EXTENDED(offset); |
1031 | |
1032 | target = m_debugger.GetSelectedTarget(); |
1033 | if (!target.IsValid()) |
1034 | { |
1035 | goto exit; |
1036 | } |
1037 | |
1038 | numModules = target.GetNumModules(); |
1039 | for (int mi = startIndex; mi < numModules; mi++) |
1040 | { |
1041 | lldb::SBModule module = target.GetModuleAtIndex(mi); |
1042 | |
1043 | int numSections = module.GetNumSections(); |
1044 | for (int si = 0; si < numSections; si++) |
1045 | { |
1046 | lldb::SBSection section = module.GetSectionAtIndex(si); |
1047 | if (section.IsValid()) |
1048 | { |
1049 | lldb::addr_t baseAddress = section.GetLoadAddress(target); |
1050 | if (baseAddress != LLDB_INVALID_ADDRESS) |
1051 | { |
1052 | if (offset > baseAddress) |
1053 | { |
1054 | if ((offset - baseAddress) < section.GetByteSize()) |
1055 | { |
1056 | moduleIndex = mi; |
1057 | moduleBase = baseAddress - section.GetFileOffset(); |
1058 | goto exit; |
1059 | } |
1060 | } |
1061 | } |
1062 | } |
1063 | } |
1064 | } |
1065 | |
1066 | exit: |
1067 | if (index) |
1068 | { |
1069 | *index = moduleIndex; |
1070 | } |
1071 | if (base) |
1072 | { |
1073 | *base = moduleBase; |
1074 | } |
1075 | return moduleBase == UINT64_MAX ? E_FAIL : S_OK; |
1076 | } |
1077 | |
1078 | HRESULT |
1079 | LLDBServices::GetModuleNames( |
1080 | ULONG index, |
1081 | ULONG64 base, |
1082 | PSTR imageNameBuffer, |
1083 | ULONG imageNameBufferSize, |
1084 | PULONG imageNameSize, |
1085 | PSTR moduleNameBuffer, |
1086 | ULONG moduleNameBufferSize, |
1087 | PULONG moduleNameSize, |
1088 | PSTR loadedImageNameBuffer, |
1089 | ULONG loadedImageNameBufferSize, |
1090 | PULONG loadedImageNameSize) |
1091 | { |
1092 | lldb::SBTarget target; |
1093 | lldb::SBFileSpec fileSpec; |
1094 | HRESULT hr = S_OK; |
1095 | |
1096 | // lldb doesn't expect sign-extended address |
1097 | base = CONVERT_FROM_SIGN_EXTENDED(base); |
1098 | |
1099 | target = m_debugger.GetSelectedTarget(); |
1100 | if (!target.IsValid()) |
1101 | { |
1102 | hr = E_FAIL; |
1103 | goto exit; |
1104 | } |
1105 | |
1106 | if (index != DEBUG_ANY_ID) |
1107 | { |
1108 | lldb::SBModule module = target.GetModuleAtIndex(index); |
1109 | if (module.IsValid()) |
1110 | { |
1111 | fileSpec = module.GetFileSpec(); |
1112 | } |
1113 | } |
1114 | else |
1115 | { |
1116 | int numModules = target.GetNumModules(); |
1117 | for (int mi = 0; mi < numModules; mi++) |
1118 | { |
1119 | lldb::SBModule module = target.GetModuleAtIndex(mi); |
1120 | if (module.IsValid()) |
1121 | { |
1122 | ULONG64 moduleBase = GetModuleBase(target, module); |
1123 | if (base == moduleBase) |
1124 | { |
1125 | fileSpec = module.GetFileSpec(); |
1126 | break; |
1127 | } |
1128 | } |
1129 | } |
1130 | } |
1131 | |
1132 | if (!fileSpec.IsValid()) |
1133 | { |
1134 | hr = E_FAIL; |
1135 | goto exit; |
1136 | } |
1137 | |
1138 | exit: |
1139 | if (imageNameBuffer) |
1140 | { |
1141 | int size = fileSpec.GetPath(imageNameBuffer, imageNameBufferSize); |
1142 | if (imageNameSize) |
1143 | { |
1144 | *imageNameSize = size; |
1145 | } |
1146 | } |
1147 | if (moduleNameBuffer) |
1148 | { |
1149 | const char *fileName = fileSpec.GetFilename(); |
1150 | if (fileName == NULL) |
1151 | { |
1152 | fileName = "" ; |
1153 | } |
1154 | stpncpy(moduleNameBuffer, fileName, moduleNameBufferSize); |
1155 | if (moduleNameSize) |
1156 | { |
1157 | *moduleNameSize = strlen(fileName); |
1158 | } |
1159 | } |
1160 | if (loadedImageNameBuffer) |
1161 | { |
1162 | int size = fileSpec.GetPath(loadedImageNameBuffer, loadedImageNameBufferSize); |
1163 | if (loadedImageNameSize) |
1164 | { |
1165 | *loadedImageNameSize = size; |
1166 | } |
1167 | } |
1168 | return hr; |
1169 | } |
1170 | |
1171 | HRESULT |
1172 | LLDBServices::GetLineByOffset( |
1173 | ULONG64 offset, |
1174 | PULONG fileLine, |
1175 | PSTR fileBuffer, |
1176 | ULONG fileBufferSize, |
1177 | PULONG fileSize, |
1178 | PULONG64 displacement) |
1179 | { |
1180 | ULONG64 disp = DEBUG_INVALID_OFFSET; |
1181 | HRESULT hr = S_OK; |
1182 | ULONG line = 0; |
1183 | |
1184 | lldb::SBTarget target; |
1185 | lldb::SBAddress address; |
1186 | lldb::SBFileSpec file; |
1187 | lldb::SBLineEntry lineEntry; |
1188 | std::string str; |
1189 | |
1190 | // lldb doesn't expect sign-extended address |
1191 | offset = CONVERT_FROM_SIGN_EXTENDED(offset); |
1192 | |
1193 | target = m_debugger.GetSelectedTarget(); |
1194 | if (!target.IsValid()) |
1195 | { |
1196 | hr = E_FAIL; |
1197 | goto exit; |
1198 | } |
1199 | |
1200 | address = target.ResolveLoadAddress(offset); |
1201 | if (!address.IsValid()) |
1202 | { |
1203 | hr = E_INVALIDARG; |
1204 | goto exit; |
1205 | } |
1206 | |
1207 | if (displacement) |
1208 | { |
1209 | lldb::SBSymbol symbol = address.GetSymbol(); |
1210 | if (symbol.IsValid()) |
1211 | { |
1212 | lldb::SBAddress startAddress = symbol.GetStartAddress(); |
1213 | disp = address.GetOffset() - startAddress.GetOffset(); |
1214 | } |
1215 | } |
1216 | |
1217 | lineEntry = address.GetLineEntry(); |
1218 | if (!lineEntry.IsValid()) |
1219 | { |
1220 | hr = E_FAIL; |
1221 | goto exit; |
1222 | } |
1223 | |
1224 | line = lineEntry.GetLine(); |
1225 | file = lineEntry.GetFileSpec(); |
1226 | if (file.IsValid()) |
1227 | { |
1228 | str.append(file.GetDirectory()); |
1229 | str.append(1, '/'); |
1230 | str.append(file.GetFilename()); |
1231 | } |
1232 | |
1233 | str.append(1, '\0'); |
1234 | |
1235 | exit: |
1236 | if (fileLine) |
1237 | { |
1238 | *fileLine = line; |
1239 | } |
1240 | if (fileSize) |
1241 | { |
1242 | *fileSize = str.length(); |
1243 | } |
1244 | if (fileBuffer) |
1245 | { |
1246 | str.copy(fileBuffer, fileBufferSize); |
1247 | } |
1248 | if (displacement) |
1249 | { |
1250 | *displacement = disp; |
1251 | } |
1252 | return hr; |
1253 | } |
1254 | |
1255 | HRESULT |
1256 | LLDBServices::GetSourceFileLineOffsets( |
1257 | PCSTR file, |
1258 | PULONG64 buffer, |
1259 | ULONG bufferLines, |
1260 | PULONG fileLines) |
1261 | { |
1262 | if (fileLines != NULL) |
1263 | { |
1264 | *fileLines = (ULONG)-1; |
1265 | } |
1266 | return E_NOTIMPL; |
1267 | } |
1268 | |
1269 | HRESULT |
1270 | LLDBServices::FindSourceFile( |
1271 | ULONG startElement, |
1272 | PCSTR file, |
1273 | ULONG flags, |
1274 | PULONG foundElement, |
1275 | PSTR buffer, |
1276 | ULONG bufferSize, |
1277 | PULONG foundSize) |
1278 | { |
1279 | return E_NOTIMPL; |
1280 | } |
1281 | |
1282 | // Internal functions |
1283 | PCSTR |
1284 | LLDBServices::GetModuleDirectory( |
1285 | PCSTR name) |
1286 | { |
1287 | lldb::SBTarget target = m_debugger.GetSelectedTarget(); |
1288 | if (!target.IsValid()) |
1289 | { |
1290 | return NULL; |
1291 | } |
1292 | |
1293 | lldb::SBFileSpec fileSpec; |
1294 | fileSpec.SetFilename(name); |
1295 | |
1296 | lldb::SBModule module = target.FindModule(fileSpec); |
1297 | if (!module.IsValid()) |
1298 | { |
1299 | return NULL; |
1300 | } |
1301 | |
1302 | return module.GetFileSpec().GetDirectory(); |
1303 | } |
1304 | |
1305 | ULONG64 |
1306 | LLDBServices::GetModuleBase( |
1307 | /* const */ lldb::SBTarget& target, |
1308 | /* const */ lldb::SBModule& module) |
1309 | { |
1310 | // Find the first section with an valid base address |
1311 | int numSections = module.GetNumSections(); |
1312 | for (int si = 0; si < numSections; si++) |
1313 | { |
1314 | lldb::SBSection section = module.GetSectionAtIndex(si); |
1315 | if (section.IsValid()) |
1316 | { |
1317 | lldb::addr_t baseAddress = section.GetLoadAddress(target); |
1318 | if (baseAddress != LLDB_INVALID_ADDRESS) |
1319 | { |
1320 | return baseAddress - section.GetFileOffset(); |
1321 | } |
1322 | } |
1323 | } |
1324 | |
1325 | return UINT64_MAX; |
1326 | } |
1327 | |
1328 | //---------------------------------------------------------------------------- |
1329 | // IDebugSystemObjects |
1330 | //---------------------------------------------------------------------------- |
1331 | |
1332 | HRESULT |
1333 | LLDBServices::GetCurrentProcessId( |
1334 | PULONG id) |
1335 | { |
1336 | if (id == NULL) |
1337 | { |
1338 | return E_INVALIDARG; |
1339 | } |
1340 | |
1341 | lldb::SBProcess process = GetCurrentProcess(); |
1342 | if (!process.IsValid()) |
1343 | { |
1344 | *id = 0; |
1345 | return E_FAIL; |
1346 | } |
1347 | |
1348 | *id = process.GetProcessID(); |
1349 | return S_OK; |
1350 | } |
1351 | |
1352 | HRESULT |
1353 | LLDBServices::GetCurrentThreadId( |
1354 | PULONG id) |
1355 | { |
1356 | if (id == NULL) |
1357 | { |
1358 | return E_INVALIDARG; |
1359 | } |
1360 | |
1361 | lldb::SBThread thread = GetCurrentThread(); |
1362 | if (!thread.IsValid()) |
1363 | { |
1364 | *id = 0; |
1365 | return E_FAIL; |
1366 | } |
1367 | |
1368 | // This is allow the a valid current TID to be returned to |
1369 | // workaround a bug in lldb on core dumps. |
1370 | if (g_currentThreadIndex != -1) |
1371 | { |
1372 | *id = g_currentThreadIndex; |
1373 | return S_OK; |
1374 | } |
1375 | |
1376 | *id = thread.GetIndexID(); |
1377 | return S_OK; |
1378 | } |
1379 | |
1380 | HRESULT |
1381 | LLDBServices::SetCurrentThreadId( |
1382 | ULONG id) |
1383 | { |
1384 | lldb::SBProcess process = GetCurrentProcess(); |
1385 | if (!process.IsValid()) |
1386 | { |
1387 | return E_FAIL; |
1388 | } |
1389 | |
1390 | if (!process.SetSelectedThreadByIndexID(id)) |
1391 | { |
1392 | return E_FAIL; |
1393 | } |
1394 | |
1395 | return S_OK; |
1396 | } |
1397 | |
1398 | HRESULT |
1399 | LLDBServices::GetCurrentThreadSystemId( |
1400 | PULONG sysId) |
1401 | { |
1402 | if (sysId == NULL) |
1403 | { |
1404 | return E_INVALIDARG; |
1405 | } |
1406 | |
1407 | lldb::SBThread thread = GetCurrentThread(); |
1408 | if (!thread.IsValid()) |
1409 | { |
1410 | *sysId = 0; |
1411 | return E_FAIL; |
1412 | } |
1413 | |
1414 | // This is allow the a valid current TID to be returned to |
1415 | // workaround a bug in lldb on core dumps. |
1416 | if (g_currentThreadSystemId != -1) |
1417 | { |
1418 | *sysId = g_currentThreadSystemId; |
1419 | return S_OK; |
1420 | } |
1421 | |
1422 | *sysId = thread.GetThreadID(); |
1423 | return S_OK; |
1424 | } |
1425 | |
1426 | HRESULT |
1427 | LLDBServices::GetThreadIdBySystemId( |
1428 | ULONG sysId, |
1429 | PULONG threadId) |
1430 | { |
1431 | HRESULT hr = E_FAIL; |
1432 | ULONG id = 0; |
1433 | |
1434 | lldb::SBProcess process; |
1435 | lldb::SBThread thread; |
1436 | |
1437 | if (threadId == NULL) |
1438 | { |
1439 | return E_INVALIDARG; |
1440 | } |
1441 | |
1442 | process = GetCurrentProcess(); |
1443 | if (!process.IsValid()) |
1444 | { |
1445 | goto exit; |
1446 | } |
1447 | |
1448 | // If we have a "fake" thread OS (system) id and a fake thread index, |
1449 | // we need to return fake thread index. |
1450 | if (g_currentThreadSystemId == sysId && g_currentThreadIndex != -1) |
1451 | { |
1452 | id = g_currentThreadIndex; |
1453 | } |
1454 | else |
1455 | { |
1456 | thread = process.GetThreadByID(sysId); |
1457 | if (!thread.IsValid()) |
1458 | { |
1459 | goto exit; |
1460 | } |
1461 | |
1462 | id = thread.GetIndexID(); |
1463 | } |
1464 | hr = S_OK; |
1465 | |
1466 | exit: |
1467 | *threadId = id; |
1468 | return hr; |
1469 | } |
1470 | |
1471 | HRESULT |
1472 | LLDBServices::GetThreadContextById( |
1473 | /* in */ ULONG32 threadID, |
1474 | /* in */ ULONG32 contextFlags, |
1475 | /* in */ ULONG32 contextSize, |
1476 | /* out */ PBYTE context) |
1477 | { |
1478 | lldb::SBProcess process; |
1479 | lldb::SBThread thread; |
1480 | lldb::SBFrame frame; |
1481 | DT_CONTEXT *dtcontext; |
1482 | HRESULT hr = E_FAIL; |
1483 | |
1484 | if (context == NULL || contextSize < sizeof(DT_CONTEXT)) |
1485 | { |
1486 | goto exit; |
1487 | } |
1488 | memset(context, 0, contextSize); |
1489 | |
1490 | process = GetCurrentProcess(); |
1491 | if (!process.IsValid()) |
1492 | { |
1493 | goto exit; |
1494 | } |
1495 | |
1496 | // If we have a "fake" thread OS (system) id and a fake thread index, |
1497 | // use the fake thread index to get the context. |
1498 | if (g_currentThreadSystemId == threadID && g_currentThreadIndex != -1) |
1499 | { |
1500 | thread = process.GetThreadByIndexID(g_currentThreadIndex); |
1501 | } |
1502 | else |
1503 | { |
1504 | thread = process.GetThreadByID(threadID); |
1505 | } |
1506 | |
1507 | if (!thread.IsValid()) |
1508 | { |
1509 | goto exit; |
1510 | } |
1511 | |
1512 | frame = thread.GetFrameAtIndex(0); |
1513 | if (!frame.IsValid()) |
1514 | { |
1515 | goto exit; |
1516 | } |
1517 | |
1518 | dtcontext = (DT_CONTEXT*)context; |
1519 | dtcontext->ContextFlags = contextFlags; |
1520 | |
1521 | GetContextFromFrame(frame, dtcontext); |
1522 | hr = S_OK; |
1523 | |
1524 | exit: |
1525 | return hr; |
1526 | } |
1527 | |
1528 | // Internal function |
1529 | void |
1530 | LLDBServices::GetContextFromFrame( |
1531 | /* const */ lldb::SBFrame& frame, |
1532 | DT_CONTEXT *dtcontext) |
1533 | { |
1534 | #ifdef DBG_TARGET_AMD64 |
1535 | dtcontext->Rip = frame.GetPC(); |
1536 | dtcontext->Rsp = frame.GetSP(); |
1537 | dtcontext->Rbp = frame.GetFP(); |
1538 | dtcontext->EFlags = GetRegister(frame, "rflags" ); |
1539 | |
1540 | dtcontext->Rax = GetRegister(frame, "rax" ); |
1541 | dtcontext->Rbx = GetRegister(frame, "rbx" ); |
1542 | dtcontext->Rcx = GetRegister(frame, "rcx" ); |
1543 | dtcontext->Rdx = GetRegister(frame, "rdx" ); |
1544 | dtcontext->Rsi = GetRegister(frame, "rsi" ); |
1545 | dtcontext->Rdi = GetRegister(frame, "rdi" ); |
1546 | dtcontext->R8 = GetRegister(frame, "r8" ); |
1547 | dtcontext->R9 = GetRegister(frame, "r9" ); |
1548 | dtcontext->R10 = GetRegister(frame, "r10" ); |
1549 | dtcontext->R11 = GetRegister(frame, "r11" ); |
1550 | dtcontext->R12 = GetRegister(frame, "r12" ); |
1551 | dtcontext->R13 = GetRegister(frame, "r13" ); |
1552 | dtcontext->R14 = GetRegister(frame, "r14" ); |
1553 | dtcontext->R15 = GetRegister(frame, "r15" ); |
1554 | |
1555 | dtcontext->SegCs = GetRegister(frame, "cs" ); |
1556 | dtcontext->SegSs = GetRegister(frame, "ss" ); |
1557 | dtcontext->SegDs = GetRegister(frame, "ds" ); |
1558 | dtcontext->SegEs = GetRegister(frame, "es" ); |
1559 | dtcontext->SegFs = GetRegister(frame, "fs" ); |
1560 | dtcontext->SegGs = GetRegister(frame, "gs" ); |
1561 | #elif DBG_TARGET_ARM |
1562 | dtcontext->Pc = frame.GetPC(); |
1563 | dtcontext->Sp = frame.GetSP(); |
1564 | dtcontext->Lr = GetRegister(frame, "lr" ); |
1565 | dtcontext->Cpsr = GetRegister(frame, "cpsr" ); |
1566 | |
1567 | dtcontext->R0 = GetRegister(frame, "r0" ); |
1568 | dtcontext->R1 = GetRegister(frame, "r1" ); |
1569 | dtcontext->R2 = GetRegister(frame, "r2" ); |
1570 | dtcontext->R3 = GetRegister(frame, "r3" ); |
1571 | dtcontext->R4 = GetRegister(frame, "r4" ); |
1572 | dtcontext->R5 = GetRegister(frame, "r5" ); |
1573 | dtcontext->R6 = GetRegister(frame, "r6" ); |
1574 | dtcontext->R7 = GetRegister(frame, "r7" ); |
1575 | dtcontext->R8 = GetRegister(frame, "r8" ); |
1576 | dtcontext->R9 = GetRegister(frame, "r9" ); |
1577 | dtcontext->R10 = GetRegister(frame, "r10" ); |
1578 | dtcontext->R11 = GetRegister(frame, "r11" ); |
1579 | dtcontext->R12 = GetRegister(frame, "r12" ); |
1580 | #elif DBG_TARGET_X86 |
1581 | dtcontext->Eip = frame.GetPC(); |
1582 | dtcontext->Esp = frame.GetSP(); |
1583 | dtcontext->Ebp = frame.GetFP(); |
1584 | dtcontext->EFlags = GetRegister(frame, "eflags" ); |
1585 | |
1586 | dtcontext->Edi = GetRegister(frame, "edi" ); |
1587 | dtcontext->Esi = GetRegister(frame, "esi" ); |
1588 | dtcontext->Ebx = GetRegister(frame, "ebx" ); |
1589 | dtcontext->Edx = GetRegister(frame, "edx" ); |
1590 | dtcontext->Ecx = GetRegister(frame, "ecx" ); |
1591 | dtcontext->Eax = GetRegister(frame, "eax" ); |
1592 | |
1593 | dtcontext->SegCs = GetRegister(frame, "cs" ); |
1594 | dtcontext->SegSs = GetRegister(frame, "ss" ); |
1595 | dtcontext->SegDs = GetRegister(frame, "ds" ); |
1596 | dtcontext->SegEs = GetRegister(frame, "es" ); |
1597 | dtcontext->SegFs = GetRegister(frame, "fs" ); |
1598 | dtcontext->SegGs = GetRegister(frame, "gs" ); |
1599 | #endif |
1600 | } |
1601 | |
1602 | // Internal function |
1603 | DWORD_PTR |
1604 | LLDBServices::GetRegister( |
1605 | /* const */ lldb::SBFrame& frame, |
1606 | const char *name) |
1607 | { |
1608 | lldb::SBValue regValue = frame.FindRegister(name); |
1609 | |
1610 | lldb::SBError error; |
1611 | DWORD_PTR result = regValue.GetValueAsUnsigned(error); |
1612 | |
1613 | return result; |
1614 | } |
1615 | |
1616 | //---------------------------------------------------------------------------- |
1617 | // IDebugRegisters |
1618 | //---------------------------------------------------------------------------- |
1619 | |
1620 | HRESULT |
1621 | LLDBServices::GetValueByName( |
1622 | PCSTR name, |
1623 | PDWORD_PTR debugValue) |
1624 | { |
1625 | lldb::SBFrame frame = GetCurrentFrame(); |
1626 | if (!frame.IsValid()) |
1627 | { |
1628 | *debugValue = 0; |
1629 | return E_FAIL; |
1630 | } |
1631 | |
1632 | lldb::SBValue value = frame.FindRegister(name); |
1633 | if (!value.IsValid()) |
1634 | { |
1635 | *debugValue = 0; |
1636 | return E_FAIL; |
1637 | } |
1638 | |
1639 | *debugValue = value.GetValueAsUnsigned(); |
1640 | return S_OK; |
1641 | } |
1642 | |
1643 | HRESULT |
1644 | LLDBServices::GetInstructionOffset( |
1645 | PULONG64 offset) |
1646 | { |
1647 | lldb::SBFrame frame = GetCurrentFrame(); |
1648 | if (!frame.IsValid()) |
1649 | { |
1650 | *offset = 0; |
1651 | return E_FAIL; |
1652 | } |
1653 | |
1654 | *offset = frame.GetPC(); |
1655 | return S_OK; |
1656 | } |
1657 | |
1658 | HRESULT |
1659 | LLDBServices::GetStackOffset( |
1660 | PULONG64 offset) |
1661 | { |
1662 | lldb::SBFrame frame = GetCurrentFrame(); |
1663 | if (!frame.IsValid()) |
1664 | { |
1665 | *offset = 0; |
1666 | return E_FAIL; |
1667 | } |
1668 | |
1669 | *offset = frame.GetSP(); |
1670 | return S_OK; |
1671 | } |
1672 | |
1673 | HRESULT |
1674 | LLDBServices::GetFrameOffset( |
1675 | PULONG64 offset) |
1676 | { |
1677 | lldb::SBFrame frame = GetCurrentFrame(); |
1678 | if (!frame.IsValid()) |
1679 | { |
1680 | *offset = 0; |
1681 | return E_FAIL; |
1682 | } |
1683 | |
1684 | *offset = frame.GetFP(); |
1685 | return S_OK; |
1686 | } |
1687 | |
1688 | //---------------------------------------------------------------------------- |
1689 | // Helper functions |
1690 | //---------------------------------------------------------------------------- |
1691 | |
1692 | lldb::SBProcess |
1693 | LLDBServices::GetCurrentProcess() |
1694 | { |
1695 | lldb::SBProcess process; |
1696 | |
1697 | if (m_currentProcess == nullptr) |
1698 | { |
1699 | lldb::SBTarget target = m_debugger.GetSelectedTarget(); |
1700 | if (target.IsValid()) |
1701 | { |
1702 | process = target.GetProcess(); |
1703 | } |
1704 | } |
1705 | else |
1706 | { |
1707 | process = *m_currentProcess; |
1708 | } |
1709 | |
1710 | return process; |
1711 | } |
1712 | |
1713 | lldb::SBThread |
1714 | LLDBServices::GetCurrentThread() |
1715 | { |
1716 | lldb::SBThread thread; |
1717 | |
1718 | if (m_currentThread == nullptr) |
1719 | { |
1720 | lldb::SBProcess process = GetCurrentProcess(); |
1721 | if (process.IsValid()) |
1722 | { |
1723 | thread = process.GetSelectedThread(); |
1724 | } |
1725 | } |
1726 | else |
1727 | { |
1728 | thread = *m_currentThread; |
1729 | } |
1730 | |
1731 | return thread; |
1732 | } |
1733 | |
1734 | lldb::SBFrame |
1735 | LLDBServices::GetCurrentFrame() |
1736 | { |
1737 | lldb::SBFrame frame; |
1738 | |
1739 | lldb::SBThread thread = GetCurrentThread(); |
1740 | if (thread.IsValid()) |
1741 | { |
1742 | frame = thread.GetSelectedFrame(); |
1743 | } |
1744 | |
1745 | return frame; |
1746 | } |
1747 | |