Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/tools/driver/Driver.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- Driver.cpp ----------------------------------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "Driver.h"
10
11
#include "lldb/API/SBCommandInterpreter.h"
12
#include "lldb/API/SBCommandInterpreterRunOptions.h"
13
#include "lldb/API/SBCommandReturnObject.h"
14
#include "lldb/API/SBDebugger.h"
15
#include "lldb/API/SBFile.h"
16
#include "lldb/API/SBHostOS.h"
17
#include "lldb/API/SBLanguageRuntime.h"
18
#include "lldb/API/SBReproducer.h"
19
#include "lldb/API/SBStream.h"
20
#include "lldb/API/SBStringList.h"
21
#include "lldb/API/SBStructuredData.h"
22
23
#include "llvm/ADT/StringRef.h"
24
#include "llvm/Support/Format.h"
25
#include "llvm/Support/InitLLVM.h"
26
#include "llvm/Support/Path.h"
27
#include "llvm/Support/Signals.h"
28
#include "llvm/Support/WithColor.h"
29
#include "llvm/Support/raw_ostream.h"
30
31
#include <algorithm>
32
#include <atomic>
33
#include <bitset>
34
#include <clocale>
35
#include <csignal>
36
#include <string>
37
#include <thread>
38
#include <utility>
39
40
#include <climits>
41
#include <cstdio>
42
#include <cstdlib>
43
#include <cstring>
44
#include <fcntl.h>
45
46
#if !defined(__APPLE__)
47
#include "llvm/Support/DataTypes.h"
48
#endif
49
50
using namespace lldb;
51
using namespace llvm;
52
53
namespace {
54
enum ID {
55
  OPT_INVALID = 0, // This is not an option ID.
56
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
57
               HELPTEXT, METAVAR, VALUES)                                      \
58
  OPT_##ID,
59
#include "Options.inc"
60
#undef OPTION
61
};
62
63
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
64
#include "Options.inc"
65
#undef PREFIX
66
67
const opt::OptTable::Info InfoTable[] = {
68
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
69
               HELPTEXT, METAVAR, VALUES)                                      \
