blob: 260257fdb0bbfbffb221339663fe5c1b6561da70 [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
Jim Ingham74989e82010-08-30 19:44:40 +000073 { LLDB_OPT_SET_ALL, false, "editor", 'e', no_argument, NULL, NULL, "<external-editor>",
74 "Tells the debugger to open source files using the host's \"external editor\" mechanism." },
75
Greg Clayton12bec712010-06-28 21:30:43 +000076// { LLDB_OPT_SET_4, true, "crash-log", 'c', required_argument, NULL, NULL, "<file>",
77// "Load executable images from a crash log for symbolication." },
Chris Lattner24943d22010-06-08 16:52:24 +000078
79 { 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL }
80};
81
82
83Driver::Driver () :
84 SBBroadcaster ("Driver"),
Greg Clayton63094e02010-06-23 01:19:29 +000085 m_debugger (SBDebugger::Create()),
Chris Lattner24943d22010-06-08 16:52:24 +000086 m_editline_pty (),
87 m_editline_slave_fh (NULL),
88 m_editline_reader (),
89 m_io_channel_ap (),
90 m_option_data (),
91 m_waiting_for_command (false)
92{
93}
94
95Driver::~Driver ()
96{
97}
98
99void
100Driver::CloseIOChannelFile ()
101{
102 // Write and End of File sequence to the file descriptor to ensure any
103 // read functions can exit.
104 char eof_str[] = "\x04";
105 ::write (m_editline_pty.GetMasterFileDescriptor(), eof_str, strlen(eof_str));
106
107 m_editline_pty.CloseMasterFileDescriptor();
108
109 if (m_editline_slave_fh)
110 {
111 ::fclose (m_editline_slave_fh);
112 m_editline_slave_fh = NULL;
113 }
114}
115
Greg Clayton54e7afa2010-07-09 20:39:50 +0000116// This function takes INDENT, which tells how many spaces to output at the front
117// of each line; TEXT, which is the text that is to be output. It outputs the
118// text, on multiple lines if necessary, to RESULT, with INDENT spaces at the
119// front of each line. It breaks lines on spaces, tabs or newlines, shortening
120// the line if necessary to not break in the middle of a word. It assumes that
121// each output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
Chris Lattner24943d22010-06-08 16:52:24 +0000122
123void
Greg Clayton54e7afa2010-07-09 20:39:50 +0000124OutputFormattedUsageText (FILE *out, int indent, const char *text, int output_max_columns)
Chris Lattner24943d22010-06-08 16:52:24 +0000125{
126 int len = strlen (text);
127 std::string text_string (text);
Chris Lattner24943d22010-06-08 16:52:24 +0000128
129 // Force indentation to be reasonable.
130 if (indent >= output_max_columns)
131 indent = 0;
132
133 // Will it all fit on one line?
134
135 if (len + indent < output_max_columns)
136 // Output as a single line
Greg Clayton54e7afa2010-07-09 20:39:50 +0000137 fprintf (out, "%*s%s\n", indent, "", text);
Chris Lattner24943d22010-06-08 16:52:24 +0000138 else
139 {
140 // We need to break it up into multiple lines.
141 int text_width = output_max_columns - indent - 1;
142 int start = 0;
143 int end = start;
144 int final_end = len;
145 int sub_len;
146
147 while (end < final_end)
148 {
149 // Dont start the 'text' on a space, since we're already outputting the indentation.
150 while ((start < final_end) && (text[start] == ' '))
151 start++;
152
153 end = start + text_width;
154 if (end > final_end)
155 end = final_end;
156 else
157 {
158 // If we're not at the end of the text, make sure we break the line on white space.
159 while (end > start
160 && text[end] != ' ' && text[end] != '\t' && text[end] != '\n')
161 end--;
162 }
163 sub_len = end - start;
164 std::string substring = text_string.substr (start, sub_len);
Greg Clayton54e7afa2010-07-09 20:39:50 +0000165 fprintf (out, "%*s%s\n", indent, "", substring.c_str());
Chris Lattner24943d22010-06-08 16:52:24 +0000166 start = end + 1;
167 }
168 }
169}
170
171void
172ShowUsage (FILE *out, lldb::OptionDefinition *option_table, Driver::OptionData data)
173{
174 uint32_t screen_width = 80;
175 uint32_t indent_level = 0;
176 const char *name = "lldb";
Jim Ingham34e9a982010-06-15 18:47:14 +0000177
Chris Lattner24943d22010-06-08 16:52:24 +0000178 fprintf (out, "\nUsage:\n\n");
179
180 indent_level += 2;
181
182
183 // First, show each usage level set of options, e.g. <cmd> [options-for-level-0]
184 // <cmd> [options-for-level-1]
185 // etc.
186
Chris Lattner24943d22010-06-08 16:52:24 +0000187 uint32_t num_options;
Jim Ingham34e9a982010-06-15 18:47:14 +0000188 uint32_t num_option_sets = 0;
189
190 for (num_options = 0; option_table[num_options].long_option != NULL; ++num_options)
Chris Lattner24943d22010-06-08 16:52:24 +0000191 {
Jim Ingham34e9a982010-06-15 18:47:14 +0000192 uint32_t this_usage_mask = option_table[num_options].usage_mask;
193 if (this_usage_mask == LLDB_OPT_SET_ALL)
Chris Lattner24943d22010-06-08 16:52:24 +0000194 {
Jim Ingham34e9a982010-06-15 18:47:14 +0000195 if (num_option_sets == 0)
196 num_option_sets = 1;
Chris Lattner24943d22010-06-08 16:52:24 +0000197 }
198 else
199 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000200 for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++)
Jim Ingham34e9a982010-06-15 18:47:14 +0000201 {
202 if (this_usage_mask & 1 << j)
203 {
204 if (num_option_sets <= j)
205 num_option_sets = j + 1;
206 }
207 }
208 }
209 }
210
211 for (uint32_t opt_set = 0; opt_set < num_option_sets; opt_set++)
212 {
213 uint32_t opt_set_mask;
214
215 opt_set_mask = 1 << opt_set;
216
217 if (opt_set > 0)
218 fprintf (out, "\n");
Greg Clayton54e7afa2010-07-09 20:39:50 +0000219 fprintf (out, "%*s%s", indent_level, "", name);
Jim Ingham34e9a982010-06-15 18:47:14 +0000220
221 for (uint32_t i = 0; i < num_options; ++i)
222 {
223 if (option_table[i].usage_mask & opt_set_mask)
224 {
225 if (option_table[i].required)
226 {
227 if (option_table[i].option_has_arg == required_argument)
228 fprintf (out, " -%c %s", option_table[i].short_option, option_table[i].argument_name);
229 else if (option_table[i].option_has_arg == optional_argument)
230 fprintf (out, " -%c [%s]", option_table[i].short_option, option_table[i].argument_name);
231 else
232 fprintf (out, " -%c", option_table[i].short_option);
233 }
234 else
235 {
236 if (option_table[i].option_has_arg == required_argument)
237 fprintf (out, " [-%c %s]", option_table[i].short_option, option_table[i].argument_name);
238 else if (option_table[i].option_has_arg == optional_argument)
239 fprintf (out, " [-%c [%s]]", option_table[i].short_option, option_table[i].argument_name);
240 else
241 fprintf (out, " [-%c]", option_table[i].short_option);
242 }
243 }
Chris Lattner24943d22010-06-08 16:52:24 +0000244 }
245 }
246
247 fprintf (out, "\n\n");
248
249 // Now print out all the detailed information about the various options: long form, short form and help text:
250 // -- long_name <argument>
251 // - short <argument>
252 // help text
253
254 // This variable is used to keep track of which options' info we've printed out, because some options can be in
255 // more than one usage level, but we only want to print the long form of its information once.
256
257 Driver::OptionData::OptionSet options_seen;
258 Driver::OptionData::OptionSet::iterator pos;
259
260 indent_level += 5;
261
Jim Ingham34e9a982010-06-15 18:47:14 +0000262 for (uint32_t i = 0; i < num_options; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000263 {
264 // Only print this option if we haven't already seen it.
265 pos = options_seen.find (option_table[i].short_option);
266 if (pos == options_seen.end())
267 {
268 options_seen.insert (option_table[i].short_option);
Greg Clayton54e7afa2010-07-09 20:39:50 +0000269 fprintf (out, "%*s-%c ", indent_level, "", option_table[i].short_option);
Chris Lattner24943d22010-06-08 16:52:24 +0000270 if (option_table[i].argument_name != NULL)
271 fprintf (out, "%s", option_table[i].argument_name);
272 fprintf (out, "\n");
Greg Clayton54e7afa2010-07-09 20:39:50 +0000273 fprintf (out, "%*s--%s ", indent_level, "", option_table[i].long_option);
Chris Lattner24943d22010-06-08 16:52:24 +0000274 if (option_table[i].argument_name != NULL)
275 fprintf (out, "%s", option_table[i].argument_name);
276 fprintf (out, "\n");
277 indent_level += 5;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000278 OutputFormattedUsageText (out, indent_level, option_table[i].usage_text, screen_width);
Chris Lattner24943d22010-06-08 16:52:24 +0000279 indent_level -= 5;
280 fprintf (out, "\n");
281 }
282 }
283
284 indent_level -= 5;
285
Greg Clayton54e7afa2010-07-09 20:39:50 +0000286 fprintf (out, "\n%*s('%s <filename>' also works, to specify the file to be debugged.)\n\n",
287 indent_level, "", name);
Chris Lattner24943d22010-06-08 16:52:24 +0000288}
289
290void
Greg Clayton54e7afa2010-07-09 20:39:50 +0000291BuildGetOptTable (lldb::OptionDefinition *expanded_option_table, struct option **getopt_table, uint32_t num_options)
Chris Lattner24943d22010-06-08 16:52:24 +0000292{
293 if (num_options == 0)
294 return;
295
296 uint32_t i;
297 uint32_t j;
298 std::bitset<256> option_seen;
299
300 for (i = 0, j = 0; i < num_options; ++i)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000301 {
Chris Lattner24943d22010-06-08 16:52:24 +0000302 char short_opt = expanded_option_table[i].short_option;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000303
Chris Lattner24943d22010-06-08 16:52:24 +0000304 if (option_seen.test(short_opt) == false)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000305 {
Chris Lattner24943d22010-06-08 16:52:24 +0000306 (*getopt_table)[j].name = expanded_option_table[i].long_option;
307 (*getopt_table)[j].has_arg = expanded_option_table[i].option_has_arg;
308 (*getopt_table)[j].flag = NULL;
309 (*getopt_table)[j].val = expanded_option_table[i].short_option;
310 option_seen.set(short_opt);
311 ++j;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000312 }
313 }
Chris Lattner24943d22010-06-08 16:52:24 +0000314
315 (*getopt_table)[j].name = NULL;
316 (*getopt_table)[j].has_arg = 0;
317 (*getopt_table)[j].flag = NULL;
318 (*getopt_table)[j].val = 0;
319
320}
321
Greg Clayton63094e02010-06-23 01:19:29 +0000322Driver::OptionData::OptionData () :
323 m_filename(),
324 m_script_lang (lldb::eScriptLanguageDefault),
Greg Clayton54e7afa2010-07-09 20:39:50 +0000325 m_crash_log (),
Greg Clayton63094e02010-06-23 01:19:29 +0000326 m_source_command_files (),
327 m_debug_mode (false),
Greg Clayton54e7afa2010-07-09 20:39:50 +0000328 m_print_version (false),
Greg Clayton63094e02010-06-23 01:19:29 +0000329 m_print_help (false),
Jim Ingham74989e82010-08-30 19:44:40 +0000330 m_seen_options(),
331 m_use_external_editor(false)
Chris Lattner24943d22010-06-08 16:52:24 +0000332{
Greg Clayton63094e02010-06-23 01:19:29 +0000333}
334
335Driver::OptionData::~OptionData ()
336{
337}
338
339void
340Driver::OptionData::Clear ()
341{
342 m_filename.clear ();
343 m_script_lang = lldb::eScriptLanguageDefault;
344 m_source_command_files.clear ();
345 m_debug_mode = false;
346 m_print_help = false;
347 m_print_version = false;
Jim Ingham74989e82010-08-30 19:44:40 +0000348 m_use_external_editor = false;
Greg Clayton63094e02010-06-23 01:19:29 +0000349}
350
351void
352Driver::ResetOptionValues ()
353{
354 m_option_data.Clear ();
355}
356
357const char *
358Driver::GetFilename() const
359{
360 if (m_option_data.m_filename.empty())
361 return NULL;
362 return m_option_data.m_filename.c_str();
363}
364
365const char *
366Driver::GetCrashLogFilename() const
367{
368 if (m_option_data.m_crash_log.empty())
369 return NULL;
370 return m_option_data.m_crash_log.c_str();
371}
372
373lldb::ScriptLanguage
374Driver::GetScriptLanguage() const
375{
376 return m_option_data.m_script_lang;
377}
378
379size_t
380Driver::GetNumSourceCommandFiles () const
381{
382 return m_option_data.m_source_command_files.size();
383}
384
385const char *
386Driver::GetSourceCommandFileAtIndex (uint32_t idx) const
387{
388 if (idx < m_option_data.m_source_command_files.size())
389 return m_option_data.m_source_command_files[idx].c_str();
390 return NULL;
391}
392
393bool
394Driver::GetDebugMode() const
395{
396 return m_option_data.m_debug_mode;
397}
398
399
400// Check the arguments that were passed to this program to make sure they are valid and to get their
401// argument values (if any). Return a boolean value indicating whether or not to start up the full
402// debugger (i.e. the Command Interpreter) or not. Return FALSE if the arguments were invalid OR
403// if the user only wanted help or version information.
404
405SBError
406Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exit)
407{
408 ResetOptionValues ();
409
410 SBCommandReturnObject result;
411
Chris Lattner24943d22010-06-08 16:52:24 +0000412 SBError error;
413 std::string option_string;
414 struct option *long_options = NULL;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000415 uint32_t num_options;
Chris Lattner24943d22010-06-08 16:52:24 +0000416
Greg Clayton54e7afa2010-07-09 20:39:50 +0000417 for (num_options = 0; g_options[num_options].long_option != NULL; ++num_options)
418 /* Do Nothing. */;
Chris Lattner24943d22010-06-08 16:52:24 +0000419
420 if (num_options == 0)
421 {
422 if (argc > 1)
423 error.SetErrorStringWithFormat ("invalid number of options");
424 return error;
425 }
426
427 long_options = (struct option *) malloc ((num_options + 1) * sizeof (struct option));
428
429 BuildGetOptTable (g_options, &long_options, num_options);
430
431 if (long_options == NULL)
432 {
433 error.SetErrorStringWithFormat ("invalid long options");
434 return error;
435 }
436
437 // Build the option_string argument for call to getopt_long.
438
439 for (int i = 0; long_options[i].name != NULL; ++i)
440 {
441 if (long_options[i].flag == NULL)
442 {
443 option_string.push_back ((char) long_options[i].val);
444 switch (long_options[i].has_arg)
445 {
446 default:
447 case no_argument:
448 break;
449 case required_argument:
450 option_string.push_back (':');
451 break;
452 case optional_argument:
453 option_string.append ("::");
454 break;
455 }
456 }
457 }
458
459 // Prepare for & make calls to getopt_long.
Eli Friedmanef2bc872010-06-13 19:18:49 +0000460#if __GLIBC__
461 optind = 0;
462#else
Chris Lattner24943d22010-06-08 16:52:24 +0000463 optreset = 1;
464 optind = 1;
Eli Friedmanef2bc872010-06-13 19:18:49 +0000465#endif
Chris Lattner24943d22010-06-08 16:52:24 +0000466 int val;
467 while (1)
468 {
469 int long_options_index = -1;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000470 val = ::getopt_long (argc, const_cast<char **>(argv), option_string.c_str(), long_options, &long_options_index);
Chris Lattner24943d22010-06-08 16:52:24 +0000471
472 if (val == -1)
473 break;
474 else if (val == '?')
475 {
Greg Clayton63094e02010-06-23 01:19:29 +0000476 m_option_data.m_print_help = true;
Chris Lattner24943d22010-06-08 16:52:24 +0000477 error.SetErrorStringWithFormat ("unknown or ambiguous option");
478 break;
479 }
480 else if (val == 0)
481 continue;
482 else
483 {
Greg Clayton63094e02010-06-23 01:19:29 +0000484 m_option_data.m_seen_options.insert ((char) val);
Chris Lattner24943d22010-06-08 16:52:24 +0000485 if (long_options_index == -1)
486 {
487 for (int i = 0;
488 long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val;
489 ++i)
490 {
491 if (long_options[i].val == val)
492 {
493 long_options_index = i;
494 break;
495 }
496 }
497 }
498
499 if (long_options_index >= 0)
500 {
Greg Clayton63094e02010-06-23 01:19:29 +0000501 const char short_option = (char) g_options[long_options_index].short_option;
502
503 switch (short_option)
504 {
505 case 'h':
506 m_option_data.m_print_help = true;
507 break;
508
509 case 'v':
510 m_option_data.m_print_version = true;
511 break;
512
513 case 'c':
514 m_option_data.m_crash_log = optarg;
515 break;
Jim Ingham74989e82010-08-30 19:44:40 +0000516 case 'e':
517 m_option_data.m_use_external_editor = true;
518 break;
519
Greg Clayton63094e02010-06-23 01:19:29 +0000520 case 'f':
521 {
522 SBFileSpec file(optarg);
523 if (file.Exists())
524 m_option_data.m_filename = optarg;
525 else
526 error.SetErrorStringWithFormat("file specified in --file (-f) option doesn't exist: '%s'", optarg);
527 }
528 break;
529
530 case 'a':
531 if (!m_debugger.SetDefaultArchitecture (optarg))
532 error.SetErrorStringWithFormat("invalid architecture in the -a or --arch option: '%s'", optarg);
533 break;
534
535 case 'l':
536 m_option_data.m_script_lang = m_debugger.GetScriptingLanguage (optarg);
537 break;
538
539 case 'd':
540 m_option_data.m_debug_mode = true;
541 break;
542
543 case 's':
544 {
545 SBFileSpec file(optarg);
546 if (file.Exists())
547 m_option_data.m_source_command_files.push_back (optarg);
548 else
549 error.SetErrorStringWithFormat("file specified in --source (-s) option doesn't exist: '%s'", optarg);
550 }
551 break;
552
553 default:
554 m_option_data.m_print_help = true;
555 error.SetErrorStringWithFormat ("unrecognized option %c", short_option);
556 break;
557 }
Chris Lattner24943d22010-06-08 16:52:24 +0000558 }
559 else
560 {
561 error.SetErrorStringWithFormat ("invalid option with value %i", val);
562 }
563 if (error.Fail())
Greg Clayton63094e02010-06-23 01:19:29 +0000564 return error;
Chris Lattner24943d22010-06-08 16:52:24 +0000565 }
566 }
Jim Ingham34e9a982010-06-15 18:47:14 +0000567
568 // If there is a trailing argument, it is the filename.
569 if (optind == argc - 1)
570 {
571 if (m_option_data.m_filename.empty())
Chris Lattner24943d22010-06-08 16:52:24 +0000572 {
Jim Ingham34e9a982010-06-15 18:47:14 +0000573 m_option_data.m_filename = argv[optind];
Chris Lattner24943d22010-06-08 16:52:24 +0000574 }
Jim Ingham34e9a982010-06-15 18:47:14 +0000575 else
576 {
Greg Clayton63094e02010-06-23 01:19:29 +0000577 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 +0000578 }
579
Chris Lattner24943d22010-06-08 16:52:24 +0000580 }
Jim Ingham34e9a982010-06-15 18:47:14 +0000581 else if (optind < argc - 1)
582 {
583 // Trailing extra arguments...
Greg Clayton63094e02010-06-23 01:19:29 +0000584 error.SetErrorStringWithFormat ("error: trailing extra arguments - only one the filename is allowed.");
Jim Ingham34e9a982010-06-15 18:47:14 +0000585 }
586
Greg Clayton63094e02010-06-23 01:19:29 +0000587 if (error.Fail() || m_option_data.m_print_help)
Chris Lattner24943d22010-06-08 16:52:24 +0000588 {
589 ShowUsage (out_fh, g_options, m_option_data);
Chris Lattner24943d22010-06-08 16:52:24 +0000590 }
591 else if (m_option_data.m_print_version)
592 {
Greg Clayton63094e02010-06-23 01:19:29 +0000593 ::fprintf (out_fh, "%s\n", m_debugger.GetVersionString());
594 exit = true;
Chris Lattner24943d22010-06-08 16:52:24 +0000595 }
596 else if (! m_option_data.m_crash_log.empty())
597 {
598 // Handle crash log stuff here.
599 }
600 else
601 {
602 // All other combinations are valid; do nothing more here.
603 }
604
Greg Clayton63094e02010-06-23 01:19:29 +0000605 return error;
Chris Lattner24943d22010-06-08 16:52:24 +0000606}
607
608void
609Driver::GetProcessSTDOUT ()
610{
611 // The process has stuff waiting for stdout; get it and write it out to the appropriate place.
612 char stdio_buffer[1024];
613 size_t len;
Jim Inghamc8332952010-08-26 21:32:51 +0000614 while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
Chris Lattner24943d22010-06-08 16:52:24 +0000615 m_io_channel_ap->OutWrite (stdio_buffer, len);
616}
617
618void
619Driver::GetProcessSTDERR ()
620{
621 // The process has stuff waiting for stderr; get it and write it out to the appropriate place.
622 char stdio_buffer[1024];
623 size_t len;
Jim Inghamc8332952010-08-26 21:32:51 +0000624 while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
Chris Lattner24943d22010-06-08 16:52:24 +0000625 m_io_channel_ap->ErrWrite (stdio_buffer, len);
626}
627
628void
Jim Inghamc8332952010-08-26 21:32:51 +0000629Driver::UpdateSelectedThread ()
Chris Lattner24943d22010-06-08 16:52:24 +0000630{
631 using namespace lldb;
Jim Inghamc8332952010-08-26 21:32:51 +0000632 SBProcess process(m_debugger.GetSelectedTarget().GetProcess());
Chris Lattner24943d22010-06-08 16:52:24 +0000633 if (process.IsValid())
634 {
Jim Inghamc8332952010-08-26 21:32:51 +0000635 SBThread curr_thread (process.GetSelectedThread());
Chris Lattner24943d22010-06-08 16:52:24 +0000636 SBThread thread;
637 StopReason curr_thread_stop_reason = eStopReasonInvalid;
638 curr_thread_stop_reason = curr_thread.GetStopReason();
639
640 if (!curr_thread.IsValid() ||
641 curr_thread_stop_reason == eStopReasonInvalid ||
642 curr_thread_stop_reason == eStopReasonNone)
643 {
644 // Prefer a thread that has just completed its plan over another thread as current thread.
645 SBThread plan_thread;
646 SBThread other_thread;
647 const size_t num_threads = process.GetNumThreads();
648 size_t i;
649 for (i = 0; i < num_threads; ++i)
650 {
651 thread = process.GetThreadAtIndex(i);
652 StopReason thread_stop_reason = thread.GetStopReason();
653 switch (thread_stop_reason)
654 {
655 default:
656 case eStopReasonInvalid:
657 case eStopReasonNone:
658 break;
659
660 case eStopReasonTrace:
661 case eStopReasonBreakpoint:
662 case eStopReasonWatchpoint:
663 case eStopReasonSignal:
664 case eStopReasonException:
665 if (!other_thread.IsValid())
666 other_thread = thread;
667 break;
668 case eStopReasonPlanComplete:
669 if (!plan_thread.IsValid())
670 plan_thread = thread;
671 break;
672 }
673 }
674 if (plan_thread.IsValid())
Jim Inghamc8332952010-08-26 21:32:51 +0000675 process.SetSelectedThread (plan_thread);
Chris Lattner24943d22010-06-08 16:52:24 +0000676 else if (other_thread.IsValid())
Jim Inghamc8332952010-08-26 21:32:51 +0000677 process.SetSelectedThread (other_thread);
Chris Lattner24943d22010-06-08 16:52:24 +0000678 else
679 {
680 if (curr_thread.IsValid())
681 thread = curr_thread;
682 else
683 thread = process.GetThreadAtIndex(0);
684
685 if (thread.IsValid())
Jim Inghamc8332952010-08-26 21:32:51 +0000686 process.SetSelectedThread (thread);
Chris Lattner24943d22010-06-08 16:52:24 +0000687 }
688 }
689 }
690}
691
692
693// This function handles events that were broadcast by the process.
694void
695Driver::HandleProcessEvent (const SBEvent &event)
696{
697 using namespace lldb;
698 const uint32_t event_type = event.GetType();
699
700 if (event_type & SBProcess::eBroadcastBitSTDOUT)
701 {
702 // The process has stdout available, get it and write it out to the
703 // appropriate place.
704 GetProcessSTDOUT ();
705 }
706 else if (event_type & SBProcess::eBroadcastBitSTDERR)
707 {
708 // The process has stderr available, get it and write it out to the
709 // appropriate place.
710 GetProcessSTDERR ();
711 }
712 else if (event_type & SBProcess::eBroadcastBitStateChanged)
713 {
714 // Drain all stout and stderr so we don't see any output come after
715 // we print our prompts
716 GetProcessSTDOUT ();
717 GetProcessSTDERR ();
718
719 // Something changed in the process; get the event and report the process's current status and location to
720 // the user.
721 StateType event_state = SBProcess::GetStateFromEvent (event);
722 if (event_state == eStateInvalid)
723 return;
724
725 SBProcess process (SBProcess::GetProcessFromEvent (event));
726 assert (process.IsValid());
727
728 switch (event_state)
729 {
730 case eStateInvalid:
731 case eStateUnloaded:
732 case eStateAttaching:
733 case eStateLaunching:
734 case eStateStepping:
735 case eStateDetached:
736 {
737 char message[1024];
738 int message_len = ::snprintf (message, sizeof(message), "Process %d %s\n", process.GetProcessID(),
Greg Clayton63094e02010-06-23 01:19:29 +0000739 m_debugger.StateAsCString (event_state));
Chris Lattner24943d22010-06-08 16:52:24 +0000740 m_io_channel_ap->OutWrite(message, message_len);
741 }
742 break;
743
744 case eStateRunning:
745 // Don't be chatty when we run...
746 break;
747
748 case eStateExited:
Greg Clayton63094e02010-06-23 01:19:29 +0000749 m_debugger.HandleCommand("process status");
Chris Lattner24943d22010-06-08 16:52:24 +0000750 m_io_channel_ap->RefreshPrompt();
751 break;
752
753 case eStateStopped:
754 case eStateCrashed:
755 case eStateSuspended:
756 // Make sure the program hasn't been auto-restarted:
757 if (SBProcess::GetRestartedFromEvent (event))
758 {
759 // FIXME: Do we want to report this, or would that just be annoyingly chatty?
760 char message[1024];
761 int message_len = ::snprintf (message, sizeof(message), "Process %d stopped and was programmatically restarted.\n",
762 process.GetProcessID());
763 m_io_channel_ap->OutWrite(message, message_len);
764 }
765 else
766 {
Jim Inghamc8332952010-08-26 21:32:51 +0000767 UpdateSelectedThread ();
Greg Clayton63094e02010-06-23 01:19:29 +0000768 m_debugger.HandleCommand("process status");
Chris Lattner24943d22010-06-08 16:52:24 +0000769 m_io_channel_ap->RefreshPrompt();
770 }
771 break;
772 }
773 }
774}
775
776// This function handles events broadcast by the IOChannel (HasInput, UserInterrupt, or ThreadShouldExit).
777
778bool
779Driver::HandleIOEvent (const SBEvent &event)
780{
781 bool quit = false;
782
783 const uint32_t event_type = event.GetType();
784
785 if (event_type & IOChannel::eBroadcastBitHasUserInput)
786 {
787 // We got some input (i.e. a command string) from the user; pass it off to the command interpreter for
788 // handling.
789
790 const char *command_string = SBEvent::GetCStringFromEvent(event);
791 if (command_string == NULL)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000792 command_string = "";
Chris Lattner24943d22010-06-08 16:52:24 +0000793 SBCommandReturnObject result;
Greg Clayton63094e02010-06-23 01:19:29 +0000794 if (m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, true) != lldb::eReturnStatusQuit)
Chris Lattner24943d22010-06-08 16:52:24 +0000795 {
796 m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize());
797 m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize());
798 }
799 // We are done getting and running our command, we can now clear the
800 // m_waiting_for_command so we can get another one.
801 m_waiting_for_command = false;
802
803 // If our editline input reader is active, it means another input reader
804 // got pushed onto the input reader and caused us to become deactivated.
805 // When the input reader above us gets popped, we will get re-activated
806 // and our prompt will refresh in our callback
807 if (m_editline_reader.IsActive())
808 {
809 ReadyForCommand ();
810 }
811 }
812 else if (event_type & IOChannel::eBroadcastBitUserInterrupt)
813 {
814 // This is here to handle control-c interrupts from the user. It has not yet really been implemented.
815 // TO BE DONE: PROPERLY HANDLE CONTROL-C FROM USER
816 //m_io_channel_ap->CancelInput();
817 // Anything else? Send Interrupt to process?
818 }
819 else if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) ||
820 (event_type & IOChannel::eBroadcastBitThreadDidExit))
821 {
822 // If the IOChannel thread is trying to go away, then it is definitely
823 // time to end the debugging session.
824 quit = true;
825 }
826
827 return quit;
828}
829
830
831//struct CrashImageInfo
832//{
833// std::string path;
834// VMRange text_range;
835// UUID uuid;
836//};
837//
838//void
839//Driver::ParseCrashLog (const char *crash_log)
840//{
841// printf("Parsing crash log: %s\n", crash_log);
842//
843// char image_path[PATH_MAX];
844// std::vector<CrashImageInfo> crash_infos;
845// if (crash_log && crash_log[0])
846// {
847// FileSpec crash_log_file (crash_log);
848// STLStringArray crash_log_lines;
849// if (crash_log_file.ReadFileLines (crash_log_lines))
850// {
851// const size_t num_crash_log_lines = crash_log_lines.size();
852// size_t i;
853// for (i=0; i<num_crash_log_lines; ++i)
854// {
855// const char *line = crash_log_lines[i].c_str();
856// if (strstr (line, "Code Type:"))
857// {
858// char arch_string[256];
859// if (sscanf(line, "%s", arch_string))
860// {
861// if (strcmp(arch_string, "X86-64"))
862// lldb::GetDefaultArchitecture ().SetArch ("x86_64");
863// else if (strcmp(arch_string, "X86"))
864// lldb::GetDefaultArchitecture ().SetArch ("i386");
865// else
866// {
867// ArchSpec arch(arch_string);
868// if (arch.IsValid ())
869// lldb::GetDefaultArchitecture () = arch;
870// else
871// fprintf(stderr, "Unrecognized architecture: %s\n", arch_string);
872// }
873// }
874// }
875// else
876// if (strstr(line, "Path:"))
877// {
878// const char *p = line + strlen("Path:");
879// while (isspace(*p))
880// ++p;
881//
882// m_option_data.m_filename.assign (p);
883// }
884// else
885// if (strstr(line, "Binary Images:"))
886// {
887// while (++i < num_crash_log_lines)
888// {
889// if (crash_log_lines[i].empty())
890// break;
891//
892// line = crash_log_lines[i].c_str();
893// uint64_t text_start_addr;
894// uint64_t text_end_addr;
895// char uuid_cstr[64];
896// int bytes_consumed_before_uuid = 0;
897// int bytes_consumed_after_uuid = 0;
898//
899// int items_parsed = ::sscanf (line,
900// "%llx - %llx %*s %*s %*s %n%s %n",
901// &text_start_addr,
902// &text_end_addr,
903// &bytes_consumed_before_uuid,
904// uuid_cstr,
905// &bytes_consumed_after_uuid);
906//
907// if (items_parsed == 3)
908// {
909//
910// CrashImageInfo info;
911// info.text_range.SetBaseAddress(text_start_addr);
912// info.text_range.SetEndAddress(text_end_addr);
913//
914// if (uuid_cstr[0] == '<')
915// {
916// if (info.uuid.SetfromCString (&uuid_cstr[1]) == 0)
917// info.uuid.Clear();
918//
919// ::strncpy (image_path, line + bytes_consumed_after_uuid, sizeof(image_path));
920// }
921// else
922// {
923// ::strncpy (image_path, line + bytes_consumed_before_uuid, sizeof(image_path));
924// }
925//
926// info.path = image_path;
927//
928// crash_infos.push_back (info);
929//
930// info.uuid.GetAsCString(uuid_cstr, sizeof(uuid_cstr));
931//
932// printf("0x%16.16llx - 0x%16.16llx <%s> %s\n",
933// text_start_addr,
934// text_end_addr,
935// uuid_cstr,
936// image_path);
937// }
938// }
939// }
940// }
941// }
942//
943// if (crash_infos.size())
944// {
Greg Clayton63094e02010-06-23 01:19:29 +0000945// SBTarget target (m_debugger.CreateTarget (crash_infos.front().path.c_str(),
Chris Lattner24943d22010-06-08 16:52:24 +0000946// lldb::GetDefaultArchitecture().AsCString (),
947// false));
948// if (target.IsValid())
949// {
950//
951// }
952// }
953// }
954//}
955//
956
957void
958Driver::MasterThreadBytesReceived (void *baton, const void *src, size_t src_len)
959{
960 Driver *driver = (Driver*)baton;
961 driver->GetFromMaster ((const char *)src, src_len);
962}
963
964void
965Driver::GetFromMaster (const char *src, size_t src_len)
966{
967 // Echo the characters back to the Debugger's stdout, that way if you
968 // type characters while a command is running, you'll see what you've typed.
Greg Clayton63094e02010-06-23 01:19:29 +0000969 FILE *out_fh = m_debugger.GetOutputFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000970 if (out_fh)
971 ::fwrite (src, 1, src_len, out_fh);
972}
973
974size_t
975Driver::EditLineInputReaderCallback
976(
977 void *baton,
978 SBInputReader *reader,
979 InputReaderAction notification,
980 const char *bytes,
981 size_t bytes_len
982)
983{
984 Driver *driver = (Driver *)baton;
985
986 switch (notification)
987 {
988 case eInputReaderActivate:
989 break;
990
991 case eInputReaderReactivate:
992 driver->ReadyForCommand();
993 break;
994
995 case eInputReaderDeactivate:
996 break;
997
998 case eInputReaderGotToken:
999 write (driver->m_editline_pty.GetMasterFileDescriptor(), bytes, bytes_len);
1000 break;
1001
1002 case eInputReaderDone:
1003 break;
1004 }
1005 return bytes_len;
1006}
1007
1008void
1009Driver::MainLoop ()
1010{
1011 char error_str[1024];
1012 if (m_editline_pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, error_str, sizeof(error_str)) == false)
1013 {
1014 ::fprintf (stderr, "error: failed to open driver pseudo terminal : %s", error_str);
1015 exit(1);
1016 }
1017 else
1018 {
1019 const char *driver_slave_name = m_editline_pty.GetSlaveName (error_str, sizeof(error_str));
1020 if (driver_slave_name == NULL)
1021 {
1022 ::fprintf (stderr, "error: failed to get slave name for driver pseudo terminal : %s", error_str);
1023 exit(2);
1024 }
1025 else
1026 {
1027 m_editline_slave_fh = ::fopen (driver_slave_name, "r+");
1028 if (m_editline_slave_fh == NULL)
1029 {
1030 SBError error;
1031 error.SetErrorToErrno();
1032 ::fprintf (stderr, "error: failed to get open slave for driver pseudo terminal : %s",
1033 error.GetCString());
1034 exit(3);
1035 }
1036
1037 ::setbuf (m_editline_slave_fh, NULL);
1038 }
1039 }
1040
1041
1042 // struct termios stdin_termios;
1043
1044 if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0)
1045 atexit (reset_stdin_termios);
1046
1047 ::setbuf (stdin, NULL);
1048 ::setbuf (stdout, NULL);
1049
Greg Clayton63094e02010-06-23 01:19:29 +00001050 m_debugger.SetErrorFileHandle (stderr, false);
1051 m_debugger.SetOutputFileHandle (stdout, false);
1052 m_debugger.SetInputFileHandle (stdin, true);
Jim Ingham74989e82010-08-30 19:44:40 +00001053
1054 m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
Chris Lattner24943d22010-06-08 16:52:24 +00001055
1056 // You have to drain anything that comes to the master side of the PTY. master_out_comm is
1057 // for that purpose. The reason you need to do this is a curious reason... editline will echo
1058 // characters to the PTY when it gets characters while el_gets is not running, and then when
1059 // you call el_gets (or el_getc) it will try to reset the terminal back to raw mode which blocks
1060 // if there are unconsumed characters in the out buffer.
1061 // However, you don't need to do anything with the characters, since editline will dump these
1062 // unconsumed characters after printing the prompt again in el_gets.
1063
1064 SBCommunication master_out_comm("driver.editline");
1065 master_out_comm.AdoptFileDesriptor(m_editline_pty.GetMasterFileDescriptor(), false);
1066 master_out_comm.SetReadThreadBytesReceivedCallback(Driver::MasterThreadBytesReceived, this);
1067
1068 if (master_out_comm.ReadThreadStart () == false)
1069 {
1070 ::fprintf (stderr, "error: failed to start master out read thread");
1071 exit(5);
1072 }
1073
1074// const char *crash_log = GetCrashLogFilename();
1075// if (crash_log)
1076// {
1077// ParseCrashLog (crash_log);
1078// }
1079//
Greg Clayton63094e02010-06-23 01:19:29 +00001080 SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
Chris Lattner24943d22010-06-08 16:52:24 +00001081
1082 m_io_channel_ap.reset (new IOChannel(m_editline_slave_fh, stdout, stderr, this));
1083
1084 struct winsize window_size;
1085 if (isatty (STDIN_FILENO)
1086 && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
1087 {
1088 char buffer[25];
1089
1090 sprintf (buffer, "set term-width %d", window_size.ws_col);
Greg Clayton63094e02010-06-23 01:19:29 +00001091 m_debugger.HandleCommand ((const char *) buffer);
Chris Lattner24943d22010-06-08 16:52:24 +00001092 }
1093
1094 // Since input can be redirected by the debugger, we must insert our editline
1095 // input reader in the queue so we know when our reader should be active
1096 // and so we can receive bytes only when we are supposed to.
Greg Clayton63094e02010-06-23 01:19:29 +00001097 SBError err (m_editline_reader.Initialize (m_debugger,
1098 Driver::EditLineInputReaderCallback, // callback
Chris Lattner24943d22010-06-08 16:52:24 +00001099 this, // baton
1100 eInputReaderGranularityByte, // token_size
1101 NULL, // end token - NULL means never done
1102 NULL, // prompt - taken care of elsewhere
1103 false)); // echo input - don't need Debugger
1104 // to do this, we handle it elsewhere
1105
1106 if (err.Fail())
1107 {
1108 ::fprintf (stderr, "error: %s", err.GetCString());
1109 exit (6);
1110 }
1111
Greg Clayton63094e02010-06-23 01:19:29 +00001112 m_debugger.PushInputReader (m_editline_reader);
Chris Lattner24943d22010-06-08 16:52:24 +00001113
Greg Clayton63094e02010-06-23 01:19:29 +00001114 SBListener listener(m_debugger.GetListener());
Chris Lattner24943d22010-06-08 16:52:24 +00001115 if (listener.IsValid())
1116 {
1117
1118 listener.StartListeningForEvents (*m_io_channel_ap,
1119 IOChannel::eBroadcastBitHasUserInput |
1120 IOChannel::eBroadcastBitUserInterrupt |
1121 IOChannel::eBroadcastBitThreadShouldExit |
1122 IOChannel::eBroadcastBitThreadDidStart |
1123 IOChannel::eBroadcastBitThreadDidExit);
1124
1125 if (m_io_channel_ap->Start ())
1126 {
1127 bool iochannel_thread_exited = false;
1128
1129 listener.StartListeningForEvents (sb_interpreter.GetBroadcaster(),
1130 SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
1131
1132 // Before we handle any options from the command line, we parse the
1133 // .lldbinit file in the user's home directory.
1134 SBCommandReturnObject result;
1135 sb_interpreter.SourceInitFileInHomeDirectory(result);
1136 if (GetDebugMode())
1137 {
Greg Clayton63094e02010-06-23 01:19:29 +00001138 result.PutError (m_debugger.GetErrorFileHandle());
1139 result.PutOutput (m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001140 }
1141
1142 // Now we handle options we got from the command line
1143 char command_string[PATH_MAX * 2];
1144 const size_t num_source_command_files = GetNumSourceCommandFiles();
1145 if (num_source_command_files > 0)
1146 {
1147 for (size_t i=0; i < num_source_command_files; ++i)
1148 {
1149 const char *command_file = GetSourceCommandFileAtIndex(i);
Johnny Chen7c984242010-07-28 21:16:11 +00001150 ::snprintf (command_string, sizeof(command_string), "command source '%s'", command_file);
Greg Clayton63094e02010-06-23 01:19:29 +00001151 m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, false);
Chris Lattner24943d22010-06-08 16:52:24 +00001152 if (GetDebugMode())
1153 {
Greg Clayton63094e02010-06-23 01:19:29 +00001154 result.PutError (m_debugger.GetErrorFileHandle());
1155 result.PutOutput (m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001156 }
1157 }
1158 }
1159
1160 if (!m_option_data.m_filename.empty())
1161 {
1162 char arch_name[64];
Greg Clayton63094e02010-06-23 01:19:29 +00001163 if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name)))
Chris Lattner24943d22010-06-08 16:52:24 +00001164 ::snprintf (command_string, sizeof (command_string), "file --arch=%s '%s'", arch_name,
1165 m_option_data.m_filename.c_str());
1166 else
1167 ::snprintf (command_string, sizeof(command_string), "file '%s'", m_option_data.m_filename.c_str());
1168
Greg Clayton63094e02010-06-23 01:19:29 +00001169 m_debugger.HandleCommand (command_string);
Chris Lattner24943d22010-06-08 16:52:24 +00001170 }
1171
1172 // Now that all option parsing is done, we try and parse the .lldbinit
1173 // file in the current working directory
1174 sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result);
1175 if (GetDebugMode())
1176 {
Greg Clayton63094e02010-06-23 01:19:29 +00001177 result.PutError(m_debugger.GetErrorFileHandle());
1178 result.PutOutput(m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001179 }
1180
1181 SBEvent event;
1182
1183 // Make sure the IO channel is started up before we try to tell it we
1184 // are ready for input
1185 listener.WaitForEventForBroadcasterWithType (UINT32_MAX,
1186 *m_io_channel_ap,
1187 IOChannel::eBroadcastBitThreadDidStart,
1188 event);
1189
1190 ReadyForCommand ();
1191
1192 bool done = false;
1193 while (!done)
1194 {
1195 listener.WaitForEvent (UINT32_MAX, event);
1196 if (event.IsValid())
1197 {
1198 if (event.GetBroadcaster().IsValid())
1199 {
1200 uint32_t event_type = event.GetType();
1201 if (event.BroadcasterMatchesRef (*m_io_channel_ap))
1202 {
1203 if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) ||
1204 (event_type & IOChannel::eBroadcastBitThreadDidExit))
1205 {
1206 done = true;
1207 if (event_type & IOChannel::eBroadcastBitThreadDidExit)
1208 iochannel_thread_exited = true;
1209 break;
1210 }
1211 else
1212 done = HandleIOEvent (event);
1213 }
Jim Inghamc8332952010-08-26 21:32:51 +00001214 else if (event.BroadcasterMatchesRef (m_debugger.GetSelectedTarget().GetProcess().GetBroadcaster()))
Chris Lattner24943d22010-06-08 16:52:24 +00001215 {
1216 HandleProcessEvent (event);
1217 }
1218 else if (event.BroadcasterMatchesRef (sb_interpreter.GetBroadcaster()))
1219 {
1220 if (event_type & SBCommandInterpreter::eBroadcastBitQuitCommandReceived)
1221 done = true;
1222 }
1223 }
1224 }
1225 }
1226
1227 reset_stdin_termios ();
1228
1229 CloseIOChannelFile ();
1230
1231 if (!iochannel_thread_exited)
1232 {
Greg Claytonbef15832010-07-14 00:18:15 +00001233 event.Clear();
Chris Lattner24943d22010-06-08 16:52:24 +00001234 listener.GetNextEventForBroadcasterWithType (*m_io_channel_ap,
1235 IOChannel::eBroadcastBitThreadDidExit,
1236 event);
1237 if (!event.IsValid())
1238 {
1239 // Send end EOF to the driver file descriptor
1240 m_io_channel_ap->Stop();
1241 }
1242 }
1243
Jim Inghamc8332952010-08-26 21:32:51 +00001244 SBProcess process = m_debugger.GetSelectedTarget().GetProcess();
Chris Lattner24943d22010-06-08 16:52:24 +00001245 if (process.IsValid())
1246 process.Destroy();
1247 }
1248 }
1249}
1250
1251
1252void
1253Driver::ReadyForCommand ()
1254{
1255 if (m_waiting_for_command == false)
1256 {
1257 m_waiting_for_command = true;
1258 BroadcastEventByType (Driver::eBroadcastBitReadyForInput, true);
1259 }
1260}
1261
1262
1263int
1264main (int argc, char const *argv[])
1265{
Chris Lattner24943d22010-06-08 16:52:24 +00001266 SBDebugger::Initialize();
1267
1268 SBHostOS::ThreadCreated ("[main]");
1269
Greg Clayton63094e02010-06-23 01:19:29 +00001270 // Create a scope for driver so that the driver object will destroy itself
1271 // before SBDebugger::Terminate() is called.
Chris Lattner24943d22010-06-08 16:52:24 +00001272 {
Greg Clayton63094e02010-06-23 01:19:29 +00001273 Driver driver;
1274
1275 bool exit = false;
1276 SBError error (driver.ParseArgs (argc, argv, stdout, exit));
1277 if (error.Fail())
1278 {
1279 const char *error_cstr = error.GetCString ();
1280 if (error_cstr)
1281 ::fprintf (stderr, "error: %s\n", error_cstr);
1282 }
1283 else if (!exit)
1284 {
1285 driver.MainLoop ();
1286 }
Chris Lattner24943d22010-06-08 16:52:24 +00001287 }
1288
1289 SBDebugger::Terminate();
1290 return 0;
1291}