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