blob: 10ab1a11359321ffdb28bdb0f9ff817b671704eb [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
Caroline Ticeb8314fe2010-09-09 17:45:09 +000042static char *g_debugger_name = (char *) "";
43
Chris Lattner24943d22010-06-08 16:52:24 +000044// In the Driver::MainLoop, we change the terminal settings. This function is
45// added as an atexit handler to make sure we clean them up.
46static void
47reset_stdin_termios ()
48{
49 ::tcsetattr (STDIN_FILENO, TCSANOW, &g_old_stdin_termios);
50}
51
52static lldb::OptionDefinition g_options[] =
53{
Greg Clayton12bec712010-06-28 21:30:43 +000054 { LLDB_OPT_SET_1, true, "help", 'h', no_argument, NULL, NULL, NULL,
Chris Lattner24943d22010-06-08 16:52:24 +000055 "Prints out the usage information for the LLDB debugger." },
56
Greg Clayton12bec712010-06-28 21:30:43 +000057 { LLDB_OPT_SET_2, true, "version", 'v', no_argument, NULL, NULL, NULL,
Chris Lattner24943d22010-06-08 16:52:24 +000058 "Prints out the current version number of the LLDB debugger." },
59
Greg Clayton12bec712010-06-28 21:30:43 +000060 { LLDB_OPT_SET_3, true, "arch", 'a', required_argument, NULL, NULL, "<architecture>",
Chris Lattner24943d22010-06-08 16:52:24 +000061 "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." },
62
Jim Ingham34e9a982010-06-15 18:47:14 +000063 { 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 +000064 "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." },
65
Jim Ingham34e9a982010-06-15 18:47:14 +000066 { LLDB_OPT_SET_3 | LLDB_OPT_SET_4, false, "debug", 'd', no_argument, NULL, NULL, NULL,
Chris Lattner24943d22010-06-08 16:52:24 +000067 "Tells the debugger to print out extra information for debugging itself." },
68
Jim Ingham34e9a982010-06-15 18:47:14 +000069 { LLDB_OPT_SET_3 | LLDB_OPT_SET_4, false, "source", 's', required_argument, NULL, NULL, "<file>",
Chris Lattner24943d22010-06-08 16:52:24 +000070 "Tells the debugger to read in and execute the file <file>, which should contain lldb commands." },
71
Greg Clayton12bec712010-06-28 21:30:43 +000072 { LLDB_OPT_SET_3, true, "file", 'f', required_argument, NULL, NULL, "<filename>",
Jim Ingham34e9a982010-06-15 18:47:14 +000073 "Tells the debugger to use the file <filename> as the program to be debugged." },
74
Jim Ingham537926c2010-09-02 00:18:39 +000075 { LLDB_OPT_SET_ALL, false, "editor", 'e', no_argument, NULL, NULL, NULL,
Jim Ingham74989e82010-08-30 19:44:40 +000076 "Tells the debugger to open source files using the host's \"external editor\" mechanism." },
77
Greg Clayton12bec712010-06-28 21:30:43 +000078// { LLDB_OPT_SET_4, true, "crash-log", 'c', required_argument, NULL, NULL, "<file>",
79// "Load executable images from a crash log for symbolication." },
Chris Lattner24943d22010-06-08 16:52:24 +000080
81 { 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL }
82};
83
84
85Driver::Driver () :
86 SBBroadcaster ("Driver"),
Greg Clayton63094e02010-06-23 01:19:29 +000087 m_debugger (SBDebugger::Create()),
Chris Lattner24943d22010-06-08 16:52:24 +000088 m_editline_pty (),
89 m_editline_slave_fh (NULL),
90 m_editline_reader (),
91 m_io_channel_ap (),
92 m_option_data (),
93 m_waiting_for_command (false)
94{
Caroline Ticeb8314fe2010-09-09 17:45:09 +000095 g_debugger_name = (char *) m_debugger.GetInstanceName();
96 if (g_debugger_name == NULL)
97 g_debugger_name = (char *) "";
Chris Lattner24943d22010-06-08 16:52:24 +000098}
99
100Driver::~Driver ()
101{
102}
103
104void
105Driver::CloseIOChannelFile ()
106{
107 // Write and End of File sequence to the file descriptor to ensure any
108 // read functions can exit.
109 char eof_str[] = "\x04";
110 ::write (m_editline_pty.GetMasterFileDescriptor(), eof_str, strlen(eof_str));
111
112 m_editline_pty.CloseMasterFileDescriptor();
113
114 if (m_editline_slave_fh)
115 {
116 ::fclose (m_editline_slave_fh);
117 m_editline_slave_fh = NULL;
118 }
119}
120
Greg Clayton54e7afa2010-07-09 20:39:50 +0000121// This function takes INDENT, which tells how many spaces to output at the front
122// of each line; TEXT, which is the text that is to be output. It outputs the
123// text, on multiple lines if necessary, to RESULT, with INDENT spaces at the
124// front of each line. It breaks lines on spaces, tabs or newlines, shortening
125// the line if necessary to not break in the middle of a word. It assumes that
126// each output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
Chris Lattner24943d22010-06-08 16:52:24 +0000127
128void
Greg Clayton54e7afa2010-07-09 20:39:50 +0000129OutputFormattedUsageText (FILE *out, int indent, const char *text, int output_max_columns)
Chris Lattner24943d22010-06-08 16:52:24 +0000130{
131 int len = strlen (text);
132 std::string text_string (text);
Chris Lattner24943d22010-06-08 16:52:24 +0000133
134 // Force indentation to be reasonable.
135 if (indent >= output_max_columns)
136 indent = 0;
137
138 // Will it all fit on one line?
139
140 if (len + indent < output_max_columns)
141 // Output as a single line
Greg Clayton54e7afa2010-07-09 20:39:50 +0000142 fprintf (out, "%*s%s\n", indent, "", text);
Chris Lattner24943d22010-06-08 16:52:24 +0000143 else
144 {
145 // We need to break it up into multiple lines.
146 int text_width = output_max_columns - indent - 1;
147 int start = 0;
148 int end = start;
149 int final_end = len;
150 int sub_len;
151
152 while (end < final_end)
153 {
154 // Dont start the 'text' on a space, since we're already outputting the indentation.
155 while ((start < final_end) && (text[start] == ' '))
156 start++;
157
158 end = start + text_width;
159 if (end > final_end)
160 end = final_end;
161 else
162 {
163 // If we're not at the end of the text, make sure we break the line on white space.
164 while (end > start
165 && text[end] != ' ' && text[end] != '\t' && text[end] != '\n')
166 end--;
167 }
168 sub_len = end - start;
169 std::string substring = text_string.substr (start, sub_len);
Greg Clayton54e7afa2010-07-09 20:39:50 +0000170 fprintf (out, "%*s%s\n", indent, "", substring.c_str());
Chris Lattner24943d22010-06-08 16:52:24 +0000171 start = end + 1;
172 }
173 }
174}
175
176void
177ShowUsage (FILE *out, lldb::OptionDefinition *option_table, Driver::OptionData data)
178{
179 uint32_t screen_width = 80;
180 uint32_t indent_level = 0;
181 const char *name = "lldb";
Jim Ingham34e9a982010-06-15 18:47:14 +0000182
Chris Lattner24943d22010-06-08 16:52:24 +0000183 fprintf (out, "\nUsage:\n\n");
184
185 indent_level += 2;
186
187
188 // First, show each usage level set of options, e.g. <cmd> [options-for-level-0]
189 // <cmd> [options-for-level-1]
190 // etc.
191
Chris Lattner24943d22010-06-08 16:52:24 +0000192 uint32_t num_options;
Jim Ingham34e9a982010-06-15 18:47:14 +0000193 uint32_t num_option_sets = 0;
194
195 for (num_options = 0; option_table[num_options].long_option != NULL; ++num_options)
Chris Lattner24943d22010-06-08 16:52:24 +0000196 {
Jim Ingham34e9a982010-06-15 18:47:14 +0000197 uint32_t this_usage_mask = option_table[num_options].usage_mask;
198 if (this_usage_mask == LLDB_OPT_SET_ALL)
Chris Lattner24943d22010-06-08 16:52:24 +0000199 {
Jim Ingham34e9a982010-06-15 18:47:14 +0000200 if (num_option_sets == 0)
201 num_option_sets = 1;
Chris Lattner24943d22010-06-08 16:52:24 +0000202 }
203 else
204 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000205 for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++)
Jim Ingham34e9a982010-06-15 18:47:14 +0000206 {
207 if (this_usage_mask & 1 << j)
208 {
209 if (num_option_sets <= j)
210 num_option_sets = j + 1;
211 }
212 }
213 }
214 }
215
216 for (uint32_t opt_set = 0; opt_set < num_option_sets; opt_set++)
217 {
218 uint32_t opt_set_mask;
219
220 opt_set_mask = 1 << opt_set;
221
222 if (opt_set > 0)
223 fprintf (out, "\n");
Greg Clayton54e7afa2010-07-09 20:39:50 +0000224 fprintf (out, "%*s%s", indent_level, "", name);
Jim Ingham34e9a982010-06-15 18:47:14 +0000225
226 for (uint32_t i = 0; i < num_options; ++i)
227 {
228 if (option_table[i].usage_mask & opt_set_mask)
229 {
230 if (option_table[i].required)
231 {
232 if (option_table[i].option_has_arg == required_argument)
233 fprintf (out, " -%c %s", option_table[i].short_option, option_table[i].argument_name);
234 else if (option_table[i].option_has_arg == optional_argument)
235 fprintf (out, " -%c [%s]", option_table[i].short_option, option_table[i].argument_name);
236 else
237 fprintf (out, " -%c", option_table[i].short_option);
238 }
239 else
240 {
241 if (option_table[i].option_has_arg == required_argument)
242 fprintf (out, " [-%c %s]", option_table[i].short_option, option_table[i].argument_name);
243 else if (option_table[i].option_has_arg == optional_argument)
244 fprintf (out, " [-%c [%s]]", option_table[i].short_option, option_table[i].argument_name);
245 else
246 fprintf (out, " [-%c]", option_table[i].short_option);
247 }
248 }
Chris Lattner24943d22010-06-08 16:52:24 +0000249 }
250 }
251
252 fprintf (out, "\n\n");
253
254 // Now print out all the detailed information about the various options: long form, short form and help text:
255 // -- long_name <argument>
256 // - short <argument>
257 // help text
258
259 // This variable is used to keep track of which options' info we've printed out, because some options can be in
260 // more than one usage level, but we only want to print the long form of its information once.
261
262 Driver::OptionData::OptionSet options_seen;
263 Driver::OptionData::OptionSet::iterator pos;
264
265 indent_level += 5;
266
Jim Ingham34e9a982010-06-15 18:47:14 +0000267 for (uint32_t i = 0; i < num_options; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000268 {
269 // Only print this option if we haven't already seen it.
270 pos = options_seen.find (option_table[i].short_option);
271 if (pos == options_seen.end())
272 {
273 options_seen.insert (option_table[i].short_option);
Greg Clayton54e7afa2010-07-09 20:39:50 +0000274 fprintf (out, "%*s-%c ", indent_level, "", option_table[i].short_option);
Chris Lattner24943d22010-06-08 16:52:24 +0000275 if (option_table[i].argument_name != NULL)
276 fprintf (out, "%s", option_table[i].argument_name);
277 fprintf (out, "\n");
Greg Clayton54e7afa2010-07-09 20:39:50 +0000278 fprintf (out, "%*s--%s ", indent_level, "", option_table[i].long_option);
Chris Lattner24943d22010-06-08 16:52:24 +0000279 if (option_table[i].argument_name != NULL)
280 fprintf (out, "%s", option_table[i].argument_name);
281 fprintf (out, "\n");
282 indent_level += 5;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000283 OutputFormattedUsageText (out, indent_level, option_table[i].usage_text, screen_width);
Chris Lattner24943d22010-06-08 16:52:24 +0000284 indent_level -= 5;
285 fprintf (out, "\n");
286 }
287 }
288
289 indent_level -= 5;
290
Greg Clayton54e7afa2010-07-09 20:39:50 +0000291 fprintf (out, "\n%*s('%s <filename>' also works, to specify the file to be debugged.)\n\n",
292 indent_level, "", name);
Chris Lattner24943d22010-06-08 16:52:24 +0000293}
294
295void
Greg Clayton54e7afa2010-07-09 20:39:50 +0000296BuildGetOptTable (lldb::OptionDefinition *expanded_option_table, struct option **getopt_table, uint32_t num_options)
Chris Lattner24943d22010-06-08 16:52:24 +0000297{
298 if (num_options == 0)
299 return;
300
301 uint32_t i;
302 uint32_t j;
303 std::bitset<256> option_seen;
304
305 for (i = 0, j = 0; i < num_options; ++i)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000306 {
Chris Lattner24943d22010-06-08 16:52:24 +0000307 char short_opt = expanded_option_table[i].short_option;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000308
Chris Lattner24943d22010-06-08 16:52:24 +0000309 if (option_seen.test(short_opt) == false)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000310 {
Chris Lattner24943d22010-06-08 16:52:24 +0000311 (*getopt_table)[j].name = expanded_option_table[i].long_option;
312 (*getopt_table)[j].has_arg = expanded_option_table[i].option_has_arg;
313 (*getopt_table)[j].flag = NULL;
314 (*getopt_table)[j].val = expanded_option_table[i].short_option;
315 option_seen.set(short_opt);
316 ++j;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000317 }
318 }
Chris Lattner24943d22010-06-08 16:52:24 +0000319
320 (*getopt_table)[j].name = NULL;
321 (*getopt_table)[j].has_arg = 0;
322 (*getopt_table)[j].flag = NULL;
323 (*getopt_table)[j].val = 0;
324
325}
326
Greg Clayton63094e02010-06-23 01:19:29 +0000327Driver::OptionData::OptionData () :
328 m_filename(),
329 m_script_lang (lldb::eScriptLanguageDefault),
Greg Clayton54e7afa2010-07-09 20:39:50 +0000330 m_crash_log (),
Greg Clayton63094e02010-06-23 01:19:29 +0000331 m_source_command_files (),
332 m_debug_mode (false),
Greg Clayton54e7afa2010-07-09 20:39:50 +0000333 m_print_version (false),
Greg Clayton63094e02010-06-23 01:19:29 +0000334 m_print_help (false),
Jim Ingham74989e82010-08-30 19:44:40 +0000335 m_seen_options(),
336 m_use_external_editor(false)
Chris Lattner24943d22010-06-08 16:52:24 +0000337{
Greg Clayton63094e02010-06-23 01:19:29 +0000338}
339
340Driver::OptionData::~OptionData ()
341{
342}
343
344void
345Driver::OptionData::Clear ()
346{
347 m_filename.clear ();
348 m_script_lang = lldb::eScriptLanguageDefault;
349 m_source_command_files.clear ();
350 m_debug_mode = false;
351 m_print_help = false;
352 m_print_version = false;
Jim Ingham74989e82010-08-30 19:44:40 +0000353 m_use_external_editor = false;
Greg Clayton63094e02010-06-23 01:19:29 +0000354}
355
356void
357Driver::ResetOptionValues ()
358{
359 m_option_data.Clear ();
360}
361
362const char *
363Driver::GetFilename() const
364{
365 if (m_option_data.m_filename.empty())
366 return NULL;
367 return m_option_data.m_filename.c_str();
368}
369
370const char *
371Driver::GetCrashLogFilename() const
372{
373 if (m_option_data.m_crash_log.empty())
374 return NULL;
375 return m_option_data.m_crash_log.c_str();
376}
377
378lldb::ScriptLanguage
379Driver::GetScriptLanguage() const
380{
381 return m_option_data.m_script_lang;
382}
383
384size_t
385Driver::GetNumSourceCommandFiles () const
386{
387 return m_option_data.m_source_command_files.size();
388}
389
390const char *
391Driver::GetSourceCommandFileAtIndex (uint32_t idx) const
392{
393 if (idx < m_option_data.m_source_command_files.size())
394 return m_option_data.m_source_command_files[idx].c_str();
395 return NULL;
396}
397
398bool
399Driver::GetDebugMode() const
400{
401 return m_option_data.m_debug_mode;
402}
403
404
405// Check the arguments that were passed to this program to make sure they are valid and to get their
406// argument values (if any). Return a boolean value indicating whether or not to start up the full
407// debugger (i.e. the Command Interpreter) or not. Return FALSE if the arguments were invalid OR
408// if the user only wanted help or version information.
409
410SBError
411Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exit)
412{
413 ResetOptionValues ();
414
415 SBCommandReturnObject result;
416
Chris Lattner24943d22010-06-08 16:52:24 +0000417 SBError error;
418 std::string option_string;
419 struct option *long_options = NULL;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000420 uint32_t num_options;
Chris Lattner24943d22010-06-08 16:52:24 +0000421
Greg Clayton54e7afa2010-07-09 20:39:50 +0000422 for (num_options = 0; g_options[num_options].long_option != NULL; ++num_options)
423 /* Do Nothing. */;
Chris Lattner24943d22010-06-08 16:52:24 +0000424
425 if (num_options == 0)
426 {
427 if (argc > 1)
428 error.SetErrorStringWithFormat ("invalid number of options");
429 return error;
430 }
431
432 long_options = (struct option *) malloc ((num_options + 1) * sizeof (struct option));
433
434 BuildGetOptTable (g_options, &long_options, num_options);
435
436 if (long_options == NULL)
437 {
438 error.SetErrorStringWithFormat ("invalid long options");
439 return error;
440 }
441
442 // Build the option_string argument for call to getopt_long.
443
444 for (int i = 0; long_options[i].name != NULL; ++i)
445 {
446 if (long_options[i].flag == NULL)
447 {
448 option_string.push_back ((char) long_options[i].val);
449 switch (long_options[i].has_arg)
450 {
451 default:
452 case no_argument:
453 break;
454 case required_argument:
455 option_string.push_back (':');
456 break;
457 case optional_argument:
458 option_string.append ("::");
459 break;
460 }
461 }
462 }
463
464 // Prepare for & make calls to getopt_long.
Eli Friedmanef2bc872010-06-13 19:18:49 +0000465#if __GLIBC__
466 optind = 0;
467#else
Chris Lattner24943d22010-06-08 16:52:24 +0000468 optreset = 1;
469 optind = 1;
Eli Friedmanef2bc872010-06-13 19:18:49 +0000470#endif
Chris Lattner24943d22010-06-08 16:52:24 +0000471 int val;
472 while (1)
473 {
474 int long_options_index = -1;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000475 val = ::getopt_long (argc, const_cast<char **>(argv), option_string.c_str(), long_options, &long_options_index);
Chris Lattner24943d22010-06-08 16:52:24 +0000476
477 if (val == -1)
478 break;
479 else if (val == '?')
480 {
Greg Clayton63094e02010-06-23 01:19:29 +0000481 m_option_data.m_print_help = true;
Chris Lattner24943d22010-06-08 16:52:24 +0000482 error.SetErrorStringWithFormat ("unknown or ambiguous option");
483 break;
484 }
485 else if (val == 0)
486 continue;
487 else
488 {
Greg Clayton63094e02010-06-23 01:19:29 +0000489 m_option_data.m_seen_options.insert ((char) val);
Chris Lattner24943d22010-06-08 16:52:24 +0000490 if (long_options_index == -1)
491 {
492 for (int i = 0;
493 long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val;
494 ++i)
495 {
496 if (long_options[i].val == val)
497 {
498 long_options_index = i;
499 break;
500 }
501 }
502 }
503
504 if (long_options_index >= 0)
505 {
Greg Clayton63094e02010-06-23 01:19:29 +0000506 const char short_option = (char) g_options[long_options_index].short_option;
507
508 switch (short_option)
509 {
510 case 'h':
511 m_option_data.m_print_help = true;
512 break;
513
514 case 'v':
515 m_option_data.m_print_version = true;
516 break;
517
518 case 'c':
519 m_option_data.m_crash_log = optarg;
520 break;
Jim Ingham74989e82010-08-30 19:44:40 +0000521 case 'e':
522 m_option_data.m_use_external_editor = true;
523 break;
524
Greg Clayton63094e02010-06-23 01:19:29 +0000525 case 'f':
526 {
527 SBFileSpec file(optarg);
528 if (file.Exists())
529 m_option_data.m_filename = optarg;
530 else
531 error.SetErrorStringWithFormat("file specified in --file (-f) option doesn't exist: '%s'", optarg);
532 }
533 break;
534
535 case 'a':
536 if (!m_debugger.SetDefaultArchitecture (optarg))
537 error.SetErrorStringWithFormat("invalid architecture in the -a or --arch option: '%s'", optarg);
538 break;
539
540 case 'l':
541 m_option_data.m_script_lang = m_debugger.GetScriptingLanguage (optarg);
542 break;
543
544 case 'd':
545 m_option_data.m_debug_mode = true;
546 break;
547
548 case 's':
549 {
550 SBFileSpec file(optarg);
551 if (file.Exists())
552 m_option_data.m_source_command_files.push_back (optarg);
553 else
554 error.SetErrorStringWithFormat("file specified in --source (-s) option doesn't exist: '%s'", optarg);
555 }
556 break;
557
558 default:
559 m_option_data.m_print_help = true;
560 error.SetErrorStringWithFormat ("unrecognized option %c", short_option);
561 break;
562 }
Chris Lattner24943d22010-06-08 16:52:24 +0000563 }
564 else
565 {
566 error.SetErrorStringWithFormat ("invalid option with value %i", val);
567 }
568 if (error.Fail())
Greg Clayton63094e02010-06-23 01:19:29 +0000569 return error;
Chris Lattner24943d22010-06-08 16:52:24 +0000570 }
571 }
Jim Ingham34e9a982010-06-15 18:47:14 +0000572
573 // If there is a trailing argument, it is the filename.
574 if (optind == argc - 1)
575 {
576 if (m_option_data.m_filename.empty())
Chris Lattner24943d22010-06-08 16:52:24 +0000577 {
Jim Ingham34e9a982010-06-15 18:47:14 +0000578 m_option_data.m_filename = argv[optind];
Chris Lattner24943d22010-06-08 16:52:24 +0000579 }
Jim Ingham34e9a982010-06-15 18:47:14 +0000580 else
581 {
Greg Clayton63094e02010-06-23 01:19:29 +0000582 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 +0000583 }
584
Chris Lattner24943d22010-06-08 16:52:24 +0000585 }
Jim Ingham34e9a982010-06-15 18:47:14 +0000586 else if (optind < argc - 1)
587 {
588 // Trailing extra arguments...
Greg Clayton63094e02010-06-23 01:19:29 +0000589 error.SetErrorStringWithFormat ("error: trailing extra arguments - only one the filename is allowed.");
Jim Ingham34e9a982010-06-15 18:47:14 +0000590 }
591
Greg Clayton63094e02010-06-23 01:19:29 +0000592 if (error.Fail() || m_option_data.m_print_help)
Chris Lattner24943d22010-06-08 16:52:24 +0000593 {
594 ShowUsage (out_fh, g_options, m_option_data);
Chris Lattner24943d22010-06-08 16:52:24 +0000595 }
596 else if (m_option_data.m_print_version)
597 {
Greg Clayton63094e02010-06-23 01:19:29 +0000598 ::fprintf (out_fh, "%s\n", m_debugger.GetVersionString());
599 exit = true;
Chris Lattner24943d22010-06-08 16:52:24 +0000600 }
601 else if (! m_option_data.m_crash_log.empty())
602 {
603 // Handle crash log stuff here.
604 }
605 else
606 {
607 // All other combinations are valid; do nothing more here.
608 }
609
Greg Clayton63094e02010-06-23 01:19:29 +0000610 return error;
Chris Lattner24943d22010-06-08 16:52:24 +0000611}
612
613void
614Driver::GetProcessSTDOUT ()
615{
616 // The process has stuff waiting for stdout; get it and write it out to the appropriate place.
617 char stdio_buffer[1024];
618 size_t len;
Jim Inghamc8332952010-08-26 21:32:51 +0000619 while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
Chris Lattner24943d22010-06-08 16:52:24 +0000620 m_io_channel_ap->OutWrite (stdio_buffer, len);
621}
622
623void
624Driver::GetProcessSTDERR ()
625{
626 // The process has stuff waiting for stderr; get it and write it out to the appropriate place.
627 char stdio_buffer[1024];
628 size_t len;
Jim Inghamc8332952010-08-26 21:32:51 +0000629 while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
Chris Lattner24943d22010-06-08 16:52:24 +0000630 m_io_channel_ap->ErrWrite (stdio_buffer, len);
631}
632
633void
Jim Inghamc8332952010-08-26 21:32:51 +0000634Driver::UpdateSelectedThread ()
Chris Lattner24943d22010-06-08 16:52:24 +0000635{
636 using namespace lldb;
Jim Inghamc8332952010-08-26 21:32:51 +0000637 SBProcess process(m_debugger.GetSelectedTarget().GetProcess());
Chris Lattner24943d22010-06-08 16:52:24 +0000638 if (process.IsValid())
639 {
Jim Inghamc8332952010-08-26 21:32:51 +0000640 SBThread curr_thread (process.GetSelectedThread());
Chris Lattner24943d22010-06-08 16:52:24 +0000641 SBThread thread;
642 StopReason curr_thread_stop_reason = eStopReasonInvalid;
643 curr_thread_stop_reason = curr_thread.GetStopReason();
644
645 if (!curr_thread.IsValid() ||
646 curr_thread_stop_reason == eStopReasonInvalid ||
647 curr_thread_stop_reason == eStopReasonNone)
648 {
649 // Prefer a thread that has just completed its plan over another thread as current thread.
650 SBThread plan_thread;
651 SBThread other_thread;
652 const size_t num_threads = process.GetNumThreads();
653 size_t i;
654 for (i = 0; i < num_threads; ++i)
655 {
656 thread = process.GetThreadAtIndex(i);
657 StopReason thread_stop_reason = thread.GetStopReason();
658 switch (thread_stop_reason)
659 {
660 default:
661 case eStopReasonInvalid:
662 case eStopReasonNone:
663 break;
664
665 case eStopReasonTrace:
666 case eStopReasonBreakpoint:
667 case eStopReasonWatchpoint:
668 case eStopReasonSignal:
669 case eStopReasonException:
670 if (!other_thread.IsValid())
671 other_thread = thread;
672 break;
673 case eStopReasonPlanComplete:
674 if (!plan_thread.IsValid())
675 plan_thread = thread;
676 break;
677 }
678 }
679 if (plan_thread.IsValid())
Jim Inghamc8332952010-08-26 21:32:51 +0000680 process.SetSelectedThread (plan_thread);
Chris Lattner24943d22010-06-08 16:52:24 +0000681 else if (other_thread.IsValid())
Jim Inghamc8332952010-08-26 21:32:51 +0000682 process.SetSelectedThread (other_thread);
Chris Lattner24943d22010-06-08 16:52:24 +0000683 else
684 {
685 if (curr_thread.IsValid())
686 thread = curr_thread;
687 else
688 thread = process.GetThreadAtIndex(0);
689
690 if (thread.IsValid())
Jim Inghamc8332952010-08-26 21:32:51 +0000691 process.SetSelectedThread (thread);
Chris Lattner24943d22010-06-08 16:52:24 +0000692 }
693 }
694 }
695}
696
697
698// This function handles events that were broadcast by the process.
699void
700Driver::HandleProcessEvent (const SBEvent &event)
701{
702 using namespace lldb;
703 const uint32_t event_type = event.GetType();
704
705 if (event_type & SBProcess::eBroadcastBitSTDOUT)
706 {
707 // The process has stdout available, get it and write it out to the
708 // appropriate place.
709 GetProcessSTDOUT ();
710 }
711 else if (event_type & SBProcess::eBroadcastBitSTDERR)
712 {
713 // The process has stderr available, get it and write it out to the
714 // appropriate place.
715 GetProcessSTDERR ();
716 }
717 else if (event_type & SBProcess::eBroadcastBitStateChanged)
718 {
719 // Drain all stout and stderr so we don't see any output come after
720 // we print our prompts
721 GetProcessSTDOUT ();
722 GetProcessSTDERR ();
723
724 // Something changed in the process; get the event and report the process's current status and location to
725 // the user.
726 StateType event_state = SBProcess::GetStateFromEvent (event);
727 if (event_state == eStateInvalid)
728 return;
729
730 SBProcess process (SBProcess::GetProcessFromEvent (event));
731 assert (process.IsValid());
732
733 switch (event_state)
734 {
735 case eStateInvalid:
736 case eStateUnloaded:
737 case eStateAttaching:
738 case eStateLaunching:
739 case eStateStepping:
740 case eStateDetached:
741 {
742 char message[1024];
743 int message_len = ::snprintf (message, sizeof(message), "Process %d %s\n", process.GetProcessID(),
Greg Clayton63094e02010-06-23 01:19:29 +0000744 m_debugger.StateAsCString (event_state));
Chris Lattner24943d22010-06-08 16:52:24 +0000745 m_io_channel_ap->OutWrite(message, message_len);
746 }
747 break;
748
749 case eStateRunning:
750 // Don't be chatty when we run...
751 break;
752
753 case eStateExited:
Greg Clayton63094e02010-06-23 01:19:29 +0000754 m_debugger.HandleCommand("process status");
Chris Lattner24943d22010-06-08 16:52:24 +0000755 m_io_channel_ap->RefreshPrompt();
756 break;
757
758 case eStateStopped:
759 case eStateCrashed:
760 case eStateSuspended:
761 // Make sure the program hasn't been auto-restarted:
762 if (SBProcess::GetRestartedFromEvent (event))
763 {
764 // FIXME: Do we want to report this, or would that just be annoyingly chatty?
765 char message[1024];
766 int message_len = ::snprintf (message, sizeof(message), "Process %d stopped and was programmatically restarted.\n",
767 process.GetProcessID());
768 m_io_channel_ap->OutWrite(message, message_len);
769 }
770 else
771 {
Jim Inghamc8332952010-08-26 21:32:51 +0000772 UpdateSelectedThread ();
Greg Clayton63094e02010-06-23 01:19:29 +0000773 m_debugger.HandleCommand("process status");
Chris Lattner24943d22010-06-08 16:52:24 +0000774 m_io_channel_ap->RefreshPrompt();
775 }
776 break;
777 }
778 }
779}
780
781// This function handles events broadcast by the IOChannel (HasInput, UserInterrupt, or ThreadShouldExit).
782
783bool
784Driver::HandleIOEvent (const SBEvent &event)
785{
786 bool quit = false;
787
788 const uint32_t event_type = event.GetType();
789
790 if (event_type & IOChannel::eBroadcastBitHasUserInput)
791 {
792 // We got some input (i.e. a command string) from the user; pass it off to the command interpreter for
793 // handling.
794
795 const char *command_string = SBEvent::GetCStringFromEvent(event);
796 if (command_string == NULL)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000797 command_string = "";
Chris Lattner24943d22010-06-08 16:52:24 +0000798 SBCommandReturnObject result;
Greg Clayton63094e02010-06-23 01:19:29 +0000799 if (m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, true) != lldb::eReturnStatusQuit)
Chris Lattner24943d22010-06-08 16:52:24 +0000800 {
801 m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize());
802 m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize());
803 }
804 // We are done getting and running our command, we can now clear the
805 // m_waiting_for_command so we can get another one.
806 m_waiting_for_command = false;
807
808 // If our editline input reader is active, it means another input reader
809 // got pushed onto the input reader and caused us to become deactivated.
810 // When the input reader above us gets popped, we will get re-activated
811 // and our prompt will refresh in our callback
812 if (m_editline_reader.IsActive())
813 {
814 ReadyForCommand ();
815 }
816 }
817 else if (event_type & IOChannel::eBroadcastBitUserInterrupt)
818 {
819 // This is here to handle control-c interrupts from the user. It has not yet really been implemented.
820 // TO BE DONE: PROPERLY HANDLE CONTROL-C FROM USER
821 //m_io_channel_ap->CancelInput();
822 // Anything else? Send Interrupt to process?
823 }
824 else if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) ||
825 (event_type & IOChannel::eBroadcastBitThreadDidExit))
826 {
827 // If the IOChannel thread is trying to go away, then it is definitely
828 // time to end the debugging session.
829 quit = true;
830 }
831
832 return quit;
833}
834
835
836//struct CrashImageInfo
837//{
838// std::string path;
839// VMRange text_range;
840// UUID uuid;
841//};
842//
843//void
844//Driver::ParseCrashLog (const char *crash_log)
845//{
846// printf("Parsing crash log: %s\n", crash_log);
847//
848// char image_path[PATH_MAX];
849// std::vector<CrashImageInfo> crash_infos;
850// if (crash_log && crash_log[0])
851// {
852// FileSpec crash_log_file (crash_log);
853// STLStringArray crash_log_lines;
854// if (crash_log_file.ReadFileLines (crash_log_lines))
855// {
856// const size_t num_crash_log_lines = crash_log_lines.size();
857// size_t i;
858// for (i=0; i<num_crash_log_lines; ++i)
859// {
860// const char *line = crash_log_lines[i].c_str();
861// if (strstr (line, "Code Type:"))
862// {
863// char arch_string[256];
864// if (sscanf(line, "%s", arch_string))
865// {
866// if (strcmp(arch_string, "X86-64"))
867// lldb::GetDefaultArchitecture ().SetArch ("x86_64");
868// else if (strcmp(arch_string, "X86"))
869// lldb::GetDefaultArchitecture ().SetArch ("i386");
870// else
871// {
872// ArchSpec arch(arch_string);
873// if (arch.IsValid ())
874// lldb::GetDefaultArchitecture () = arch;
875// else
876// fprintf(stderr, "Unrecognized architecture: %s\n", arch_string);
877// }
878// }
879// }
880// else
881// if (strstr(line, "Path:"))
882// {
883// const char *p = line + strlen("Path:");
884// while (isspace(*p))
885// ++p;
886//
887// m_option_data.m_filename.assign (p);
888// }
889// else
890// if (strstr(line, "Binary Images:"))
891// {
892// while (++i < num_crash_log_lines)
893// {
894// if (crash_log_lines[i].empty())
895// break;
896//
897// line = crash_log_lines[i].c_str();
898// uint64_t text_start_addr;
899// uint64_t text_end_addr;
900// char uuid_cstr[64];
901// int bytes_consumed_before_uuid = 0;
902// int bytes_consumed_after_uuid = 0;
903//
904// int items_parsed = ::sscanf (line,
905// "%llx - %llx %*s %*s %*s %n%s %n",
906// &text_start_addr,
907// &text_end_addr,
908// &bytes_consumed_before_uuid,
909// uuid_cstr,
910// &bytes_consumed_after_uuid);
911//
912// if (items_parsed == 3)
913// {
914//
915// CrashImageInfo info;
916// info.text_range.SetBaseAddress(text_start_addr);
917// info.text_range.SetEndAddress(text_end_addr);
918//
919// if (uuid_cstr[0] == '<')
920// {
921// if (info.uuid.SetfromCString (&uuid_cstr[1]) == 0)
922// info.uuid.Clear();
923//
924// ::strncpy (image_path, line + bytes_consumed_after_uuid, sizeof(image_path));
925// }
926// else
927// {
928// ::strncpy (image_path, line + bytes_consumed_before_uuid, sizeof(image_path));
929// }
930//
931// info.path = image_path;
932//
933// crash_infos.push_back (info);
934//
935// info.uuid.GetAsCString(uuid_cstr, sizeof(uuid_cstr));
936//
937// printf("0x%16.16llx - 0x%16.16llx <%s> %s\n",
938// text_start_addr,
939// text_end_addr,
940// uuid_cstr,
941// image_path);
942// }
943// }
944// }
945// }
946// }
947//
948// if (crash_infos.size())
949// {
Greg Clayton63094e02010-06-23 01:19:29 +0000950// SBTarget target (m_debugger.CreateTarget (crash_infos.front().path.c_str(),
Chris Lattner24943d22010-06-08 16:52:24 +0000951// lldb::GetDefaultArchitecture().AsCString (),
952// false));
953// if (target.IsValid())
954// {
955//
956// }
957// }
958// }
959//}
960//
961
962void
963Driver::MasterThreadBytesReceived (void *baton, const void *src, size_t src_len)
964{
965 Driver *driver = (Driver*)baton;
966 driver->GetFromMaster ((const char *)src, src_len);
967}
968
969void
970Driver::GetFromMaster (const char *src, size_t src_len)
971{
972 // Echo the characters back to the Debugger's stdout, that way if you
973 // type characters while a command is running, you'll see what you've typed.
Greg Clayton63094e02010-06-23 01:19:29 +0000974 FILE *out_fh = m_debugger.GetOutputFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000975 if (out_fh)
976 ::fwrite (src, 1, src_len, out_fh);
977}
978
979size_t
980Driver::EditLineInputReaderCallback
981(
982 void *baton,
983 SBInputReader *reader,
984 InputReaderAction notification,
985 const char *bytes,
986 size_t bytes_len
987)
988{
989 Driver *driver = (Driver *)baton;
990
991 switch (notification)
992 {
993 case eInputReaderActivate:
994 break;
995
996 case eInputReaderReactivate:
997 driver->ReadyForCommand();
998 break;
999
1000 case eInputReaderDeactivate:
1001 break;
1002
1003 case eInputReaderGotToken:
1004 write (driver->m_editline_pty.GetMasterFileDescriptor(), bytes, bytes_len);
1005 break;
1006
1007 case eInputReaderDone:
1008 break;
1009 }
1010 return bytes_len;
1011}
1012
1013void
1014Driver::MainLoop ()
1015{
1016 char error_str[1024];
1017 if (m_editline_pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, error_str, sizeof(error_str)) == false)
1018 {
1019 ::fprintf (stderr, "error: failed to open driver pseudo terminal : %s", error_str);
1020 exit(1);
1021 }
1022 else
1023 {
1024 const char *driver_slave_name = m_editline_pty.GetSlaveName (error_str, sizeof(error_str));
1025 if (driver_slave_name == NULL)
1026 {
1027 ::fprintf (stderr, "error: failed to get slave name for driver pseudo terminal : %s", error_str);
1028 exit(2);
1029 }
1030 else
1031 {
1032 m_editline_slave_fh = ::fopen (driver_slave_name, "r+");
1033 if (m_editline_slave_fh == NULL)
1034 {
1035 SBError error;
1036 error.SetErrorToErrno();
1037 ::fprintf (stderr, "error: failed to get open slave for driver pseudo terminal : %s",
1038 error.GetCString());
1039 exit(3);
1040 }
1041
1042 ::setbuf (m_editline_slave_fh, NULL);
1043 }
1044 }
1045
1046
1047 // struct termios stdin_termios;
1048
1049 if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0)
1050 atexit (reset_stdin_termios);
1051
1052 ::setbuf (stdin, NULL);
1053 ::setbuf (stdout, NULL);
1054
Greg Clayton63094e02010-06-23 01:19:29 +00001055 m_debugger.SetErrorFileHandle (stderr, false);
1056 m_debugger.SetOutputFileHandle (stdout, false);
1057 m_debugger.SetInputFileHandle (stdin, true);
Jim Ingham74989e82010-08-30 19:44:40 +00001058
1059 m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
Chris Lattner24943d22010-06-08 16:52:24 +00001060
1061 // You have to drain anything that comes to the master side of the PTY. master_out_comm is
1062 // for that purpose. The reason you need to do this is a curious reason... editline will echo
1063 // characters to the PTY when it gets characters while el_gets is not running, and then when
1064 // you call el_gets (or el_getc) it will try to reset the terminal back to raw mode which blocks
1065 // if there are unconsumed characters in the out buffer.
1066 // However, you don't need to do anything with the characters, since editline will dump these
1067 // unconsumed characters after printing the prompt again in el_gets.
1068
1069 SBCommunication master_out_comm("driver.editline");
1070 master_out_comm.AdoptFileDesriptor(m_editline_pty.GetMasterFileDescriptor(), false);
1071 master_out_comm.SetReadThreadBytesReceivedCallback(Driver::MasterThreadBytesReceived, this);
1072
1073 if (master_out_comm.ReadThreadStart () == false)
1074 {
1075 ::fprintf (stderr, "error: failed to start master out read thread");
1076 exit(5);
1077 }
1078
1079// const char *crash_log = GetCrashLogFilename();
1080// if (crash_log)
1081// {
1082// ParseCrashLog (crash_log);
1083// }
1084//
Greg Clayton63094e02010-06-23 01:19:29 +00001085 SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
Chris Lattner24943d22010-06-08 16:52:24 +00001086
1087 m_io_channel_ap.reset (new IOChannel(m_editline_slave_fh, stdout, stderr, this));
1088
1089 struct winsize window_size;
1090 if (isatty (STDIN_FILENO)
1091 && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
1092 {
Greg Claytone40e7642010-09-06 23:04:11 +00001093 char buffer[256];
Chris Lattner24943d22010-06-08 16:52:24 +00001094
Caroline Tice6e4c5ce2010-09-04 00:03:46 +00001095 if (window_size.ws_col > 0)
Greg Clayton72f8a3c2010-09-06 23:01:25 +00001096 {
Greg Claytone40e7642010-09-06 23:04:11 +00001097 ::snprintf (buffer, sizeof(buffer), "settings set term-width %d", window_size.ws_col);
Greg Clayton72f8a3c2010-09-06 23:01:25 +00001098 m_debugger.HandleCommand ((const char *) buffer);
1099 }
Chris Lattner24943d22010-06-08 16:52:24 +00001100 }
1101
1102 // Since input can be redirected by the debugger, we must insert our editline
1103 // input reader in the queue so we know when our reader should be active
1104 // and so we can receive bytes only when we are supposed to.
Greg Clayton63094e02010-06-23 01:19:29 +00001105 SBError err (m_editline_reader.Initialize (m_debugger,
1106 Driver::EditLineInputReaderCallback, // callback
Chris Lattner24943d22010-06-08 16:52:24 +00001107 this, // baton
1108 eInputReaderGranularityByte, // token_size
1109 NULL, // end token - NULL means never done
1110 NULL, // prompt - taken care of elsewhere
1111 false)); // echo input - don't need Debugger
1112 // to do this, we handle it elsewhere
1113
1114 if (err.Fail())
1115 {
1116 ::fprintf (stderr, "error: %s", err.GetCString());
1117 exit (6);
1118 }
1119
Greg Clayton63094e02010-06-23 01:19:29 +00001120 m_debugger.PushInputReader (m_editline_reader);
Chris Lattner24943d22010-06-08 16:52:24 +00001121
Greg Clayton63094e02010-06-23 01:19:29 +00001122 SBListener listener(m_debugger.GetListener());
Chris Lattner24943d22010-06-08 16:52:24 +00001123 if (listener.IsValid())
1124 {
1125
1126 listener.StartListeningForEvents (*m_io_channel_ap,
1127 IOChannel::eBroadcastBitHasUserInput |
1128 IOChannel::eBroadcastBitUserInterrupt |
1129 IOChannel::eBroadcastBitThreadShouldExit |
1130 IOChannel::eBroadcastBitThreadDidStart |
1131 IOChannel::eBroadcastBitThreadDidExit);
1132
1133 if (m_io_channel_ap->Start ())
1134 {
1135 bool iochannel_thread_exited = false;
1136
1137 listener.StartListeningForEvents (sb_interpreter.GetBroadcaster(),
1138 SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
1139
1140 // Before we handle any options from the command line, we parse the
1141 // .lldbinit file in the user's home directory.
1142 SBCommandReturnObject result;
1143 sb_interpreter.SourceInitFileInHomeDirectory(result);
1144 if (GetDebugMode())
1145 {
Greg Clayton63094e02010-06-23 01:19:29 +00001146 result.PutError (m_debugger.GetErrorFileHandle());
1147 result.PutOutput (m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001148 }
1149
1150 // Now we handle options we got from the command line
1151 char command_string[PATH_MAX * 2];
1152 const size_t num_source_command_files = GetNumSourceCommandFiles();
1153 if (num_source_command_files > 0)
1154 {
1155 for (size_t i=0; i < num_source_command_files; ++i)
1156 {
1157 const char *command_file = GetSourceCommandFileAtIndex(i);
Johnny Chen7c984242010-07-28 21:16:11 +00001158 ::snprintf (command_string, sizeof(command_string), "command source '%s'", command_file);
Greg Clayton63094e02010-06-23 01:19:29 +00001159 m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, false);
Chris Lattner24943d22010-06-08 16:52:24 +00001160 if (GetDebugMode())
1161 {
Greg Clayton63094e02010-06-23 01:19:29 +00001162 result.PutError (m_debugger.GetErrorFileHandle());
1163 result.PutOutput (m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001164 }
1165 }
1166 }
1167
1168 if (!m_option_data.m_filename.empty())
1169 {
1170 char arch_name[64];
Greg Clayton63094e02010-06-23 01:19:29 +00001171 if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name)))
Chris Lattner24943d22010-06-08 16:52:24 +00001172 ::snprintf (command_string, sizeof (command_string), "file --arch=%s '%s'", arch_name,
1173 m_option_data.m_filename.c_str());
1174 else
1175 ::snprintf (command_string, sizeof(command_string), "file '%s'", m_option_data.m_filename.c_str());
1176
Greg Clayton63094e02010-06-23 01:19:29 +00001177 m_debugger.HandleCommand (command_string);
Chris Lattner24943d22010-06-08 16:52:24 +00001178 }
1179
1180 // Now that all option parsing is done, we try and parse the .lldbinit
1181 // file in the current working directory
1182 sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result);
1183 if (GetDebugMode())
1184 {
Greg Clayton63094e02010-06-23 01:19:29 +00001185 result.PutError(m_debugger.GetErrorFileHandle());
1186 result.PutOutput(m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001187 }
1188
1189 SBEvent event;
1190
1191 // Make sure the IO channel is started up before we try to tell it we
1192 // are ready for input
1193 listener.WaitForEventForBroadcasterWithType (UINT32_MAX,
1194 *m_io_channel_ap,
1195 IOChannel::eBroadcastBitThreadDidStart,
1196 event);
1197
1198 ReadyForCommand ();
1199
1200 bool done = false;
1201 while (!done)
1202 {
1203 listener.WaitForEvent (UINT32_MAX, event);
1204 if (event.IsValid())
1205 {
1206 if (event.GetBroadcaster().IsValid())
1207 {
1208 uint32_t event_type = event.GetType();
1209 if (event.BroadcasterMatchesRef (*m_io_channel_ap))
1210 {
1211 if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) ||
1212 (event_type & IOChannel::eBroadcastBitThreadDidExit))
1213 {
1214 done = true;
1215 if (event_type & IOChannel::eBroadcastBitThreadDidExit)
1216 iochannel_thread_exited = true;
1217 break;
1218 }
1219 else
1220 done = HandleIOEvent (event);
1221 }
Jim Inghamc8332952010-08-26 21:32:51 +00001222 else if (event.BroadcasterMatchesRef (m_debugger.GetSelectedTarget().GetProcess().GetBroadcaster()))
Chris Lattner24943d22010-06-08 16:52:24 +00001223 {
1224 HandleProcessEvent (event);
1225 }
1226 else if (event.BroadcasterMatchesRef (sb_interpreter.GetBroadcaster()))
1227 {
1228 if (event_type & SBCommandInterpreter::eBroadcastBitQuitCommandReceived)
1229 done = true;
1230 }
1231 }
1232 }
1233 }
1234
1235 reset_stdin_termios ();
1236
1237 CloseIOChannelFile ();
1238
1239 if (!iochannel_thread_exited)
1240 {
Greg Claytonbef15832010-07-14 00:18:15 +00001241 event.Clear();
Chris Lattner24943d22010-06-08 16:52:24 +00001242 listener.GetNextEventForBroadcasterWithType (*m_io_channel_ap,
1243 IOChannel::eBroadcastBitThreadDidExit,
1244 event);
1245 if (!event.IsValid())
1246 {
1247 // Send end EOF to the driver file descriptor
1248 m_io_channel_ap->Stop();
1249 }
1250 }
1251
Jim Inghamc8332952010-08-26 21:32:51 +00001252 SBProcess process = m_debugger.GetSelectedTarget().GetProcess();
Chris Lattner24943d22010-06-08 16:52:24 +00001253 if (process.IsValid())
1254 process.Destroy();
1255 }
1256 }
1257}
1258
1259
1260void
1261Driver::ReadyForCommand ()
1262{
1263 if (m_waiting_for_command == false)
1264 {
1265 m_waiting_for_command = true;
1266 BroadcastEventByType (Driver::eBroadcastBitReadyForInput, true);
1267 }
1268}
1269
1270
Caroline Ticeb8314fe2010-09-09 17:45:09 +00001271void
1272sigwinch_handler (int signo)
1273{
1274 struct winsize window_size;
1275 if (isatty (STDIN_FILENO)
1276 && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
1277 {
1278 if ((window_size.ws_col > 0) && (strlen (g_debugger_name) > 0))
1279 {
1280 char width_str_buffer[25];
1281 ::sprintf (width_str_buffer, "%d", window_size.ws_col);
1282 SBDebugger::SetInternalVariable ("term-width", width_str_buffer, g_debugger_name);
1283 }
1284 }
1285}
1286
Chris Lattner24943d22010-06-08 16:52:24 +00001287int
1288main (int argc, char const *argv[])
1289{
Chris Lattner24943d22010-06-08 16:52:24 +00001290 SBDebugger::Initialize();
1291
1292 SBHostOS::ThreadCreated ("[main]");
1293
Caroline Ticeb8314fe2010-09-09 17:45:09 +00001294 signal (SIGWINCH, sigwinch_handler);
1295
Greg Clayton63094e02010-06-23 01:19:29 +00001296 // Create a scope for driver so that the driver object will destroy itself
1297 // before SBDebugger::Terminate() is called.
Chris Lattner24943d22010-06-08 16:52:24 +00001298 {
Greg Clayton63094e02010-06-23 01:19:29 +00001299 Driver driver;
1300
1301 bool exit = false;
1302 SBError error (driver.ParseArgs (argc, argv, stdout, exit));
1303 if (error.Fail())
1304 {
1305 const char *error_cstr = error.GetCString ();
1306 if (error_cstr)
1307 ::fprintf (stderr, "error: %s\n", error_cstr);
1308 }
1309 else if (!exit)
1310 {
1311 driver.MainLoop ();
1312 }
Chris Lattner24943d22010-06-08 16:52:24 +00001313 }
1314
1315 SBDebugger::Terminate();
1316 return 0;
1317}