70
  {                                                                            \
71
      PREFIX,      NAME,      HELPTEXT,                                        \
72
      METAVAR,     OPT_##ID,  opt::Option::KIND##Class,                        \
73
      PARAM,       FLAGS,     OPT_##GROUP,                                     \
74
      OPT_##ALIAS, ALIASARGS, VALUES},
75
#include "Options.inc"
76
#undef OPTION
77
};
78
79
class LLDBOptTable : public opt::OptTable {
80
public:
81
2.34k
  LLDBOptTable() : OptTable(InfoTable) {}
82
};
83
} // namespace
84
85
static void reset_stdin_termios();
86
static bool g_old_stdin_termios_is_valid = false;
87
static struct termios g_old_stdin_termios;
88
89
static Driver *g_driver = nullptr;
90
91
// In the Driver::MainLoop, we change the terminal settings.  This function is
92
// added as an atexit handler to make sure we clean them up.
93
331
static void reset_stdin_termios() {
94
331
  if (g_old_stdin_termios_is_valid) {
95
8
    g_old_stdin_termios_is_valid = false;
96
8
    ::tcsetattr(STDIN_FILENO, TCSANOW, &g_old_stdin_termios);
97
8
  }
98
331
}
99
100
Driver::Driver()
101
2.34k
    : SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)) {
102
  // We want to be able to handle CTRL+D in the terminal to have it terminate
103
  // certain input
104
2.34k
  m_debugger.SetCloseInputOnEOF(false);
105
2.34k
  g_driver = this;
106
2.34k
}
107
108
2.34k
Driver::~Driver() {
109
2.34k
  SBDebugger::Destroy(m_debugger);
110
2.34k
  g_driver = nullptr;
111
2.34k
}
112
113
void Driver::OptionData::AddInitialCommand(std::string command,
114
                                           CommandPlacement placement,
115
955
                                           bool is_file, SBError &error) {
116
955
  std::vector<InitialCmdEntry> *command_set;
117
955
  switch (placement) {
118
413
  case eCommandPlacementBeforeFile:
119
413
    command_set = &(m_initial_commands);
120
413
    break;
121
541
  case eCommandPlacementAfterFile:
122
541
    command_set = &(m_after_file_commands);
123
541
    break;
124
1
  case eCommandPlacementAfterCrash:
125
1
    command_set = &(m_after_crash_commands);
126
1
    break;
127
955
  }
128
129
955
  if (is_file) {
130
461
    SBFileSpec file(command.c_str());
131
461
    if (file.Exists())
132
461
      command_set->push_back(InitialCmdEntry(command, is_file));
133
0
    else if (file.ResolveExecutableLocation()) {
134
0
      char final_path[PATH_MAX];
135
0
      file.GetPath(final_path, sizeof(final_path));
136
0
      command_set->push_back(InitialCmdEntry(final_path, is_file));
137
0
    } else
138
0
      error.SetErrorStringWithFormat(
139
0
          "file specified in --source (-s) option doesn't exist: '%s'",
140
0
          command.c_str());
141
461
  } else
142
494
    command_set->push_back(InitialCmdEntry(command, is_file));
143
955
}
144
145
void Driver::WriteCommandsForSourcing(CommandPlacement placement,
146
694
                                      SBStream &strm) {
147
694
  std::vector<OptionData::InitialCmdEntry> *command_set;
148
694
  switch (placement) {
149
348
  case eCommandPlacementBeforeFile:
150
348
    command_set = &m_option_data.m_initial_commands;
151
348
    break;
152
345
  case eCommandPlacementAfterFile:
153
345
    command_set = &m_option_data.m_after_file_commands;
154
345
    break;
155
1
  case eCommandPlacementAfterCrash:
156
1
    command_set = &m_option_data.m_after_crash_commands;
157
1
    break;
158
694
  }
159
160
953
  
for (const auto &command_entry : *command_set)694
{
161
953
    const char *command = command_entry.contents.c_str();
162
953
    if (command_entry.is_file) {
163
460
      bool source_quietly =
164
460
          m_option_data.m_source_quietly || 
command_entry.source_quietly456
;
165
460
      strm.Printf("command source -s %i '%s'\n",
166
460
                  static_cast<int>(source_quietly), command);
167
460
    } else
168
493
      strm.Printf("%s\n", command);
169
953
  }
170
694
}
171
172
// Check the arguments that were passed to this program to make sure they are
173
// valid and to get their argument values (if any).  Return a boolean value
174
// indicating whether or not to start up the full debugger (i.e. the Command
175
// Interpreter) or not.  Return FALSE if the arguments were invalid OR if the
176
// user only wanted help or version information.
177
2.34k
SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {
178
2.34k
  SBError error;
179
180
  // This is kind of a pain, but since we make the debugger in the Driver's
181
  // constructor, we can't know at that point whether we should read in init
182
  // files yet.  So we don't read them in in the Driver constructor, then set
183
  // the flags back to "read them in" here, and then if we see the "-n" flag,
184
  // we'll turn it off again.  Finally we have to read them in by hand later in
185
  // the main loop.
186
2.34k
  m_debugger.SkipLLDBInitFiles(false);
187
2.34k
  m_debugger.SkipAppInitFiles(false);
188
189
2.34k
  if (args.hasArg(OPT_version)) {
190
996
    m_option_data.m_print_version = true;
191
996
  }
192
193
2.34k
  if (args.hasArg(OPT_python_path)) {
194
996
    m_option_data.m_print_python_path = true;
195
996
  }
196
2.34k
  if (args.hasArg(OPT_print_script_interpreter_info)) {
197
0
    m_option_data.m_print_script_interpreter_info = true;
198
0
  }
199
200
2.34k
  if (args.hasArg(OPT_batch)) {
201
186
    m_option_data.m_batch = true;
202
186
  }
203
204
2.34k
  if (auto *arg = args.getLastArg(OPT_core)) {
205
84
    auto arg_value = arg->getValue();
206
84
    SBFileSpec file(arg_value);
207
84
    if (!file.Exists()) {
208
1
      error.SetErrorStringWithFormat(
209
1
          "file specified in --core (-c) option doesn't exist: '%s'",
210
1
          arg_value);
211
1
      return error;
212
1
    }
213
83
    m_option_data.m_core_file = arg_value;
214
83
  }
215
216
2.34k
  if (args.hasArg(OPT_editor)) {
217
0
    m_option_data.m_use_external_editor = true;
218
0
  }
219
220
2.34k
  if (args.hasArg(OPT_no_lldbinit)) {
221
339
    m_debugger.SkipLLDBInitFiles(true);
222
339
    m_debugger.SkipAppInitFiles(true);
223
339
  }
224
225
2.34k
  if (args.hasArg(OPT_local_lldbinit)) {
226
1
    lldb::SBDebugger::SetInternalVariable("target.load-cwd-lldbinit", "true",
227
1
                                          m_debugger.GetInstanceName());
228
1
  }
229
230
2.34k
  if (args.hasArg(OPT_no_use_colors)) {
231
8
    m_debugger.SetUseColor(false);
232
8
    m_option_data.m_debug_mode = true;
233
8
  }
234
235
2.34k
  if (auto *arg = args.getLastArg(OPT_file)) {
236
15
    auto arg_value = arg->getValue();
237
15
    SBFileSpec file(arg_value);
238
15
    if (file.Exists()) {
239
14
      m_option_data.m_args.emplace_back(arg_value);
240
14
    } else 
if (1
file.ResolveExecutableLocation()1
) {
241
0
      char path[PATH_MAX];
242
0
      file.GetPath(path, sizeof(path));
243
0
      m_option_data.m_args.emplace_back(path);
244
1
    } else {
245
1
      error.SetErrorStringWithFormat(
246
1
          "file specified in --file (-f) option doesn't exist: '%s'",
247
1
          arg_value);
248
1
      return error;
249
1
    }
250
15
  }
251
252
2.34k
  if (auto *arg = args.getLastArg(OPT_arch)) {
253
0
    auto arg_value = arg->getValue();
254
0
    if (!lldb::SBDebugger::SetDefaultArchitecture(arg_value)) {
255
0
      error.SetErrorStringWithFormat(
256
0
          "invalid architecture in the -a or --arch option: '%s'", arg_value);
257
0
      return error;
258
0
    }
259
0
  }
260
261
2.34k
  if (auto *arg = args.getLastArg(OPT_script_language)) {
262
18
    auto arg_value = arg->getValue();
263
18
    m_debugger.SetScriptLanguage(m_debugger.GetScriptingLanguage(arg_value));
264
18
  }
265
266
2.34k
  if (args.hasArg(OPT_source_quietly)) {
267
3
    m_option_data.m_source_quietly = true;
268
3
  }
269
270
2.34k
  if (auto *arg = args.getLastArg(OPT_attach_name)) {
271
0
    auto arg_value = arg->getValue();
272
0
    m_option_data.m_process_name = arg_value;
273
0
  }
274
275
2.34k
  if (args.hasArg(OPT_wait_for)) {
276
0
    m_option_data.m_wait_for = true;
277
0
  }
278
279
2.34k
  if (auto *arg = args.getLastArg(OPT_attach_pid)) {
280
0
    auto arg_value = arg->getValue();
281
0
    char *remainder;
282
0
    m_option_data.m_process_pid = strtol(arg_value, &remainder, 0);
283
0
    if (remainder == arg_value || *remainder != '\0') {
284
0
      error.SetErrorStringWithFormat(
285
0
          "Could not convert process PID: \"%s\" into a pid.", arg_value);
286
0
      return error;
287
0
    }
288
0
  }
289
290
2.34k
  if (auto *arg = args.getLastArg(OPT_repl_language)) {
291
3
    auto arg_value = arg->getValue();
292
3
    m_option_data.m_repl_lang =
293
3
        SBLanguageRuntime::GetLanguageTypeFromString(arg_value);
294
3
    if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {
295
1
      error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",
296
1
                                     arg_value);
297
1
      return error;
298
1
    }
299
2
    m_debugger.SetREPLLanguage(m_option_data.m_repl_lang);
300
2
  }
