blob: 2add92717d423d2135b72c8d790c635420ea2cdb [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- Driver.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 "Driver.h"
11
12#include <getopt.h>
13#include <libgen.h>
14#include <sys/ioctl.h>
15#include <termios.h>
16#include <unistd.h>
Eli Friedmanf2f321d2010-06-09 09:50:17 +000017#include <string.h>
18#include <stdlib.h>
19#include <limits.h>
Eli Friedmand6e167d2010-06-09 19:11:30 +000020#include <fcntl.h>
Chris Lattner24943d22010-06-08 16:52:24 +000021
22#include <string>
23
24#include "IOChannel.h"
Eli Friedmanf2f321d2010-06-09 09:50:17 +000025#include "lldb/API/SBCommandInterpreter.h"
26#include "lldb/API/SBCommandReturnObject.h"
27#include "lldb/API/SBCommunication.h"
28#include "lldb/API/SBDebugger.h"
29#include "lldb/API/SBEvent.h"
30#include "lldb/API/SBHostOS.h"
31#include "lldb/API/SBListener.h"
32#include "lldb/API/SBSourceManager.h"
33#include "lldb/API/SBTarget.h"
34#include "lldb/API/SBThread.h"
35#include "lldb/API/SBProcess.h"
Chris Lattner24943d22010-06-08 16:52:24 +000036
37using namespace lldb;
38
39static void reset_stdin_termios ();
40static struct termios g_old_stdin_termios;
41
42// In the Driver::MainLoop, we change the terminal settings. This function is
43// added as an atexit handler to make sure we clean them up.
44static void
45reset_stdin_termios ()
46{
47 ::tcsetattr (STDIN_FILENO, TCSANOW, &g_old_stdin_termios);
48}
49
50static lldb::OptionDefinition g_options[] =
51{
Greg Clayton12bec712010-06-28 21:30:43 +000052 { LLDB_OPT_SET_1, true, "help", 'h', no_argument, NULL, NULL, NULL,
Chris Lattner24943d22010-06-08 16:52:24 +000053 "Prints out the usage information for the LLDB debugger." },
54
Greg Clayton12bec712010-06-28 21:30:43 +000055 { LLDB_OPT_SET_2, true, "version", 'v', no_argument, NULL, NULL, NULL,
Chris Lattner24943d22010-06-08 16:52:24 +000056 "Prints out the current version number of the LLDB debugger." },
57
Greg Clayton12bec712010-06-28 21:30:43 +000058 { LLDB_OPT_SET_3, true, "arch", 'a', required_argument, NULL, NULL, "<architecture>",
Chris Lattner24943d22010-06-08 16:52:24 +000059 "Tells the debugger to use the specified architecture when starting and running the program. <architecture> must be one of the architectures for which the program was compiled." },
60
Jim Ingham34e9a982010-06-15 18:47:14 +000061 { LLDB_OPT_SET_3 | LLDB_OPT_SET_4, false, "script-language",'l', required_argument, NULL, NULL, "<scripting-language>",
Chris Lattner24943d22010-06-08 16:52:24 +000062 "Tells the debugger to use the specified scripting language for user-defined scripts, rather than the default. Valid scripting languages that can be specified include Python, Perl, Ruby and Tcl. Currently only the Python extensions have been implemented." },
63
Jim Ingham34e9a982010-06-15 18:47:14 +000064 { LLDB_OPT_SET_3 | LLDB_OPT_SET_4, false, "debug", 'd', no_argument, NULL, NULL, NULL,
Chris Lattner24943d22010-06-08 16:52:24 +000065 "Tells the debugger to print out extra information for debugging itself." },
66
Jim Ingham34e9a982010-06-15 18:47:14 +000067 { LLDB_OPT_SET_3 | LLDB_OPT_SET_4, false, "source", 's', required_argument, NULL, NULL, "<file>",
Chris Lattner24943d22010-06-08 16:52:24 +000068 "Tells the debugger to read in and execute the file <file>, which should contain lldb commands." },
69
Greg Clayton12bec712010-06-28 21:30:43 +000070 { LLDB_OPT_SET_3, true, "file", 'f', required_argument, NULL, NULL, "<filename>",
Jim Ingham34e9a982010-06-15 18:47:14 +000071 "Tells the debugger to use the file <filename> as the program to be debugged." },
72
Greg Clayton12bec712010-06-28 21:30:43 +000073// { LLDB_OPT_SET_4, true, "crash-log", 'c', required_argument, NULL, NULL, "<file>",
74// "Load executable images from a crash log for symbolication." },
Chris Lattner24943d22010-06-08 16:52:24 +000075
76 { 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL }
77};
78
79
80Driver::Driver () :
81 SBBroadcaster ("Driver"),
Greg Clayton63094e02010-06-23 01:19:29 +000082 m_debugger (SBDebugger::Create()),
Chris Lattner24943d22010-06-08 16:52:24 +000083 m_editline_pty (),
84 m_editline_slave_fh (NULL),
85 m_editline_reader (),
86 m_io_channel_ap (),
87 m_option_data (),
88 m_waiting_for_command (false)
89{
90}
91
92Driver::~Driver ()
93{
94}
95
96void
97Driver::CloseIOChannelFile ()
98{
99 // Write and End of File sequence to the file descriptor to ensure any
100 // read functions can exit.
101 char eof_str[] = "\x04";
102 ::write (m_editline_pty.GetMasterFileDescriptor(), eof_str, strlen(eof_str));
103
104 m_editline_pty.CloseMasterFileDescriptor();
105
106 if (m_editline_slave_fh)
107 {
108 ::fclose (m_editline_slave_fh);
109 m_editline_slave_fh = NULL;
110 }
111}
112
Greg Clayton54e7afa2010-07-09 20:39:50 +0000113// This function takes INDENT, which tells how many spaces to output at the front
114// of each line; TEXT, which is the text that is to be output. It outputs the
115// text, on multiple lines if necessary, to RESULT, with INDENT spaces at the
116// front of each line. It breaks lines on spaces, tabs or newlines, shortening
117// the line if necessary to not break in the middle of a word. It assumes that
118// each output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
Chris Lattner24943d22010-06-08 16:52:24 +0000119
120void
Greg Clayton54e7afa2010-07-09 20:39:50 +0000121OutputFormattedUsageText (FILE *out, int indent, const char *text, int output_max_columns)
Chris Lattner24943d22010-06-08 16:52:24 +0000122{
123 int len = strlen (text);
124 std::string text_string (text);
Chris Lattner24943d22010-06-08 16:52:24 +0000125
126 // Force indentation to be reasonable.
127 if (indent >= output_max_columns)
128 indent = 0;
129
130 // Will it all fit on one line?
131
132 if (len + indent < output_max_columns)
133 // Output as a single line
Greg Clayton54e7afa2010-07-09 20:39:50 +0000134 fprintf (out, "%*s%s\n", indent, "", text);
Chris Lattner24943d22010-06-08 16:52:24 +0000135 else
136 {
137 // We need to break it up into multiple lines.
138 int text_width = output_max_columns - indent - 1;
139 int start = 0;
140 int end = start;
141 int final_end = len;
142 int sub_len;
143
144 while (end < final_end)
145 {
146 // Dont start the 'text' on a space, since we're already outputting the indentation.
147 while ((start < final_end) && (text[start] == ' '))
148 start++;
149
150 end = start + text_width;
151 if (end > final_end)
152 end = final_end;
153 else
154 {
155 // If we're not at the end of the text, make sure we break the line on white space.
156 while (end > start
157 && text[end] != ' ' && text[end] != '\t' && text[end] != '\n')
158 end--;
159 }
160 sub_len = end - start;
161 std::string substring = text_string.substr (start, sub_len);
Greg Clayton54e7afa2010-07-09 20:39:50 +0000162 fprintf (out, "%*s%s\n", indent, "", substring.c_str());
Chris Lattner24943d22010-06-08 16:52:24 +0000163 start = end + 1;
164 }
165 }
166}
167
168void
169ShowUsage (FILE *out, lldb::OptionDefinition *option_table, Driver::OptionData data)
170{
171 uint32_t screen_width = 80;
172 uint32_t indent_level = 0;
173 const char *name = "lldb";
Jim Ingham34e9a982010-06-15 18:47:14 +0000174
Chris Lattner24943d22010-06-08 16:52:24 +0000175 fprintf (out, "\nUsage:\n\n");
176
177 indent_level += 2;
178
179
180 // First, show each usage level set of options, e.g. <cmd> [options-for-level-0]
181 // <cmd> [options-for-level-1]
182 // etc.
183
Chris Lattner24943d22010-06-08 16:52:24 +0000184 uint32_t num_options;
Jim Ingham34e9a982010-06-15 18:47:14 +0000185 uint32_t num_option_sets = 0;
186
187 for (num_options = 0; option_table[num_options].long_option != NULL; ++num_options)
Chris Lattner24943d22010-06-08 16:52:24 +0000188 {
Jim Ingham34e9a982010-06-15 18:47:14 +0000189 uint32_t this_usage_mask = option_table[num_options].usage_mask;
190 if (this_usage_mask == LLDB_OPT_SET_ALL)
Chris Lattner24943d22010-06-08 16:52:24 +0000191 {
Jim Ingham34e9a982010-06-15 18:47:14 +0000192 if (num_option_sets == 0)
193 num_option_sets = 1;
Chris Lattner24943d22010-06-08 16:52:24 +0000194 }
195 else
196 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000197 for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++)
Jim Ingham34e9a982010-06-15 18:47:14 +0000198 {
199 if (this_usage_mask & 1 << j)
200 {
201 if (num_option_sets <= j)
202 num_option_sets = j + 1;
203 }
204 }
205 }
206 }
207
208 for (uint32_t opt_set = 0; opt_set < num_option_sets; opt_set++)
209 {
210 uint32_t opt_set_mask;
211
212 opt_set_mask = 1 << opt_set;
213
214 if (opt_set > 0)
215 fprintf (out, "\n");
Greg Clayton54e7afa2010-07-09 20:39:50 +0000216 fprintf (out, "%*s%s", indent_level, "", name);
Jim Ingham34e9a982010-06-15 18:47:14 +0000217
218 for (uint32_t i = 0; i < num_options; ++i)
219 {
220 if (option_table[i].usage_mask & opt_set_mask)
221 {
222 if (option_table[i].required)
223 {
224 if (option_table[i].option_has_arg == required_argument)
225 fprintf (out, " -%c %s", option_table[i].short_option, option_table[i].argument_name);
226 else if (option_table[i].option_has_arg == optional_argument)
227 fprintf (out, " -%c [%s]", option_table[i].short_option, option_table[i].argument_name);
228 else
229 fprintf (out, " -%c", option_table[i].short_option);
230 }
231 else
232 {
233 if (option_table[i].option_has_arg == required_argument)
234 fprintf (out, " [-%c %s]", option_table[i].short_option, option_table[i].argument_name);
235 else if (option_table[i].option_has_arg == optional_argument)
236 fprintf (out, " [-%c [%s]]", option_table[i].short_option, option_table[i].argument_name);
237 else
238 fprintf (out, " [-%c]", option_table[i].short_option);
239 }
240 }
Chris Lattner24943d22010-06-08 16:52:24 +0000241 }
242 }
243
244 fprintf (out, "\n\n");
245
246 // Now print out all the detailed information about the various options: long form, short form and help text:
247 // -- long_name <argument>
248 // - short <argument>
249 // help text
250
251 // This variable is used to keep track of which options' info we've printed out, because some options can be in
252 // more than one usage level, but we only want to print the long form of its information once.
253
254 Driver::OptionData::OptionSet options_seen;
255 Driver::OptionData::OptionSet::iterator pos;
256
257 indent_level += 5;
258
Jim Ingham34e9a982010-06-15 18:47:14 +0000259 for (uint32_t i = 0; i < num_options; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000260 {
261 // Only print this option if we haven't already seen it.
262 pos = options_seen.find (option_table[i].short_option);
263 if (pos == options_seen.end())
264 {
265 options_seen.insert (option_table[i].short_option);
Greg Clayton54e7afa2010-07-09 20:39:50 +0000266 fprintf (out, "%*s-%c ", indent_level, "", option_table[i].short_option);
Chris Lattner24943d22010-06-08 16:52:24 +0000267 if (option_table[i].argument_name != NULL)
268 fprintf (out, "%s", option_table[i].argument_name);
269 fprintf (out, "\n");
Greg Clayton54e7afa2010-07-09 20:39:50 +0000270 fprintf (out, "%*s--%s ", indent_level, "", option_table[i].long_option);
Chris Lattner24943d22010-06-08 16:52:24 +0000271 if (option_table[i].argument_name != NULL)
272 fprintf (out, "%s", option_table[i].argument_name);
273 fprintf (out, "\n");
274 indent_level += 5;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000275 OutputFormattedUsageText (out, indent_level, option_table[i].usage_text, screen_width);
Chris Lattner24943d22010-06-08 16:52:24 +0000276 indent_level -= 5;
277 fprintf (out, "\n");
278 }
279 }
280
281 indent_level -= 5;
282
Greg Clayton54e7afa2010-07-09 20:39:50 +0000283 fprintf (out, "\n%*s('%s <filename>' also works, to specify the file to be debugged.)\n\n",
284 indent_level, "", name);
Chris Lattner24943d22010-06-08 16:52:24 +0000285}
286
287void
Greg Clayton54e7afa2010-07-09 20:39:50 +0000288BuildGetOptTable (lldb::OptionDefinition *expanded_option_table, struct option **getopt_table, uint32_t num_options)
Chris Lattner24943d22010-06-08 16:52:24 +0000289{
290 if (num_options == 0)
291 return;
292
293 uint32_t i;
294 uint32_t j;
295 std::bitset<256> option_seen;
296
297 for (i = 0, j = 0; i < num_options; ++i)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000298 {
Chris Lattner24943d22010-06-08 16:52:24 +0000299 char short_opt = expanded_option_table[i].short_option;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000300
Chris Lattner24943d22010-06-08 16:52:24 +0000301 if (option_seen.test(short_opt) == false)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000302 {
Chris Lattner24943d22010-06-08 16:52:24 +0000303 (*getopt_table)[j].name = expanded_option_table[i].long_option;
304 (*getopt_table)[j].has_arg = expanded_option_table[i].option_has_arg;
305 (*getopt_table)[j].flag = NULL;
306 (*getopt_table)[j].val = expanded_option_table[i].short_option;
307 option_seen.set(short_opt);
308 ++j;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000309 }
310 }
Chris Lattner24943d22010-06-08 16:52:24 +0000311
312 (*getopt_table)[j].name = NULL;
313 (*getopt_table)[j].has_arg = 0;
314 (*getopt_table)[j].flag = NULL;
315 (*getopt_table)[j].val = 0;
316
317}
318
Greg Clayton63094e02010-06-23 01:19:29 +0000319Driver::OptionData::OptionData () :
320 m_filename(),
321 m_script_lang (lldb::eScriptLanguageDefault),
Greg Clayton54e7afa2010-07-09 20:39:50 +0000322 m_crash_log (),
Greg Clayton63094e02010-06-23 01:19:29 +0000323 m_source_command_files (),
324 m_debug_mode (false),
Greg Clayton54e7afa2010-07-09 20:39:50 +0000325 m_print_version (false),
Greg Clayton63094e02010-06-23 01:19:29 +0000326 m_print_help (false),
Greg Clayton54e7afa2010-07-09 20:39:50 +0000327 m_seen_options()
Chris Lattner24943d22010-06-08 16:52:24 +0000328{
Greg Clayton63094e02010-06-23 01:19:29 +0000329}
330
331Driver::OptionData::~OptionData ()
332{
333}
334
335void
336Driver::OptionData::Clear ()
337{
338 m_filename.clear ();
339 m_script_lang = lldb::eScriptLanguageDefault;
340 m_source_command_files.clear ();
341 m_debug_mode = false;
342 m_print_help = false;
343 m_print_version = false;
344}
345
346void
347Driver::ResetOptionValues ()
348{
349 m_option_data.Clear ();
350}
351
352const char *
353Driver::GetFilename() const
354{
355 if (m_option_data.m_filename.empty())
356 return NULL;
357 return m_option_data.m_filename.c_str();
358}
359
360const char *
361Driver::GetCrashLogFilename() const
362{
363 if (m_option_data.m_crash_log.empty())
364 return NULL;
365 return m_option_data.m_crash_log.c_str();
366}
367
368lldb::ScriptLanguage
369Driver::GetScriptLanguage() const
370{
371 return m_option_data.m_script_lang;
372}
373
374size_t
375Driver::GetNumSourceCommandFiles () const
376{
377 return m_option_data.m_source_command_files.size();
378}
379
380const char *
381Driver::GetSourceCommandFileAtIndex (uint32_t idx) const
382{
383 if (idx < m_option_data.m_source_command_files.size())
384 return m_option_data.m_source_command_files[idx].c_str();
385 return NULL;
386}
387
388bool
389Driver::GetDebugMode() const
390{
391 return m_option_data.m_debug_mode;
392}
393
394
395// Check the arguments that were passed to this program to make sure they are valid and to get their
396// argument values (if any). Return a boolean value indicating whether or not to start up the full
397// debugger (i.e. the Command Interpreter) or not. Return FALSE if the arguments were invalid OR
398// if the user only wanted help or version information.
399
400SBError
401Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exit)
402{
403 ResetOptionValues ();
404
405 SBCommandReturnObject result;
406
Chris Lattner24943d22010-06-08 16:52:24 +0000407 SBError error;
408 std::string option_string;
409 struct option *long_options = NULL;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000410 uint32_t num_options;
Chris Lattner24943d22010-06-08 16:52:24 +0000411
Greg Clayton54e7afa2010-07-09 20:39:50 +0000412 for (num_options = 0; g_options[num_options].long_option != NULL; ++num_options)
413 /* Do Nothing. */;
Chris Lattner24943d22010-06-08 16:52:24 +0000414
415 if (num_options == 0)
416 {
417 if (argc > 1)
418 error.SetErrorStringWithFormat ("invalid number of options");
419 return error;
420 }
421
422 long_options = (struct option *) malloc ((num_options + 1) * sizeof (struct option));
423
424 BuildGetOptTable (g_options, &long_options, num_options);
425
426 if (long_options == NULL)
427 {
428 error.SetErrorStringWithFormat ("invalid long options");
429 return error;
430 }
431
432 // Build the option_string argument for call to getopt_long.
433
434 for (int i = 0; long_options[i].name != NULL; ++i)
435 {
436 if (long_options[i].flag == NULL)
437 {
438 option_string.push_back ((char) long_options[i].val);
439 switch (long_options[i].has_arg)
440 {
441 default:
442 case no_argument:
443 break;
444 case required_argument:
445 option_string.push_back (':');
446 break;
447 case optional_argument:
448 option_string.append ("::");
449 break;
450 }
451 }
452 }
453
454 // Prepare for & make calls to getopt_long.
Eli Friedmanef2bc872010-06-13 19:18:49 +0000455#if __GLIBC__
456 optind = 0;
457#else
Chris Lattner24943d22010-06-08 16:52:24 +0000458 optreset = 1;
459 optind = 1;
Eli Friedmanef2bc872010-06-13 19:18:49 +0000460#endif
Chris Lattner24943d22010-06-08 16:52:24 +0000461 int val;
462 while (1)
463 {
464 int long_options_index = -1;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000465 val = ::getopt_long (argc, const_cast<char **>(argv), option_string.c_str(), long_options, &long_options_index);
Chris Lattner24943d22010-06-08 16:52:24 +0000466
467 if (val == -1)
468 break;
469 else if (val == '?')
470 {
Greg Clayton63094e02010-06-23 01:19:29 +0000471 m_option_data.m_print_help = true;
Chris Lattner24943d22010-06-08 16:52:24 +0000472 error.SetErrorStringWithFormat ("unknown or ambiguous option");
473 break;
474 }
475 else if (val == 0)
476 continue;
477 else
478 {
Greg Clayton63094e02010-06-23 01:19:29 +0000479 m_option_data.m_seen_options.insert ((char) val);
Chris Lattner24943d22010-06-08 16:52:24 +0000480 if (long_options_index == -1)
481 {
482 for (int i = 0;
483 long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val;
484 ++i)
485 {
486 if (long_options[i].val == val)
487 {
488 long_options_index = i;
489 break;
490 }
491 }
492 }
493
494 if (long_options_index >= 0)
495 {
Greg Clayton63094e02010-06-23 01:19:29 +0000496 const char short_option = (char) g_options[long_options_index].short_option;
497
498 switch (short_option)
499 {
500 case 'h':
501 m_option_data.m_print_help = true;
502 break;
503
504 case 'v':
505 m_option_data.m_print_version = true;
506 break;
507
508 case 'c':
509 m_option_data.m_crash_log = optarg;
510 break;
511
512 case 'f':
513 {
514 SBFileSpec file(optarg);
515 if (file.Exists())
516 m_option_data.m_filename = optarg;
517 else
518 error.SetErrorStringWithFormat("file specified in --file (-f) option doesn't exist: '%s'", optarg);
519 }
520 break;
521
522 case 'a':
523 if (!m_debugger.SetDefaultArchitecture (optarg))
524 error.SetErrorStringWithFormat("invalid architecture in the -a or --arch option: '%s'", optarg);
525 break;
526
527 case 'l':
528 m_option_data.m_script_lang = m_debugger.GetScriptingLanguage (optarg);
529 break;
530
531 case 'd':
532 m_option_data.m_debug_mode = true;
533 break;
534
535 case 's':
536 {
537 SBFileSpec file(optarg);
538 if (file.Exists())
539 m_option_data.m_source_command_files.push_back (optarg);
540 else
541 error.SetErrorStringWithFormat("file specified in --source (-s) option doesn't exist: '%s'", optarg);
542 }
543 break;
544
545 default:
546 m_option_data.m_print_help = true;
547 error.SetErrorStringWithFormat ("unrecognized option %c", short_option);
548 break;
549 }
Chris Lattner24943d22010-06-08 16:52:24 +0000550 }
551 else
552 {
553 error.SetErrorStringWithFormat ("invalid option with value %i", val);
554 }
555 if (error.Fail())
Greg Clayton63094e02010-06-23 01:19:29 +0000556 return error;
Chris Lattner24943d22010-06-08 16:52:24 +0000557 }
558 }
Jim Ingham34e9a982010-06-15 18:47:14 +0000559
560 // If there is a trailing argument, it is the filename.
561 if (optind == argc - 1)
562 {
563 if (m_option_data.m_filename.empty())
Chris Lattner24943d22010-06-08 16:52:24 +0000564 {
Jim Ingham34e9a982010-06-15 18:47:14 +0000565 m_option_data.m_filename = argv[optind];
Chris Lattner24943d22010-06-08 16:52:24 +0000566 }
Jim Ingham34e9a982010-06-15 18:47:14 +0000567 else
568 {
Greg Clayton63094e02010-06-23 01:19:29 +0000569 error.SetErrorStringWithFormat ("error: don't provide a file both on in the -f option and as an argument.");
Jim Ingham34e9a982010-06-15 18:47:14 +0000570 }
571
Chris Lattner24943d22010-06-08 16:52:24 +0000572 }
Jim Ingham34e9a982010-06-15 18:47:14 +0000573 else if (optind < argc - 1)
574 {
575 // Trailing extra arguments...
Greg Clayton63094e02010-06-23 01:19:29 +0000576 error.SetErrorStringWithFormat ("error: trailing extra arguments - only one the filename is allowed.");
Jim Ingham34e9a982010-06-15 18:47:14 +0000577 }
578
Greg Clayton63094e02010-06-23 01:19:29 +0000579 if (error.Fail() || m_option_data.m_print_help)
Chris Lattner24943d22010-06-08 16:52:24 +0000580 {
581 ShowUsage (out_fh, g_options, m_option_data);
Chris Lattner24943d22010-06-08 16:52:24 +0000582 }
583 else if (m_option_data.m_print_version)
584 {
Greg Clayton63094e02010-06-23 01:19:29 +0000585 ::fprintf (out_fh, "%s\n", m_debugger.GetVersionString());
586 exit = true;
Chris Lattner24943d22010-06-08 16:52:24 +0000587 }
588 else if (! m_option_data.m_crash_log.empty())
589 {
590 // Handle crash log stuff here.
591 }
592 else
593 {
594 // All other combinations are valid; do nothing more here.
595 }
596
Greg Clayton63094e02010-06-23 01:19:29 +0000597 return error;
Chris Lattner24943d22010-06-08 16:52:24 +0000598}
599
600void
601Driver::GetProcessSTDOUT ()
602{
603 // The process has stuff waiting for stdout; get it and write it out to the appropriate place.
604 char stdio_buffer[1024];
605 size_t len;
Greg Clayton63094e02010-06-23 01:19:29 +0000606 while ((len = m_debugger.GetCurrentTarget().GetProcess().GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
Chris Lattner24943d22010-06-08 16:52:24 +0000607 m_io_channel_ap->OutWrite (stdio_buffer, len);
608}
609
610void
611Driver::GetProcessSTDERR ()
612{
613 // The process has stuff waiting for stderr; get it and write it out to the appropriate place.
614 char stdio_buffer[1024];
615 size_t len;
Greg Clayton63094e02010-06-23 01:19:29 +0000616 while ((len = m_debugger.GetCurrentTarget().GetProcess().GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
Chris Lattner24943d22010-06-08 16:52:24 +0000617 m_io_channel_ap->ErrWrite (stdio_buffer, len);
618}
619
620void
621Driver::UpdateCurrentThread ()
622{
623 using namespace lldb;
Greg Clayton63094e02010-06-23 01:19:29 +0000624 SBProcess process(m_debugger.GetCurrentTarget().GetProcess());
Chris Lattner24943d22010-06-08 16:52:24 +0000625 if (process.IsValid())
626 {
627 SBThread curr_thread (process.GetCurrentThread());
628 SBThread thread;
629 StopReason curr_thread_stop_reason = eStopReasonInvalid;
630 curr_thread_stop_reason = curr_thread.GetStopReason();
631
632 if (!curr_thread.IsValid() ||
633 curr_thread_stop_reason == eStopReasonInvalid ||
634 curr_thread_stop_reason == eStopReasonNone)
635 {
636 // Prefer a thread that has just completed its plan over another thread as current thread.
637 SBThread plan_thread;
638 SBThread other_thread;
639 const size_t num_threads = process.GetNumThreads();
640 size_t i;
641 for (i = 0; i < num_threads; ++i)
642 {
643 thread = process.GetThreadAtIndex(i);
644 StopReason thread_stop_reason = thread.GetStopReason();
645 switch (thread_stop_reason)
646 {
647 default:
648 case eStopReasonInvalid:
649 case eStopReasonNone:
650 break;
651
652 case eStopReasonTrace:
653 case eStopReasonBreakpoint:
654 case eStopReasonWatchpoint:
655 case eStopReasonSignal:
656 case eStopReasonException:
657 if (!other_thread.IsValid())
658 other_thread = thread;
659 break;
660 case eStopReasonPlanComplete:
661 if (!plan_thread.IsValid())
662 plan_thread = thread;
663 break;
664 }
665 }
666 if (plan_thread.IsValid())
667 process.SetCurrentThread (plan_thread);
668 else if (other_thread.IsValid())
669 process.SetCurrentThread (other_thread);
670 else
671 {
672 if (curr_thread.IsValid())
673 thread = curr_thread;
674 else
675 thread = process.GetThreadAtIndex(0);
676
677 if (thread.IsValid())
678 process.SetCurrentThread (thread);
679 }
680 }
681 }
682}
683
684
685// This function handles events that were broadcast by the process.
686void
687Driver::HandleProcessEvent (const SBEvent &event)
688{
689 using namespace lldb;
690 const uint32_t event_type = event.GetType();
691
692 if (event_type & SBProcess::eBroadcastBitSTDOUT)
693 {
694 // The process has stdout available, get it and write it out to the
695 // appropriate place.
696 GetProcessSTDOUT ();
697 }
698 else if (event_type & SBProcess::eBroadcastBitSTDERR)
699 {
700 // The process has stderr available, get it and write it out to the
701 // appropriate place.
702 GetProcessSTDERR ();
703 }
704 else if (event_type & SBProcess::eBroadcastBitStateChanged)
705 {
706 // Drain all stout and stderr so we don't see any output come after
707 // we print our prompts
708 GetProcessSTDOUT ();
709 GetProcessSTDERR ();
710
711 // Something changed in the process; get the event and report the process's current status and location to
712 // the user.
713 StateType event_state = SBProcess::GetStateFromEvent (event);
714 if (event_state == eStateInvalid)
715 return;
716
717 SBProcess process (SBProcess::GetProcessFromEvent (event));
718 assert (process.IsValid());
719
720 switch (event_state)
721 {
722 case eStateInvalid:
723 case eStateUnloaded:
724 case eStateAttaching:
725 case eStateLaunching:
726 case eStateStepping:
727 case eStateDetached:
728 {
729 char message[1024];
730 int message_len = ::snprintf (message, sizeof(message), "Process %d %s\n", process.GetProcessID(),
Greg Clayton63094e02010-06-23 01:19:29 +0000731 m_debugger.StateAsCString (event_state));
Chris Lattner24943d22010-06-08 16:52:24 +0000732 m_io_channel_ap->OutWrite(message, message_len);
733 }
734 break;
735
736 case eStateRunning:
737 // Don't be chatty when we run...
738 break;
739
740 case eStateExited:
Greg Clayton63094e02010-06-23 01:19:29 +0000741 m_debugger.HandleCommand("process status");
Chris Lattner24943d22010-06-08 16:52:24 +0000742 m_io_channel_ap->RefreshPrompt();
743 break;
744
745 case eStateStopped:
746 case eStateCrashed:
747 case eStateSuspended:
748 // Make sure the program hasn't been auto-restarted:
749 if (SBProcess::GetRestartedFromEvent (event))
750 {
751 // FIXME: Do we want to report this, or would that just be annoyingly chatty?
752 char message[1024];
753 int message_len = ::snprintf (message, sizeof(message), "Process %d stopped and was programmatically restarted.\n",
754 process.GetProcessID());
755 m_io_channel_ap->OutWrite(message, message_len);
756 }
757 else
758 {
759 UpdateCurrentThread ();
Greg Clayton63094e02010-06-23 01:19:29 +0000760 m_debugger.HandleCommand("process status");
Chris Lattner24943d22010-06-08 16:52:24 +0000761 m_io_channel_ap->RefreshPrompt();
762 }
763 break;
764 }
765 }
766}
767
768// This function handles events broadcast by the IOChannel (HasInput, UserInterrupt, or ThreadShouldExit).
769
770bool
771Driver::HandleIOEvent (const SBEvent &event)
772{
773 bool quit = false;
774
775 const uint32_t event_type = event.GetType();
776
777 if (event_type & IOChannel::eBroadcastBitHasUserInput)
778 {
779 // We got some input (i.e. a command string) from the user; pass it off to the command interpreter for
780 // handling.
781
782 const char *command_string = SBEvent::GetCStringFromEvent(event);
783 if (command_string == NULL)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000784 command_string = "";
Chris Lattner24943d22010-06-08 16:52:24 +0000785 SBCommandReturnObject result;
Greg Clayton63094e02010-06-23 01:19:29 +0000786 if (m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, true) != lldb::eReturnStatusQuit)
Chris Lattner24943d22010-06-08 16:52:24 +0000787 {
788 m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize());
789 m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize());
790 }
791 // We are done getting and running our command, we can now clear the
792 // m_waiting_for_command so we can get another one.
793 m_waiting_for_command = false;
794
795 // If our editline input reader is active, it means another input reader
796 // got pushed onto the input reader and caused us to become deactivated.
797 // When the input reader above us gets popped, we will get re-activated
798 // and our prompt will refresh in our callback
799 if (m_editline_reader.IsActive())
800 {
801 ReadyForCommand ();
802 }
803 }
804 else if (event_type & IOChannel::eBroadcastBitUserInterrupt)
805 {
806 // This is here to handle control-c interrupts from the user. It has not yet really been implemented.
807 // TO BE DONE: PROPERLY HANDLE CONTROL-C FROM USER
808 //m_io_channel_ap->CancelInput();
809 // Anything else? Send Interrupt to process?
810 }
811 else if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) ||
812 (event_type & IOChannel::eBroadcastBitThreadDidExit))
813 {
814 // If the IOChannel thread is trying to go away, then it is definitely
815 // time to end the debugging session.
816 quit = true;
817 }
818
819 return quit;
820}
821
822
823//struct CrashImageInfo
824//{
825// std::string path;
826// VMRange text_range;
827// UUID uuid;
828//};
829//
830//void
831//Driver::ParseCrashLog (const char *crash_log)
832//{
833// printf("Parsing crash log: %s\n", crash_log);
834//
835// char image_path[PATH_MAX];
836// std::vector<CrashImageInfo> crash_infos;
837// if (crash_log && crash_log[0])
838// {
839// FileSpec crash_log_file (crash_log);
840// STLStringArray crash_log_lines;
841// if (crash_log_file.ReadFileLines (crash_log_lines))
842// {
843// const size_t num_crash_log_lines = crash_log_lines.size();
844// size_t i;
845// for (i=0; i<num_crash_log_lines; ++i)
846// {
847// const char *line = crash_log_lines[i].c_str();
848// if (strstr (line, "Code Type:"))
849// {
850// char arch_string[256];
851// if (sscanf(line, "%s", arch_string))
852// {
853// if (strcmp(arch_string, "X86-64"))
854// lldb::GetDefaultArchitecture ().SetArch ("x86_64");
855// else if (strcmp(arch_string, "X86"))
856// lldb::GetDefaultArchitecture ().SetArch ("i386");
857// else
858// {
859// ArchSpec arch(arch_string);
860// if (arch.IsValid ())
861// lldb::GetDefaultArchitecture () = arch;
862// else
863// fprintf(stderr, "Unrecognized architecture: %s\n", arch_string);
864// }
865// }
866// }
867// else
868// if (strstr(line, "Path:"))
869// {
870// const char *p = line + strlen("Path:");
871// while (isspace(*p))
872// ++p;
873//
874// m_option_data.m_filename.assign (p);
875// }
876// else
877// if (strstr(line, "Binary Images:"))
878// {
879// while (++i < num_crash_log_lines)
880// {
881// if (crash_log_lines[i].empty())
882// break;
883//
884// line = crash_log_lines[i].c_str();
885// uint64_t text_start_addr;
886// uint64_t text_end_addr;
887// char uuid_cstr[64];
888// int bytes_consumed_before_uuid = 0;
889// int bytes_consumed_after_uuid = 0;
890//
891// int items_parsed = ::sscanf (line,
892// "%llx - %llx %*s %*s %*s %n%s %n",
893// &text_start_addr,
894// &text_end_addr,
895// &bytes_consumed_before_uuid,
896// uuid_cstr,
897// &bytes_consumed_after_uuid);
898//
899// if (items_parsed == 3)
900// {
901//
902// CrashImageInfo info;
903// info.text_range.SetBaseAddress(text_start_addr);
904// info.text_range.SetEndAddress(text_end_addr);
905//
906// if (uuid_cstr[0] == '<')
907// {
908// if (info.uuid.SetfromCString (&uuid_cstr[1]) == 0)
909// info.uuid.Clear();
910//
911// ::strncpy (image_path, line + bytes_consumed_after_uuid, sizeof(image_path));
912// }
913// else
914// {
915// ::strncpy (image_path, line + bytes_consumed_before_uuid, sizeof(image_path));
916// }
917//
918// info.path = image_path;
919//
920// crash_infos.push_back (info);
921//
922// info.uuid.GetAsCString(uuid_cstr, sizeof(uuid_cstr));
923//
924// printf("0x%16.16llx - 0x%16.16llx <%s> %s\n",
925// text_start_addr,
926// text_end_addr,
927// uuid_cstr,
928// image_path);
929// }
930// }
931// }
932// }
933// }
934//
935// if (crash_infos.size())
936// {
Greg Clayton63094e02010-06-23 01:19:29 +0000937// SBTarget target (m_debugger.CreateTarget (crash_infos.front().path.c_str(),
Chris Lattner24943d22010-06-08 16:52:24 +0000938// lldb::GetDefaultArchitecture().AsCString (),
939// false));
940// if (target.IsValid())
941// {
942//
943// }
944// }
945// }
946//}
947//
948
949void
950Driver::MasterThreadBytesReceived (void *baton, const void *src, size_t src_len)
951{
952 Driver *driver = (Driver*)baton;
953 driver->GetFromMaster ((const char *)src, src_len);
954}
955
956void
957Driver::GetFromMaster (const char *src, size_t src_len)
958{
959 // Echo the characters back to the Debugger's stdout, that way if you
960 // type characters while a command is running, you'll see what you've typed.
Greg Clayton63094e02010-06-23 01:19:29 +0000961 FILE *out_fh = m_debugger.GetOutputFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000962 if (out_fh)
963 ::fwrite (src, 1, src_len, out_fh);
964}
965
966size_t
967Driver::EditLineInputReaderCallback
968(
969 void *baton,
970 SBInputReader *reader,
971 InputReaderAction notification,
972 const char *bytes,
973 size_t bytes_len
974)
975{
976 Driver *driver = (Driver *)baton;
977
978 switch (notification)
979 {
980 case eInputReaderActivate:
981 break;
982
983 case eInputReaderReactivate:
984 driver->ReadyForCommand();
985 break;
986
987 case eInputReaderDeactivate:
988 break;
989
990 case eInputReaderGotToken:
991 write (driver->m_editline_pty.GetMasterFileDescriptor(), bytes, bytes_len);
992 break;
993
994 case eInputReaderDone:
995 break;
996 }
997 return bytes_len;
998}
999
1000void
1001Driver::MainLoop ()
1002{
1003 char error_str[1024];
1004 if (m_editline_pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, error_str, sizeof(error_str)) == false)
1005 {
1006 ::fprintf (stderr, "error: failed to open driver pseudo terminal : %s", error_str);
1007 exit(1);
1008 }
1009 else
1010 {
1011 const char *driver_slave_name = m_editline_pty.GetSlaveName (error_str, sizeof(error_str));
1012 if (driver_slave_name == NULL)
1013 {
1014 ::fprintf (stderr, "error: failed to get slave name for driver pseudo terminal : %s", error_str);
1015 exit(2);
1016 }
1017 else
1018 {
1019 m_editline_slave_fh = ::fopen (driver_slave_name, "r+");
1020 if (m_editline_slave_fh == NULL)
1021 {
1022 SBError error;
1023 error.SetErrorToErrno();
1024 ::fprintf (stderr, "error: failed to get open slave for driver pseudo terminal : %s",
1025 error.GetCString());
1026 exit(3);
1027 }
1028
1029 ::setbuf (m_editline_slave_fh, NULL);
1030 }
1031 }
1032
1033
1034 // struct termios stdin_termios;
1035
1036 if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0)
1037 atexit (reset_stdin_termios);
1038
1039 ::setbuf (stdin, NULL);
1040 ::setbuf (stdout, NULL);
1041
Greg Clayton63094e02010-06-23 01:19:29 +00001042 m_debugger.SetErrorFileHandle (stderr, false);
1043 m_debugger.SetOutputFileHandle (stdout, false);
1044 m_debugger.SetInputFileHandle (stdin, true);
Chris Lattner24943d22010-06-08 16:52:24 +00001045
1046 // You have to drain anything that comes to the master side of the PTY. master_out_comm is
1047 // for that purpose. The reason you need to do this is a curious reason... editline will echo
1048 // characters to the PTY when it gets characters while el_gets is not running, and then when
1049 // you call el_gets (or el_getc) it will try to reset the terminal back to raw mode which blocks
1050 // if there are unconsumed characters in the out buffer.
1051 // However, you don't need to do anything with the characters, since editline will dump these
1052 // unconsumed characters after printing the prompt again in el_gets.
1053
1054 SBCommunication master_out_comm("driver.editline");
1055 master_out_comm.AdoptFileDesriptor(m_editline_pty.GetMasterFileDescriptor(), false);
1056 master_out_comm.SetReadThreadBytesReceivedCallback(Driver::MasterThreadBytesReceived, this);
1057
1058 if (master_out_comm.ReadThreadStart () == false)
1059 {
1060 ::fprintf (stderr, "error: failed to start master out read thread");
1061 exit(5);
1062 }
1063
1064// const char *crash_log = GetCrashLogFilename();
1065// if (crash_log)
1066// {
1067// ParseCrashLog (crash_log);
1068// }
1069//
Greg Clayton63094e02010-06-23 01:19:29 +00001070 SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
Chris Lattner24943d22010-06-08 16:52:24 +00001071
1072 m_io_channel_ap.reset (new IOChannel(m_editline_slave_fh, stdout, stderr, this));
1073
1074 struct winsize window_size;
1075 if (isatty (STDIN_FILENO)
1076 && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
1077 {
1078 char buffer[25];
1079
1080 sprintf (buffer, "set term-width %d", window_size.ws_col);
Greg Clayton63094e02010-06-23 01:19:29 +00001081 m_debugger.HandleCommand ((const char *) buffer);
Chris Lattner24943d22010-06-08 16:52:24 +00001082 }
1083
1084 // Since input can be redirected by the debugger, we must insert our editline
1085 // input reader in the queue so we know when our reader should be active
1086 // and so we can receive bytes only when we are supposed to.
Greg Clayton63094e02010-06-23 01:19:29 +00001087 SBError err (m_editline_reader.Initialize (m_debugger,
1088 Driver::EditLineInputReaderCallback, // callback
Chris Lattner24943d22010-06-08 16:52:24 +00001089 this, // baton
1090 eInputReaderGranularityByte, // token_size
1091 NULL, // end token - NULL means never done
1092 NULL, // prompt - taken care of elsewhere
1093 false)); // echo input - don't need Debugger
1094 // to do this, we handle it elsewhere
1095
1096 if (err.Fail())
1097 {
1098 ::fprintf (stderr, "error: %s", err.GetCString());
1099 exit (6);
1100 }
1101
Greg Clayton63094e02010-06-23 01:19:29 +00001102 m_debugger.PushInputReader (m_editline_reader);
Chris Lattner24943d22010-06-08 16:52:24 +00001103
Greg Clayton63094e02010-06-23 01:19:29 +00001104 SBListener listener(m_debugger.GetListener());
Chris Lattner24943d22010-06-08 16:52:24 +00001105 if (listener.IsValid())
1106 {
1107
1108 listener.StartListeningForEvents (*m_io_channel_ap,
1109 IOChannel::eBroadcastBitHasUserInput |
1110 IOChannel::eBroadcastBitUserInterrupt |
1111 IOChannel::eBroadcastBitThreadShouldExit |
1112 IOChannel::eBroadcastBitThreadDidStart |
1113 IOChannel::eBroadcastBitThreadDidExit);
1114
1115 if (m_io_channel_ap->Start ())
1116 {
1117 bool iochannel_thread_exited = false;
1118
1119 listener.StartListeningForEvents (sb_interpreter.GetBroadcaster(),
1120 SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
1121
1122 // Before we handle any options from the command line, we parse the
1123 // .lldbinit file in the user's home directory.
1124 SBCommandReturnObject result;
1125 sb_interpreter.SourceInitFileInHomeDirectory(result);
1126 if (GetDebugMode())
1127 {
Greg Clayton63094e02010-06-23 01:19:29 +00001128 result.PutError (m_debugger.GetErrorFileHandle());
1129 result.PutOutput (m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001130 }
1131
1132 // Now we handle options we got from the command line
1133 char command_string[PATH_MAX * 2];
1134 const size_t num_source_command_files = GetNumSourceCommandFiles();
1135 if (num_source_command_files > 0)
1136 {
1137 for (size_t i=0; i < num_source_command_files; ++i)
1138 {
1139 const char *command_file = GetSourceCommandFileAtIndex(i);
Johnny Chen7c984242010-07-28 21:16:11 +00001140 ::snprintf (command_string, sizeof(command_string), "command source '%s'", command_file);
Greg Clayton63094e02010-06-23 01:19:29 +00001141 m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, false);
Chris Lattner24943d22010-06-08 16:52:24 +00001142 if (GetDebugMode())
1143 {
Greg Clayton63094e02010-06-23 01:19:29 +00001144 result.PutError (m_debugger.GetErrorFileHandle());
1145 result.PutOutput (m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001146 }
1147 }
1148 }
1149
1150 if (!m_option_data.m_filename.empty())
1151 {
1152 char arch_name[64];
Greg Clayton63094e02010-06-23 01:19:29 +00001153 if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name)))
Chris Lattner24943d22010-06-08 16:52:24 +00001154 ::snprintf (command_string, sizeof (command_string), "file --arch=%s '%s'", arch_name,
1155 m_option_data.m_filename.c_str());
1156 else
1157 ::snprintf (command_string, sizeof(command_string), "file '%s'", m_option_data.m_filename.c_str());
1158
Greg Clayton63094e02010-06-23 01:19:29 +00001159 m_debugger.HandleCommand (command_string);
Chris Lattner24943d22010-06-08 16:52:24 +00001160 }
1161
1162 // Now that all option parsing is done, we try and parse the .lldbinit
1163 // file in the current working directory
1164 sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result);
1165 if (GetDebugMode())
1166 {
Greg Clayton63094e02010-06-23 01:19:29 +00001167 result.PutError(m_debugger.GetErrorFileHandle());
1168 result.PutOutput(m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001169 }
1170
1171 SBEvent event;
1172
1173 // Make sure the IO channel is started up before we try to tell it we
1174 // are ready for input
1175 listener.WaitForEventForBroadcasterWithType (UINT32_MAX,
1176 *m_io_channel_ap,
1177 IOChannel::eBroadcastBitThreadDidStart,
1178 event);
1179
1180 ReadyForCommand ();
1181
1182 bool done = false;
1183 while (!done)
1184 {
1185 listener.WaitForEvent (UINT32_MAX, event);
1186 if (event.IsValid())
1187 {
1188 if (event.GetBroadcaster().IsValid())
1189 {
1190 uint32_t event_type = event.GetType();
1191 if (event.BroadcasterMatchesRef (*m_io_channel_ap))
1192 {
1193 if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) ||
1194 (event_type & IOChannel::eBroadcastBitThreadDidExit))
1195 {
1196 done = true;
1197 if (event_type & IOChannel::eBroadcastBitThreadDidExit)
1198 iochannel_thread_exited = true;
1199 break;
1200 }
1201 else
1202 done = HandleIOEvent (event);
1203 }
Greg Clayton63094e02010-06-23 01:19:29 +00001204 else if (event.BroadcasterMatchesRef (m_debugger.GetCurrentTarget().GetProcess().GetBroadcaster()))
Chris Lattner24943d22010-06-08 16:52:24 +00001205 {
1206 HandleProcessEvent (event);
1207 }
1208 else if (event.BroadcasterMatchesRef (sb_interpreter.GetBroadcaster()))
1209 {
1210 if (event_type & SBCommandInterpreter::eBroadcastBitQuitCommandReceived)
1211 done = true;
1212 }
1213 }
1214 }
1215 }
1216
1217 reset_stdin_termios ();
1218
1219 CloseIOChannelFile ();
1220
1221 if (!iochannel_thread_exited)
1222 {
Greg Claytonbef15832010-07-14 00:18:15 +00001223 event.Clear();
Chris Lattner24943d22010-06-08 16:52:24 +00001224 listener.GetNextEventForBroadcasterWithType (*m_io_channel_ap,
1225 IOChannel::eBroadcastBitThreadDidExit,
1226 event);
1227 if (!event.IsValid())
1228 {
1229 // Send end EOF to the driver file descriptor
1230 m_io_channel_ap->Stop();
1231 }
1232 }
1233
Greg Clayton63094e02010-06-23 01:19:29 +00001234 SBProcess process = m_debugger.GetCurrentTarget().GetProcess();
Chris Lattner24943d22010-06-08 16:52:24 +00001235 if (process.IsValid())
1236 process.Destroy();
1237 }
1238 }
1239}
1240
1241
1242void
1243Driver::ReadyForCommand ()
1244{
1245 if (m_waiting_for_command == false)
1246 {
1247 m_waiting_for_command = true;
1248 BroadcastEventByType (Driver::eBroadcastBitReadyForInput, true);
1249 }
1250}
1251
1252
1253int
1254main (int argc, char const *argv[])
1255{
Chris Lattner24943d22010-06-08 16:52:24 +00001256 SBDebugger::Initialize();
1257
1258 SBHostOS::ThreadCreated ("[main]");
1259
Greg Clayton63094e02010-06-23 01:19:29 +00001260 // Create a scope for driver so that the driver object will destroy itself
1261 // before SBDebugger::Terminate() is called.
Chris Lattner24943d22010-06-08 16:52:24 +00001262 {
Greg Clayton63094e02010-06-23 01:19:29 +00001263 Driver driver;
1264
1265 bool exit = false;
1266 SBError error (driver.ParseArgs (argc, argv, stdout, exit));
1267 if (error.Fail())
1268 {
1269 const char *error_cstr = error.GetCString ();
1270 if (error_cstr)
1271 ::fprintf (stderr, "error: %s\n", error_cstr);
1272 }
1273 else if (!exit)
1274 {
1275 driver.MainLoop ();
1276 }
Chris Lattner24943d22010-06-08 16:52:24 +00001277 }
1278
1279 SBDebugger::Terminate();
1280 return 0;
1281}