blob: 8e39eb6763331c39463a307036b5dba508613881 [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;
Caroline Ticeeddffe92010-09-10 04:48:55 +0000530 else if (file.ResolveExecutableLocation())
531 {
532 char path[PATH_MAX];
533 int path_len;
534 file.GetPath (path, path_len);
535 m_option_data.m_filename = path;
536 }
Greg Clayton63094e02010-06-23 01:19:29 +0000537 else
538 error.SetErrorStringWithFormat("file specified in --file (-f) option doesn't exist: '%s'", optarg);
539 }
540 break;
541
542 case 'a':
543 if (!m_debugger.SetDefaultArchitecture (optarg))
544 error.SetErrorStringWithFormat("invalid architecture in the -a or --arch option: '%s'", optarg);
545 break;
546
547 case 'l':
548 m_option_data.m_script_lang = m_debugger.GetScriptingLanguage (optarg);
549 break;
550
551 case 'd':
552 m_option_data.m_debug_mode = true;
553 break;
554
555 case 's':
556 {
557 SBFileSpec file(optarg);
558 if (file.Exists())
559 m_option_data.m_source_command_files.push_back (optarg);
Caroline Ticeeddffe92010-09-10 04:48:55 +0000560 else if (file.ResolveExecutableLocation())
561 {
562 char final_path[PATH_MAX];
563 size_t path_len;
564 file.GetPath (final_path, path_len);
565 std::string path_str (final_path);
566 m_option_data.m_source_command_files.push_back (path_str);
567 }
Greg Clayton63094e02010-06-23 01:19:29 +0000568 else
569 error.SetErrorStringWithFormat("file specified in --source (-s) option doesn't exist: '%s'", optarg);
570 }
571 break;
572
573 default:
574 m_option_data.m_print_help = true;
575 error.SetErrorStringWithFormat ("unrecognized option %c", short_option);
576 break;
577 }
Chris Lattner24943d22010-06-08 16:52:24 +0000578 }
579 else
580 {
581 error.SetErrorStringWithFormat ("invalid option with value %i", val);
582 }
583 if (error.Fail())
Greg Clayton63094e02010-06-23 01:19:29 +0000584 return error;
Chris Lattner24943d22010-06-08 16:52:24 +0000585 }
586 }
Jim Ingham34e9a982010-06-15 18:47:14 +0000587
588 // If there is a trailing argument, it is the filename.
589 if (optind == argc - 1)
590 {
591 if (m_option_data.m_filename.empty())
Chris Lattner24943d22010-06-08 16:52:24 +0000592 {
Jim Ingham34e9a982010-06-15 18:47:14 +0000593 m_option_data.m_filename = argv[optind];
Chris Lattner24943d22010-06-08 16:52:24 +0000594 }
Jim Ingham34e9a982010-06-15 18:47:14 +0000595 else
596 {
Greg Clayton63094e02010-06-23 01:19:29 +0000597 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 +0000598 }
599
Chris Lattner24943d22010-06-08 16:52:24 +0000600 }
Jim Ingham34e9a982010-06-15 18:47:14 +0000601 else if (optind < argc - 1)
602 {
603 // Trailing extra arguments...
Greg Clayton63094e02010-06-23 01:19:29 +0000604 error.SetErrorStringWithFormat ("error: trailing extra arguments - only one the filename is allowed.");
Jim Ingham34e9a982010-06-15 18:47:14 +0000605 }
606
Greg Clayton63094e02010-06-23 01:19:29 +0000607 if (error.Fail() || m_option_data.m_print_help)
Chris Lattner24943d22010-06-08 16:52:24 +0000608 {
609 ShowUsage (out_fh, g_options, m_option_data);
Chris Lattner24943d22010-06-08 16:52:24 +0000610 }
611 else if (m_option_data.m_print_version)
612 {
Greg Clayton63094e02010-06-23 01:19:29 +0000613 ::fprintf (out_fh, "%s\n", m_debugger.GetVersionString());
614 exit = true;
Chris Lattner24943d22010-06-08 16:52:24 +0000615 }
616 else if (! m_option_data.m_crash_log.empty())
617 {
618 // Handle crash log stuff here.
619 }
620 else
621 {
622 // All other combinations are valid; do nothing more here.
623 }
624
Greg Clayton63094e02010-06-23 01:19:29 +0000625 return error;
Chris Lattner24943d22010-06-08 16:52:24 +0000626}
627
Caroline Tice757500e2010-09-29 18:35:42 +0000628size_t
Chris Lattner24943d22010-06-08 16:52:24 +0000629Driver::GetProcessSTDOUT ()
630{
631 // The process has stuff waiting for stdout; get it and write it out to the appropriate place.
632 char stdio_buffer[1024];
633 size_t len;
Caroline Tice757500e2010-09-29 18:35:42 +0000634 size_t total_bytes = 0;
Jim Inghamc8332952010-08-26 21:32:51 +0000635 while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
Caroline Tice757500e2010-09-29 18:35:42 +0000636 {
Chris Lattner24943d22010-06-08 16:52:24 +0000637 m_io_channel_ap->OutWrite (stdio_buffer, len);
Caroline Tice757500e2010-09-29 18:35:42 +0000638 total_bytes += len;
639 }
640 return total_bytes;
Chris Lattner24943d22010-06-08 16:52:24 +0000641}
642
Caroline Tice757500e2010-09-29 18:35:42 +0000643size_t
Chris Lattner24943d22010-06-08 16:52:24 +0000644Driver::GetProcessSTDERR ()
645{
646 // The process has stuff waiting for stderr; get it and write it out to the appropriate place.
647 char stdio_buffer[1024];
648 size_t len;
Caroline Tice757500e2010-09-29 18:35:42 +0000649 size_t total_bytes = 0;
Jim Inghamc8332952010-08-26 21:32:51 +0000650 while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
Caroline Tice757500e2010-09-29 18:35:42 +0000651 {
Chris Lattner24943d22010-06-08 16:52:24 +0000652 m_io_channel_ap->ErrWrite (stdio_buffer, len);
Caroline Tice757500e2010-09-29 18:35:42 +0000653 total_bytes += len;
654 }
655 return total_bytes;
Chris Lattner24943d22010-06-08 16:52:24 +0000656}
657
658void
Jim Inghamc8332952010-08-26 21:32:51 +0000659Driver::UpdateSelectedThread ()
Chris Lattner24943d22010-06-08 16:52:24 +0000660{
661 using namespace lldb;
Jim Inghamc8332952010-08-26 21:32:51 +0000662 SBProcess process(m_debugger.GetSelectedTarget().GetProcess());
Chris Lattner24943d22010-06-08 16:52:24 +0000663 if (process.IsValid())
664 {
Jim Inghamc8332952010-08-26 21:32:51 +0000665 SBThread curr_thread (process.GetSelectedThread());
Chris Lattner24943d22010-06-08 16:52:24 +0000666 SBThread thread;
667 StopReason curr_thread_stop_reason = eStopReasonInvalid;
668 curr_thread_stop_reason = curr_thread.GetStopReason();
669
670 if (!curr_thread.IsValid() ||
671 curr_thread_stop_reason == eStopReasonInvalid ||
672 curr_thread_stop_reason == eStopReasonNone)
673 {
674 // Prefer a thread that has just completed its plan over another thread as current thread.
675 SBThread plan_thread;
676 SBThread other_thread;
677 const size_t num_threads = process.GetNumThreads();
678 size_t i;
679 for (i = 0; i < num_threads; ++i)
680 {
681 thread = process.GetThreadAtIndex(i);
682 StopReason thread_stop_reason = thread.GetStopReason();
683 switch (thread_stop_reason)
684 {
685 default:
686 case eStopReasonInvalid:
687 case eStopReasonNone:
688 break;
689
690 case eStopReasonTrace:
691 case eStopReasonBreakpoint:
692 case eStopReasonWatchpoint:
693 case eStopReasonSignal:
694 case eStopReasonException:
695 if (!other_thread.IsValid())
696 other_thread = thread;
697 break;
698 case eStopReasonPlanComplete:
699 if (!plan_thread.IsValid())
700 plan_thread = thread;
701 break;
702 }
703 }
704 if (plan_thread.IsValid())
Jim Inghamc8332952010-08-26 21:32:51 +0000705 process.SetSelectedThread (plan_thread);
Chris Lattner24943d22010-06-08 16:52:24 +0000706 else if (other_thread.IsValid())
Jim Inghamc8332952010-08-26 21:32:51 +0000707 process.SetSelectedThread (other_thread);
Chris Lattner24943d22010-06-08 16:52:24 +0000708 else
709 {
710 if (curr_thread.IsValid())
711 thread = curr_thread;
712 else
713 thread = process.GetThreadAtIndex(0);
714
715 if (thread.IsValid())
Jim Inghamc8332952010-08-26 21:32:51 +0000716 process.SetSelectedThread (thread);
Chris Lattner24943d22010-06-08 16:52:24 +0000717 }
718 }
719 }
720}
721
722
723// This function handles events that were broadcast by the process.
724void
725Driver::HandleProcessEvent (const SBEvent &event)
726{
727 using namespace lldb;
728 const uint32_t event_type = event.GetType();
729
730 if (event_type & SBProcess::eBroadcastBitSTDOUT)
731 {
732 // The process has stdout available, get it and write it out to the
733 // appropriate place.
Caroline Tice757500e2010-09-29 18:35:42 +0000734 if (GetProcessSTDOUT ())
735 m_io_channel_ap->RefreshPrompt();
Chris Lattner24943d22010-06-08 16:52:24 +0000736 }
737 else if (event_type & SBProcess::eBroadcastBitSTDERR)
738 {
739 // The process has stderr available, get it and write it out to the
740 // appropriate place.
Caroline Tice757500e2010-09-29 18:35:42 +0000741 if (GetProcessSTDERR ())
742 m_io_channel_ap->RefreshPrompt();
Chris Lattner24943d22010-06-08 16:52:24 +0000743 }
744 else if (event_type & SBProcess::eBroadcastBitStateChanged)
745 {
746 // Drain all stout and stderr so we don't see any output come after
747 // we print our prompts
Caroline Tice757500e2010-09-29 18:35:42 +0000748 if (GetProcessSTDOUT ()
749 || GetProcessSTDERR ())
750 m_io_channel_ap->RefreshPrompt();
Chris Lattner24943d22010-06-08 16:52:24 +0000751
752 // Something changed in the process; get the event and report the process's current status and location to
753 // the user.
754 StateType event_state = SBProcess::GetStateFromEvent (event);
755 if (event_state == eStateInvalid)
756 return;
757
758 SBProcess process (SBProcess::GetProcessFromEvent (event));
759 assert (process.IsValid());
760
761 switch (event_state)
762 {
763 case eStateInvalid:
764 case eStateUnloaded:
765 case eStateAttaching:
766 case eStateLaunching:
767 case eStateStepping:
768 case eStateDetached:
769 {
770 char message[1024];
771 int message_len = ::snprintf (message, sizeof(message), "Process %d %s\n", process.GetProcessID(),
Greg Clayton63094e02010-06-23 01:19:29 +0000772 m_debugger.StateAsCString (event_state));
Chris Lattner24943d22010-06-08 16:52:24 +0000773 m_io_channel_ap->OutWrite(message, message_len);
774 }
775 break;
776
777 case eStateRunning:
778 // Don't be chatty when we run...
779 break;
780
781 case eStateExited:
Caroline Tice757500e2010-09-29 18:35:42 +0000782 {
783 SBCommandReturnObject result;
784 m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false);
785 m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize());
786 m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize());
787 m_io_channel_ap->RefreshPrompt();
788 }
Chris Lattner24943d22010-06-08 16:52:24 +0000789 break;
790
791 case eStateStopped:
792 case eStateCrashed:
793 case eStateSuspended:
794 // Make sure the program hasn't been auto-restarted:
795 if (SBProcess::GetRestartedFromEvent (event))
796 {
797 // FIXME: Do we want to report this, or would that just be annoyingly chatty?
798 char message[1024];
799 int message_len = ::snprintf (message, sizeof(message), "Process %d stopped and was programmatically restarted.\n",
800 process.GetProcessID());
801 m_io_channel_ap->OutWrite(message, message_len);
Caroline Tice757500e2010-09-29 18:35:42 +0000802 m_io_channel_ap->RefreshPrompt ();
Chris Lattner24943d22010-06-08 16:52:24 +0000803 }
804 else
805 {
Caroline Tice757500e2010-09-29 18:35:42 +0000806 SBCommandReturnObject result;
Jim Inghamc8332952010-08-26 21:32:51 +0000807 UpdateSelectedThread ();
Caroline Tice757500e2010-09-29 18:35:42 +0000808 m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false);
809 m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize());
810 m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize());
811 m_io_channel_ap->RefreshPrompt ();
Chris Lattner24943d22010-06-08 16:52:24 +0000812 }
813 break;
814 }
815 }
816}
817
818// This function handles events broadcast by the IOChannel (HasInput, UserInterrupt, or ThreadShouldExit).
819
820bool
821Driver::HandleIOEvent (const SBEvent &event)
822{
823 bool quit = false;
824
825 const uint32_t event_type = event.GetType();
826
827 if (event_type & IOChannel::eBroadcastBitHasUserInput)
828 {
829 // We got some input (i.e. a command string) from the user; pass it off to the command interpreter for
830 // handling.
831
832 const char *command_string = SBEvent::GetCStringFromEvent(event);
833 if (command_string == NULL)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000834 command_string = "";
Chris Lattner24943d22010-06-08 16:52:24 +0000835 SBCommandReturnObject result;
Greg Clayton63094e02010-06-23 01:19:29 +0000836 if (m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, true) != lldb::eReturnStatusQuit)
Chris Lattner24943d22010-06-08 16:52:24 +0000837 {
838 m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize());
839 m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize());
840 }
841 // We are done getting and running our command, we can now clear the
842 // m_waiting_for_command so we can get another one.
843 m_waiting_for_command = false;
844
845 // If our editline input reader is active, it means another input reader
846 // got pushed onto the input reader and caused us to become deactivated.
847 // When the input reader above us gets popped, we will get re-activated
848 // and our prompt will refresh in our callback
849 if (m_editline_reader.IsActive())
850 {
851 ReadyForCommand ();
852 }
853 }
854 else if (event_type & IOChannel::eBroadcastBitUserInterrupt)
855 {
856 // This is here to handle control-c interrupts from the user. It has not yet really been implemented.
857 // TO BE DONE: PROPERLY HANDLE CONTROL-C FROM USER
858 //m_io_channel_ap->CancelInput();
859 // Anything else? Send Interrupt to process?
860 }
861 else if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) ||
862 (event_type & IOChannel::eBroadcastBitThreadDidExit))
863 {
864 // If the IOChannel thread is trying to go away, then it is definitely
865 // time to end the debugging session.
866 quit = true;
867 }
868
869 return quit;
870}
871
872
873//struct CrashImageInfo
874//{
875// std::string path;
876// VMRange text_range;
877// UUID uuid;
878//};
879//
880//void
881//Driver::ParseCrashLog (const char *crash_log)
882//{
883// printf("Parsing crash log: %s\n", crash_log);
884//
885// char image_path[PATH_MAX];
886// std::vector<CrashImageInfo> crash_infos;
887// if (crash_log && crash_log[0])
888// {
889// FileSpec crash_log_file (crash_log);
890// STLStringArray crash_log_lines;
891// if (crash_log_file.ReadFileLines (crash_log_lines))
892// {
893// const size_t num_crash_log_lines = crash_log_lines.size();
894// size_t i;
895// for (i=0; i<num_crash_log_lines; ++i)
896// {
897// const char *line = crash_log_lines[i].c_str();
898// if (strstr (line, "Code Type:"))
899// {
900// char arch_string[256];
901// if (sscanf(line, "%s", arch_string))
902// {
903// if (strcmp(arch_string, "X86-64"))
904// lldb::GetDefaultArchitecture ().SetArch ("x86_64");
905// else if (strcmp(arch_string, "X86"))
906// lldb::GetDefaultArchitecture ().SetArch ("i386");
907// else
908// {
909// ArchSpec arch(arch_string);
910// if (arch.IsValid ())
911// lldb::GetDefaultArchitecture () = arch;
912// else
913// fprintf(stderr, "Unrecognized architecture: %s\n", arch_string);
914// }
915// }
916// }
917// else
918// if (strstr(line, "Path:"))
919// {
920// const char *p = line + strlen("Path:");
921// while (isspace(*p))
922// ++p;
923//
924// m_option_data.m_filename.assign (p);
925// }
926// else
927// if (strstr(line, "Binary Images:"))
928// {
929// while (++i < num_crash_log_lines)
930// {
931// if (crash_log_lines[i].empty())
932// break;
933//
934// line = crash_log_lines[i].c_str();
935// uint64_t text_start_addr;
936// uint64_t text_end_addr;
937// char uuid_cstr[64];
938// int bytes_consumed_before_uuid = 0;
939// int bytes_consumed_after_uuid = 0;
940//
941// int items_parsed = ::sscanf (line,
942// "%llx - %llx %*s %*s %*s %n%s %n",
943// &text_start_addr,
944// &text_end_addr,
945// &bytes_consumed_before_uuid,
946// uuid_cstr,
947// &bytes_consumed_after_uuid);
948//
949// if (items_parsed == 3)
950// {
951//
952// CrashImageInfo info;
953// info.text_range.SetBaseAddress(text_start_addr);
954// info.text_range.SetEndAddress(text_end_addr);
955//
956// if (uuid_cstr[0] == '<')
957// {
958// if (info.uuid.SetfromCString (&uuid_cstr[1]) == 0)
959// info.uuid.Clear();
960//
961// ::strncpy (image_path, line + bytes_consumed_after_uuid, sizeof(image_path));
962// }
963// else
964// {
965// ::strncpy (image_path, line + bytes_consumed_before_uuid, sizeof(image_path));
966// }
967//
968// info.path = image_path;
969//
970// crash_infos.push_back (info);
971//
972// info.uuid.GetAsCString(uuid_cstr, sizeof(uuid_cstr));
973//
974// printf("0x%16.16llx - 0x%16.16llx <%s> %s\n",
975// text_start_addr,
976// text_end_addr,
977// uuid_cstr,
978// image_path);
979// }
980// }
981// }
982// }
983// }
984//
985// if (crash_infos.size())
986// {
Greg Clayton63094e02010-06-23 01:19:29 +0000987// SBTarget target (m_debugger.CreateTarget (crash_infos.front().path.c_str(),
Chris Lattner24943d22010-06-08 16:52:24 +0000988// lldb::GetDefaultArchitecture().AsCString (),
989// false));
990// if (target.IsValid())
991// {
992//
993// }
994// }
995// }
996//}
997//
998
999void
1000Driver::MasterThreadBytesReceived (void *baton, const void *src, size_t src_len)
1001{
1002 Driver *driver = (Driver*)baton;
1003 driver->GetFromMaster ((const char *)src, src_len);
1004}
1005
1006void
1007Driver::GetFromMaster (const char *src, size_t src_len)
1008{
1009 // Echo the characters back to the Debugger's stdout, that way if you
1010 // type characters while a command is running, you'll see what you've typed.
Greg Clayton63094e02010-06-23 01:19:29 +00001011 FILE *out_fh = m_debugger.GetOutputFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +00001012 if (out_fh)
1013 ::fwrite (src, 1, src_len, out_fh);
1014}
1015
1016size_t
1017Driver::EditLineInputReaderCallback
1018(
1019 void *baton,
1020 SBInputReader *reader,
1021 InputReaderAction notification,
1022 const char *bytes,
1023 size_t bytes_len
1024)
1025{
1026 Driver *driver = (Driver *)baton;
1027
1028 switch (notification)
1029 {
1030 case eInputReaderActivate:
1031 break;
1032
1033 case eInputReaderReactivate:
1034 driver->ReadyForCommand();
1035 break;
1036
1037 case eInputReaderDeactivate:
1038 break;
1039
1040 case eInputReaderGotToken:
1041 write (driver->m_editline_pty.GetMasterFileDescriptor(), bytes, bytes_len);
1042 break;
1043
1044 case eInputReaderDone:
1045 break;
1046 }
1047 return bytes_len;
1048}
1049
1050void
1051Driver::MainLoop ()
1052{
1053 char error_str[1024];
1054 if (m_editline_pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, error_str, sizeof(error_str)) == false)
1055 {
1056 ::fprintf (stderr, "error: failed to open driver pseudo terminal : %s", error_str);
1057 exit(1);
1058 }
1059 else
1060 {
1061 const char *driver_slave_name = m_editline_pty.GetSlaveName (error_str, sizeof(error_str));
1062 if (driver_slave_name == NULL)
1063 {
1064 ::fprintf (stderr, "error: failed to get slave name for driver pseudo terminal : %s", error_str);
1065 exit(2);
1066 }
1067 else
1068 {
1069 m_editline_slave_fh = ::fopen (driver_slave_name, "r+");
1070 if (m_editline_slave_fh == NULL)
1071 {
1072 SBError error;
1073 error.SetErrorToErrno();
1074 ::fprintf (stderr, "error: failed to get open slave for driver pseudo terminal : %s",
1075 error.GetCString());
1076 exit(3);
1077 }
1078
1079 ::setbuf (m_editline_slave_fh, NULL);
1080 }
1081 }
1082
1083
1084 // struct termios stdin_termios;
1085
1086 if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0)
1087 atexit (reset_stdin_termios);
1088
1089 ::setbuf (stdin, NULL);
1090 ::setbuf (stdout, NULL);
1091
Greg Clayton63094e02010-06-23 01:19:29 +00001092 m_debugger.SetErrorFileHandle (stderr, false);
1093 m_debugger.SetOutputFileHandle (stdout, false);
1094 m_debugger.SetInputFileHandle (stdin, true);
Jim Ingham74989e82010-08-30 19:44:40 +00001095
1096 m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
Chris Lattner24943d22010-06-08 16:52:24 +00001097
1098 // You have to drain anything that comes to the master side of the PTY. master_out_comm is
1099 // for that purpose. The reason you need to do this is a curious reason... editline will echo
1100 // characters to the PTY when it gets characters while el_gets is not running, and then when
1101 // you call el_gets (or el_getc) it will try to reset the terminal back to raw mode which blocks
1102 // if there are unconsumed characters in the out buffer.
1103 // However, you don't need to do anything with the characters, since editline will dump these
1104 // unconsumed characters after printing the prompt again in el_gets.
1105
1106 SBCommunication master_out_comm("driver.editline");
1107 master_out_comm.AdoptFileDesriptor(m_editline_pty.GetMasterFileDescriptor(), false);
1108 master_out_comm.SetReadThreadBytesReceivedCallback(Driver::MasterThreadBytesReceived, this);
1109
1110 if (master_out_comm.ReadThreadStart () == false)
1111 {
1112 ::fprintf (stderr, "error: failed to start master out read thread");
1113 exit(5);
1114 }
1115
1116// const char *crash_log = GetCrashLogFilename();
1117// if (crash_log)
1118// {
1119// ParseCrashLog (crash_log);
1120// }
1121//
Greg Clayton63094e02010-06-23 01:19:29 +00001122 SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
Chris Lattner24943d22010-06-08 16:52:24 +00001123
1124 m_io_channel_ap.reset (new IOChannel(m_editline_slave_fh, stdout, stderr, this));
1125
1126 struct winsize window_size;
1127 if (isatty (STDIN_FILENO)
1128 && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
1129 {
Caroline Tice6e4c5ce2010-09-04 00:03:46 +00001130 if (window_size.ws_col > 0)
Greg Clayton238c0a12010-09-18 01:14:36 +00001131 m_debugger.SetTerminalWidth (window_size.ws_col);
Chris Lattner24943d22010-06-08 16:52:24 +00001132 }
1133
1134 // Since input can be redirected by the debugger, we must insert our editline
1135 // input reader in the queue so we know when our reader should be active
1136 // and so we can receive bytes only when we are supposed to.
Greg Clayton63094e02010-06-23 01:19:29 +00001137 SBError err (m_editline_reader.Initialize (m_debugger,
1138 Driver::EditLineInputReaderCallback, // callback
Chris Lattner24943d22010-06-08 16:52:24 +00001139 this, // baton
1140 eInputReaderGranularityByte, // token_size
1141 NULL, // end token - NULL means never done
1142 NULL, // prompt - taken care of elsewhere
1143 false)); // echo input - don't need Debugger
1144 // to do this, we handle it elsewhere
1145
1146 if (err.Fail())
1147 {
1148 ::fprintf (stderr, "error: %s", err.GetCString());
1149 exit (6);
1150 }
1151
Greg Clayton63094e02010-06-23 01:19:29 +00001152 m_debugger.PushInputReader (m_editline_reader);
Chris Lattner24943d22010-06-08 16:52:24 +00001153
Greg Clayton63094e02010-06-23 01:19:29 +00001154 SBListener listener(m_debugger.GetListener());
Chris Lattner24943d22010-06-08 16:52:24 +00001155 if (listener.IsValid())
1156 {
1157
1158 listener.StartListeningForEvents (*m_io_channel_ap,
1159 IOChannel::eBroadcastBitHasUserInput |
1160 IOChannel::eBroadcastBitUserInterrupt |
1161 IOChannel::eBroadcastBitThreadShouldExit |
1162 IOChannel::eBroadcastBitThreadDidStart |
1163 IOChannel::eBroadcastBitThreadDidExit);
1164
1165 if (m_io_channel_ap->Start ())
1166 {
1167 bool iochannel_thread_exited = false;
1168
1169 listener.StartListeningForEvents (sb_interpreter.GetBroadcaster(),
1170 SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
1171
1172 // Before we handle any options from the command line, we parse the
1173 // .lldbinit file in the user's home directory.
1174 SBCommandReturnObject result;
1175 sb_interpreter.SourceInitFileInHomeDirectory(result);
1176 if (GetDebugMode())
1177 {
Greg Clayton63094e02010-06-23 01:19:29 +00001178 result.PutError (m_debugger.GetErrorFileHandle());
1179 result.PutOutput (m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001180 }
1181
1182 // Now we handle options we got from the command line
1183 char command_string[PATH_MAX * 2];
1184 const size_t num_source_command_files = GetNumSourceCommandFiles();
1185 if (num_source_command_files > 0)
1186 {
1187 for (size_t i=0; i < num_source_command_files; ++i)
1188 {
1189 const char *command_file = GetSourceCommandFileAtIndex(i);
Johnny Chen7c984242010-07-28 21:16:11 +00001190 ::snprintf (command_string, sizeof(command_string), "command source '%s'", command_file);
Greg Clayton63094e02010-06-23 01:19:29 +00001191 m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, false);
Chris Lattner24943d22010-06-08 16:52:24 +00001192 if (GetDebugMode())
1193 {
Greg Clayton63094e02010-06-23 01:19:29 +00001194 result.PutError (m_debugger.GetErrorFileHandle());
1195 result.PutOutput (m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001196 }
1197 }
1198 }
1199
1200 if (!m_option_data.m_filename.empty())
1201 {
1202 char arch_name[64];
Greg Clayton63094e02010-06-23 01:19:29 +00001203 if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name)))
Chris Lattner24943d22010-06-08 16:52:24 +00001204 ::snprintf (command_string, sizeof (command_string), "file --arch=%s '%s'", arch_name,
1205 m_option_data.m_filename.c_str());
1206 else
1207 ::snprintf (command_string, sizeof(command_string), "file '%s'", m_option_data.m_filename.c_str());
1208
Greg Clayton63094e02010-06-23 01:19:29 +00001209 m_debugger.HandleCommand (command_string);
Chris Lattner24943d22010-06-08 16:52:24 +00001210 }
1211
1212 // Now that all option parsing is done, we try and parse the .lldbinit
1213 // file in the current working directory
1214 sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result);
1215 if (GetDebugMode())
1216 {
Greg Clayton63094e02010-06-23 01:19:29 +00001217 result.PutError(m_debugger.GetErrorFileHandle());
1218 result.PutOutput(m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001219 }
1220
1221 SBEvent event;
1222
1223 // Make sure the IO channel is started up before we try to tell it we
1224 // are ready for input
1225 listener.WaitForEventForBroadcasterWithType (UINT32_MAX,
1226 *m_io_channel_ap,
1227 IOChannel::eBroadcastBitThreadDidStart,
1228 event);
1229
1230 ReadyForCommand ();
1231
1232 bool done = false;
1233 while (!done)
1234 {
1235 listener.WaitForEvent (UINT32_MAX, event);
1236 if (event.IsValid())
1237 {
1238 if (event.GetBroadcaster().IsValid())
1239 {
1240 uint32_t event_type = event.GetType();
1241 if (event.BroadcasterMatchesRef (*m_io_channel_ap))
1242 {
1243 if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) ||
1244 (event_type & IOChannel::eBroadcastBitThreadDidExit))
1245 {
1246 done = true;
1247 if (event_type & IOChannel::eBroadcastBitThreadDidExit)
1248 iochannel_thread_exited = true;
1249 break;
1250 }
1251 else
1252 done = HandleIOEvent (event);
1253 }
Jim Inghamc8332952010-08-26 21:32:51 +00001254 else if (event.BroadcasterMatchesRef (m_debugger.GetSelectedTarget().GetProcess().GetBroadcaster()))
Chris Lattner24943d22010-06-08 16:52:24 +00001255 {
1256 HandleProcessEvent (event);
1257 }
1258 else if (event.BroadcasterMatchesRef (sb_interpreter.GetBroadcaster()))
1259 {
1260 if (event_type & SBCommandInterpreter::eBroadcastBitQuitCommandReceived)
1261 done = true;
1262 }
1263 }
1264 }
1265 }
1266
1267 reset_stdin_termios ();
1268
1269 CloseIOChannelFile ();
1270
1271 if (!iochannel_thread_exited)
1272 {
Greg Claytonbef15832010-07-14 00:18:15 +00001273 event.Clear();
Chris Lattner24943d22010-06-08 16:52:24 +00001274 listener.GetNextEventForBroadcasterWithType (*m_io_channel_ap,
1275 IOChannel::eBroadcastBitThreadDidExit,
1276 event);
1277 if (!event.IsValid())
1278 {
1279 // Send end EOF to the driver file descriptor
1280 m_io_channel_ap->Stop();
1281 }
1282 }
1283
Jim Inghamc8332952010-08-26 21:32:51 +00001284 SBProcess process = m_debugger.GetSelectedTarget().GetProcess();
Chris Lattner24943d22010-06-08 16:52:24 +00001285 if (process.IsValid())
1286 process.Destroy();
1287 }
1288 }
1289}
1290
1291
1292void
1293Driver::ReadyForCommand ()
1294{
1295 if (m_waiting_for_command == false)
1296 {
1297 m_waiting_for_command = true;
1298 BroadcastEventByType (Driver::eBroadcastBitReadyForInput, true);
1299 }
1300}
1301
1302
Caroline Ticeb8314fe2010-09-09 17:45:09 +00001303void
1304sigwinch_handler (int signo)
1305{
1306 struct winsize window_size;
1307 if (isatty (STDIN_FILENO)
1308 && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
1309 {
1310 if ((window_size.ws_col > 0) && (strlen (g_debugger_name) > 0))
1311 {
1312 char width_str_buffer[25];
1313 ::sprintf (width_str_buffer, "%d", window_size.ws_col);
1314 SBDebugger::SetInternalVariable ("term-width", width_str_buffer, g_debugger_name);
1315 }
1316 }
1317}
1318
Chris Lattner24943d22010-06-08 16:52:24 +00001319int
1320main (int argc, char const *argv[])
1321{
Chris Lattner24943d22010-06-08 16:52:24 +00001322 SBDebugger::Initialize();
1323
1324 SBHostOS::ThreadCreated ("[main]");
1325
Caroline Ticeb8314fe2010-09-09 17:45:09 +00001326 signal (SIGWINCH, sigwinch_handler);
1327
Greg Clayton63094e02010-06-23 01:19:29 +00001328 // Create a scope for driver so that the driver object will destroy itself
1329 // before SBDebugger::Terminate() is called.
Chris Lattner24943d22010-06-08 16:52:24 +00001330 {
Greg Clayton63094e02010-06-23 01:19:29 +00001331 Driver driver;
1332
1333 bool exit = false;
1334 SBError error (driver.ParseArgs (argc, argv, stdout, exit));
1335 if (error.Fail())
1336 {
1337 const char *error_cstr = error.GetCString ();
1338 if (error_cstr)
1339 ::fprintf (stderr, "error: %s\n", error_cstr);
1340 }
1341 else if (!exit)
1342 {
1343 driver.MainLoop ();
1344 }
Chris Lattner24943d22010-06-08 16:52:24 +00001345 }
1346
1347 SBDebugger::Terminate();
1348 return 0;
1349}