| 155 | |
| 156 | |
| 157 | bool LldbAdapter::ExecuteWithArgs(const std::string& path, const std::string& args, const std::string& workingDir, |
| 158 | const LaunchConfigurations& configs) |
| 159 | { |
| 160 | m_debugger.SetAsync(true); |
| 161 | |
| 162 | // We must start the event listener before calling CreateTarget, since CreateTarget will send out the initial |
| 163 | // batch of module load events. |
| 164 | std::thread thread([&]() { EventListener(); }); |
| 165 | thread.detach(); |
| 166 | |
| 167 | SBError err; |
| 168 | |
| 169 | // *Attempt* to create a functional target triple for the binary. |
| 170 | // This allows attaching to fat binaries. If the triple is empty, it will still attach on thin binaries. |
| 171 | auto archName = lldbArchNameForBinaryNinjaArchName(m_defaultArchitecture); |
| 172 | std::string triple = ""; |
| 173 | if (!archName.empty()) |
| 174 | triple = archName + "-unknown-none"; |
| 175 | |
| 176 | m_target = m_debugger.CreateTarget(path.c_str(), triple.c_str(), "", true, err); |
| 177 | |
| 178 | if (!m_target.IsValid()) |
| 179 | { |
| 180 | // It is likely lldb did not like our target triple. |
| 181 | if (err.GetCString() && std::string(err.GetCString()).find("is not compatible with") != std::string::npos) |
| 182 | { |
| 183 | // Last-ditch effort. If it is a thin binary, we will be able to attach without passing a triple. |
| 184 | m_target = m_debugger.CreateTarget(path.c_str(), "", "", true, err); |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | if (!m_target.IsValid()) |
| 189 | { |
| 190 | DebuggerEvent event; |
| 191 | event.type = LaunchFailureEventType; |
| 192 | event.data.errorData.shortError = "LLDB failed to create target."; |
| 193 | event.data.errorData.error = |
| 194 | fmt::format("LLDB Failed to create target with \"{}\"", err.GetCString() ? err.GetCString() : ""); |
| 195 | PostDebuggerEvent(event); |
| 196 | return false; |
| 197 | } |
| 198 | |
| 199 | m_targetActive = true; |
| 200 | // Breakpoints are added to this adapter right after the adapter gets created. However, at that time, the target is |
| 201 | // not created yet, so there is no way the adapter could apply the breakpoints to the target. Instead, the adapter |
| 202 | // stores all the breakpoints in m_pendingBreakpoints, and applies them when launching/connecting/attaching to the |
| 203 | // target. |
| 204 | ApplyBreakpoints(); |
| 205 | |
| 206 | if (Settings::Instance()->Get<bool>("debugger.stopAtEntryPoint") && m_hasEntryFunction) |
| 207 | AddBreakpoint(ModuleNameAndOffset(configs.inputFile, m_entryPoint - m_start)); |
| 208 | |
| 209 | std::string launchCommand = "process launch"; |
| 210 | if (Settings::Instance()->Get<bool>("debugger.stopAtSystemEntryPoint") || |
| 211 | (m_isElFWithoutDynamicLoader && (path == configs.inputFile))) |
| 212 | launchCommand += " --stop-at-entry"; |
| 213 | |
| 214 | if (configs.requestTerminalEmulator) |
no test coverage detected