blob: bf558423c5917b66edc54b8a179d8f5f3e0efd3b [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- Debugger.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 "lldb/lldb-private.h"
11#include "lldb/Core/ConnectionFileDescriptor.h"
12#include "lldb/Core/Debugger.h"
13#include "lldb/Core/InputReader.h"
14#include "lldb/Core/State.h"
15#include "lldb/Core/Timer.h"
Greg Clayton66111032010-06-23 01:19:29 +000016#include "lldb/Interpreter/CommandInterpreter.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000017#include "lldb/Target/TargetList.h"
18#include "lldb/Target/Process.h"
19#include "lldb/Target/Thread.h"
20
21
22using namespace lldb;
23using namespace lldb_private;
24
Greg Clayton66111032010-06-23 01:19:29 +000025static uint32_t g_shared_debugger_refcount = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000026
Caroline Ticeebc1bb22010-06-30 16:22:25 +000027static lldb::user_id_t g_unique_id = 1;
28
Chris Lattner30fdc8d2010-06-08 16:52:24 +000029void
30Debugger::Initialize ()
31{
Greg Clayton66111032010-06-23 01:19:29 +000032 if (g_shared_debugger_refcount == 0)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000033 lldb_private::Initialize();
Greg Clayton66111032010-06-23 01:19:29 +000034 g_shared_debugger_refcount++;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000035}
36
37void
38Debugger::Terminate ()
39{
Greg Clayton66111032010-06-23 01:19:29 +000040 if (g_shared_debugger_refcount > 0)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000041 {
Greg Clayton66111032010-06-23 01:19:29 +000042 g_shared_debugger_refcount--;
43 if (g_shared_debugger_refcount == 0)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000044 {
Greg Clayton66111032010-06-23 01:19:29 +000045 lldb_private::WillTerminate();
46 lldb_private::Terminate();
Chris Lattner30fdc8d2010-06-08 16:52:24 +000047 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000048 }
49}
50
Greg Clayton66111032010-06-23 01:19:29 +000051typedef std::vector<DebuggerSP> DebuggerList;
52
53static Mutex &
54GetDebuggerListMutex ()
Chris Lattner30fdc8d2010-06-08 16:52:24 +000055{
Greg Clayton66111032010-06-23 01:19:29 +000056 static Mutex g_mutex(Mutex::eMutexTypeRecursive);
57 return g_mutex;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000058}
59
Greg Clayton66111032010-06-23 01:19:29 +000060static DebuggerList &
61GetDebuggerList()
62{
63 // hide the static debugger list inside a singleton accessor to avoid
64 // global init contructors
65 static DebuggerList g_list;
66 return g_list;
67}
68
69
70DebuggerSP
71Debugger::CreateInstance ()
72{
73 DebuggerSP debugger_sp (new Debugger);
74 // Scope for locker
75 {
76 Mutex::Locker locker (GetDebuggerListMutex ());
77 GetDebuggerList().push_back(debugger_sp);
78 }
79 return debugger_sp;
80}
81
82lldb::DebuggerSP
83Debugger::GetSP ()
84{
85 lldb::DebuggerSP debugger_sp;
86
87 Mutex::Locker locker (GetDebuggerListMutex ());
88 DebuggerList &debugger_list = GetDebuggerList();
89 DebuggerList::iterator pos, end = debugger_list.end();
90 for (pos = debugger_list.begin(); pos != end; ++pos)
91 {
92 if ((*pos).get() == this)
93 {
94 debugger_sp = *pos;
95 break;
96 }
97 }
98 return debugger_sp;
99}
100
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000101lldb::DebuggerSP
102Debugger::FindDebuggerWithInstanceName (const ConstString &instance_name)
103{
104 lldb::DebuggerSP debugger_sp;
105
106 Mutex::Locker locker (GetDebuggerListMutex ());
107 DebuggerList &debugger_list = GetDebuggerList();
108 DebuggerList::iterator pos, end = debugger_list.end();
109
110 for (pos = debugger_list.begin(); pos != end; ++pos)
111 {
112 if ((*pos).get()->m_instance_name == instance_name)
113 {
114 debugger_sp = *pos;
115 break;
116 }
117 }
118 return debugger_sp;
119}
Greg Clayton66111032010-06-23 01:19:29 +0000120
121TargetSP
122Debugger::FindTargetWithProcessID (lldb::pid_t pid)
123{
124 lldb::TargetSP target_sp;
125 Mutex::Locker locker (GetDebuggerListMutex ());
126 DebuggerList &debugger_list = GetDebuggerList();
127 DebuggerList::iterator pos, end = debugger_list.end();
128 for (pos = debugger_list.begin(); pos != end; ++pos)
129 {
130 target_sp = (*pos)->GetTargetList().FindTargetWithProcessID (pid);
131 if (target_sp)
132 break;
133 }
134 return target_sp;
135}
136
137
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000138Debugger::Debugger () :
Caroline Ticeebc1bb22010-06-30 16:22:25 +0000139 UserID (g_unique_id++),
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000140 DebuggerInstanceSettings (*(Debugger::GetSettingsController().get())),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000141 m_input_comm("debugger.input"),
142 m_input_file (),
143 m_output_file (),
144 m_error_file (),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000145 m_target_list (),
146 m_listener ("lldb.Debugger"),
147 m_source_manager (),
Greg Clayton66111032010-06-23 01:19:29 +0000148 m_command_interpreter_ap (new CommandInterpreter (*this, eScriptLanguageDefault, false)),
149 m_exe_ctx (),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000150 m_input_readers (),
Jim Inghame40e4212010-08-30 19:44:40 +0000151 m_input_reader_data (),
152 m_use_external_editor(false)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000153{
Greg Clayton66111032010-06-23 01:19:29 +0000154 m_command_interpreter_ap->Initialize ();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000155}
156
157Debugger::~Debugger ()
158{
Greg Clayton66111032010-06-23 01:19:29 +0000159 int num_targets = m_target_list.GetNumTargets();
160 for (int i = 0; i < num_targets; i++)
161 {
162 ProcessSP process_sp (m_target_list.GetTargetAtIndex (i)->GetProcessSP());
163 if (process_sp)
164 process_sp->Destroy();
165 }
166 DisconnectInput();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000167}
168
169
170bool
171Debugger::GetAsyncExecution ()
172{
Greg Clayton66111032010-06-23 01:19:29 +0000173 return !m_command_interpreter_ap->GetSynchronous();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000174}
175
176void
177Debugger::SetAsyncExecution (bool async_execution)
178{
Greg Clayton66111032010-06-23 01:19:29 +0000179 m_command_interpreter_ap->SetSynchronous (!async_execution);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000180}
181
182void
183Debugger::DisconnectInput()
184{
185 m_input_comm.Clear ();
186}
187
188void
189Debugger::SetInputFileHandle (FILE *fh, bool tranfer_ownership)
190{
191 m_input_file.SetFileHandle (fh, tranfer_ownership);
192 if (m_input_file.GetFileHandle() == NULL)
193 m_input_file.SetFileHandle (stdin, false);
194
195 // Disconnect from any old connection if we had one
196 m_input_comm.Disconnect ();
197 m_input_comm.SetConnection (new ConnectionFileDescriptor (::fileno (GetInputFileHandle()), true));
198 m_input_comm.SetReadThreadBytesReceivedCallback (Debugger::DispatchInputCallback, this);
199
200 Error error;
201 if (m_input_comm.StartReadThread (&error) == false)
202 {
203 FILE *err_fh = GetErrorFileHandle();
204 if (err_fh)
205 {
206 ::fprintf (err_fh, "error: failed to main input read thread: %s", error.AsCString() ? error.AsCString() : "unkown error");
207 exit(1);
208 }
209 }
210
211}
212
213FILE *
214Debugger::GetInputFileHandle ()
215{
216 return m_input_file.GetFileHandle();
217}
218
219
220void
221Debugger::SetOutputFileHandle (FILE *fh, bool tranfer_ownership)
222{
223 m_output_file.SetFileHandle (fh, tranfer_ownership);
224 if (m_output_file.GetFileHandle() == NULL)
225 m_output_file.SetFileHandle (stdin, false);
226}
227
228FILE *
229Debugger::GetOutputFileHandle ()
230{
231 return m_output_file.GetFileHandle();
232}
233
234void
235Debugger::SetErrorFileHandle (FILE *fh, bool tranfer_ownership)
236{
237 m_error_file.SetFileHandle (fh, tranfer_ownership);
238 if (m_error_file.GetFileHandle() == NULL)
239 m_error_file.SetFileHandle (stdin, false);
240}
241
242
243FILE *
244Debugger::GetErrorFileHandle ()
245{
246 return m_error_file.GetFileHandle();
247}
248
249CommandInterpreter &
250Debugger::GetCommandInterpreter ()
251{
Greg Clayton66111032010-06-23 01:19:29 +0000252 assert (m_command_interpreter_ap.get());
253 return *m_command_interpreter_ap;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000254}
255
256Listener &
257Debugger::GetListener ()
258{
259 return m_listener;
260}
261
262
263TargetSP
Jim Ingham2976d002010-08-26 21:32:51 +0000264Debugger::GetSelectedTarget ()
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000265{
Jim Ingham2976d002010-08-26 21:32:51 +0000266 return m_target_list.GetSelectedTarget ();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000267}
268
269ExecutionContext
Jim Ingham2976d002010-08-26 21:32:51 +0000270Debugger::GetSelectedExecutionContext ()
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000271{
272 ExecutionContext exe_ctx;
273 exe_ctx.Clear();
274
Jim Ingham2976d002010-08-26 21:32:51 +0000275 lldb::TargetSP target_sp = GetSelectedTarget();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000276 exe_ctx.target = target_sp.get();
277
278 if (target_sp)
279 {
280 exe_ctx.process = target_sp->GetProcessSP().get();
281 if (exe_ctx.process && exe_ctx.process->IsRunning() == false)
282 {
Jim Ingham2976d002010-08-26 21:32:51 +0000283 exe_ctx.thread = exe_ctx.process->GetThreadList().GetSelectedThread().get();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000284 if (exe_ctx.thread == NULL)
285 exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get();
286 if (exe_ctx.thread)
287 {
Jim Ingham2976d002010-08-26 21:32:51 +0000288 exe_ctx.frame = exe_ctx.thread->GetSelectedFrame().get();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000289 if (exe_ctx.frame == NULL)
290 exe_ctx.frame = exe_ctx.thread->GetStackFrameAtIndex (0).get();
291 }
292 }
293 }
294 return exe_ctx;
295
296}
297
298SourceManager &
299Debugger::GetSourceManager ()
300{
301 return m_source_manager;
302}
303
304
305TargetList&
306Debugger::GetTargetList ()
307{
308 return m_target_list;
309}
310
311void
312Debugger::DispatchInputCallback (void *baton, const void *bytes, size_t bytes_len)
313{
314 ((Debugger *)baton)->DispatchInput ((char *)bytes, bytes_len);
315}
316
317
318void
319Debugger::DispatchInput (const char *bytes, size_t bytes_len)
320{
321 if (bytes == NULL || bytes_len == 0)
322 return;
323
324 // TODO: implement the STDIO to the process as an input reader...
Jim Ingham2976d002010-08-26 21:32:51 +0000325 TargetSP target = GetSelectedTarget();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000326 if (target.get() != NULL)
327 {
328 ProcessSP process_sp = target->GetProcessSP();
329 if (process_sp.get() != NULL
330 && StateIsRunningState (process_sp->GetState()))
331 {
332 Error error;
333 if (process_sp->PutSTDIN (bytes, bytes_len, error) == bytes_len)
334 return;
335 }
336 }
337
338 WriteToDefaultReader (bytes, bytes_len);
339}
340
341void
342Debugger::WriteToDefaultReader (const char *bytes, size_t bytes_len)
343{
344 if (bytes && bytes_len)
345 m_input_reader_data.append (bytes, bytes_len);
346
347 if (m_input_reader_data.empty())
348 return;
349
350 while (!m_input_readers.empty() && !m_input_reader_data.empty())
351 {
352 while (CheckIfTopInputReaderIsDone ())
353 /* Do nothing. */;
354
355 // Get the input reader from the top of the stack
356 InputReaderSP reader_sp(m_input_readers.top());
357
358 if (!reader_sp)
359 break;
360
Greg Clayton471b31c2010-07-20 22:52:08 +0000361 size_t bytes_handled = reader_sp->HandleRawBytes (m_input_reader_data.c_str(),
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000362 m_input_reader_data.size());
363 if (bytes_handled)
364 {
365 m_input_reader_data.erase (0, bytes_handled);
366 }
367 else
368 {
369 // No bytes were handled, we might not have reached our
370 // granularity, just return and wait for more data
371 break;
372 }
373 }
374
375 // Flush out any input readers that are donesvn
376 while (CheckIfTopInputReaderIsDone ())
377 /* Do nothing. */;
378
379}
380
381void
382Debugger::PushInputReader (const InputReaderSP& reader_sp)
383{
384 if (!reader_sp)
385 return;
386 if (!m_input_readers.empty())
387 {
388 // Deactivate the old top reader
389 InputReaderSP top_reader_sp (m_input_readers.top());
390 if (top_reader_sp)
391 top_reader_sp->Notify (eInputReaderDeactivate);
392 }
393 m_input_readers.push (reader_sp);
394 reader_sp->Notify (eInputReaderActivate);
395 ActivateInputReader (reader_sp);
396}
397
398bool
399Debugger::PopInputReader (const lldb::InputReaderSP& pop_reader_sp)
400{
401 bool result = false;
402
403 // The reader on the stop of the stack is done, so let the next
404 // read on the stack referesh its prompt and if there is one...
405 if (!m_input_readers.empty())
406 {
407 InputReaderSP reader_sp(m_input_readers.top());
408
409 if (!pop_reader_sp || pop_reader_sp.get() == reader_sp.get())
410 {
411 m_input_readers.pop ();
412 reader_sp->Notify (eInputReaderDeactivate);
413 reader_sp->Notify (eInputReaderDone);
414 result = true;
415
416 if (!m_input_readers.empty())
417 {
418 reader_sp = m_input_readers.top();
419 if (reader_sp)
420 {
421 ActivateInputReader (reader_sp);
422 reader_sp->Notify (eInputReaderReactivate);
423 }
424 }
425 }
426 }
427 return result;
428}
429
430bool
431Debugger::CheckIfTopInputReaderIsDone ()
432{
433 bool result = false;
434 if (!m_input_readers.empty())
435 {
436 InputReaderSP reader_sp(m_input_readers.top());
437
438 if (reader_sp && reader_sp->IsDone())
439 {
440 result = true;
441 PopInputReader (reader_sp);
442 }
443 }
444 return result;
445}
446
447void
448Debugger::ActivateInputReader (const InputReaderSP &reader_sp)
449{
450 FILE *in_fh = GetInputFileHandle();
451
452 if (in_fh)
453 {
454 struct termios in_fh_termios;
455 int in_fd = fileno (in_fh);
456 if (::tcgetattr(in_fd, &in_fh_termios) == 0)
457 {
458 if (reader_sp->GetEcho())
459 in_fh_termios.c_lflag |= ECHO; // Turn on echoing
460 else
461 in_fh_termios.c_lflag &= ~ECHO; // Turn off echoing
462
463 switch (reader_sp->GetGranularity())
464 {
465 case eInputReaderGranularityByte:
466 case eInputReaderGranularityWord:
467 in_fh_termios.c_lflag &= ~ICANON; // Get one char at a time
468 break;
469
470 case eInputReaderGranularityLine:
471 case eInputReaderGranularityAll:
472 in_fh_termios.c_lflag |= ICANON; // Get lines at a time
473 break;
474
475 default:
476 break;
477 }
478 ::tcsetattr (in_fd, TCSANOW, &in_fh_termios);
479 }
480 }
481}
Greg Clayton66111032010-06-23 01:19:29 +0000482
483void
484Debugger::UpdateExecutionContext (ExecutionContext *override_context)
485{
486 m_exe_ctx.Clear();
487
488 if (override_context != NULL)
489 {
490 m_exe_ctx.target = override_context->target;
491 m_exe_ctx.process = override_context->process;
492 m_exe_ctx.thread = override_context->thread;
493 m_exe_ctx.frame = override_context->frame;
494 }
495 else
496 {
Jim Ingham2976d002010-08-26 21:32:51 +0000497 TargetSP target_sp (GetSelectedTarget());
Greg Clayton66111032010-06-23 01:19:29 +0000498 if (target_sp)
499 {
500 m_exe_ctx.target = target_sp.get();
501 m_exe_ctx.process = target_sp->GetProcessSP().get();
Johnny Chen725945d2010-09-03 22:35:47 +0000502 if (m_exe_ctx.process && m_exe_ctx.process->IsAlive() && !m_exe_ctx.process->IsRunning())
Greg Clayton66111032010-06-23 01:19:29 +0000503 {
Jim Ingham2976d002010-08-26 21:32:51 +0000504 m_exe_ctx.thread = m_exe_ctx.process->GetThreadList().GetSelectedThread().get();
Greg Clayton66111032010-06-23 01:19:29 +0000505 if (m_exe_ctx.thread == NULL)
Jim Ingham59ce7fe2010-09-10 23:06:30 +0000506 {
Greg Clayton66111032010-06-23 01:19:29 +0000507 m_exe_ctx.thread = m_exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get();
Jim Ingham59ce7fe2010-09-10 23:06:30 +0000508 // If we didn't have a selected thread, select one here.
509 if (m_exe_ctx.thread != NULL)
Johnny Chenc13ee522010-09-14 00:53:53 +0000510 m_exe_ctx.process->GetThreadList().SetSelectedThreadByID(m_exe_ctx.thread->GetID());
Jim Ingham59ce7fe2010-09-10 23:06:30 +0000511 }
Greg Clayton66111032010-06-23 01:19:29 +0000512 if (m_exe_ctx.thread)
513 {
Jim Ingham2976d002010-08-26 21:32:51 +0000514 m_exe_ctx.frame = m_exe_ctx.thread->GetSelectedFrame().get();
Greg Clayton66111032010-06-23 01:19:29 +0000515 if (m_exe_ctx.frame == NULL)
Jim Ingham59ce7fe2010-09-10 23:06:30 +0000516 {
Greg Clayton66111032010-06-23 01:19:29 +0000517 m_exe_ctx.frame = m_exe_ctx.thread->GetStackFrameAtIndex (0).get();
Jim Ingham59ce7fe2010-09-10 23:06:30 +0000518 // If we didn't have a selected frame select one here.
519 if (m_exe_ctx.frame != NULL)
520 m_exe_ctx.thread->SetSelectedFrame(m_exe_ctx.frame);
521 }
Greg Clayton66111032010-06-23 01:19:29 +0000522 }
523 }
524 }
525 }
526}
527
Caroline Ticeebc1bb22010-06-30 16:22:25 +0000528DebuggerSP
529Debugger::FindDebuggerWithID (lldb::user_id_t id)
530{
531 lldb::DebuggerSP debugger_sp;
532
533 Mutex::Locker locker (GetDebuggerListMutex ());
534 DebuggerList &debugger_list = GetDebuggerList();
535 DebuggerList::iterator pos, end = debugger_list.end();
536 for (pos = debugger_list.begin(); pos != end; ++pos)
537 {
538 if ((*pos).get()->GetID() == id)
539 {
540 debugger_sp = *pos;
541 break;
542 }
543 }
544 return debugger_sp;
545}
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000546
547lldb::UserSettingsControllerSP &
548Debugger::GetSettingsController (bool finish)
549{
550 static lldb::UserSettingsControllerSP g_settings_controller (new DebuggerSettingsController);
551 static bool initialized = false;
552
553 if (!initialized)
554 {
Jim Ingham95852752010-09-07 20:27:09 +0000555 initialized = UserSettingsController::InitializeSettingsController (g_settings_controller,
556 Debugger::DebuggerSettingsController::global_settings_table,
557 Debugger::DebuggerSettingsController::instance_settings_table);
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000558 }
559
560 if (finish)
561 {
562 UserSettingsControllerSP parent = g_settings_controller->GetParent();
563 if (parent)
564 parent->RemoveChild (g_settings_controller);
565 g_settings_controller.reset();
566 }
567 return g_settings_controller;
568}
569
570//--------------------------------------------------
571// class Debugger::DebuggerSettingsController
572//--------------------------------------------------
573
574Debugger::DebuggerSettingsController::DebuggerSettingsController () :
Caroline Tice101c7c22010-09-09 06:25:08 +0000575 UserSettingsController ("", lldb::UserSettingsControllerSP())
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000576{
Caroline Tice91123da2010-09-08 17:48:55 +0000577 m_default_settings.reset (new DebuggerInstanceSettings (*this, false,
578 InstanceSettings::GetDefaultName().AsCString()));
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000579}
580
581Debugger::DebuggerSettingsController::~DebuggerSettingsController ()
582{
583}
584
585
586lldb::InstanceSettingsSP
Caroline Tice91123da2010-09-08 17:48:55 +0000587Debugger::DebuggerSettingsController::CreateNewInstanceSettings (const char *instance_name)
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000588{
Caroline Tice91123da2010-09-08 17:48:55 +0000589 DebuggerInstanceSettings *new_settings = new DebuggerInstanceSettings (*(Debugger::GetSettingsController().get()),
590 false, instance_name);
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000591 lldb::InstanceSettingsSP new_settings_sp (new_settings);
592 return new_settings_sp;
593}
594
595bool
Caroline Tice101c7c22010-09-09 06:25:08 +0000596Debugger::DebuggerInstanceSettings::ValidTermWidthValue (const char *value, Error err)
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000597{
Greg Claytona7015092010-09-18 01:14:36 +0000598 bool valid = false;
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000599
600 // Verify we have a value string.
Greg Claytona7015092010-09-18 01:14:36 +0000601 if (value == NULL || value[0] == '\0')
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000602 {
Greg Claytona7015092010-09-18 01:14:36 +0000603 err.SetErrorString ("Missing value. Can't set terminal width without a value.\n");
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000604 }
Greg Claytona7015092010-09-18 01:14:36 +0000605 else
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000606 {
Greg Claytona7015092010-09-18 01:14:36 +0000607 char *end = NULL;
608 const uint32_t width = ::strtoul (value, &end, 0);
609
610 if (end && end == '\0')
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000611 {
Greg Claytona7015092010-09-18 01:14:36 +0000612 if (width >= 10 || width <= 1024)
613 valid = true;
614 else
615 err.SetErrorString ("Invalid term-width value; value must be between 10 and 1024.\n");
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000616 }
Greg Claytona7015092010-09-18 01:14:36 +0000617 else
618 err.SetErrorStringWithFormat ("'%s' is not a valid unsigned integer string.\n", value);
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000619 }
620
621 return valid;
622}
623
624
625//--------------------------------------------------
626// class DebuggerInstanceSettings
627//--------------------------------------------------
628
Greg Claytona7015092010-09-18 01:14:36 +0000629DebuggerInstanceSettings::DebuggerInstanceSettings
630(
631 UserSettingsController &owner,
632 bool live_instance,
633 const char *name
634) :
Caroline Tice9e41c152010-09-16 19:05:55 +0000635 InstanceSettings (owner, (name == NULL ? InstanceSettings::InvalidName().AsCString() : name), live_instance),
Greg Claytona7015092010-09-18 01:14:36 +0000636 m_term_width (80),
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000637 m_prompt (),
638 m_script_lang ()
639{
Caroline Ticef20e8232010-09-09 18:26:37 +0000640 // CopyInstanceSettings is a pure virtual function in InstanceSettings; it therefore cannot be called
641 // until the vtables for DebuggerInstanceSettings are properly set up, i.e. AFTER all the initializers.
642 // For this reason it has to be called here, rather than in the initializer or in the parent constructor.
Caroline Tice9e41c152010-09-16 19:05:55 +0000643 // The same is true of CreateInstanceName().
644
645 if (GetInstanceName() == InstanceSettings::InvalidName())
646 {
647 ChangeInstanceName (std::string (CreateInstanceName().AsCString()));
648 m_owner.RegisterInstanceSettings (this);
649 }
Caroline Ticef20e8232010-09-09 18:26:37 +0000650
651 if (live_instance)
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000652 {
653 const lldb::InstanceSettingsSP &pending_settings = m_owner.FindPendingSettings (m_instance_name);
654 CopyInstanceSettings (pending_settings, false);
Caroline Ticef20e8232010-09-09 18:26:37 +0000655 //m_owner.RemovePendingSettings (m_instance_name);
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000656 }
657}
658
659DebuggerInstanceSettings::DebuggerInstanceSettings (const DebuggerInstanceSettings &rhs) :
660 InstanceSettings (*(Debugger::GetSettingsController().get()), CreateInstanceName ().AsCString()),
661 m_prompt (rhs.m_prompt),
662 m_script_lang (rhs.m_script_lang)
663{
664 const lldb::InstanceSettingsSP &pending_settings = m_owner.FindPendingSettings (m_instance_name);
665 CopyInstanceSettings (pending_settings, false);
666 m_owner.RemovePendingSettings (m_instance_name);
667}
668
669DebuggerInstanceSettings::~DebuggerInstanceSettings ()
670{
671}
672
673DebuggerInstanceSettings&
674DebuggerInstanceSettings::operator= (const DebuggerInstanceSettings &rhs)
675{
676 if (this != &rhs)
677 {
678 m_prompt = rhs.m_prompt;
679 m_script_lang = rhs.m_script_lang;
680 }
681
682 return *this;
683}
684
685void
686DebuggerInstanceSettings::UpdateInstanceSettingsVariable (const ConstString &var_name,
687 const char *index_value,
688 const char *value,
689 const ConstString &instance_name,
690 const SettingEntry &entry,
691 lldb::VarSetOperationType op,
692 Error &err,
693 bool pending)
694{
695 if (var_name == PromptVarName())
696 {
Caroline Tice101c7c22010-09-09 06:25:08 +0000697 UserSettingsController::UpdateStringVariable (op, m_prompt, value, err);
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000698 if (!pending)
699 {
Caroline Tice49e27372010-09-07 18:35:40 +0000700 // 'instance_name' is actually (probably) in the form '[<instance_name>]'; if so, we need to
701 // strip off the brackets before passing it to BroadcastPromptChange.
702
703 std::string tmp_instance_name (instance_name.AsCString());
704 if ((tmp_instance_name[0] == '[')
705 && (tmp_instance_name[instance_name.GetLength() - 1] == ']'))
706 tmp_instance_name = tmp_instance_name.substr (1, instance_name.GetLength() - 2);
707 ConstString new_name (tmp_instance_name.c_str());
708
709 BroadcastPromptChange (new_name, m_prompt.c_str());
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000710 }
711 }
712 else if (var_name == ScriptLangVarName())
713 {
714 bool success;
715 m_script_lang = Args::StringToScriptLanguage (value, eScriptLanguageDefault,
716 &success);
717 }
Caroline Tice101c7c22010-09-09 06:25:08 +0000718 else if (var_name == TermWidthVarName())
719 {
720 if (ValidTermWidthValue (value, err))
721 {
Greg Claytona7015092010-09-18 01:14:36 +0000722 m_term_width = ::strtoul (value, NULL, 0);
Caroline Tice101c7c22010-09-09 06:25:08 +0000723 }
724 }
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000725}
726
727void
728Debugger::DebuggerSettingsController::UpdateGlobalVariable (const ConstString &var_name,
729 const char *index_value,
730 const char *value,
731 const SettingEntry &entry,
732 lldb::VarSetOperationType op,
733 Error &err)
734{
Caroline Tice101c7c22010-09-09 06:25:08 +0000735 // There should not be any global variables at the Debugger level.
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000736}
737
738void
739DebuggerInstanceSettings::GetInstanceSettingsValue (const SettingEntry &entry,
740 const ConstString &var_name,
741 StringList &value)
742{
743 if (var_name == PromptVarName())
744 {
745 value.AppendString (m_prompt.c_str());
746
747 }
748 else if (var_name == ScriptLangVarName())
749 {
750 value.AppendString (ScriptInterpreter::LanguageToString (m_script_lang).c_str());
751 }
Caroline Tice101c7c22010-09-09 06:25:08 +0000752 else if (var_name == TermWidthVarName())
753 {
754 StreamString width_str;
755 width_str.Printf ("%d", m_term_width);
756 value.AppendString (width_str.GetData());
757 }
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000758}
759
760void
761DebuggerInstanceSettings::CopyInstanceSettings (const lldb::InstanceSettingsSP &new_settings,
762 bool pending)
763{
764 if (new_settings.get() == NULL)
765 return;
766
767 DebuggerInstanceSettings *new_debugger_settings = (DebuggerInstanceSettings *) new_settings.get();
768
769 m_prompt = new_debugger_settings->m_prompt;
770 if (!pending)
Caroline Tice49e27372010-09-07 18:35:40 +0000771 {
772 // 'instance_name' is actually (probably) in the form '[<instance_name>]'; if so, we need to
773 // strip off the brackets before passing it to BroadcastPromptChange.
774
775 std::string tmp_instance_name (m_instance_name.AsCString());
776 if ((tmp_instance_name[0] == '[')
777 && (tmp_instance_name[m_instance_name.GetLength() - 1] == ']'))
778 tmp_instance_name = tmp_instance_name.substr (1, m_instance_name.GetLength() - 2);
779 ConstString new_name (tmp_instance_name.c_str());
780
781 BroadcastPromptChange (new_name, m_prompt.c_str());
782 }
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000783
784 m_script_lang = new_debugger_settings->m_script_lang;
785}
786
787void
788Debugger::DebuggerSettingsController::GetGlobalSettingsValue (const ConstString &var_name,
789 StringList &value)
790{
Caroline Tice101c7c22010-09-09 06:25:08 +0000791 // There should not be any global variables at the Debugger level.
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000792}
793
794bool
795DebuggerInstanceSettings::BroadcastPromptChange (const ConstString &instance_name, const char *new_prompt)
796{
797 std::string tmp_prompt;
798
799 if (new_prompt != NULL)
800 {
801 tmp_prompt = new_prompt ;
802 int len = tmp_prompt.size();
803 if (len > 1
804 && (tmp_prompt[0] == '\'' || tmp_prompt[0] == '"')
805 && (tmp_prompt[len-1] == tmp_prompt[0]))
806 {
807 tmp_prompt = tmp_prompt.substr(1,len-2);
808 }
809 len = tmp_prompt.size();
810 if (tmp_prompt[len-1] != ' ')
811 tmp_prompt.append(" ");
812 }
813 EventSP new_event_sp;
814 new_event_sp.reset (new Event(CommandInterpreter::eBroadcastBitResetPrompt,
815 new EventDataBytes (tmp_prompt.c_str())));
816
817 if (instance_name.GetLength() != 0)
818 {
819 // Set prompt for a particular instance.
820 Debugger *dbg = Debugger::FindDebuggerWithInstanceName (instance_name).get();
821 if (dbg != NULL)
822 {
823 dbg->GetCommandInterpreter().BroadcastEvent (new_event_sp);
824 }
825 }
826
827 return true;
828}
829
830const ConstString
831DebuggerInstanceSettings::CreateInstanceName ()
832{
833 static int instance_count = 1;
834 StreamString sstr;
835
836 sstr.Printf ("debugger_%d", instance_count);
837 ++instance_count;
838
839 const ConstString ret_val (sstr.GetData());
840
841 return ret_val;
842}
843
844const ConstString &
845DebuggerInstanceSettings::PromptVarName ()
846{
847 static ConstString prompt_var_name ("prompt");
848
849 return prompt_var_name;
850}
851
852const ConstString &
853DebuggerInstanceSettings::ScriptLangVarName ()
854{
855 static ConstString script_lang_var_name ("script-lang");
856
857 return script_lang_var_name;
858}
859
Caroline Tice101c7c22010-09-09 06:25:08 +0000860const ConstString &
861DebuggerInstanceSettings::TermWidthVarName ()
862{
863 static ConstString term_width_var_name ("term-width");
864
865 return term_width_var_name;
866}
867
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000868//--------------------------------------------------
869// DebuggerSettingsController Variable Tables
870//--------------------------------------------------
871
872
873SettingEntry
874Debugger::DebuggerSettingsController::global_settings_table[] =
875{
876 //{ "var-name", var-type, "default", enum-table, init'd, hidden, "help-text"},
Caroline Tice101c7c22010-09-09 06:25:08 +0000877 // The Debugger level global table should always be empty; all Debugger settable variables should be instance
878 // variables.
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000879 { NULL, eSetVarTypeNone, NULL, NULL, 0, 0, NULL }
880};
881
882
883
884SettingEntry
885Debugger::DebuggerSettingsController::instance_settings_table[] =
886{
887 //{ "var-name", var-type , "default", enum-table, init'd, hidden, "help-text"},
Caroline Tice101c7c22010-09-09 06:25:08 +0000888 { "term-width" , eSetVarTypeInt, "80" , NULL, false , false , "The maximum number of columns to use for displaying text." },
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000889 { "script-lang" , eSetVarTypeString, "python", NULL, false, false, "The script language to be used for evaluating user-written scripts." },
890 { "prompt" , eSetVarTypeString, "(lldb)", NULL, false, false, "The debugger command line prompt displayed for the user." },
891 { NULL, eSetVarTypeNone, NULL, NULL, 0, 0, NULL }
892};