1 //===-- SBDebugger.cpp ------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "SBDebugger.h"
11 
12 #include "lldb/lldb-include.h"
13 #include "lldb/Core/Args.h"
14 #include "lldb/Core/Debugger.h"
15 #include "lldb/Core/State.h"
16 #include "lldb/Target/Process.h"
17 #include "lldb/Target/TargetList.h"
18 
19 #include "SBListener.h"
20 #include "SBBroadcaster.h"
21 #include "SBCommandInterpreter.h"
22 #include "SBCommandReturnObject.h"
23 #include "SBEvent.h"
24 #include "SBFrame.h"
25 #include "SBTarget.h"
26 #include "SBProcess.h"
27 #include "SBThread.h"
28 #include "SBSourceManager.h"
29 #include "SBInputReader.h"
30 
31 using namespace lldb;
32 using namespace lldb_private;
33 
34 void
35 SBDebugger::Initialize ()
36 {
37     Debugger::Initialize();
38 }
39 
40 void
41 SBDebugger::Terminate ()
42 {
43     Debugger::Terminate();
44 }
45 
46 void
47 SBDebugger::SetAsync (bool b)
48 {
49     static bool value_set_once = false;
50 
51     if (!value_set_once)
52     {
53         value_set_once = true;
54         Debugger::GetSharedInstance().SetAsyncExecution(b);
55     }
56 }
57 
58 void
59 SBDebugger::SetInputFile (const char *tty_name)
60 {
61     // DEPRECATED: will be removed in next submission
62     FILE *fh = ::fopen (tty_name, "r");
63     SetInputFileHandle  (fh, true);
64 }
65 
66 void
67 SBDebugger::SetOutputFile (const char *tty_name)
68 {
69     // DEPRECATED: will be removed in next submission
70     FILE *fh = ::fopen (tty_name, "w");
71     SetOutputFileHandle (fh, true);
72     SetErrorFileHandle  (fh, false);
73 }
74 
75 void
76 SBDebugger::SetErrorFile (const char *tty_name)
77 {
78     // DEPRECATED: will be removed in next submission
79 }
80 
81 
82 // Shouldn't really be settable after initialization as this could cause lots of problems; don't want users
83 // trying to switch modes in the middle of a debugging session.
84 void
85 SBDebugger::SetInputFileHandle (FILE *fh, bool transfer_ownership)
86 {
87     Debugger::GetSharedInstance().SetInputFileHandle (fh, transfer_ownership);
88 }
89 
90 void
91 SBDebugger::SetOutputFileHandle (FILE *fh, bool transfer_ownership)
92 {
93     Debugger::GetSharedInstance().SetOutputFileHandle (fh, transfer_ownership);
94 }
95 
96 void
97 SBDebugger::SetErrorFileHandle (FILE *fh, bool transfer_ownership)
98 {
99     Debugger::GetSharedInstance().SetErrorFileHandle (fh, transfer_ownership);
100 }
101 
102 FILE *
103 SBDebugger::GetInputFileHandle ()
104 {
105     return Debugger::GetSharedInstance().GetInputFileHandle();
106 }
107 
108 FILE *
109 SBDebugger::GetOutputFileHandle ()
110 {
111     return Debugger::GetSharedInstance().GetOutputFileHandle();
112 }
113 
114 FILE *
115 SBDebugger::GetErrorFileHandle ()
116 {
117     return Debugger::GetSharedInstance().GetErrorFileHandle();
118 }
119 
120 SBCommandInterpreter
121 SBDebugger::GetCommandInterpreter ()
122 {
123     SBCommandInterpreter sb_interpreter(Debugger::GetSharedInstance().GetCommandInterpreter());
124     return sb_interpreter;
125 }
126 
127 void
128 SBDebugger::HandleCommand (const char *command)
129 {
130     SBProcess process;
131     SBCommandInterpreter sb_interpreter(Debugger::GetSharedInstance().GetCommandInterpreter());
132     SBCommandReturnObject result;
133 
134     sb_interpreter.HandleCommand (command, result, false);
135 
136     if (GetErrorFileHandle() != NULL)
137         result.PutError (GetErrorFileHandle());
138     if (GetOutputFileHandle() != NULL)
139         result.PutOutput (GetOutputFileHandle());
140 
141     if (Debugger::GetSharedInstance().GetAsyncExecution() == false)
142     {
143         process = GetCommandInterpreter().GetProcess ();
144         if (process.IsValid())
145         {
146             EventSP event_sp;
147             Listener &lldb_listener = Debugger::GetSharedInstance().GetListener();
148             while (lldb_listener.GetNextEventForBroadcaster (process.get(), event_sp))
149             {
150                 SBEvent event(event_sp);
151                 HandleProcessEvent (process, event, GetOutputFileHandle(), GetErrorFileHandle());
152             }
153         }
154     }
155 }
156 
157 SBListener
158 SBDebugger::GetListener ()
159 {
160     SBListener sb_listener(Debugger::GetSharedInstance().GetListener());
161     return sb_listener;
162 }
163 
164 void
165 SBDebugger::HandleProcessEvent (const SBProcess &process, const SBEvent &event, FILE *out, FILE *err)
166 {
167      const uint32_t event_type = event.GetType();
168      char stdio_buffer[1024];
169      size_t len;
170 
171      if (event_type & Process::eBroadcastBitSTDOUT)
172      {
173          while ((len = process.GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
174              if (out != NULL)
175                  ::fwrite (stdio_buffer, 1, len, out);
176      }
177      else if (event_type & Process::eBroadcastBitSTDERR)
178      {
179          while ((len = process.GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
180              if (out != NULL)
181                  ::fwrite (stdio_buffer, 1, len, out);
182      }
183      else if (event_type & Process::eBroadcastBitStateChanged)
184      {
185          // Drain any stdout messages.
186          while ((len = process.GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
187              if (out != NULL)
188                  ::fwrite (stdio_buffer, 1, len, out);
189 
190          // Drain any stderr messages.
191          while ((len = process.GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
192              if (out != NULL)
193                  ::fwrite (stdio_buffer, 1, len, out);
194 
195          StateType event_state = SBProcess::GetStateFromEvent (event);
196 
197          if (event_state == eStateInvalid)
198              return;
199 
200          bool is_stopped = StateIsStoppedState (event_state);
201          if (!is_stopped)
202              process.ReportCurrentState (event, out);
203    }
204 }
205 
206 void
207 SBDebugger::UpdateCurrentThread (SBProcess &process)
208 {
209     if (process.IsValid())
210     {
211         SBThread curr_thread = process.GetCurrentThread ();
212         SBThread thread;
213         StopReason curr_thread_stop_reason = eStopReasonInvalid;
214         if (curr_thread.IsValid())
215         {
216             if (curr_thread.GetStopReason() != eStopReasonInvalid)
217                 curr_thread_stop_reason = curr_thread.GetStopReason ();
218         }
219 
220         if (! curr_thread.IsValid()
221             || curr_thread_stop_reason == eStopReasonInvalid
222             || curr_thread_stop_reason == eStopReasonNone)
223           {
224             // Prefer a thread that has just completed its plan over another thread as current thread.
225             SBThread plan_thread;
226             SBThread other_thread;
227             const size_t num_threads = process.GetNumThreads ();
228             size_t i;
229             for (i = 0; i < num_threads; ++i)
230             {
231                 thread = process.GetThreadAtIndex(i);
232                 if (thread.GetStopReason () != eStopReasonInvalid)
233                 {
234                     switch (thread.GetStopReason ())
235                     {
236                         default:
237                         case eStopReasonInvalid:
238                         case eStopReasonNone:
239                             break;
240 
241                         case eStopReasonTrace:
242                         case eStopReasonBreakpoint:
243                         case eStopReasonWatchpoint:
244                         case eStopReasonSignal:
245                         case eStopReasonException:
246                             if (! other_thread.IsValid())
247                                 other_thread = thread;
248                             break;
249                         case eStopReasonPlanComplete:
250                             if (! plan_thread.IsValid())
251                                 plan_thread = thread;
252                             break;
253                     }
254                 }
255             }
256             if (plan_thread.IsValid())
257                 process.SetCurrentThreadByID (plan_thread.GetThreadID());
258             else if (other_thread.IsValid())
259                 process.SetCurrentThreadByID (other_thread.GetThreadID());
260             else
261             {
262                 if (curr_thread.IsValid())
263                     thread = curr_thread;
264                 else
265                     thread = process.GetThreadAtIndex(0);
266 
267                 if (thread.IsValid())
268                     process.SetCurrentThreadByID (thread.GetThreadID());
269             }
270         }
271     }
272 }
273 
274 void
275 SBDebugger::ReportCurrentLocation (FILE *out, FILE *err)
276 {
277     if ((out == NULL) || (err == NULL))
278         return;
279 
280     SBTarget sb_target (GetCurrentTarget());
281     if (!sb_target.IsValid())
282     {
283         fprintf (out, "no target\n");
284         return;
285     }
286 
287     SBProcess process = sb_target.GetProcess ();
288     if (process.IsValid())
289     {
290         StateType state = process.GetState();
291 
292         if (StateIsStoppedState (state))
293         {
294             if (state == eStateExited)
295             {
296                 int exit_status = process.GetExitStatus();
297                 const char *exit_description = process.GetExitDescription();
298                 ::fprintf (out, "Process %d exited with status = %i (0x%8.8x) %s\n",
299                            process.GetProcessID(),
300                            exit_status,
301                            exit_status,
302                            exit_description ? exit_description : "");
303             }
304             else
305             {
306                 fprintf (out, "Process %d %s\n", process.GetProcessID(), StateAsCString (state));
307                 SBThread current_thread = process.GetThreadAtIndex (0);
308                 if (current_thread.IsValid())
309                 {
310                     process.DisplayThreadsInfo (out, err, true);
311                 }
312                 else
313                     fprintf (out, "No valid thread found in current process\n");
314             }
315         }
316         else
317             fprintf (out, "No current location or status available\n");
318     }
319 }
320 
321 SBSourceManager &
322 SBDebugger::GetSourceManager ()
323 {
324     static SourceManager g_lldb_source_manager;
325     static SBSourceManager g_sb_source_manager (g_lldb_source_manager);
326     return g_sb_source_manager;
327 }
328 
329 
330 bool
331 SBDebugger::GetDefaultArchitecture (char *arch_name, size_t arch_name_len)
332 {
333     if (arch_name && arch_name_len)
334     {
335         ArchSpec &default_arch = lldb_private::GetDefaultArchitecture ();
336         if (default_arch.IsValid())
337         {
338             ::snprintf (arch_name, arch_name_len, "%s", default_arch.AsCString());
339             return true;
340         }
341     }
342     if (arch_name && arch_name_len)
343         arch_name[0] = '\0';
344     return false;
345 }
346 
347 
348 bool
349 SBDebugger::SetDefaultArchitecture (const char *arch_name)
350 {
351     if (arch_name)
352     {
353         ArchSpec arch (arch_name);
354         if (arch.IsValid())
355         {
356             lldb_private::GetDefaultArchitecture () = arch;
357             return true;
358         }
359     }
360     return false;
361 }
362 
363 ScriptLanguage
364 SBDebugger::GetScriptingLanguage (const char *script_language_name)
365 {
366     return Args::StringToScriptLanguage (script_language_name,
367                                          eScriptLanguageDefault,
368                                          NULL);
369 }
370 //pid_t
371 /*
372 SBDebugger::AttachByName (const char *process_name, const char *filename)
373 {
374     SBTarget *temp_target = GetCurrentTarget();
375     SBTarget sb_target;
376     pid_t return_pid = (pid_t) LLDB_INVALID_PROCESS_ID;
377 
378     if (temp_target == NULL)
379     {
380         if (filename != NULL)
381         {
382             sb_target = CreateWithFile (filename);
383             sb_target.SetArch (LLDB_ARCH_DEFAULT);
384         }
385     }
386     else
387     {
388           sb_target = *temp_target;
389     }
390 
391     if (sb_target.IsValid())
392     {
393         SBProcess process = sb_target.GetProcess ();
394         if (process.IsValid())
395         {
396             return_pid = process.AttachByName (process_name);
397         }
398     }
399     return return_pid;
400 }
401 */
402 
403 const char *
404 SBDebugger::GetVersionString ()
405 {
406     return lldb_private::GetVersion();
407 }
408 
409 const char *
410 SBDebugger::StateAsCString (lldb::StateType state)
411 {
412     return lldb_private::StateAsCString (state);
413 }
414 
415 bool
416 SBDebugger::StateIsRunningState (lldb::StateType state)
417 {
418     return lldb_private::StateIsRunningState (state);
419 }
420 
421 bool
422 SBDebugger::StateIsStoppedState (lldb::StateType state)
423 {
424     return lldb_private::StateIsStoppedState (state);
425 }
426 
427 
428 SBTarget
429 SBDebugger::CreateTargetWithFileAndTargetTriple (const char *filename,
430                                                  const char *target_triple)
431 {
432     ArchSpec arch;
433     FileSpec file_spec (filename);
434     arch.SetArchFromTargetTriple(target_triple);
435     TargetSP target_sp;
436     Error error (Debugger::GetSharedInstance().GetTargetList().CreateTarget (file_spec, arch, NULL, true, target_sp));
437     SBTarget target(target_sp);
438     return target;
439 }
440 
441 SBTarget
442 SBDebugger::CreateTargetWithFileAndArch (const char *filename, const char *archname)
443 {
444     FileSpec file (filename);
445     ArchSpec arch = lldb_private::GetDefaultArchitecture();
446     TargetSP target_sp;
447     Error error;
448 
449     if (archname != NULL)
450     {
451         ArchSpec arch2 (archname);
452         error = Debugger::GetSharedInstance().GetTargetList().CreateTarget (file, arch2, NULL, true, target_sp);
453     }
454     else
455     {
456         if (!arch.IsValid())
457             arch = LLDB_ARCH_DEFAULT;
458 
459         error = Debugger::GetSharedInstance().GetTargetList().CreateTarget (file, arch, NULL, true, target_sp);
460 
461         if (error.Fail())
462         {
463             if (arch == LLDB_ARCH_DEFAULT_32BIT)
464                 arch = LLDB_ARCH_DEFAULT_64BIT;
465             else
466                 arch = LLDB_ARCH_DEFAULT_32BIT;
467 
468             error = Debugger::GetSharedInstance().GetTargetList().CreateTarget (file, arch, NULL, true, target_sp);
469         }
470     }
471 
472     if (error.Success())
473         Debugger::GetSharedInstance().GetTargetList().SetCurrentTarget (target_sp.get());
474     else
475         target_sp.reset();
476 
477     SBTarget sb_target (target_sp);
478     return sb_target;
479 }
480 
481 SBTarget
482 SBDebugger::CreateTarget (const char *filename)
483 {
484     FileSpec file (filename);
485     ArchSpec arch = lldb_private::GetDefaultArchitecture();
486     TargetSP target_sp;
487     Error error;
488 
489     if (!arch.IsValid())
490         arch = LLDB_ARCH_DEFAULT;
491 
492     error = Debugger::GetSharedInstance().GetTargetList().CreateTarget (file, arch, NULL, true, target_sp);
493 
494     if (error.Fail())
495     {
496         if (arch == LLDB_ARCH_DEFAULT_32BIT)
497             arch = LLDB_ARCH_DEFAULT_64BIT;
498         else
499             arch = LLDB_ARCH_DEFAULT_32BIT;
500 
501         error = Debugger::GetSharedInstance().GetTargetList().CreateTarget (file, arch, NULL, true, target_sp);
502     }
503 
504     if (!error.Fail())
505         Debugger::GetSharedInstance().GetTargetList().SetCurrentTarget (target_sp.get());
506 
507     SBTarget sb_target (target_sp);
508     return sb_target;
509 }
510 
511 SBTarget
512 SBDebugger::GetTargetAtIndex (uint32_t idx)
513 {
514     SBTarget sb_target (Debugger::GetSharedInstance().GetTargetList().GetTargetAtIndex (idx));
515     return sb_target;
516 }
517 
518 SBTarget
519 SBDebugger::FindTargetWithProcessID (pid_t pid)
520 {
521     SBTarget sb_target(Debugger::GetSharedInstance().GetTargetList().FindTargetWithProcessID (pid));
522     return sb_target;
523 }
524 
525 SBTarget
526 SBDebugger::FindTargetWithFileAndArch (const char *filename, const char *arch_name)
527 {
528     ArchSpec arch;
529     if (arch_name)
530         arch.SetArch(arch_name);
531     return SBTarget (Debugger::GetSharedInstance().GetTargetList().FindTargetWithExecutableAndArchitecture (FileSpec(filename),
532                                                                                                             arch_name ? &arch : NULL));
533 }
534 
535 SBTarget
536 SBDebugger::FindTargetWithLLDBProcess (const lldb::ProcessSP &process_sp)
537 {
538     SBTarget sb_target(Debugger::GetSharedInstance().GetTargetList().FindTargetWithProcess (process_sp.get()));
539     return sb_target;
540 }
541 
542 
543 uint32_t
544 SBDebugger::GetNumTargets ()
545 {
546     return Debugger::GetSharedInstance().GetTargetList().GetNumTargets ();}
547 
548 SBTarget
549 SBDebugger::GetCurrentTarget ()
550 {
551     SBTarget sb_target(Debugger::GetSharedInstance().GetTargetList().GetCurrentTarget ());
552     return sb_target;
553 }
554 
555 void
556 SBDebugger::DispatchInput (void *baton, const void *data, size_t data_len)
557 {
558     Debugger::GetSharedInstance().DispatchInput ((const char *) data, data_len);
559 }
560 
561 void
562 SBDebugger::PushInputReader (SBInputReader &reader)
563 {
564     if (reader.IsValid())
565     {
566         InputReaderSP reader_sp(*reader);
567         Debugger::GetSharedInstance().PushInputReader (reader_sp);
568     }
569 }
570