blob: c4f4aad475363f8aa1cc1ae9369b03eea84f7294 [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
628void
629Driver::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;
Jim Inghamc8332952010-08-26 21:32:51 +0000634 while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
Chris Lattner24943d22010-06-08 16:52:24 +0000635 m_io_channel_ap->OutWrite (stdio_buffer, len);
636}
637
638void
639Driver::GetProcessSTDERR ()
640{
641 // The process has stuff waiting for stderr; get it and write it out to the appropriate place.
642 char stdio_buffer[1024];
643 size_t len;
Jim Inghamc8332952010-08-26 21:32:51 +0000644 while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
Chris Lattner24943d22010-06-08 16:52:24 +0000645 m_io_channel_ap->ErrWrite (stdio_buffer, len);
646}
647
648void
Jim Inghamc8332952010-08-26 21:32:51 +0000649Driver::UpdateSelectedThread ()
Chris Lattner24943d22010-06-08 16:52:24 +0000650{
651 using namespace lldb;
Jim Inghamc8332952010-08-26 21:32:51 +0000652 SBProcess process(m_debugger.GetSelectedTarget().GetProcess());
Chris Lattner24943d22010-06-08 16:52:24 +0000653 if (process.IsValid())
654 {
Jim Inghamc8332952010-08-26 21:32:51 +0000655 SBThread curr_thread (process.GetSelectedThread());
Chris Lattner24943d22010-06-08 16:52:24 +0000656 SBThread thread;
657 StopReason curr_thread_stop_reason = eStopReasonInvalid;
658 curr_thread_stop_reason = curr_thread.GetStopReason();
659
660 if (!curr_thread.IsValid() ||
661 curr_thread_stop_reason == eStopReasonInvalid ||
662 curr_thread_stop_reason == eStopReasonNone)
663 {
664 // Prefer a thread that has just completed its plan over another thread as current thread.
665 SBThread plan_thread;
666 SBThread other_thread;
667 const size_t num_threads = process.GetNumThreads();
668 size_t i;
669 for (i = 0; i < num_threads; ++i)
670 {
671 thread = process.GetThreadAtIndex(i);
672 StopReason thread_stop_reason = thread.GetStopReason();
673 switch (thread_stop_reason)
674 {
675 default:
676 case eStopReasonInvalid:
677 case eStopReasonNone:
678 break;
679
680 case eStopReasonTrace:
681 case eStopReasonBreakpoint:
682 case eStopReasonWatchpoint:
683 case eStopReasonSignal:
684 case eStopReasonException:
685 if (!other_thread.IsValid())
686 other_thread = thread;
687 break;
688 case eStopReasonPlanComplete:
689 if (!plan_thread.IsValid())
690 plan_thread = thread;
691 break;
692 }
693 }
694 if (plan_thread.IsValid())
Jim Inghamc8332952010-08-26 21:32:51 +0000695 process.SetSelectedThread (plan_thread);
Chris Lattner24943d22010-06-08 16:52:24 +0000696 else if (other_thread.IsValid())
Jim Inghamc8332952010-08-26 21:32:51 +0000697 process.SetSelectedThread (other_thread);
Chris Lattner24943d22010-06-08 16:52:24 +0000698 else
699 {
700 if (curr_thread.IsValid())
701 thread = curr_thread;
702 else
703 thread = process.GetThreadAtIndex(0);
704
705 if (thread.IsValid())
Jim Inghamc8332952010-08-26 21:32:51 +0000706 process.SetSelectedThread (thread);
Chris Lattner24943d22010-06-08 16:52:24 +0000707 }
708 }
709 }
710}
711
712
713// This function handles events that were broadcast by the process.
714void
715Driver::HandleProcessEvent (const SBEvent &event)
716{
717 using namespace lldb;
718 const uint32_t event_type = event.GetType();
719
720 if (event_type & SBProcess::eBroadcastBitSTDOUT)
721 {
722 // The process has stdout available, get it and write it out to the
723 // appropriate place.
724 GetProcessSTDOUT ();
725 }
726 else if (event_type & SBProcess::eBroadcastBitSTDERR)
727 {
728 // The process has stderr available, get it and write it out to the
729 // appropriate place.
730 GetProcessSTDERR ();
731 }
732 else if (event_type & SBProcess::eBroadcastBitStateChanged)
733 {
734 // Drain all stout and stderr so we don't see any output come after
735 // we print our prompts
736 GetProcessSTDOUT ();
737 GetProcessSTDERR ();
738
739 // Something changed in the process; get the event and report the process's current status and location to
740 // the user.
741 StateType event_state = SBProcess::GetStateFromEvent (event);
742 if (event_state == eStateInvalid)
743 return;
744
745 SBProcess process (SBProcess::GetProcessFromEvent (event));
746 assert (process.IsValid());
747
748 switch (event_state)
749 {
750 case eStateInvalid:
751 case eStateUnloaded:
752 case eStateAttaching:
753 case eStateLaunching:
754 case eStateStepping:
755 case eStateDetached:
756 {
757 char message[1024];
758 int message_len = ::snprintf (message, sizeof(message), "Process %d %s\n", process.GetProcessID(),
Greg Clayton63094e02010-06-23 01:19:29 +0000759 m_debugger.StateAsCString (event_state));
Chris Lattner24943d22010-06-08 16:52:24 +0000760 m_io_channel_ap->OutWrite(message, message_len);
761 }
762 break;
763
764 case eStateRunning:
765 // Don't be chatty when we run...
766 break;
767
768 case eStateExited:
Greg Clayton63094e02010-06-23 01:19:29 +0000769 m_debugger.HandleCommand("process status");
Chris Lattner24943d22010-06-08 16:52:24 +0000770 m_io_channel_ap->RefreshPrompt();
771 break;
772
773 case eStateStopped:
774 case eStateCrashed:
775 case eStateSuspended:
776 // Make sure the program hasn't been auto-restarted:
777 if (SBProcess::GetRestartedFromEvent (event))
778 {
779 // FIXME: Do we want to report this, or would that just be annoyingly chatty?
780 char message[1024];
781 int message_len = ::snprintf (message, sizeof(message), "Process %d stopped and was programmatically restarted.\n",
782 process.GetProcessID());
783 m_io_channel_ap->OutWrite(message, message_len);
784 }
785 else
786 {
Jim Inghamc8332952010-08-26 21:32:51 +0000787 UpdateSelectedThread ();
Greg Clayton63094e02010-06-23 01:19:29 +0000788 m_debugger.HandleCommand("process status");
Chris Lattner24943d22010-06-08 16:52:24 +0000789 m_io_channel_ap->RefreshPrompt();
790 }
791 break;
792 }
793 }
794}
795
796// This function handles events broadcast by the IOChannel (HasInput, UserInterrupt, or ThreadShouldExit).
797
798bool
799Driver::HandleIOEvent (const SBEvent &event)
800{
801 bool quit = false;
802
803 const uint32_t event_type = event.GetType();
804
805 if (event_type & IOChannel::eBroadcastBitHasUserInput)
806 {
807 // We got some input (i.e. a command string) from the user; pass it off to the command interpreter for
808 // handling.
809
810 const char *command_string = SBEvent::GetCStringFromEvent(event);
811 if (command_string == NULL)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000812 command_string = "";
Chris Lattner24943d22010-06-08 16:52:24 +0000813 SBCommandReturnObject result;
Greg Clayton63094e02010-06-23 01:19:29 +0000814 if (m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, true) != lldb::eReturnStatusQuit)
Chris Lattner24943d22010-06-08 16:52:24 +0000815 {
816 m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize());
817 m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize());
818 }
819 // We are done getting and running our command, we can now clear the
820 // m_waiting_for_command so we can get another one.
821 m_waiting_for_command = false;
822
823 // If our editline input reader is active, it means another input reader
824 // got pushed onto the input reader and caused us to become deactivated.
825 // When the input reader above us gets popped, we will get re-activated
826 // and our prompt will refresh in our callback
827 if (m_editline_reader.IsActive())
828 {
829 ReadyForCommand ();
830 }
831 }
832 else if (event_type & IOChannel::eBroadcastBitUserInterrupt)
833 {
834 // This is here to handle control-c interrupts from the user. It has not yet really been implemented.
835 // TO BE DONE: PROPERLY HANDLE CONTROL-C FROM USER
836 //m_io_channel_ap->CancelInput();
837 // Anything else? Send Interrupt to process?
838 }
839 else if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) ||
840 (event_type & IOChannel::eBroadcastBitThreadDidExit))
841 {
842 // If the IOChannel thread is trying to go away, then it is definitely
843 // time to end the debugging session.
844 quit = true;
845 }
846
847 return quit;
848}
849
850
851//struct CrashImageInfo
852//{
853// std::string path;
854// VMRange text_range;
855// UUID uuid;
856//};
857//
858//void
859//Driver::ParseCrashLog (const char *crash_log)
860//{
861// printf("Parsing crash log: %s\n", crash_log);
862//
863// char image_path[PATH_MAX];
864// std::vector<CrashImageInfo> crash_infos;
865// if (crash_log && crash_log[0])
866// {
867// FileSpec crash_log_file (crash_log);
868// STLStringArray crash_log_lines;
869// if (crash_log_file.ReadFileLines (crash_log_lines))
870// {
871// const size_t num_crash_log_lines = crash_log_lines.size();
872// size_t i;
873// for (i=0; i<num_crash_log_lines; ++i)
874// {
875// const char *line = crash_log_lines[i].c_str();
876// if (strstr (line, "Code Type:"))
877// {
878// char arch_string[256];
879// if (sscanf(line, "%s", arch_string))
880// {
881// if (strcmp(arch_string, "X86-64"))
882// lldb::GetDefaultArchitecture ().SetArch ("x86_64");
883// else if (strcmp(arch_string, "X86"))
884// lldb::GetDefaultArchitecture ().SetArch ("i386");
885// else
886// {
887// ArchSpec arch(arch_string);
888// if (arch.IsValid ())
889// lldb::GetDefaultArchitecture () = arch;
890// else
891// fprintf(stderr, "Unrecognized architecture: %s\n", arch_string);
892// }
893// }
894// }
895// else
896// if (strstr(line, "Path:"))
897// {
898// const char *p = line + strlen("Path:");
899// while (isspace(*p))
900// ++p;
901//
902// m_option_data.m_filename.assign (p);
903// }
904// else
905// if (strstr(line, "Binary Images:"))
906// {
907// while (++i < num_crash_log_lines)
908// {
909// if (crash_log_lines[i].empty())
910// break;
911//
912// line = crash_log_lines[i].c_str();
913// uint64_t text_start_addr;
914// uint64_t text_end_addr;
915// char uuid_cstr[64];
916// int bytes_consumed_before_uuid = 0;
917// int bytes_consumed_after_uuid = 0;
918//
919// int items_parsed = ::sscanf (line,
920// "%llx - %llx %*s %*s %*s %n%s %n",
921// &text_start_addr,
922// &text_end_addr,
923// &bytes_consumed_before_uuid,
924// uuid_cstr,
925// &bytes_consumed_after_uuid);
926//
927// if (items_parsed == 3)
928// {
929//
930// CrashImageInfo info;
931// info.text_range.SetBaseAddress(text_start_addr);
932// info.text_range.SetEndAddress(text_end_addr);
933//
934// if (uuid_cstr[0] == '<')
935// {
936// if (info.uuid.SetfromCString (&uuid_cstr[1]) == 0)
937// info.uuid.Clear();
938//
939// ::strncpy (image_path, line + bytes_consumed_after_uuid, sizeof(image_path));
940// }
941// else
942// {
943// ::strncpy (image_path, line + bytes_consumed_before_uuid, sizeof(image_path));
944// }
945//
946// info.path = image_path;
947//
948// crash_infos.push_back (info);
949//
950// info.uuid.GetAsCString(uuid_cstr, sizeof(uuid_cstr));
951//
952// printf("0x%16.16llx - 0x%16.16llx <%s> %s\n",
953// text_start_addr,
954// text_end_addr,
955// uuid_cstr,
956// image_path);
957// }
958// }
959// }
960// }
961// }
962//
963// if (crash_infos.size())
964// {
Greg Clayton63094e02010-06-23 01:19:29 +0000965// SBTarget target (m_debugger.CreateTarget (crash_infos.front().path.c_str(),
Chris Lattner24943d22010-06-08 16:52:24 +0000966// lldb::GetDefaultArchitecture().AsCString (),
967// false));
968// if (target.IsValid())
969// {
970//
971// }
972// }
973// }
974//}
975//
976
977void
978Driver::MasterThreadBytesReceived (void *baton, const void *src, size_t src_len)
979{
980 Driver *driver = (Driver*)baton;
981 driver->GetFromMaster ((const char *)src, src_len);
982}
983
984void
985Driver::GetFromMaster (const char *src, size_t src_len)
986{
987 // Echo the characters back to the Debugger's stdout, that way if you
988 // type characters while a command is running, you'll see what you've typed.
Greg Clayton63094e02010-06-23 01:19:29 +0000989 FILE *out_fh = m_debugger.GetOutputFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000990 if (out_fh)
991 ::fwrite (src, 1, src_len, out_fh);
992}
993
994size_t
995Driver::EditLineInputReaderCallback
996(
997 void *baton,
998 SBInputReader *reader,
999 InputReaderAction notification,
1000 const char *bytes,
1001 size_t bytes_len
1002)
1003{
1004 Driver *driver = (Driver *)baton;
1005
1006 switch (notification)
1007 {
1008 case eInputReaderActivate:
1009 break;
1010
1011 case eInputReaderReactivate:
1012 driver->ReadyForCommand();
1013 break;
1014
1015 case eInputReaderDeactivate:
1016 break;
1017
1018 case eInputReaderGotToken:
1019 write (driver->m_editline_pty.GetMasterFileDescriptor(), bytes, bytes_len);
1020 break;
1021
1022 case eInputReaderDone:
1023 break;
1024 }
1025 return bytes_len;
1026}
1027
1028void
1029Driver::MainLoop ()
1030{
1031 char error_str[1024];
1032 if (m_editline_pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, error_str, sizeof(error_str)) == false)
1033 {
1034 ::fprintf (stderr, "error: failed to open driver pseudo terminal : %s", error_str);
1035 exit(1);
1036 }
1037 else
1038 {
1039 const char *driver_slave_name = m_editline_pty.GetSlaveName (error_str, sizeof(error_str));
1040 if (driver_slave_name == NULL)
1041 {
1042 ::fprintf (stderr, "error: failed to get slave name for driver pseudo terminal : %s", error_str);
1043 exit(2);
1044 }
1045 else
1046 {
1047 m_editline_slave_fh = ::fopen (driver_slave_name, "r+");
1048 if (m_editline_slave_fh == NULL)
1049 {
1050 SBError error;
1051 error.SetErrorToErrno();
1052 ::fprintf (stderr, "error: failed to get open slave for driver pseudo terminal : %s",
1053 error.GetCString());
1054 exit(3);
1055 }
1056
1057 ::setbuf (m_editline_slave_fh, NULL);
1058 }
1059 }
1060
1061
1062 // struct termios stdin_termios;
1063
1064 if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0)
1065 atexit (reset_stdin_termios);
1066
1067 ::setbuf (stdin, NULL);
1068 ::setbuf (stdout, NULL);
1069
Greg Clayton63094e02010-06-23 01:19:29 +00001070 m_debugger.SetErrorFileHandle (stderr, false);
1071 m_debugger.SetOutputFileHandle (stdout, false);
1072 m_debugger.SetInputFileHandle (stdin, true);
Jim Ingham74989e82010-08-30 19:44:40 +00001073
1074 m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
Chris Lattner24943d22010-06-08 16:52:24 +00001075
1076 // You have to drain anything that comes to the master side of the PTY. master_out_comm is
1077 // for that purpose. The reason you need to do this is a curious reason... editline will echo
1078 // characters to the PTY when it gets characters while el_gets is not running, and then when
1079 // you call el_gets (or el_getc) it will try to reset the terminal back to raw mode which blocks
1080 // if there are unconsumed characters in the out buffer.
1081 // However, you don't need to do anything with the characters, since editline will dump these
1082 // unconsumed characters after printing the prompt again in el_gets.
1083
1084 SBCommunication master_out_comm("driver.editline");
1085 master_out_comm.AdoptFileDesriptor(m_editline_pty.GetMasterFileDescriptor(), false);
1086 master_out_comm.SetReadThreadBytesReceivedCallback(Driver::MasterThreadBytesReceived, this);
1087
1088 if (master_out_comm.ReadThreadStart () == false)
1089 {
1090 ::fprintf (stderr, "error: failed to start master out read thread");
1091 exit(5);
1092 }
1093
1094// const char *crash_log = GetCrashLogFilename();
1095// if (crash_log)
1096// {
1097// ParseCrashLog (crash_log);
1098// }
1099//
Greg Clayton63094e02010-06-23 01:19:29 +00001100 SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
Chris Lattner24943d22010-06-08 16:52:24 +00001101
1102 m_io_channel_ap.reset (new IOChannel(m_editline_slave_fh, stdout, stderr, this));
1103
1104 struct winsize window_size;
1105 if (isatty (STDIN_FILENO)
1106 && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
1107 {
Caroline Tice6e4c5ce2010-09-04 00:03:46 +00001108 if (window_size.ws_col > 0)
Greg Clayton238c0a12010-09-18 01:14:36 +00001109 m_debugger.SetTerminalWidth (window_size.ws_col);
Chris Lattner24943d22010-06-08 16:52:24 +00001110 }
1111
1112 // Since input can be redirected by the debugger, we must insert our editline
1113 // input reader in the queue so we know when our reader should be active
1114 // and so we can receive bytes only when we are supposed to.
Greg Clayton63094e02010-06-23 01:19:29 +00001115 SBError err (m_editline_reader.Initialize (m_debugger,
1116 Driver::EditLineInputReaderCallback, // callback
Chris Lattner24943d22010-06-08 16:52:24 +00001117 this, // baton
1118 eInputReaderGranularityByte, // token_size
1119 NULL, // end token - NULL means never done
1120 NULL, // prompt - taken care of elsewhere
1121 false)); // echo input - don't need Debugger
1122 // to do this, we handle it elsewhere
1123
1124 if (err.Fail())
1125 {
1126 ::fprintf (stderr, "error: %s", err.GetCString());
1127 exit (6);
1128 }
1129
Greg Clayton63094e02010-06-23 01:19:29 +00001130 m_debugger.PushInputReader (m_editline_reader);
Chris Lattner24943d22010-06-08 16:52:24 +00001131
Greg Clayton63094e02010-06-23 01:19:29 +00001132 SBListener listener(m_debugger.GetListener());
Chris Lattner24943d22010-06-08 16:52:24 +00001133 if (listener.IsValid())
1134 {
1135
1136 listener.StartListeningForEvents (*m_io_channel_ap,
1137 IOChannel::eBroadcastBitHasUserInput |
1138 IOChannel::eBroadcastBitUserInterrupt |
1139 IOChannel::eBroadcastBitThreadShouldExit |
1140 IOChannel::eBroadcastBitThreadDidStart |
1141 IOChannel::eBroadcastBitThreadDidExit);
1142
1143 if (m_io_channel_ap->Start ())
1144 {
1145 bool iochannel_thread_exited = false;
1146
1147 listener.StartListeningForEvents (sb_interpreter.GetBroadcaster(),
1148 SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
1149
1150 // Before we handle any options from the command line, we parse the
1151 // .lldbinit file in the user's home directory.
1152 SBCommandReturnObject result;
1153 sb_interpreter.SourceInitFileInHomeDirectory(result);
1154 if (GetDebugMode())
1155 {
Greg Clayton63094e02010-06-23 01:19:29 +00001156 result.PutError (m_debugger.GetErrorFileHandle());
1157 result.PutOutput (m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001158 }
1159
1160 // Now we handle options we got from the command line
1161 char command_string[PATH_MAX * 2];
1162 const size_t num_source_command_files = GetNumSourceCommandFiles();
1163 if (num_source_command_files > 0)
1164 {
1165 for (size_t i=0; i < num_source_command_files; ++i)
1166 {
1167 const char *command_file = GetSourceCommandFileAtIndex(i);
Johnny Chen7c984242010-07-28 21:16:11 +00001168 ::snprintf (command_string, sizeof(command_string), "command source '%s'", command_file);
Greg Clayton63094e02010-06-23 01:19:29 +00001169 m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, false);
Chris Lattner24943d22010-06-08 16:52:24 +00001170 if (GetDebugMode())
1171 {
Greg Clayton63094e02010-06-23 01:19:29 +00001172 result.PutError (m_debugger.GetErrorFileHandle());
1173 result.PutOutput (m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001174 }
1175 }
1176 }
1177
1178 if (!m_option_data.m_filename.empty())
1179 {
1180 char arch_name[64];
Greg Clayton63094e02010-06-23 01:19:29 +00001181 if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name)))
Chris Lattner24943d22010-06-08 16:52:24 +00001182 ::snprintf (command_string, sizeof (command_string), "file --arch=%s '%s'", arch_name,
1183 m_option_data.m_filename.c_str());
1184 else
1185 ::snprintf (command_string, sizeof(command_string), "file '%s'", m_option_data.m_filename.c_str());
1186
Greg Clayton63094e02010-06-23 01:19:29 +00001187 m_debugger.HandleCommand (command_string);
Chris Lattner24943d22010-06-08 16:52:24 +00001188 }
1189
1190 // Now that all option parsing is done, we try and parse the .lldbinit
1191 // file in the current working directory
1192 sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result);
1193 if (GetDebugMode())
1194 {
Greg Clayton63094e02010-06-23 01:19:29 +00001195 result.PutError(m_debugger.GetErrorFileHandle());
1196 result.PutOutput(m_debugger.GetOutputFileHandle());
Chris Lattner24943d22010-06-08 16:52:24 +00001197 }
1198
1199 SBEvent event;
1200
1201 // Make sure the IO channel is started up before we try to tell it we
1202 // are ready for input
1203 listener.WaitForEventForBroadcasterWithType (UINT32_MAX,
1204 *m_io_channel_ap,
1205 IOChannel::eBroadcastBitThreadDidStart,
1206 event);
1207
1208 ReadyForCommand ();
1209
1210 bool done = false;
1211 while (!done)
1212 {
1213 listener.WaitForEvent (UINT32_MAX, event);
1214 if (event.IsValid())
1215 {
1216 if (event.GetBroadcaster().IsValid())
1217 {
1218 uint32_t event_type = event.GetType();
1219 if (event.BroadcasterMatchesRef (*m_io_channel_ap))
1220 {
1221 if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) ||
1222 (event_type & IOChannel::eBroadcastBitThreadDidExit))
1223 {
1224 done = true;
1225 if (event_type & IOChannel::eBroadcastBitThreadDidExit)
1226 iochannel_thread_exited = true;
1227 break;
1228 }
1229 else
1230 done = HandleIOEvent (event);
1231 }
Jim Inghamc8332952010-08-26 21:32:51 +00001232 else if (event.BroadcasterMatchesRef (m_debugger.GetSelectedTarget().GetProcess().GetBroadcaster()))
Chris Lattner24943d22010-06-08 16:52:24 +00001233 {
1234 HandleProcessEvent (event);
1235 }
1236 else if (event.BroadcasterMatchesRef (sb_interpreter.GetBroadcaster()))
1237 {
1238 if (event_type & SBCommandInterpreter::eBroadcastBitQuitCommandReceived)
1239 done = true;
1240 }
1241 }
1242 }
1243 }
1244
1245 reset_stdin_termios ();
1246
1247 CloseIOChannelFile ();
1248
1249 if (!iochannel_thread_exited)
1250 {
Greg Claytonbef15832010-07-14 00:18:15 +00001251 event.Clear();
Chris Lattner24943d22010-06-08 16:52:24 +00001252 listener.GetNextEventForBroadcasterWithType (*m_io_channel_ap,
1253 IOChannel::eBroadcastBitThreadDidExit,
1254 event);
1255 if (!event.IsValid())
1256 {
1257 // Send end EOF to the driver file descriptor
1258 m_io_channel_ap->Stop();
1259 }
1260 }
1261
Jim Inghamc8332952010-08-26 21:32:51 +00001262 SBProcess process = m_debugger.GetSelectedTarget().GetProcess();
Chris Lattner24943d22010-06-08 16:52:24 +00001263 if (process.IsValid())
1264 process.Destroy();
1265 }
1266 }
1267}
1268
1269
1270void
1271Driver::ReadyForCommand ()
1272{
1273 if (m_waiting_for_command == false)
1274 {
1275 m_waiting_for_command = true;
1276 BroadcastEventByType (Driver::eBroadcastBitReadyForInput, true);
1277 }
1278}
1279
1280
Caroline Ticeb8314fe2010-09-09 17:45:09 +00001281void
1282sigwinch_handler (int signo)
1283{
1284 struct winsize window_size;
1285 if (isatty (STDIN_FILENO)
1286 && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
1287 {
1288 if ((window_size.ws_col > 0) && (strlen (g_debugger_name) > 0))
1289 {
1290 char width_str_buffer[25];
1291 ::sprintf (width_str_buffer, "%d", window_size.ws_col);
1292 SBDebugger::SetInternalVariable ("term-width", width_str_buffer, g_debugger_name);
1293 }
1294 }
1295}
1296
Chris Lattner24943d22010-06-08 16:52:24 +00001297int
1298main (int argc, char const *argv[])
1299{
Chris Lattner24943d22010-06-08 16:52:24 +00001300 SBDebugger::Initialize();
1301
1302 SBHostOS::ThreadCreated ("[main]");
1303
Caroline Ticeb8314fe2010-09-09 17:45:09 +00001304 signal (SIGWINCH, sigwinch_handler);
1305
Greg Clayton63094e02010-06-23 01:19:29 +00001306 // Create a scope for driver so that the driver object will destroy itself
1307 // before SBDebugger::Terminate() is called.
Chris Lattner24943d22010-06-08 16:52:24 +00001308 {
Greg Clayton63094e02010-06-23 01:19:29 +00001309 Driver driver;
1310
1311 bool exit = false;
1312 SBError error (driver.ParseArgs (argc, argv, stdout, exit));
1313 if (error.Fail())
1314 {
1315 const char *error_cstr = error.GetCString ();
1316 if (error_cstr)
1317 ::fprintf (stderr, "error: %s\n", error_cstr);
1318 }
1319 else if (!exit)
1320 {
1321 driver.MainLoop ();
1322 }
Chris Lattner24943d22010-06-08 16:52:24 +00001323 }
1324
1325 SBDebugger::Terminate();
1326 return 0;
1327}