blob: 2c20a7b855359c5875fd2ca2626436ca69b4f27c [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)
510 m_exe_ctx.process->GetThreadList().SetSelectedThreadByIndexID(0);
511 }
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{
598 bool valid = true;
599
600 // Verify we have a value string.
601 if (value == NULL
602 || strlen (value) == 0)
603 {
604 valid = false;
605 err.SetErrorString ("Missing value. Can't set terminal width without a value.\n");
606 }
607
608 // Verify the string consists entirely of digits.
609 if (valid)
610 {
611 int len = strlen (value);
612 for (int i = 0; i < len; ++i)
613 if (! isdigit (value[i]))
614 {
615 valid = false;
Caroline Tice101c7c22010-09-09 06:25:08 +0000616 err.SetErrorStringWithFormat ("'%s' is not a valid representation of an unsigned integer.\n", value);
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000617 }
618 }
619
620 // Verify the term-width is 'reasonable' (e.g. 10 <= width <= 250).
621 if (valid)
622 {
623 int width = atoi (value);
624 if (width < 10
625 || width > 250)
626 {
627 valid = false;
628 err.SetErrorString ("Invalid term-width value; value must be between 10 and 250.\n");
629 }
630 }
631
632 return valid;
633}
634
635
636//--------------------------------------------------
637// class DebuggerInstanceSettings
638//--------------------------------------------------
639
Caroline Tice91123da2010-09-08 17:48:55 +0000640DebuggerInstanceSettings::DebuggerInstanceSettings (UserSettingsController &owner, bool live_instance,
641 const char *name) :
642 InstanceSettings (owner, (name == NULL ? CreateInstanceName ().AsCString() : name), live_instance),
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000643 m_prompt (),
644 m_script_lang ()
645{
Caroline Ticef20e8232010-09-09 18:26:37 +0000646 // CopyInstanceSettings is a pure virtual function in InstanceSettings; it therefore cannot be called
647 // until the vtables for DebuggerInstanceSettings are properly set up, i.e. AFTER all the initializers.
648 // For this reason it has to be called here, rather than in the initializer or in the parent constructor.
649
650 if (live_instance)
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000651 {
652 const lldb::InstanceSettingsSP &pending_settings = m_owner.FindPendingSettings (m_instance_name);
653 CopyInstanceSettings (pending_settings, false);
Caroline Ticef20e8232010-09-09 18:26:37 +0000654 //m_owner.RemovePendingSettings (m_instance_name);
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000655 }
656}
657
658DebuggerInstanceSettings::DebuggerInstanceSettings (const DebuggerInstanceSettings &rhs) :
659 InstanceSettings (*(Debugger::GetSettingsController().get()), CreateInstanceName ().AsCString()),
660 m_prompt (rhs.m_prompt),
661 m_script_lang (rhs.m_script_lang)
662{
663 const lldb::InstanceSettingsSP &pending_settings = m_owner.FindPendingSettings (m_instance_name);
664 CopyInstanceSettings (pending_settings, false);
665 m_owner.RemovePendingSettings (m_instance_name);
666}
667
668DebuggerInstanceSettings::~DebuggerInstanceSettings ()
669{
670}
671
672DebuggerInstanceSettings&
673DebuggerInstanceSettings::operator= (const DebuggerInstanceSettings &rhs)
674{
675 if (this != &rhs)
676 {
677 m_prompt = rhs.m_prompt;
678 m_script_lang = rhs.m_script_lang;
679 }
680
681 return *this;
682}
683
684void
685DebuggerInstanceSettings::UpdateInstanceSettingsVariable (const ConstString &var_name,
686 const char *index_value,
687 const char *value,
688 const ConstString &instance_name,
689 const SettingEntry &entry,
690 lldb::VarSetOperationType op,
691 Error &err,
692 bool pending)
693{
694 if (var_name == PromptVarName())
695 {
Caroline Tice101c7c22010-09-09 06:25:08 +0000696 UserSettingsController::UpdateStringVariable (op, m_prompt, value, err);
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000697 if (!pending)
698 {
Caroline Tice49e27372010-09-07 18:35:40 +0000699 // 'instance_name' is actually (probably) in the form '[<instance_name>]'; if so, we need to
700 // strip off the brackets before passing it to BroadcastPromptChange.
701
702 std::string tmp_instance_name (instance_name.AsCString());
703 if ((tmp_instance_name[0] == '[')
704 && (tmp_instance_name[instance_name.GetLength() - 1] == ']'))
705 tmp_instance_name = tmp_instance_name.substr (1, instance_name.GetLength() - 2);
706 ConstString new_name (tmp_instance_name.c_str());
707
708 BroadcastPromptChange (new_name, m_prompt.c_str());
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000709 }
710 }
711 else if (var_name == ScriptLangVarName())
712 {
713 bool success;
714 m_script_lang = Args::StringToScriptLanguage (value, eScriptLanguageDefault,
715 &success);
716 }
Caroline Tice101c7c22010-09-09 06:25:08 +0000717 else if (var_name == TermWidthVarName())
718 {
719 if (ValidTermWidthValue (value, err))
720 {
721 m_term_width = atoi (value);
722 }
723 }
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000724}
725
726void
727Debugger::DebuggerSettingsController::UpdateGlobalVariable (const ConstString &var_name,
728 const char *index_value,
729 const char *value,
730 const SettingEntry &entry,
731 lldb::VarSetOperationType op,
732 Error &err)
733{
Caroline Tice101c7c22010-09-09 06:25:08 +0000734 // There should not be any global variables at the Debugger level.
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000735}
736
737void
738DebuggerInstanceSettings::GetInstanceSettingsValue (const SettingEntry &entry,
739 const ConstString &var_name,
740 StringList &value)
741{
742 if (var_name == PromptVarName())
743 {
744 value.AppendString (m_prompt.c_str());
745
746 }
747 else if (var_name == ScriptLangVarName())
748 {
749 value.AppendString (ScriptInterpreter::LanguageToString (m_script_lang).c_str());
750 }
Caroline Tice101c7c22010-09-09 06:25:08 +0000751 else if (var_name == TermWidthVarName())
752 {
753 StreamString width_str;
754 width_str.Printf ("%d", m_term_width);
755 value.AppendString (width_str.GetData());
756 }
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000757}
758
759void
760DebuggerInstanceSettings::CopyInstanceSettings (const lldb::InstanceSettingsSP &new_settings,
761 bool pending)
762{
763 if (new_settings.get() == NULL)
764 return;
765
766 DebuggerInstanceSettings *new_debugger_settings = (DebuggerInstanceSettings *) new_settings.get();
767
768 m_prompt = new_debugger_settings->m_prompt;
769 if (!pending)
Caroline Tice49e27372010-09-07 18:35:40 +0000770 {
771 // 'instance_name' is actually (probably) in the form '[<instance_name>]'; if so, we need to
772 // strip off the brackets before passing it to BroadcastPromptChange.
773
774 std::string tmp_instance_name (m_instance_name.AsCString());
775 if ((tmp_instance_name[0] == '[')
776 && (tmp_instance_name[m_instance_name.GetLength() - 1] == ']'))
777 tmp_instance_name = tmp_instance_name.substr (1, m_instance_name.GetLength() - 2);
778 ConstString new_name (tmp_instance_name.c_str());
779
780 BroadcastPromptChange (new_name, m_prompt.c_str());
781 }
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000782
783 m_script_lang = new_debugger_settings->m_script_lang;
784}
785
786void
787Debugger::DebuggerSettingsController::GetGlobalSettingsValue (const ConstString &var_name,
788 StringList &value)
789{
Caroline Tice101c7c22010-09-09 06:25:08 +0000790 // There should not be any global variables at the Debugger level.
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000791}
792
793bool
794DebuggerInstanceSettings::BroadcastPromptChange (const ConstString &instance_name, const char *new_prompt)
795{
796 std::string tmp_prompt;
797
798 if (new_prompt != NULL)
799 {
800 tmp_prompt = new_prompt ;
801 int len = tmp_prompt.size();
802 if (len > 1
803 && (tmp_prompt[0] == '\'' || tmp_prompt[0] == '"')
804 && (tmp_prompt[len-1] == tmp_prompt[0]))
805 {
806 tmp_prompt = tmp_prompt.substr(1,len-2);
807 }
808 len = tmp_prompt.size();
809 if (tmp_prompt[len-1] != ' ')
810 tmp_prompt.append(" ");
811 }
812 EventSP new_event_sp;
813 new_event_sp.reset (new Event(CommandInterpreter::eBroadcastBitResetPrompt,
814 new EventDataBytes (tmp_prompt.c_str())));
815
816 if (instance_name.GetLength() != 0)
817 {
818 // Set prompt for a particular instance.
819 Debugger *dbg = Debugger::FindDebuggerWithInstanceName (instance_name).get();
820 if (dbg != NULL)
821 {
822 dbg->GetCommandInterpreter().BroadcastEvent (new_event_sp);
823 }
824 }
825
826 return true;
827}
828
829const ConstString
830DebuggerInstanceSettings::CreateInstanceName ()
831{
832 static int instance_count = 1;
833 StreamString sstr;
834
835 sstr.Printf ("debugger_%d", instance_count);
836 ++instance_count;
837
838 const ConstString ret_val (sstr.GetData());
839
840 return ret_val;
841}
842
843const ConstString &
844DebuggerInstanceSettings::PromptVarName ()
845{
846 static ConstString prompt_var_name ("prompt");
847
848 return prompt_var_name;
849}
850
851const ConstString &
852DebuggerInstanceSettings::ScriptLangVarName ()
853{
854 static ConstString script_lang_var_name ("script-lang");
855
856 return script_lang_var_name;
857}
858
Caroline Tice101c7c22010-09-09 06:25:08 +0000859const ConstString &
860DebuggerInstanceSettings::TermWidthVarName ()
861{
862 static ConstString term_width_var_name ("term-width");
863
864 return term_width_var_name;
865}
866
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000867//--------------------------------------------------
868// DebuggerSettingsController Variable Tables
869//--------------------------------------------------
870
871
872SettingEntry
873Debugger::DebuggerSettingsController::global_settings_table[] =
874{
875 //{ "var-name", var-type, "default", enum-table, init'd, hidden, "help-text"},
Caroline Tice101c7c22010-09-09 06:25:08 +0000876 // The Debugger level global table should always be empty; all Debugger settable variables should be instance
877 // variables.
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000878 { NULL, eSetVarTypeNone, NULL, NULL, 0, 0, NULL }
879};
880
881
882
883SettingEntry
884Debugger::DebuggerSettingsController::instance_settings_table[] =
885{
886 //{ "var-name", var-type , "default", enum-table, init'd, hidden, "help-text"},
Caroline Tice101c7c22010-09-09 06:25:08 +0000887 { "term-width" , eSetVarTypeInt, "80" , NULL, false , false , "The maximum number of columns to use for displaying text." },
Caroline Tice3df9a8d2010-09-04 00:03:46 +0000888 { "script-lang" , eSetVarTypeString, "python", NULL, false, false, "The script language to be used for evaluating user-written scripts." },
889 { "prompt" , eSetVarTypeString, "(lldb)", NULL, false, false, "The debugger command line prompt displayed for the user." },
890 { NULL, eSetVarTypeNone, NULL, NULL, 0, 0, NULL }
891};