301
302
2.34k
  if (args.hasArg(OPT_repl)) {
303
3
    m_option_data.m_repl = true;
304
3
  }
305
306
2.34k
  if (auto *arg = args.getLastArg(OPT_repl_)) {
307
0
    m_option_data.m_repl = true;
308
0
    if (auto arg_value = arg->getValue())
309
0
      m_option_data.m_repl_options = arg_value;
310
0
  }
311
312
  // We need to process the options below together as their relative order
313
  // matters.
314
2.34k
  for (auto *arg : args.filtered(OPT_source_on_crash, OPT_one_line_on_crash,
315
2.34k
                                 OPT_source, OPT_source_before_file,
316
2.34k
                                 OPT_one_line, OPT_one_line_before_file)) {
317
955
    auto arg_value = arg->getValue();
318
955
    if (arg->getOption().matches(OPT_source_on_crash)) {
319
0
      m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
320
0
                                      true, error);
321
0
      if (error.Fail())
322
0
        return error;
323
0
    }
324
325
955
    if (arg->getOption().matches(OPT_one_line_on_crash)) {
326
1
      m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
327
1
                                      false, error);
328
1
      if (error.Fail())
329
0
        return error;
330
1
    }
331
332
955
    if (arg->getOption().matches(OPT_source)) {
333
123
      m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
334
123
                                      true, error);
