Chris Lattner | 2eacf26 | 2004-01-05 05:25:10 +0000 | [diff] [blame] | 1 | //===-- UnixLocalInferiorProcess.cpp - A Local process on a Unixy system --===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file was developed by the LLVM research group and is distributed under |
| 6 | // the University of Illinois Open Source License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file provides one implementation of the InferiorProcess class, which is |
| 11 | // designed to be used on unixy systems (those that support pipe, fork, exec, |
| 12 | // and signals). |
| 13 | // |
| 14 | // When the process is started, the debugger creates a pair of pipes, forks, and |
| 15 | // makes the child starts executing the program. The child executes the process |
| 16 | // with an IntrinsicLowering instance that turns debugger intrinsics into actual |
| 17 | // callbacks. |
| 18 | // |
| 19 | // This target takes advantage of the fact that the Module* addresses in the |
| 20 | // parent and the Module* addresses in the child will be the same, due to the |
| 21 | // use of fork(). As such, global addresses looked up in the child can be sent |
| 22 | // over the pipe to the debugger. |
| 23 | // |
| 24 | //===----------------------------------------------------------------------===// |
| 25 | |
| 26 | #include "llvm/Debugger/InferiorProcess.h" |
| 27 | #include "llvm/IntrinsicLowering.h" |
| 28 | #include "llvm/Constant.h" |
| 29 | #include "llvm/Module.h" |
| 30 | #include "llvm/ModuleProvider.h" |
| 31 | #include "llvm/Type.h" |
| 32 | #include "llvm/iOther.h" |
| 33 | #include "llvm/ExecutionEngine/GenericValue.h" |
| 34 | #include "llvm/ExecutionEngine/ExecutionEngine.h" |
| 35 | #include "Support/FileUtilities.h" |
| 36 | #include "Support/StringExtras.h" |
| 37 | #include <cerrno> |
| 38 | #include <unistd.h> // Unix specific debugger support |
| 39 | #include <sys/types.h> |
| 40 | #include <sys/wait.h> |
| 41 | using namespace llvm; |
| 42 | |
| 43 | // runChild - Entry point for the child process. |
| 44 | static void runChild(Module *M, const std::vector<std::string> &Arguments, |
| 45 | const char * const *envp, |
| 46 | FDHandle ReadFD, FDHandle WriteFD); |
| 47 | |
| 48 | //===----------------------------------------------------------------------===// |
| 49 | // Parent/Child Pipe Protocol |
| 50 | //===----------------------------------------------------------------------===// |
| 51 | // |
| 52 | // The parent/child communication protocol is designed to have the child process |
| 53 | // responding to requests that the debugger makes. Whenever the child process |
| 54 | // has stopped (due to a break point, single stepping, etc), the child process |
| 55 | // enters a message processing loop, where it reads and responds to commands |
| 56 | // until the parent decides that it wants to continue execution in some way. |
| 57 | // |
| 58 | // Whenever the child process stops, it notifies the debugger by sending an |
| 59 | // character over the wire. |
| 60 | // |
| 61 | |
| 62 | namespace { |
| 63 | /// LocationToken - Objects of this type are sent across the pipe from the |
| 64 | /// child to the parent to indicate where various stack frames are located. |
| 65 | struct LocationToken { |
| 66 | unsigned Line, Col; |
| 67 | const GlobalVariable *File; |
| 68 | LocationToken(unsigned L = 0, unsigned C = 0, const GlobalVariable *F = 0) |
| 69 | : Line(L), Col(C), File(F) {} |
| 70 | }; |
| 71 | } |
| 72 | |
| 73 | // Once the debugger process has received the LocationToken, it can make |
| 74 | // requests of the child by sending one of the following enum values followed by |
| 75 | // any data required by that command. The child responds with data appropriate |
| 76 | // to the command. |
| 77 | // |
| 78 | namespace { |
| 79 | /// CommandID - This enum defines all of the commands that the child process |
| 80 | /// can respond to. The actual expected data and responses are defined as the |
| 81 | /// enum values are defined. |
| 82 | /// |
| 83 | enum CommandID { |
| 84 | //===------------------------------------------------------------------===// |
| 85 | // Execution commands - These are sent to the child to from the debugger to |
| 86 | // get it to do certain things. |
| 87 | // |
| 88 | |
| 89 | // StepProgram: void->char - This command causes the program to continue |
| 90 | // execution, but stop as soon as it reaches another stoppoint. |
| 91 | StepProgram, |
| 92 | |
| 93 | // FinishProgram: FrameDesc*->char - This command causes the program to |
| 94 | // continue execution until the specified function frame returns. |
| 95 | FinishProgram, |
| 96 | |
| 97 | // ContProgram: void->char - This command causes the program to continue |
| 98 | // execution, stopping at some point in the future. |
| 99 | ContProgram, |
| 100 | |
| 101 | // GetSubprogramDescriptor: FrameDesc*->GlobalValue* - This command returns |
| 102 | // the GlobalValue* descriptor object for the specified stack frame. |
| 103 | GetSubprogramDescriptor, |
| 104 | |
| 105 | // GetParentFrame: FrameDesc*->FrameDesc* - This command returns the frame |
| 106 | // descriptor for the parent stack frame to the specified one, or null if |
| 107 | // there is none. |
| 108 | GetParentFrame, |
| 109 | |
| 110 | // GetFrameLocation - FrameDesc*->LocationToken - This command returns the |
| 111 | // location that a particular stack frame is stopped at. |
| 112 | GetFrameLocation, |
| 113 | |
| 114 | // AddBreakpoint - LocationToken->unsigned - This command instructs the |
| 115 | // target to install a breakpoint at the specified location. |
| 116 | AddBreakpoint, |
| 117 | |
| 118 | // RemoveBreakpoint - unsigned->void - This command instructs the target to |
| 119 | // remove a breakpoint. |
| 120 | RemoveBreakpoint, |
| 121 | }; |
| 122 | } |
| 123 | |
| 124 | |
| 125 | |
| 126 | |
| 127 | //===----------------------------------------------------------------------===// |
| 128 | // Parent Process Code |
| 129 | //===----------------------------------------------------------------------===// |
| 130 | |
| 131 | namespace { |
| 132 | class IP : public InferiorProcess { |
| 133 | // ReadFD, WriteFD - The file descriptors to read/write to the inferior |
| 134 | // process. |
| 135 | FDHandle ReadFD, WriteFD; |
| 136 | |
| 137 | // ChildPID - The unix PID of the child process we forked. |
| 138 | mutable pid_t ChildPID; |
| 139 | public: |
| 140 | IP(Module *M, const std::vector<std::string> &Arguments, |
| 141 | const char * const *envp); |
| 142 | ~IP(); |
| 143 | |
| 144 | std::string getStatus() const; |
| 145 | |
| 146 | /// Execution method implementations... |
| 147 | virtual void stepProgram(); |
| 148 | virtual void finishProgram(void *Frame); |
| 149 | virtual void contProgram(); |
| 150 | |
| 151 | |
| 152 | // Stack frame method implementations... |
| 153 | virtual void *getPreviousFrame(void *Frame) const; |
| 154 | virtual const GlobalVariable *getSubprogramDesc(void *Frame) const; |
| 155 | virtual void getFrameLocation(void *Frame, unsigned &LineNo, |
| 156 | unsigned &ColNo, |
| 157 | const GlobalVariable *&SourceDesc) const; |
| 158 | |
| 159 | // Breakpoint implementation methods |
| 160 | virtual unsigned addBreakpoint(unsigned LineNo, unsigned ColNo, |
| 161 | const GlobalVariable *SourceDesc); |
| 162 | virtual void removeBreakpoint(unsigned ID); |
| 163 | |
| 164 | |
| 165 | private: |
| 166 | /// startChild - This starts up the child process, and initializes the |
| 167 | /// ChildPID member. |
| 168 | /// |
| 169 | void startChild(Module *M, const std::vector<std::string> &Arguments, |
| 170 | const char * const *envp); |
| 171 | |
| 172 | /// killChild - Kill or reap the child process. This throws the |
| 173 | /// InferiorProcessDead exception an exit code if the process had already |
| 174 | /// died, otherwise it just kills it and returns. |
| 175 | void killChild() const; |
| 176 | |
| 177 | private: |
| 178 | // Methods for communicating with the child process. If the child exits or |
| 179 | // dies while attempting to communicate with it, ChildPID is set to zero and |
| 180 | // an exception is thrown. |
| 181 | |
| 182 | /// readFromChild - Low-level primitive to read some data from the child, |
| 183 | /// throwing an exception if it dies. |
| 184 | void readFromChild(void *Buffer, unsigned Size) const; |
| 185 | |
| 186 | /// writeToChild - Low-level primitive to send some data to the child |
| 187 | /// process, throwing an exception if the child died. |
| 188 | void writeToChild(void *Buffer, unsigned Size) const; |
| 189 | |
| 190 | /// sendCommand - Send a command token and the request data to the child. |
| 191 | /// |
| 192 | void sendCommand(CommandID Command, void *Data, unsigned Size) const; |
| 193 | |
| 194 | /// waitForStop - This method waits for the child process to reach a stop |
| 195 | /// point. |
| 196 | void waitForStop(); |
| 197 | }; |
| 198 | } |
| 199 | |
| 200 | // create - This is the factory method for the InferiorProcess class. Since |
| 201 | // there is currently only one subclass of InferiorProcess, we just define it |
| 202 | // here. |
| 203 | InferiorProcess * |
| 204 | InferiorProcess::create(Module *M, const std::vector<std::string> &Arguments, |
| 205 | const char * const *envp) { |
| 206 | return new IP(M, Arguments, envp); |
| 207 | } |
| 208 | |
| 209 | /// IP constructor - Create some pipes, them fork a child process. The child |
| 210 | /// process should start execution of the debugged program, but stop at the |
| 211 | /// first available opportunity. |
| 212 | IP::IP(Module *M, const std::vector<std::string> &Arguments, |
| 213 | const char * const *envp) |
| 214 | : InferiorProcess(M) { |
| 215 | |
| 216 | // Start the child running... |
| 217 | startChild(M, Arguments, envp); |
| 218 | |
| 219 | // Okay, we created the program and it is off and running. Wait for it to |
| 220 | // stop now. |
| 221 | try { |
| 222 | waitForStop(); |
| 223 | } catch (InferiorProcessDead &IPD) { |
| 224 | throw "Error waiting for the child process to stop. " |
| 225 | "It exited with status " + itostr(IPD.getExitCode()); |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | IP::~IP() { |
| 230 | // If the child is still running, kill it. |
| 231 | if (!ChildPID) return; |
| 232 | |
| 233 | killChild(); |
| 234 | } |
| 235 | |
| 236 | /// getStatus - Return information about the unix process being debugged. |
| 237 | /// |
| 238 | std::string IP::getStatus() const { |
| 239 | if (ChildPID == 0) |
| 240 | return "Unix target. ERROR: child process appears to be dead!\n"; |
| 241 | |
| 242 | return "Unix target: PID #" + utostr((unsigned)ChildPID) + "\n"; |
| 243 | } |
| 244 | |
| 245 | |
| 246 | /// startChild - This starts up the child process, and initializes the |
| 247 | /// ChildPID member. |
| 248 | /// |
| 249 | void IP::startChild(Module *M, const std::vector<std::string> &Arguments, |
| 250 | const char * const *envp) { |
| 251 | // Create the pipes. Make sure to immediately assign the returned file |
| 252 | // descriptors to FDHandle's so they get destroyed if an exception is thrown. |
| 253 | int FDs[2]; |
| 254 | if (pipe(FDs)) throw "Error creating a pipe!"; |
| 255 | FDHandle ChildReadFD(FDs[0]); |
| 256 | WriteFD = FDs[1]; |
| 257 | |
| 258 | if (pipe(FDs)) throw "Error creating a pipe!"; |
| 259 | ReadFD = FDs[0]; |
| 260 | FDHandle ChildWriteFD(FDs[1]); |
| 261 | |
| 262 | // Fork off the child process. |
| 263 | switch (ChildPID = fork()) { |
| 264 | case -1: throw "Error forking child process!"; |
| 265 | case 0: // child |
| 266 | delete this; // Free parent pipe file descriptors |
| 267 | runChild(M, Arguments, envp, ChildReadFD, ChildWriteFD); |
| 268 | exit(1); |
| 269 | default: break; |
| 270 | } |
| 271 | } |
| 272 | |
| 273 | /// sendCommand - Send a command token and the request data to the child. |
| 274 | /// |
| 275 | void IP::sendCommand(CommandID Command, void *Data, unsigned Size) const { |
| 276 | writeToChild(&Command, sizeof(Command)); |
| 277 | writeToChild(Data, Size); |
| 278 | } |
| 279 | |
| 280 | /// stepProgram - Implement the 'step' command, continuing execution until |
| 281 | /// the next possible stop point. |
| 282 | void IP::stepProgram() { |
| 283 | sendCommand(StepProgram, 0, 0); |
| 284 | waitForStop(); |
| 285 | } |
| 286 | |
| 287 | /// finishProgram - Implement the 'finish' command, executing the program until |
| 288 | /// the current function returns to its caller. |
| 289 | void IP::finishProgram(void *Frame) { |
| 290 | sendCommand(FinishProgram, &Frame, sizeof(Frame)); |
| 291 | waitForStop(); |
| 292 | } |
| 293 | |
| 294 | /// contProgram - Implement the 'cont' command, continuing execution until |
| 295 | /// a breakpoint is encountered. |
| 296 | void IP::contProgram() { |
| 297 | sendCommand(ContProgram, 0, 0); |
| 298 | waitForStop(); |
| 299 | } |
| 300 | |
| 301 | |
| 302 | //===----------------------------------------------------------------------===// |
| 303 | // Stack manipulation methods |
| 304 | // |
| 305 | |
| 306 | /// getPreviousFrame - Given the descriptor for the current stack frame, |
| 307 | /// return the descriptor for the caller frame. This returns null when it |
| 308 | /// runs out of frames. |
| 309 | void *IP::getPreviousFrame(void *Frame) const { |
| 310 | sendCommand(GetParentFrame, &Frame, sizeof(Frame)); |
| 311 | readFromChild(&Frame, sizeof(Frame)); |
| 312 | return Frame; |
| 313 | } |
| 314 | |
| 315 | /// getSubprogramDesc - Return the subprogram descriptor for the current |
| 316 | /// stack frame. |
| 317 | const GlobalVariable *IP::getSubprogramDesc(void *Frame) const { |
| 318 | sendCommand(GetSubprogramDescriptor, &Frame, sizeof(Frame)); |
| 319 | const GlobalVariable *Desc; |
| 320 | readFromChild(&Desc, sizeof(Desc)); |
| 321 | return Desc; |
| 322 | } |
| 323 | |
| 324 | /// getFrameLocation - This method returns the source location where each stack |
| 325 | /// frame is stopped. |
| 326 | void IP::getFrameLocation(void *Frame, unsigned &LineNo, unsigned &ColNo, |
| 327 | const GlobalVariable *&SourceDesc) const { |
| 328 | sendCommand(GetFrameLocation, &Frame, sizeof(Frame)); |
| 329 | LocationToken Loc; |
| 330 | readFromChild(&Loc, sizeof(Loc)); |
| 331 | LineNo = Loc.Line; |
| 332 | ColNo = Loc.Col; |
| 333 | SourceDesc = Loc.File; |
| 334 | } |
| 335 | |
| 336 | |
| 337 | //===----------------------------------------------------------------------===// |
| 338 | // Breakpoint manipulation methods |
| 339 | // |
| 340 | unsigned IP::addBreakpoint(unsigned LineNo, unsigned ColNo, |
| 341 | const GlobalVariable *SourceDesc) { |
| 342 | LocationToken Loc; |
| 343 | Loc.Line = LineNo; |
| 344 | Loc.Col = ColNo; |
| 345 | Loc.File = SourceDesc; |
| 346 | sendCommand(AddBreakpoint, &Loc, sizeof(Loc)); |
| 347 | unsigned ID; |
| 348 | readFromChild(&ID, sizeof(ID)); |
| 349 | return ID; |
| 350 | } |
| 351 | |
| 352 | void IP::removeBreakpoint(unsigned ID) { |
| 353 | sendCommand(RemoveBreakpoint, &ID, sizeof(ID)); |
| 354 | } |
| 355 | |
| 356 | |
| 357 | //===----------------------------------------------------------------------===// |
| 358 | // Methods for communication with the child process |
| 359 | // |
| 360 | // Methods for communicating with the child process. If the child exits or dies |
| 361 | // while attempting to communicate with it, ChildPID is set to zero and an |
| 362 | // exception is thrown. |
| 363 | // |
| 364 | |
| 365 | /// readFromChild - Low-level primitive to read some data from the child, |
| 366 | /// throwing an exception if it dies. |
| 367 | void IP::readFromChild(void *Buffer, unsigned Size) const { |
| 368 | assert(ChildPID && |
| 369 | "Child process died and still attempting to communicate with it!"); |
| 370 | while (Size) { |
| 371 | ssize_t Amount = read(ReadFD, Buffer, Size); |
| 372 | if (Amount == 0) { |
| 373 | // If we cannot communicate with the process, kill it. |
| 374 | killChild(); |
| 375 | // If killChild succeeded, then the process must have closed the pipe FD |
| 376 | // or something, because the child existed, but we cannot communicate with |
| 377 | // it. |
| 378 | throw InferiorProcessDead(-1); |
| 379 | } else if (Amount == -1) { |
| 380 | if (errno != EINTR) { |
| 381 | ChildPID = 0; |
| 382 | killChild(); |
| 383 | throw "Error reading from child process!"; |
| 384 | } |
| 385 | } else { |
| 386 | // We read a chunk. |
| 387 | Buffer = (char*)Buffer + Amount; |
| 388 | Size -= Amount; |
| 389 | } |
| 390 | } |
| 391 | } |
| 392 | |
| 393 | /// writeToChild - Low-level primitive to send some data to the child |
| 394 | /// process, throwing an exception if the child died. |
| 395 | void IP::writeToChild(void *Buffer, unsigned Size) const { |
| 396 | while (Size) { |
| 397 | ssize_t Amount = write(WriteFD, Buffer, Size); |
| 398 | if (Amount < 0 && errno == EINTR) continue; |
| 399 | if (Amount <= 0) { |
| 400 | // If we cannot communicate with the process, kill it. |
| 401 | killChild(); |
| 402 | |
| 403 | // If killChild succeeded, then the process must have closed the pipe FD |
| 404 | // or something, because the child existed, but we cannot communicate with |
| 405 | // it. |
| 406 | throw InferiorProcessDead(-1); |
| 407 | } else { |
| 408 | // We wrote a chunk. |
| 409 | Buffer = (char*)Buffer + Amount; |
| 410 | Size -= Amount; |
| 411 | } |
| 412 | } |
| 413 | } |
| 414 | |
| 415 | /// killChild - Kill or reap the child process. This throws the |
| 416 | /// InferiorProcessDead exception an exit code if the process had already |
| 417 | /// died, otherwise it just returns the exit code if it had to be killed. |
| 418 | void IP::killChild() const { |
| 419 | assert(ChildPID != 0 && "Child has already been reaped!"); |
| 420 | |
| 421 | int Status = 0; |
| 422 | int PID; |
| 423 | do { |
| 424 | PID = waitpid(ChildPID, &Status, WNOHANG); |
| 425 | } while (PID < 0 && errno == EINTR); |
| 426 | if (PID < 0) throw "Error waiting for child to exit!"; |
| 427 | |
| 428 | // If the child process was already dead, then it died unexpectedly. |
| 429 | if (PID) { |
| 430 | assert(PID == ChildPID && "Didn't reap child?"); |
| 431 | ChildPID = 0; // Child has been reaped |
| 432 | if (WIFEXITED(Status)) |
| 433 | throw InferiorProcessDead(WEXITSTATUS(Status)); |
| 434 | else if (WIFSIGNALED(Status)) |
| 435 | throw InferiorProcessDead(WTERMSIG(Status)); |
| 436 | throw InferiorProcessDead(-1); |
| 437 | } |
| 438 | |
| 439 | // Otherwise, the child exists and has not yet been killed. |
| 440 | if (kill(ChildPID, SIGKILL) < 0) |
| 441 | throw "Error killing child process!"; |
| 442 | |
| 443 | do { |
| 444 | PID = waitpid(ChildPID, 0, 0); |
| 445 | } while (PID < 0 && errno == EINTR); |
| 446 | if (PID <= 0) throw "Error waiting for child to exit!"; |
| 447 | |
| 448 | assert(PID == ChildPID && "Didn't reap child?"); |
| 449 | } |
| 450 | |
| 451 | |
| 452 | /// waitForStop - This method waits for the child process to reach a stop |
| 453 | /// point. When it does, it fills in the CurLocation member and returns. |
| 454 | void IP::waitForStop() { |
| 455 | char Dummy; |
| 456 | readFromChild(&Dummy, sizeof(char)); |
| 457 | } |
| 458 | |
| 459 | |
| 460 | //===----------------------------------------------------------------------===// |
| 461 | // Child Process Code |
| 462 | //===----------------------------------------------------------------------===// |
| 463 | |
| 464 | namespace { |
| 465 | class SourceSubprogram; |
| 466 | |
| 467 | /// SourceRegion - Instances of this class represent the regions that are |
| 468 | /// active in the program. |
| 469 | class SourceRegion { |
| 470 | /// Parent - A pointer to the region that encloses the current one. |
| 471 | SourceRegion *Parent; |
| 472 | |
| 473 | /// CurSubprogram - The subprogram that contains this region. This allows |
| 474 | /// efficient stack traversals. |
| 475 | SourceSubprogram *CurSubprogram; |
| 476 | |
| 477 | /// CurLine, CurCol, CurFile - The last location visited by this region. |
| 478 | /// This is used for getting the source location of callers in stack frames. |
| 479 | unsigned CurLine, CurCol; |
| 480 | void *CurFileDesc; |
| 481 | |
| 482 | //std::vector<void*> ActiveObjects; |
| 483 | public: |
| 484 | SourceRegion(SourceRegion *p, SourceSubprogram *Subprogram = 0) |
| 485 | : Parent(p), CurSubprogram(Subprogram ? Subprogram : p->getSubprogram()) { |
| 486 | CurLine = 0; CurCol = 0; |
| 487 | CurFileDesc = 0; |
| 488 | } |
| 489 | |
| 490 | virtual ~SourceRegion() {} |
| 491 | |
| 492 | SourceRegion *getParent() const { return Parent; } |
| 493 | SourceSubprogram *getSubprogram() const { return CurSubprogram; } |
| 494 | |
| 495 | void updateLocation(unsigned Line, unsigned Col, void *File) { |
| 496 | CurLine = Line; |
| 497 | CurCol = Col; |
| 498 | CurFileDesc = File; |
| 499 | } |
| 500 | |
| 501 | /// Return a LocationToken for the place that this stack frame stopped or |
| 502 | /// called a sub-function. |
| 503 | LocationToken getLocation(ExecutionEngine *EE) { |
| 504 | LocationToken LT; |
| 505 | LT.Line = CurLine; |
| 506 | LT.Col = CurCol; |
| 507 | const GlobalValue *GV = EE->getGlobalValueAtAddress(CurFileDesc); |
| 508 | LT.File = dyn_cast_or_null<GlobalVariable>(GV); |
| 509 | return LT; |
| 510 | } |
| 511 | }; |
| 512 | |
| 513 | /// SourceSubprogram - This is a stack-frame that represents a source program. |
| 514 | /// |
| 515 | class SourceSubprogram : public SourceRegion { |
| 516 | /// Desc - A pointer to the descriptor for the subprogram that this frame |
| 517 | /// represents. |
| 518 | void *Desc; |
| 519 | public: |
| 520 | SourceSubprogram(SourceRegion *P, void *desc) |
| 521 | : SourceRegion(P, this), Desc(desc) {} |
| 522 | void *getDescriptor() const { return Desc; } |
| 523 | }; |
| 524 | |
| 525 | |
| 526 | /// Child class - This class contains all of the information and methods used |
| 527 | /// by the child side of the debugger. The single instance of this object is |
| 528 | /// pointed to by the "TheChild" global variable. |
| 529 | class Child { |
| 530 | /// M - The module for the program currently being debugged. |
| 531 | /// |
| 532 | Module *M; |
| 533 | |
| 534 | /// EE - The execution engine that we are using to run the program. |
| 535 | /// |
| 536 | ExecutionEngine *EE; |
| 537 | |
| 538 | /// ReadFD, WriteFD - The file descriptor handles for this side of the |
| 539 | /// debugger pipe. |
| 540 | FDHandle ReadFD, WriteFD; |
| 541 | |
| 542 | /// RegionStack - A linked list of all of the regions dynamically active. |
| 543 | /// |
| 544 | SourceRegion *RegionStack; |
| 545 | |
| 546 | /// StopAtNextOpportunity - If this flag is set, the child process will stop |
| 547 | /// and report to the debugger at the next possible chance it gets. |
| 548 | volatile bool StopAtNextOpportunity; |
| 549 | |
| 550 | /// StopWhenSubprogramReturns - If this is non-null, the debugger requests |
| 551 | /// that the program stops when the specified function frame is destroyed. |
| 552 | SourceSubprogram *StopWhenSubprogramReturns; |
| 553 | |
| 554 | /// Breakpoints - This contains a list of active breakpoints and their IDs. |
| 555 | /// |
| 556 | std::vector<std::pair<unsigned, LocationToken> > Breakpoints; |
| 557 | |
| 558 | /// CurBreakpoint - The last assigned breakpoint. |
| 559 | /// |
| 560 | unsigned CurBreakpoint; |
| 561 | |
| 562 | public: |
| 563 | Child(Module *m, ExecutionEngine *ee, FDHandle &Read, FDHandle &Write) |
| 564 | : M(m), EE(ee), ReadFD(Read), WriteFD(Write), |
| 565 | RegionStack(0), CurBreakpoint(0) { |
| 566 | StopAtNextOpportunity = true; |
| 567 | StopWhenSubprogramReturns = 0; |
| 568 | } |
| 569 | |
| 570 | /// writeToParent - Send the specified buffer of data to the debugger |
| 571 | /// process. |
| 572 | void writeToParent(const void *Buffer, unsigned Size); |
| 573 | |
| 574 | /// readFromParent - Read the specified number of bytes from the parent. |
| 575 | /// |
| 576 | void readFromParent(void *Buffer, unsigned Size); |
| 577 | |
| 578 | /// childStopped - This method is called whenever the child has stopped |
| 579 | /// execution due to a breakpoint, step command, interruption, or whatever. |
| 580 | /// This stops the process, responds to any requests from the debugger, and |
| 581 | /// when commanded to, can continue execution by returning. |
| 582 | /// |
| 583 | void childStopped(); |
| 584 | |
| 585 | /// startSubprogram - This method creates a new region for the subroutine |
| 586 | /// with the specified descriptor. |
| 587 | void startSubprogram(void *FuncDesc); |
| 588 | |
| 589 | /// startRegion - This method initiates the creation of an anonymous region. |
| 590 | /// |
| 591 | void startRegion(); |
| 592 | |
| 593 | /// endRegion - This method terminates the last active region. |
| 594 | /// |
| 595 | void endRegion(); |
| 596 | |
| 597 | /// reachedLine - This method is automatically called by the program every |
| 598 | /// time it executes an llvm.dbg.stoppoint intrinsic. If the debugger wants |
| 599 | /// us to stop here, we do so, otherwise we continue execution. |
| 600 | void reachedLine(unsigned Line, unsigned Col, void *SourceDesc); |
| 601 | }; |
| 602 | |
| 603 | /// TheChild - The single instance of the Child class, which only gets created |
| 604 | /// in the child process. |
| 605 | Child *TheChild = 0; |
| 606 | } // end anonymous namespace |
| 607 | |
| 608 | |
| 609 | // writeToParent - Send the specified buffer of data to the debugger process. |
| 610 | void Child::writeToParent(const void *Buffer, unsigned Size) { |
| 611 | while (Size) { |
| 612 | ssize_t Amount = write(WriteFD, Buffer, Size); |
| 613 | if (Amount < 0 && errno == EINTR) continue; |
| 614 | if (Amount <= 0) { |
| 615 | write(2, "ERROR: Connection to debugger lost!\n", 36); |
| 616 | abort(); |
| 617 | } else { |
| 618 | // We wrote a chunk. |
| 619 | Buffer = (const char*)Buffer + Amount; |
| 620 | Size -= Amount; |
| 621 | } |
| 622 | } |
| 623 | } |
| 624 | |
| 625 | // readFromParent - Read the specified number of bytes from the parent. |
| 626 | void Child::readFromParent(void *Buffer, unsigned Size) { |
| 627 | while (Size) { |
| 628 | ssize_t Amount = read(ReadFD, Buffer, Size); |
| 629 | if (Amount < 0 && errno == EINTR) continue; |
| 630 | if (Amount <= 0) { |
| 631 | write(2, "ERROR: Connection to debugger lost!\n", 36); |
| 632 | abort(); |
| 633 | } else { |
| 634 | // We read a chunk. |
| 635 | Buffer = (char*)Buffer + Amount; |
| 636 | Size -= Amount; |
| 637 | } |
| 638 | } |
| 639 | } |
| 640 | |
| 641 | /// childStopped - This method is called whenever the child has stopped |
| 642 | /// execution due to a breakpoint, step command, interruption, or whatever. |
| 643 | /// This stops the process, responds to any requests from the debugger, and when |
| 644 | /// commanded to, can continue execution by returning. |
| 645 | /// |
| 646 | void Child::childStopped() { |
| 647 | // Since we stopped, notify the parent that we did so. |
| 648 | char Token = 0; |
| 649 | writeToParent(&Token, sizeof(char)); |
| 650 | |
| 651 | StopAtNextOpportunity = false; |
| 652 | StopWhenSubprogramReturns = 0; |
| 653 | |
| 654 | // Now that the debugger knows that we stopped, read commands from it and |
| 655 | // respond to them appropriately. |
| 656 | CommandID Command; |
| 657 | while (1) { |
| 658 | SourceRegion *Frame; |
| 659 | const void *Result; |
| 660 | readFromParent(&Command, sizeof(CommandID)); |
| 661 | |
| 662 | switch (Command) { |
| 663 | case StepProgram: |
| 664 | // To step the program, just return. |
| 665 | StopAtNextOpportunity = true; |
| 666 | return; |
| 667 | |
| 668 | case FinishProgram: // Run until exit from the specified function... |
| 669 | readFromParent(&Frame, sizeof(Frame)); |
| 670 | // The user wants us to stop when the specified FUNCTION exits, not when |
| 671 | // the specified REGION exits. |
| 672 | StopWhenSubprogramReturns = Frame->getSubprogram(); |
| 673 | return; |
| 674 | |
| 675 | case ContProgram: |
| 676 | // To continue, just return back to execution. |
| 677 | return; |
| 678 | |
| 679 | case GetSubprogramDescriptor: |
| 680 | readFromParent(&Frame, sizeof(Frame)); |
| 681 | Result = |
| 682 | EE->getGlobalValueAtAddress(Frame->getSubprogram()->getDescriptor()); |
| 683 | writeToParent(&Result, sizeof(Result)); |
| 684 | break; |
| 685 | |
| 686 | case GetParentFrame: |
| 687 | readFromParent(&Frame, sizeof(Frame)); |
| 688 | Result = Frame ? Frame->getSubprogram()->getParent() : RegionStack; |
| 689 | writeToParent(&Result, sizeof(Result)); |
| 690 | break; |
| 691 | |
| 692 | case GetFrameLocation: { |
| 693 | readFromParent(&Frame, sizeof(Frame)); |
| 694 | LocationToken LT = Frame->getLocation(EE); |
| 695 | writeToParent(<, sizeof(LT)); |
| 696 | break; |
| 697 | } |
| 698 | case AddBreakpoint: { |
| 699 | LocationToken Loc; |
| 700 | readFromParent(&Loc, sizeof(Loc)); |
| 701 | // Convert the GlobalVariable pointer to the address it was emitted to. |
| 702 | Loc.File = (GlobalVariable*)EE->getPointerToGlobal(Loc.File); |
| 703 | unsigned ID = CurBreakpoint++; |
| 704 | Breakpoints.push_back(std::make_pair(ID, Loc)); |
| 705 | writeToParent(&ID, sizeof(ID)); |
| 706 | break; |
| 707 | } |
| 708 | case RemoveBreakpoint: { |
| 709 | unsigned ID = 0; |
| 710 | readFromParent(&ID, sizeof(ID)); |
| 711 | for (unsigned i = 0, e = Breakpoints.size(); i != e; ++i) |
| 712 | if (Breakpoints[i].first == ID) { |
| 713 | Breakpoints.erase(Breakpoints.begin()+i); |
| 714 | break; |
| 715 | } |
| 716 | break; |
| 717 | } |
| 718 | default: |
| 719 | assert(0 && "Unknown command!"); |
| 720 | } |
| 721 | } |
| 722 | } |
| 723 | |
| 724 | |
| 725 | |
| 726 | /// startSubprogram - This method creates a new region for the subroutine |
| 727 | /// with the specified descriptor. |
| 728 | void Child::startSubprogram(void *SPDesc) { |
| 729 | RegionStack = new SourceSubprogram(RegionStack, SPDesc); |
| 730 | } |
| 731 | |
| 732 | /// startRegion - This method initiates the creation of an anonymous region. |
| 733 | /// |
| 734 | void Child::startRegion() { |
| 735 | RegionStack = new SourceRegion(RegionStack); |
| 736 | } |
| 737 | |
| 738 | /// endRegion - This method terminates the last active region. |
| 739 | /// |
| 740 | void Child::endRegion() { |
| 741 | SourceRegion *R = RegionStack->getParent(); |
| 742 | |
| 743 | // If the debugger wants us to stop when this frame is destroyed, do so. |
| 744 | if (RegionStack == StopWhenSubprogramReturns) { |
| 745 | StopAtNextOpportunity = true; |
| 746 | StopWhenSubprogramReturns = 0; |
| 747 | } |
| 748 | |
| 749 | delete RegionStack; |
| 750 | RegionStack = R; |
| 751 | } |
| 752 | |
| 753 | |
| 754 | |
| 755 | |
| 756 | /// reachedLine - This method is automatically called by the program every time |
| 757 | /// it executes an llvm.dbg.stoppoint intrinsic. If the debugger wants us to |
| 758 | /// stop here, we do so, otherwise we continue execution. Note that the Data |
| 759 | /// pointer coming in is a pointer to the LLVM global variable that represents |
| 760 | /// the source file we are in. We do not use the contents of the global |
| 761 | /// directly in the child, but we do use its address. |
| 762 | /// |
| 763 | void Child::reachedLine(unsigned Line, unsigned Col, void *SourceDesc) { |
| 764 | if (RegionStack) |
| 765 | RegionStack->updateLocation(Line, Col, SourceDesc); |
| 766 | |
| 767 | // If we hit a breakpoint, stop the program. |
| 768 | for (unsigned i = 0, e = Breakpoints.size(); i != e; ++i) |
| 769 | if (Line == Breakpoints[i].second.Line && |
| 770 | SourceDesc == (void*)Breakpoints[i].second.File && |
| 771 | Col == Breakpoints[i].second.Col) { |
| 772 | childStopped(); |
| 773 | return; |
| 774 | } |
| 775 | |
| 776 | // If we are single stepping the program, make sure to stop it. |
| 777 | if (StopAtNextOpportunity) |
| 778 | childStopped(); |
| 779 | } |
| 780 | |
| 781 | |
| 782 | |
| 783 | |
| 784 | //===----------------------------------------------------------------------===// |
| 785 | // Child class wrapper functions |
| 786 | // |
| 787 | // These functions are invoked directly by the program as it executes, in place |
| 788 | // of the debugging intrinsic functions that it contains. |
| 789 | // |
| 790 | |
| 791 | |
| 792 | /// llvm_debugger_stop - Every time the program reaches a new source line, it |
| 793 | /// will call back to this function. If the debugger has a breakpoint or |
| 794 | /// otherwise wants us to stop on this line, we do so, and notify the debugger |
| 795 | /// over the pipe. |
| 796 | /// |
| 797 | extern "C" |
| 798 | void *llvm_debugger_stop(void *Dummy, unsigned Line, unsigned Col, |
| 799 | void *SourceDescriptor) { |
| 800 | TheChild->reachedLine(Line, Col, SourceDescriptor); |
| 801 | return Dummy; |
| 802 | } |
| 803 | |
| 804 | |
| 805 | /// llvm_dbg_region_start - This function is invoked every time an anonymous |
| 806 | /// region of the source program is entered. |
| 807 | /// |
| 808 | extern "C" |
| 809 | void *llvm_dbg_region_start(void *Dummy) { |
| 810 | TheChild->startRegion(); |
| 811 | return Dummy; |
| 812 | } |
| 813 | |
| 814 | /// llvm_dbg_subprogram - This function is invoked every time a source-language |
| 815 | /// subprogram has been entered. |
| 816 | /// |
| 817 | extern "C" |
| 818 | void *llvm_dbg_subprogram(void *FuncDesc) { |
| 819 | TheChild->startSubprogram(FuncDesc); |
| 820 | return 0; |
| 821 | } |
| 822 | |
| 823 | /// llvm_dbg_region_end - This function is invoked every time a source-language |
| 824 | /// region (started with llvm.dbg.region.start or llvm.dbg.func.start) is |
| 825 | /// terminated. |
| 826 | /// |
| 827 | extern "C" |
| 828 | void llvm_dbg_region_end(void *Dummy) { |
| 829 | TheChild->endRegion(); |
| 830 | } |
| 831 | |
| 832 | |
| 833 | |
| 834 | |
| 835 | namespace { |
| 836 | /// DebuggerIntrinsicLowering - This class implements a simple intrinsic |
| 837 | /// lowering class that revectors debugging intrinsics to call actual |
| 838 | /// functions (defined above), instead of being turned into noops. |
| 839 | struct DebuggerIntrinsicLowering : public DefaultIntrinsicLowering { |
| 840 | virtual void LowerIntrinsicCall(CallInst *CI) { |
| 841 | Module *M = CI->getParent()->getParent()->getParent(); |
| 842 | switch (CI->getCalledFunction()->getIntrinsicID()) { |
| 843 | case Intrinsic::dbg_stoppoint: |
| 844 | // Turn call into a call to llvm_debugger_stop |
| 845 | CI->setOperand(0, M->getOrInsertFunction("llvm_debugger_stop", |
| 846 | CI->getCalledFunction()->getFunctionType())); |
| 847 | break; |
| 848 | case Intrinsic::dbg_region_start: |
| 849 | // Turn call into a call to llvm_dbg_region_start |
| 850 | CI->setOperand(0, M->getOrInsertFunction("llvm_dbg_region_start", |
| 851 | CI->getCalledFunction()->getFunctionType())); |
| 852 | break; |
| 853 | |
| 854 | case Intrinsic::dbg_region_end: |
| 855 | // Turn call into a call to llvm_debugger_stop |
| 856 | CI->setOperand(0, M->getOrInsertFunction("llvm_dbg_region_end", |
| 857 | CI->getCalledFunction()->getFunctionType())); |
| 858 | break; |
| 859 | case Intrinsic::dbg_func_start: |
| 860 | // Turn call into a call to llvm_debugger_stop |
| 861 | CI->setOperand(0, M->getOrInsertFunction("llvm_dbg_subprogram", |
| 862 | CI->getCalledFunction()->getFunctionType())); |
| 863 | break; |
| 864 | default: |
| 865 | DefaultIntrinsicLowering::LowerIntrinsicCall(CI); |
| 866 | break; |
| 867 | } |
| 868 | } |
| 869 | }; |
| 870 | } // end anonymous namespace |
| 871 | |
| 872 | |
| 873 | static void runChild(Module *M, const std::vector<std::string> &Arguments, |
| 874 | const char * const *envp, |
| 875 | FDHandle ReadFD, FDHandle WriteFD) { |
| 876 | |
| 877 | // Create an execution engine that uses our custom intrinsic lowering object |
| 878 | // to revector debugging intrinsic functions into actual functions defined |
| 879 | // above. |
| 880 | ExecutionEngine *EE = |
| 881 | ExecutionEngine::create(new ExistingModuleProvider(M), false, |
| 882 | new DebuggerIntrinsicLowering()); |
| 883 | assert(EE && "Couldn't create an ExecutionEngine, not even an interpreter?"); |
| 884 | |
| 885 | // Call the main function from M as if its signature were: |
| 886 | // int main (int argc, char **argv, const char **envp) |
| 887 | // using the contents of Args to determine argc & argv, and the contents of |
| 888 | // EnvVars to determine envp. |
| 889 | // |
| 890 | Function *Fn = M->getMainFunction(); |
| 891 | if (!Fn) exit(1); |
| 892 | |
| 893 | // Create the child class instance which will be used by the debugger |
| 894 | // callbacks to keep track of the current state of the process. |
| 895 | assert(TheChild == 0 && "A child process has already been created??"); |
| 896 | TheChild = new Child(M, EE, ReadFD, WriteFD); |
| 897 | |
| 898 | // Run main... |
| 899 | int Result = EE->runFunctionAsMain(Fn, Arguments, envp); |
| 900 | |
| 901 | // If the program didn't explicitly call exit, call exit now, for the program. |
| 902 | // This ensures that any atexit handlers get called correctly. |
| 903 | Function *Exit = M->getOrInsertFunction("exit", Type::VoidTy, Type::IntTy, 0); |
| 904 | |
| 905 | std::vector<GenericValue> Args; |
| 906 | GenericValue ResultGV; |
| 907 | ResultGV.IntVal = Result; |
| 908 | Args.push_back(ResultGV); |
| 909 | EE->runFunction(Exit, Args); |
| 910 | abort(); |
| 911 | } |