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