335
123
      if (error.Fail())
336
0
        return error;
337
123
    }
338
339
955
    if (arg->getOption().matches(OPT_source_before_file)) {
340
338
      m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
341
338
                                      true, error);
342
338
      if (error.Fail())
343
0
        return error;
344
338
    }
345
346
955
    if (arg->getOption().matches(OPT_one_line)) {
347
418
      m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
348
418
                                      false, error);
349
418
      if (error.Fail())
350
0
        return error;
351
418
    }
352
353
955
    if (arg->getOption().matches(OPT_one_line_before_file)) {
354
75
      m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
355
75
                                      false, error);
356
75
      if (error.Fail())
357
0
        return error;
358
75
    }
359
955
  }
360
361
2.34k
  if (m_option_data.m_process_name.empty() &&
362
2.34k
      m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {
363
364
2.34k
    for (auto *arg : args.filtered(OPT_INPUT))
365
159
      m_option_data.m_args.push_back(arg->getAsString((args)));
366
367
    // Any argument following -- is an argument for the inferior.
368
2.34k
    if (auto *arg = args.getLastArgNoClaim(OPT_REM)) {
369
13
      for (auto value : arg->getValues())
370
29
        m_option_data.m_args.emplace_back(value);
371
13
    }
372
2.34k
  } else 
if (0
args.getLastArgNoClaim() != nullptr0
) {
373
0
    WithColor::warning() << "program arguments are ignored when attaching.\n";
374
0
  }
375
376
2.34k
  if (m_option_data.m_print_version) {
377
996
    llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
378
996
    exiting = true;
379
996
    return error;
380
996
  }
381
382
1.34k
  if (m_option_data.m_print_python_path) {
383
996
    SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();
384
996
    if (python_file_spec.IsValid()) {
385
996
      char python_path[PATH_MAX];
386
996
      size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX);
387
996
      if (num_chars < PATH_MAX) {
388
996
        llvm::outs() << python_path << '\n';
389
996
      } else
390
0
        llvm::outs() << "<PATH TOO LONG>\n";
391
996
    } else
392
0
      llvm::outs() << "<COULD NOT FIND PATH>\n";
393
996
    exiting = true;
394
996
    return error;
395
996
  }
396
397
348
  if (m_option_data.m_print_script_interpreter_info) {
398
0
    SBStructuredData info =
399
0
        m_debugger.GetScriptInterpreterInfo(m_debugger.GetScriptLanguage());
400
0
    if (!info) {
401
0
      error.SetErrorString("no script interpreter.");
402
0
    } else {
403
0
      SBStream stream;
404
0
      error = info.GetAsJSON(stream);
405
0
      if (error.Success()) {
406
0
        llvm::outs() << stream.GetData() << '\n';
407
0
      }
408
0
    }
409
0
    exiting = true;
410
0
    return error;
411
0
  }
412
413
348
  return error;
414
348
}
415
416
285
std::string EscapeString(std::string arg) {
417
285
  std::string::size_type pos = 0;
418
285
  while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos) {
419
0
    arg.insert(pos, 1, '\\');
420
0
    pos += 2;
421
0
  }
422
285
  return '"' + arg + '"';
423
285
}
424
425
348
int Driver::MainLoop() {
426
348
  if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) {
427
8
    g_old_stdin_termios_is_valid = true;
428
8
    atexit(reset_stdin_termios);
429
8
  }
430
431
348
#ifndef _MSC_VER
432
  // Disabling stdin buffering with MSVC's 2015 CRT exposes a bug in fgets
433
  // which causes it to miss newlines depending on whether there have been an
434
  // odd or even number of characters.  Bug has been reported to MS via Connect.
435
348
  ::setbuf(stdin, nullptr);
436
348
#endif
437
348
  ::setbuf(stdout, nullptr);
438
439
348
  m_debugger.SetErrorFileHandle(stderr, false);
440
348
  m_debugger.SetOutputFileHandle(stdout, false);
441
  // Don't take ownership of STDIN yet...
