1 //===-- libdebugserver.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 <cerrno> 10 #include <getopt.h> 11 #include <netinet/in.h> 12 #include <sys/select.h> 13 #include <sys/socket.h> 14 #include <sys/sysctl.h> 15 #include <sys/types.h> 16 17 #include <memory> 18 19 #include "DNB.h" 20 #include "DNBLog.h" 21 #include "DNBTimer.h" 22 #include "PseudoTerminal.h" 23 #include "RNBContext.h" 24 #include "RNBRemote.h" 25 #include "RNBServices.h" 26 #include "RNBSocket.h" 27 #include "SysSignal.h" 28 29 // Run loop modes which determine which run loop function will be called 30 enum RNBRunLoopMode { 31 eRNBRunLoopModeInvalid = 0, 32 eRNBRunLoopModeGetStartModeFromRemoteProtocol, 33 eRNBRunLoopModeInferiorExecuting, 34 eRNBRunLoopModeExit 35 }; 36 37 // Global Variables 38 RNBRemoteSP g_remoteSP; 39 int g_disable_aslr = 0; 40 int g_isatty = 0; 41 42 #define RNBLogSTDOUT(fmt, ...) \ 43 do { \ 44 if (g_isatty) { \ 45 fprintf(stdout, fmt, ##__VA_ARGS__); \ 46 } else { \ 47 _DNBLog(0, fmt, ##__VA_ARGS__); \ 48 } \ 49 } while (0) 50 #define RNBLogSTDERR(fmt, ...) \ 51 do { \ 52 if (g_isatty) { \ 53 fprintf(stderr, fmt, ##__VA_ARGS__); \ 54 } else { \ 55 _DNBLog(0, fmt, ##__VA_ARGS__); \ 56 } \ 57 } while (0) 58 59 // Get our program path and arguments from the remote connection. 60 // We will need to start up the remote connection without a PID, get the 61 // arguments, wait for the new process to finish launching and hit its 62 // entry point, and then return the run loop mode that should come next. 63 RNBRunLoopMode RNBRunLoopGetStartModeFromRemote(RNBRemoteSP &remoteSP) { 64 std::string packet; 65 66 if (remoteSP.get() != NULL) { 67 RNBRemote *remote = remoteSP.get(); 68 RNBContext &ctx = remote->Context(); 69 uint32_t event_mask = RNBContext::event_read_packet_available; 70 71 // Spin waiting to get the A packet. 72 while (true) { 73 DNBLogThreadedIf(LOG_RNB_MAX, 74 "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...", 75 __FUNCTION__, event_mask); 76 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); 77 DNBLogThreadedIf(LOG_RNB_MAX, 78 "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", 79 __FUNCTION__, event_mask, set_events); 80 81 if (set_events & RNBContext::event_read_packet_available) { 82 rnb_err_t err = rnb_err; 83 RNBRemote::PacketEnum type; 84 85 err = remote->HandleReceivedPacket(&type); 86 87 // check if we tried to attach to a process 88 if (type == RNBRemote::vattach || type == RNBRemote::vattachwait) { 89 if (err == rnb_success) 90 return eRNBRunLoopModeInferiorExecuting; 91 else { 92 RNBLogSTDERR("error: attach failed."); 93 return eRNBRunLoopModeExit; 94 } 95 } 96 97 if (err == rnb_success) { 98 DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Got success...", __FUNCTION__); 99 continue; 100 } else if (err == rnb_not_connected) { 101 RNBLogSTDERR("error: connection lost."); 102 return eRNBRunLoopModeExit; 103 } else { 104 // a catch all for any other gdb remote packets that failed 105 DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Error getting packet.", 106 __FUNCTION__); 107 continue; 108 } 109 110 DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); 111 } else { 112 DNBLogThreadedIf(LOG_RNB_MINIMAL, 113 "%s Connection closed before getting \"A\" packet.", 114 __FUNCTION__); 115 return eRNBRunLoopModeExit; 116 } 117 } 118 } 119 return eRNBRunLoopModeExit; 120 } 121 122 // Watch for signals: 123 // SIGINT: so we can halt our inferior. (disabled for now) 124 // SIGPIPE: in case our child process dies 125 nub_process_t g_pid; 126 int g_sigpipe_received = 0; 127 void signal_handler(int signo) { 128 DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, 129 SysSignal::Name(signo)); 130 131 switch (signo) { 132 // case SIGINT: 133 // DNBProcessKill (g_pid, signo); 134 // break; 135 136 case SIGPIPE: 137 g_sigpipe_received = 1; 138 break; 139 } 140 } 141 142 // Return the new run loop mode based off of the current process state 143 RNBRunLoopMode HandleProcessStateChange(RNBRemoteSP &remote, bool initialize) { 144 RNBContext &ctx = remote->Context(); 145 nub_process_t pid = ctx.ProcessID(); 146 147 if (pid == INVALID_NUB_PROCESS) { 148 DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", 149 __FUNCTION__); 150 return eRNBRunLoopModeExit; 151 } 152 nub_state_t pid_state = DNBProcessGetState(pid); 153 154 DNBLogThreadedIf(LOG_RNB_MINIMAL, 155 "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, 156 (int)initialize, DNBStateAsString(pid_state)); 157 158 switch (pid_state) { 159 case eStateInvalid: 160 case eStateUnloaded: 161 // Something bad happened 162 return eRNBRunLoopModeExit; 163 break; 164 165 case eStateAttaching: 166 case eStateLaunching: 167 return eRNBRunLoopModeInferiorExecuting; 168 169 case eStateSuspended: 170 case eStateCrashed: 171 case eStateStopped: 172 if (!initialize) { 173 // Compare the last stop count to our current notion of a stop count 174 // to make sure we don't notify more than once for a given stop. 175 nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount(); 176 bool pid_stop_count_changed = 177 ctx.SetProcessStopCount(DNBProcessGetStopCount(pid)); 178 if (pid_stop_count_changed) { 179 remote->FlushSTDIO(); 180 181 if (ctx.GetProcessStopCount() == 1) { 182 DNBLogThreadedIf( 183 LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s " 184 "pid_stop_count %zu (old %zu)) Notify??? no, " 185 "first stop...", 186 __FUNCTION__, (int)initialize, DNBStateAsString(pid_state), 187 ctx.GetProcessStopCount(), prev_pid_stop_count); 188 } else { 189 190 DNBLogThreadedIf( 191 LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s " 192 "pid_stop_count %zu (old %zu)) Notify??? YES!!!", 193 __FUNCTION__, (int)initialize, DNBStateAsString(pid_state), 194 ctx.GetProcessStopCount(), prev_pid_stop_count); 195 remote->NotifyThatProcessStopped(); 196 } 197 } else { 198 DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) " 199 "pid_state = %s pid_stop_count %zu " 200 "(old %zu)) Notify??? skipping...", 201 __FUNCTION__, (int)initialize, 202 DNBStateAsString(pid_state), ctx.GetProcessStopCount(), 203 prev_pid_stop_count); 204 } 205 } 206 return eRNBRunLoopModeInferiorExecuting; 207 208 case eStateStepping: 209 case eStateRunning: 210 return eRNBRunLoopModeInferiorExecuting; 211 212 case eStateExited: 213 remote->HandlePacket_last_signal(NULL); 214 return eRNBRunLoopModeExit; 215 case eStateDetached: 216 return eRNBRunLoopModeExit; 217 } 218 219 // Catch all... 220 return eRNBRunLoopModeExit; 221 } 222 // This function handles the case where our inferior program is stopped and 223 // we are waiting for gdb remote protocol packets. When a packet occurs that 224 // makes the inferior run, we need to leave this function with a new state 225 // as the return code. 226 RNBRunLoopMode RNBRunLoopInferiorExecuting(RNBRemoteSP &remote) { 227 DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); 228 RNBContext &ctx = remote->Context(); 229 230 // Init our mode and set 'is_running' based on the current process state 231 RNBRunLoopMode mode = HandleProcessStateChange(remote, true); 232 233 while (ctx.ProcessID() != INVALID_NUB_PROCESS) { 234 235 std::string set_events_str; 236 uint32_t event_mask = ctx.NormalEventBits(); 237 238 if (!ctx.ProcessStateRunning()) { 239 // Clear the stdio bits if we are not running so we don't send any async 240 // packets 241 event_mask &= ~RNBContext::event_proc_stdio_available; 242 } 243 244 // We want to make sure we consume all process state changes and have 245 // whomever is notifying us to wait for us to reset the event bit before 246 // continuing. 247 // ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed); 248 249 DNBLogThreadedIf(LOG_RNB_EVENTS, 250 "%s ctx.Events().WaitForSetEvents(0x%08x) ...", 251 __FUNCTION__, event_mask); 252 nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); 253 DNBLogThreadedIf(LOG_RNB_EVENTS, 254 "%s ctx.Events().WaitForSetEvents(0x%08x) => 0x%08x (%s)", 255 __FUNCTION__, event_mask, set_events, 256 ctx.EventsAsString(set_events, set_events_str)); 257 258 if (set_events) { 259 if ((set_events & RNBContext::event_proc_thread_exiting) || 260 (set_events & RNBContext::event_proc_stdio_available)) { 261 remote->FlushSTDIO(); 262 } 263 264 if (set_events & RNBContext::event_read_packet_available) { 265 // handleReceivedPacket will take care of resetting the 266 // event_read_packet_available events when there are no more... 267 set_events ^= RNBContext::event_read_packet_available; 268 269 if (ctx.ProcessStateRunning()) { 270 if (remote->HandleAsyncPacket() == rnb_not_connected) { 271 // TODO: connect again? Exit? 272 } 273 } else { 274 if (remote->HandleReceivedPacket() == rnb_not_connected) { 275 // TODO: connect again? Exit? 276 } 277 } 278 } 279 280 if (set_events & RNBContext::event_proc_state_changed) { 281 mode = HandleProcessStateChange(remote, false); 282 ctx.Events().ResetEvents(RNBContext::event_proc_state_changed); 283 set_events ^= RNBContext::event_proc_state_changed; 284 } 285 286 if (set_events & RNBContext::event_proc_thread_exiting) { 287 mode = eRNBRunLoopModeExit; 288 } 289 290 if (set_events & RNBContext::event_read_thread_exiting) { 291 // Out remote packet receiving thread exited, exit for now. 292 if (ctx.HasValidProcessID()) { 293 // TODO: We should add code that will leave the current process 294 // in its current state and listen for another connection... 295 if (ctx.ProcessStateRunning()) { 296 DNBProcessKill(ctx.ProcessID()); 297 } 298 } 299 mode = eRNBRunLoopModeExit; 300 } 301 } 302 303 // Reset all event bits that weren't reset for now... 304 if (set_events != 0) 305 ctx.Events().ResetEvents(set_events); 306 307 if (mode != eRNBRunLoopModeInferiorExecuting) 308 break; 309 } 310 311 return mode; 312 } 313 314 void ASLLogCallback(void *baton, uint32_t flags, const char *format, 315 va_list args) { 316 #if 0 317 vprintf(format, args); 318 #endif 319 } 320 321 extern "C" int debug_server_main(int fd) { 322 #if 1 323 g_isatty = 0; 324 #else 325 g_isatty = ::isatty(STDIN_FILENO); 326 327 DNBLogSetDebug(1); 328 DNBLogSetVerbose(1); 329 DNBLogSetLogMask(-1); 330 DNBLogSetLogCallback(ASLLogCallback, NULL); 331 #endif 332 333 signal(SIGPIPE, signal_handler); 334 335 g_remoteSP = std::make_shared<RNBRemote>(); 336 337 RNBRemote *remote = g_remoteSP.get(); 338 if (remote == NULL) { 339 RNBLogSTDERR("error: failed to create a remote connection class\n"); 340 return -1; 341 } 342 343 RNBRunLoopMode mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol; 344 345 while (mode != eRNBRunLoopModeExit) { 346 switch (mode) { 347 case eRNBRunLoopModeGetStartModeFromRemoteProtocol: 348 if (g_remoteSP->Comm().useFD(fd) == rnb_success) { 349 RNBLogSTDOUT("Starting remote data thread.\n"); 350 g_remoteSP->StartReadRemoteDataThread(); 351 352 RNBLogSTDOUT("Waiting for start mode from remote.\n"); 353 mode = RNBRunLoopGetStartModeFromRemote(g_remoteSP); 354 } else { 355 mode = eRNBRunLoopModeExit; 356 } 357 break; 358 359 case eRNBRunLoopModeInferiorExecuting: 360 mode = RNBRunLoopInferiorExecuting(g_remoteSP); 361 break; 362 363 default: 364 mode = eRNBRunLoopModeExit; 365 break; 366 367 case eRNBRunLoopModeExit: 368 break; 369 } 370 } 371 372 g_remoteSP->StopReadRemoteDataThread(); 373 g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS); 374 375 return 0; 376 } 377