f5ec14d08d2d5cc41e4bdfcbd613943a92a071c3
[platform/upstream/coreclr.git] / src / ToolBox / SOS / lldbplugin / services.cpp
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 extraInformation,
452     ULONG extraInformationSize,
453     PULONG extraInformationUsed,
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 }