1 | //===-- LLDBUtils.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 "LLDBUtils.h" |
10 | #include "DAP.h" |
11 | |
12 | #include <mutex> |
13 | |
14 | namespace lldb_dap { |
15 | |
16 | bool RunLLDBCommands(llvm::StringRef prefix, |
17 | const llvm::ArrayRef<std::string> &commands, |
18 | llvm::raw_ostream &strm, bool parse_command_directives) { |
19 | if (commands.empty()) |
20 | return true; |
21 | |
22 | bool did_print_prefix = false; |
23 | |
24 | lldb::SBCommandInterpreter interp = g_dap.debugger.GetCommandInterpreter(); |
25 | for (llvm::StringRef command : commands) { |
26 | lldb::SBCommandReturnObject result; |
27 | bool quiet_on_success = false; |
28 | bool check_error = false; |
29 | |
30 | while (parse_command_directives) { |
31 | if (command.starts_with(Prefix: "?" )) { |
32 | command = command.drop_front(); |
33 | quiet_on_success = true; |
34 | } else if (command.starts_with(Prefix: "!" )) { |
35 | command = command.drop_front(); |
36 | check_error = true; |
37 | } else { |
38 | break; |
39 | } |
40 | } |
41 | |
42 | { |
43 | // Prevent simultaneous calls to HandleCommand, e.g. EventThreadFunction |
44 | // may asynchronously call RunExitCommands when we are already calling |
45 | // RunTerminateCommands. |
46 | static std::mutex handle_command_mutex; |
47 | std::lock_guard<std::mutex> locker(handle_command_mutex); |
48 | interp.HandleCommand(command_line: command.str().c_str(), result); |
49 | } |
50 | |
51 | const bool got_error = !result.Succeeded(); |
52 | // The if statement below is assuming we always print out `!` prefixed |
53 | // lines. The only time we don't print is when we have `quiet_on_success == |
54 | // true` and we don't have an error. |
55 | if (quiet_on_success ? got_error : true) { |
56 | if (!did_print_prefix && !prefix.empty()) { |
57 | strm << prefix << "\n" ; |
58 | did_print_prefix = true; |
59 | } |
60 | strm << "(lldb) " << command << "\n" ; |
61 | auto output_len = result.GetOutputSize(); |
62 | if (output_len) { |
63 | const char *output = result.GetOutput(); |
64 | strm << output; |
65 | } |
66 | auto error_len = result.GetErrorSize(); |
67 | if (error_len) { |
68 | const char *error = result.GetError(); |
69 | strm << error; |
70 | } |
71 | } |
72 | if (check_error && got_error) |
73 | return false; // Stop running commands. |
74 | } |
75 | return true; |
76 | } |
77 | |
78 | std::string RunLLDBCommands(llvm::StringRef prefix, |
79 | const llvm::ArrayRef<std::string> &commands, |
80 | bool &required_command_failed, |
81 | bool parse_command_directives) { |
82 | required_command_failed = false; |
83 | std::string s; |
84 | llvm::raw_string_ostream strm(s); |
85 | required_command_failed = |
86 | !RunLLDBCommands(prefix, commands, strm, parse_command_directives); |
87 | strm.flush(); |
88 | return s; |
89 | } |
90 | |
91 | std::string |
92 | RunLLDBCommandsVerbatim(llvm::StringRef prefix, |
93 | const llvm::ArrayRef<std::string> &commands) { |
94 | bool required_command_failed = false; |
95 | return RunLLDBCommands(prefix, commands, required_command_failed, |
96 | /*parse_command_directives=*/false); |
97 | } |
98 | |
99 | bool ThreadHasStopReason(lldb::SBThread &thread) { |
100 | switch (thread.GetStopReason()) { |
101 | case lldb::eStopReasonTrace: |
102 | case lldb::eStopReasonPlanComplete: |
103 | case lldb::eStopReasonBreakpoint: |
104 | case lldb::eStopReasonWatchpoint: |
105 | case lldb::eStopReasonInstrumentation: |
106 | case lldb::eStopReasonSignal: |
107 | case lldb::eStopReasonException: |
108 | case lldb::eStopReasonExec: |
109 | case lldb::eStopReasonProcessorTrace: |
110 | case lldb::eStopReasonFork: |
111 | case lldb::eStopReasonVFork: |
112 | case lldb::eStopReasonVForkDone: |
113 | return true; |
114 | case lldb::eStopReasonThreadExiting: |
115 | case lldb::eStopReasonInvalid: |
116 | case lldb::eStopReasonNone: |
117 | break; |
118 | } |
119 | return false; |
120 | } |
121 | |
122 | static uint32_t constexpr THREAD_INDEX_SHIFT = 19; |
123 | |
124 | uint32_t GetLLDBThreadIndexID(uint64_t dap_frame_id) { |
125 | return dap_frame_id >> THREAD_INDEX_SHIFT; |
126 | } |
127 | |
128 | uint32_t GetLLDBFrameID(uint64_t dap_frame_id) { |
129 | return dap_frame_id & ((1u << THREAD_INDEX_SHIFT) - 1); |
130 | } |
131 | |
132 | int64_t MakeDAPFrameID(lldb::SBFrame &frame) { |
133 | return ((int64_t)frame.GetThread().GetIndexID() << THREAD_INDEX_SHIFT) | |
134 | frame.GetFrameID(); |
135 | } |
136 | |
137 | } // namespace lldb_dap |
138 | |