442
348
  m_debugger.SetInputFileHandle(stdin, false);
443
444
348
  m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
445
446
348
  struct winsize window_size;
447
348
  if ((isatty(STDIN_FILENO) != 0) &&
448
348
      
::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 08
) {
449
8
    if (window_size.ws_col > 0)
450
8
      m_debugger.SetTerminalWidth(window_size.ws_col);
451
8
  }
452
453
348
  SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
454
455
  // Before we handle any options from the command line, we parse the
456
  // REPL init file or the default file in the user's home directory.
457
348
  SBCommandReturnObject result;
458
348
  sb_interpreter.SourceInitFileInHomeDirectory(result, m_option_data.m_repl);
459
348
  if (m_option_data.m_debug_mode) {
460
8
    result.PutError(m_debugger.GetErrorFile());
461
8
    result.PutOutput(m_debugger.GetOutputFile());
462
8
  }
463
464
  // Source the local .lldbinit file if it exists and we're allowed to source.
465
  // Here we want to always print the return object because it contains the
466
  // warning and instructions to load local lldbinit files.
467
348
  sb_interpreter.SourceInitFileInCurrentWorkingDirectory(result);
468
348
  result.PutError(m_debugger.GetErrorFile());
469
348
  result.PutOutput(m_debugger.GetOutputFile());
470
471
  // We allow the user to specify an exit code when calling quit which we will
472
  // return when exiting.
473
348
  m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true);
474
475
  // Now we handle options we got from the command line
476
348
  SBStream commands_stream;
477
478
  // First source in the commands specified to be run before the file arguments
479
  // are processed.
480
348
  WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream);
481
482
  // If we're not in --repl mode, add the commands to process the file
483
  // arguments, and the commands specified to run afterwards.
484
348
  if (!m_option_data.m_repl) {
485
345
    const size_t num_args = m_option_data.m_args.size();
486
345
    if (num_args > 0) {
487
161
      char arch_name[64];
488
161
      if (lldb::SBDebugger::GetDefaultArchitecture(arch_name,
489
161
                                                   sizeof(arch_name)))
490
0
        commands_stream.Printf("target create --arch=%s %s", arch_name,
491
0
                               EscapeString(m_option_data.m_args[0]).c_str());
492
161
      else
493
161
        commands_stream.Printf("target create %s",
494
161
                               EscapeString(m_option_data.m_args[0]).c_str());
495
496
161
      if (!m_option_data.m_core_file.empty()) {
497
5
        commands_stream.Printf(" --core %s",
498
5
                               EscapeString(m_option_data.m_core_file).c_str());
499
5
      }
500
161
      commands_stream.Printf("\n");
501
502
161
      if (num_args > 1) {
503
15
        commands_stream.Printf("settings set -- target.run-args ");
504
56
        for (size_t arg_idx = 1; arg_idx < num_args; 
++arg_idx41
)
505
41
          commands_stream.Printf(
506
41
              " %s", EscapeString(m_option_data.m_args[arg_idx]).c_str());
507
15
        commands_stream.Printf("\n");
508
15
      }
509
184
    } else if (!m_option_data.m_core_file.empty()) {
510
78
      commands_stream.Printf("target create --core %s\n",
511
78
                             EscapeString(m_option_data.m_core_file).c_str());
512
106
    } else if (!m_option_data.m_process_name.empty()) {
513
0
      commands_stream.Printf(
514
0
          "process attach --name %s",
515
0
          EscapeString(m_option_data.m_process_name).c_str());
516
517
0
      if (m_option_data.m_wait_for)
518
0
        commands_stream.Printf(" --waitfor");
519
520
0
      commands_stream.Printf("\n");
521
522
106
    } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) {
523
0
      commands_stream.Printf("process attach --pid %" PRIu64 "\n",
524
0
                             m_option_data.m_process_pid);
525
0
    }
526
527
345
    WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream);
528
345
  } else 
if (3
!m_option_data.m_after_file_commands.empty()3
) {
529
    // We're in repl mode and after-file-load commands were specified.
530
1
    WithColor::warning() << "commands specified to run after file load (via -o "
531
1
                            "or -s) are ignored in REPL mode.\n";
532
1
  }
533
534
348
  if (m_option_data.m_debug_mode) {
535
8
    result.PutError(m_debugger.GetErrorFile());
536
8
    result.PutOutput(m_debugger.GetOutputFile());
537
8
  }
