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