//===-- UnixLocalInferiorProcess.cpp - A Local process on a Unixy system --===//
-//
+//
// The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
-//
+//
//===----------------------------------------------------------------------===//
-//
+//
// This file provides one implementation of the InferiorProcess class, which is
// designed to be used on unixy systems (those that support pipe, fork, exec,
// and signals).
//
// When the process is started, the debugger creates a pair of pipes, forks, and
-// makes the child starts executing the program. The child executes the process
+// makes the child start executing the program. The child executes the process
// with an IntrinsicLowering instance that turns debugger intrinsics into actual
// callbacks.
//
//===----------------------------------------------------------------------===//
#include "llvm/Debugger/InferiorProcess.h"
-#include "llvm/IntrinsicLowering.h"
#include "llvm/Constant.h"
+#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/Type.h"
-#include "llvm/iOther.h"
+#include "llvm/CodeGen/IntrinsicLowering.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
-#include "Support/FileUtilities.h"
-#include "Support/StringExtras.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/ADT/StringExtras.h"
+#include "FDHandle.h"
#include <cerrno>
-#include <unistd.h> // Unix specific debugger support
+#include <csignal>
+#include <unistd.h> // Unix-specific debugger support
#include <sys/types.h>
#include <sys/wait.h>
using namespace llvm;
// enters a message processing loop, where it reads and responds to commands
// until the parent decides that it wants to continue execution in some way.
//
-// Whenever the child process stops, it notifies the debugger by sending an
+// Whenever the child process stops, it notifies the debugger by sending a
// character over the wire.
//
// FinishProgram: FrameDesc*->char - This command causes the program to
// continue execution until the specified function frame returns.
- FinishProgram,
+ FinishProgram,
// ContProgram: void->char - This command causes the program to continue
// execution, stopping at some point in the future.
// Start the child running...
startChild(M, Arguments, envp);
-
+
// Okay, we created the program and it is off and running. Wait for it to
// stop now.
try {
/// getFrameLocation - This method returns the source location where each stack
/// frame is stopped.
-void IP::getFrameLocation(void *Frame, unsigned &LineNo, unsigned &ColNo,
+void IP::getFrameLocation(void *Frame, unsigned &LineNo, unsigned &ColNo,
const GlobalVariable *&SourceDesc) const {
sendCommand(GetFrameLocation, &Frame, sizeof(Frame));
LocationToken Loc;
/// died, otherwise it just returns the exit code if it had to be killed.
void IP::killChild() const {
assert(ChildPID != 0 && "Child has already been reaped!");
-
+
+ // If the process terminated on its own accord, closing the pipe file
+ // descriptors, we will get here. Check to see if the process has already
+ // died in this manner, gracefully.
int Status = 0;
int PID;
do {
} while (PID < 0 && errno == EINTR);
if (PID < 0) throw "Error waiting for child to exit!";
- // If the child process was already dead, then it died unexpectedly.
+ // Ok, there is a slight race condition here. It's possible that we will find
+ // out that the file descriptor closed before waitpid will indicate that the
+ // process gracefully died. If we don't know that the process gracefully
+ // died, wait a bit and try again. This is pretty nasty.
+ if (PID == 0) {
+ usleep(10000); // Wait a bit.
+
+ // Try again.
+ Status = 0;
+ do {
+ PID = waitpid(ChildPID, &Status, WNOHANG);
+ } while (PID < 0 && errno == EINTR);
+ if (PID < 0) throw "Error waiting for child to exit!";
+ }
+
+ // If the child process was already dead, then indicate that the process
+ // terminated on its own.
if (PID) {
assert(PID == ChildPID && "Didn't reap child?");
ChildPID = 0; // Child has been reaped
throw InferiorProcessDead(WTERMSIG(Status));
throw InferiorProcessDead(-1);
}
-
+
// Otherwise, the child exists and has not yet been killed.
if (kill(ChildPID, SIGKILL) < 0)
throw "Error killing child process!";
/// writeToParent - Send the specified buffer of data to the debugger
/// process.
+ ///
void writeToParent(const void *Buffer, unsigned Size);
/// readFromParent - Read the specified number of bytes from the parent.
/// startSubprogram - This method creates a new region for the subroutine
/// with the specified descriptor.
+ ///
void startSubprogram(void *FuncDesc);
/// startRegion - This method initiates the creation of an anonymous region.
/// reachedLine - This method is automatically called by the program every
/// time it executes an llvm.dbg.stoppoint intrinsic. If the debugger wants
/// us to stop here, we do so, otherwise we continue execution.
+ ///
void reachedLine(unsigned Line, unsigned Col, void *SourceDesc);
};
break;
case Intrinsic::dbg_region_end:
- // Turn call into a call to llvm_debugger_stop
+ // Turn call into a call to llvm_dbg_region_end
CI->setOperand(0, M->getOrInsertFunction("llvm_dbg_region_end",
CI->getCalledFunction()->getFunctionType()));
break;
case Intrinsic::dbg_func_start:
- // Turn call into a call to llvm_debugger_stop
+ // Turn call into a call to llvm_dbg_subprogram
CI->setOperand(0, M->getOrInsertFunction("llvm_dbg_subprogram",
CI->getCalledFunction()->getFunctionType()));
break;
ExecutionEngine::create(new ExistingModuleProvider(M), false,
new DebuggerIntrinsicLowering());
assert(EE && "Couldn't create an ExecutionEngine, not even an interpreter?");
-
+
// Call the main function from M as if its signature were:
// int main (int argc, char **argv, const char **envp)
// using the contents of Args to determine argc & argv, and the contents of