538
539
348
  const bool handle_events = true;
540
348
  const bool spawn_thread = false;
541
542
  // Check if we have any data in the commands stream, and if so, save it to a
543
  // temp file
544
  // so we can then run the command interpreter using the file contents.
545
348
  bool go_interactive = true;
546
348
  if ((commands_stream.GetData() != nullptr) &&
547
348
      (commands_stream.GetSize() != 0u)) {
548
347
    SBError error = m_debugger.SetInputString(commands_stream.GetData());
549
347
    if (error.Fail()) {
550
0
      WithColor::error() << error.GetCString() << '\n';
551
0
      return 1;
552
0
    }
553
554
    // Set the debugger into Sync mode when running the command file. Otherwise
555
    // command files that run the target won't run in a sensible way.
556
347
    bool old_async = m_debugger.GetAsync();
557
347
    m_debugger.SetAsync(false);
558
559
347
    SBCommandInterpreterRunOptions options;
560
347
    options.SetAutoHandleEvents(true);
561
347
    options.SetSpawnThread(false);
562
347
    options.SetStopOnError(true);
563
347
    options.SetStopOnCrash(m_option_data.m_batch);
564
347
    options.SetEchoCommands(!m_option_data.m_source_quietly);
565
566
347
    SBCommandInterpreterRunResult results =
567
347
        m_debugger.RunCommandInterpreter(options);
568
347
    if (results.GetResult() == lldb::eCommandInterpreterResultQuitRequested)
569
89
      go_interactive = false;
570
347
    if (m_option_data.m_batch &&
571
347
        
results.GetResult() != lldb::eCommandInterpreterResultInferiorCrash186
)
572
185
      go_interactive = false;
573
574
    // When running in batch mode and stopped because of an error, exit with a
575
    // non-zero exit status.
576
347
    if (m_option_data.m_batch &&
577
347
        
results.GetResult() == lldb::eCommandInterpreterResultCommandError186
)
578
25
      return 1;
579
580
322
    if (m_option_data.m_batch &&
581
322
        
results.GetResult() == lldb::eCommandInterpreterResultInferiorCrash161
&&
582
322
        
!m_option_data.m_after_crash_commands.empty()1
) {
583
1
      SBStream crash_commands_stream;
584
1
      WriteCommandsForSourcing(eCommandPlacementAfterCrash,
585
1
                               crash_commands_stream);
586
1
      SBError error =
587
1
          m_debugger.SetInputString(crash_commands_stream.GetData());
588
1
      if (error.Success()) {
589
1
        SBCommandInterpreterRunResult local_results =
590
1
            m_debugger.RunCommandInterpreter(options);
591
1
        if (local_results.GetResult() ==
592
1
            lldb::eCommandInterpreterResultQuitRequested)
593
0
          go_interactive = false;
594
595
        // When running in batch mode and an error occurred while sourcing
596
        // the crash commands, exit with a non-zero exit status.
597
1
        if (m_option_data.m_batch &&
598
1
            local_results.GetResult() ==
599
1
                lldb::eCommandInterpreterResultCommandError)
600
0
          return 1;
601
1
      }
602
1
    }
603
322
    m_debugger.SetAsync(old_async);
604
322
  }
605
606
  // Now set the input file handle to STDIN and run the command interpreter
607
  // again in interactive mode or repl mode and let the debugger take ownership
608
  // of stdin.
609
323
  if (go_interactive) {
610
100
    m_debugger.SetInputFileHandle(stdin, true);
611
612
100
    if (m_option_data.m_repl) {
613
3
      const char *repl_options = nullptr;
614
3
      if (!m_option_data.m_repl_options.empty())
615
0
        repl_options = m_option_data.m_repl_options.c_str();
616
3
      SBError error(
617
3
          m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options));
618
3
      if (error.Fail()) {
619
3
        const char *error_cstr = error.GetCString();
620
3
        if ((error_cstr != nullptr) && (error_cstr[0] != 0))
621
3
          WithColor::error() << error_cstr << '\n';
622
0
        else
623
0
          WithColor::error() << error.GetError() << '\n';
624
3
      }
625
97
    } else {
626
97
      m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
627
97
    }
628
100
  }
629
630
323
  reset_stdin_termios();
631
323
  fclose(stdin);
632
633
323
  return sb_interpreter.GetQuitStatus();
634
348
}
635
636
0
void Driver::ResizeWindow(unsigned short col) {
637
0
  GetDebugger().SetTerminalWidth(col);
638
0
}
639
640
0
void sigwinch_handler(int signo) {
641
0
  struct winsize window_size;
642
0
  if ((isatty(STDIN_FILENO) != 0) &&
643
0
      ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
644
0
    if ((window_size.ws_col > 0) && g_driver != nullptr) {
645
0
      g_driver->ResizeWindow(window_size.ws_col);
646
0
    }
647
0
  }
648
0
}
649
650
0
void sigint_handler(int signo) {
651
#ifdef _WIN32 // Restore handler as it is not persistent on Windows
652
  signal(SIGINT, sigint_handler);
653
#endif
654
0
  static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
655
0
  if (g_driver != nullptr) {
656
0
    if (!g_interrupt_sent.test_and_set()) {
657
0
      g_driver->GetDebugger().DispatchInputInterrupt();
658
0
      g_interrupt_sent.clear();
659
0
      return;
660
0
    }
661
0
  }
662
663
0
  _exit(signo);
664
0
}
665
666
0
void sigtstp_handler(int signo) {
667
0
  if (g_driver != nullptr)
668
0
    g_driver->GetDebugger().SaveInputTerminalState();
669
670
0
  signal(signo, SIG_DFL);
671
0
  kill(getpid(), signo);
672
0
  signal(signo, sigtstp_handler);
673
0
}
674
675
0
void sigcont_handler(int signo) {
676
0
  if (g_driver != nullptr)
677
0
    g_driver->GetDebugger().RestoreInputTerminalState();
678
679
0
  signal(signo, SIG_DFL);
680
0
  kill(getpid(), signo);
681
0
  signal(signo, sigcont_handler);
682
0
}
683
684
0
void reproducer_handler(void *finalize_cmd) {
685
0
  if (SBReproducer::Generate()) {
686
0
    int result = std::system(static_cast<const char *>(finalize_cmd));
687
0
    (void)result;
688
0
    fflush(stdout);
689
0
  }
690
0
}
691
692
1
static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
693
1
  std::string usage_str = tool_name.str() + " [options]";
694
1
  table.printHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);
695
696
1
  std::string examples = R"___(
697
1
EXAMPLES:
698
1
  The debugger can be started in several modes.
699
1
700
1
  Passing an executable as a positional argument prepares lldb to debug the
701
1
  given executable. To disambiguate between arguments passed to lldb and
702
1
  arguments passed to the debugged executable, arguments starting with a - must
703
1
  be passed after --.
704
1
705
1
    lldb --arch x86_64 /path/to/program program argument -- --arch armv7
706
1
707
1
  For convenience, passing the executable after -- is also supported.
708
1
709
1
    lldb --arch x86_64 -- /path/to/program program argument --arch armv7
710
1
711
1
  Passing one of the attach options causes lldb to immediately attach to the
712
1
  given process.
713
1
714
1
    lldb -p <pid>
715
1
    lldb -n <process-name>
716
1
717
1
  Passing --repl starts lldb in REPL mode.
718
1
719
1
    lldb -r
720
1
721
1
  Passing --core causes lldb to debug the core file.
722
1
723
1
    lldb -c /path/to/core
724
1
725
1
  Command options can be combined with these modes and cause lldb to run the
726
1
  specified commands before or after events, like loading the file or crashing,
727
1
  in the order provided on the command line.
728
1
729
1
    lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt'
730
1
    lldb -S /source/before/file -s /source/after/file
731
1
    lldb -K /source/before/crash -k /source/after/crash
732
1
733
1
  Note: In REPL mode no file is loaded, so commands specified to run after
734
1
  loading the file (via -o or -s) will be ignored.)___";
735
1
  llvm::outs() << examples << '\n';
736
1
}
737
738
static llvm::Optional<int> InitializeReproducer(llvm::StringRef argv0,
739
2.34k
                                                opt::InputArgList &input_args) {
740
2.34k
  bool capture = input_args.hasArg(OPT_capture);
741
2.34k
  bool generate_on_exit = input_args.hasArg(OPT_generate_on_exit);
742
2.34k
  auto *capture_path = input_args.getLastArg(OPT_capture_path);
743
744
2.34k
  if (generate_on_exit && 
!capture2
) {
745
1
    WithColor::warning()
746
1
        << "-reproducer-generate-on-exit specified without -capture\n";
747
1
  }
748
749
2.34k
  if (capture || 
capture_path2.32k
) {
750
20
    if (capture_path) {
751
19
      if (!capture)
752
2
        WithColor::warning() << "-capture-path specified without -capture\n";
753
19
      if (const char *error = SBReproducer::Capture(capture_path->getValue())) {
754
1
        WithColor::error() << "reproducer capture failed: " << error << '\n';
755
1
        return 1;
756
1
      }
757
19
    } else {
758
1
      const char *error = SBReproducer::Capture();
759
1
      if (error) {
760
0
        WithColor::error() << "reproducer capture failed: " << error << '\n';
761
0
        return 1;
762
0
      }
763
1
    }
764
19
    if (generate_on_exit)
765
2
      SBReproducer::SetAutoGenerate(true);
766
19
  }
767
768
2.34k
  return llvm::None;
769
2.34k
}
770
771
2.34k
int main(int argc, char const *argv[]) {
772
  // Editline uses for example iswprint which is dependent on LC_CTYPE.
773
2.34k
  std::setlocale(LC_ALL, "");
774
2.34k
  std::setlocale(LC_CTYPE, "");
775
776
  // Setup LLVM signal handlers and make sure we call llvm_shutdown() on
777
  // destruction.
778
2.34k
  llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
779
780
  // Parse arguments.
781
2.34k
  LLDBOptTable T;
782
2.34k
  unsigned MissingArgIndex;
783
2.34k
  unsigned MissingArgCount;
784
2.34k
  ArrayRef<const char *> arg_arr = makeArrayRef(argv + 1, argc - 1);
785
2.34k
  opt::InputArgList input_args =
786
2.34k
      T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount);
787
2.34k
  llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]);
788
789
2.34k
  if (input_args.hasArg(OPT_help)) {
790
1
    printHelp(T, argv0);
791
1
    return 0;
792
1
  }
793
794
  // Check for missing argument error.
795
2.34k
  if (MissingArgCount) {
796
1
    WithColor::error() << "argument to '"
797
1
                       << input_args.getArgString(MissingArgIndex)
798
1
                       << "' is missing\n";
799
1
  }
800
  // Error out on unknown options.
801
2.34k
  if (input_args.hasArg(OPT_UNKNOWN)) {
802
4
    for (auto *arg : input_args.filtered(OPT_UNKNOWN)) {
803
4
      WithColor::error() << "unknown option: " << arg->getSpelling() << '\n';
804
4
    }
805
2
  }
806
2.34k
  if (MissingArgCount || 
input_args.hasArg(OPT_UNKNOWN)2.34k
) {
807
3
    llvm::errs() << "Use '" << argv0
808
3
                 << " --help' for a complete list of options.\n";
809
3
    return 1;
810
3
  }
811
812
2.34k
  if (auto exit_code = InitializeReproducer(argv[0], input_args)) {
813
1
    return *exit_code;
814
1
  }
815
816
2.34k
  SBError error = SBDebugger::InitializeWithErrorHandling();
817
2.34k
  if (error.Fail()) {
818
0
    WithColor::error() << "initialization failed: " << error.GetCString()
819
0
                       << '\n';
820
0
    return 1;
821
0
  }
822
2.34k
  SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
823
824
2.34k
  signal(SIGINT, sigint_handler);
825
2.34k
#if !defined(_MSC_VER)
826
2.34k
  signal(SIGPIPE, SIG_IGN);
827
2.34k
  signal(SIGWINCH, sigwinch_handler);
828
2.34k
  signal(SIGTSTP, sigtstp_handler);
829
2.34k
  signal(SIGCONT, sigcont_handler);
830
2.34k
#endif
831
832
2.34k
  int exit_code = 0;
833
  // Create a scope for driver so that the driver object will destroy itself
834
  // before SBDebugger::Terminate() is called.
835
2.34k
  {
836
2.34k
    Driver driver;
837
838
2.34k
    bool exiting = false;
839
2.34k
    SBError error(driver.ProcessArgs(input_args, exiting));
840
2.34k
    if (error.Fail()) {
841
3
      exit_code = 1;
842
3
      if (const char *error_cstr = error.GetCString())
843
3
        WithColor::error() << error_cstr << '\n';
844
2.34k
    } else if (!exiting) {
845
348
      exit_code = driver.MainLoop();
846
348
    }
847
2.34k
  }
848
849
2.34k
  SBDebugger::Terminate();
850
2.34k
  return exit_code;
851
2.34k
}