void begin_debugging(const char *name) { pid_t child_pid = fork(); if (child_pid == 0) { // If this is the child process, then begin tracing and executing it. execute_child_process(name); } else if (child_pid > 0) { // For the parent process, start up the debugger and wait for the child. start_debugger(child_pid); } else { puts("Failed to fork; exiting"); exit(1); } }
/****************************************************************** * start_debugger_atomic * * starts the debugger in an atomic way: * - either the debugger is not started and it is started * - or the debugger has already been started by another thread * - or the debugger couldn't be started * * returns TRUE for the two first conditions, FALSE for the last */ static int start_debugger_atomic(PEXCEPTION_POINTERS epointers) { static HANDLE hRunOnce /* = 0 */; if (hRunOnce == 0) { OBJECT_ATTRIBUTES attr; HANDLE hEvent; attr.Length = sizeof(attr); attr.RootDirectory = 0; attr.Attributes = OBJ_INHERIT; attr.ObjectName = NULL; attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; /* ask for manual reset, so that once the debugger is started, * every thread will know it */ NtCreateEvent( &hEvent, EVENT_ALL_ACCESS, &attr, TRUE, FALSE ); if (InterlockedCompareExchangePointer( (PVOID)&hRunOnce, hEvent, 0 ) == 0) { /* ok, our event has been set... we're the winning thread */ BOOL ret = start_debugger( epointers, hRunOnce ); DWORD tmp; if (!ret) { /* so that the other threads won't be stuck */ NtSetEvent( hRunOnce, &tmp ); } return ret; } /* someone beat us here... */ CloseHandle( hEvent ); } /* and wait for the winner to have actually created the debugger */ WaitForSingleObject( hRunOnce, INFINITE ); /* in fact, here, we only know that someone has tried to start the debugger, * we'll know by reposting the exception if it has actually attached * to the current process */ return TRUE; }
//------------------------------------------------------------------------------ // Name: main // Desc: entry point //------------------------------------------------------------------------------ int main(int argc, char *argv[]) { QT_REQUIRE_VERSION(argc, argv, "4.6.0"); QApplication app(argc, argv); QApplication::setWindowIcon(QIcon(":/debugger/images/edb48-logo.png")); qsrand(std::time(0)); // setup organization info so settings go in right place QApplication::setOrganizationName("codef00.com"); QApplication::setOrganizationDomain("codef00.com"); QApplication::setApplicationName("edb"); load_translations(); // look for some plugins.. load_plugins(edb::v1::config().plugin_path); QStringList args = app.arguments(); edb::pid_t attach_pid = 0; QList<QByteArray> run_args; QString run_app; // call the init function for each plugin, this is done after // ALL plugins are loaded in case there are inter-plugin dependencies for(QObject *plugin: edb::v1::plugin_list()) { if(auto p = qobject_cast<IPlugin *>(plugin)) { const IPlugin::ArgumentStatus r = p->parse_argments(args); switch(r) { case IPlugin::ARG_ERROR: usage(); break; case IPlugin::ARG_EXIT: std::exit(0); break; default: break; } } } if(args.size() > 1) { if(args.size() == 3 && args[1] == "--attach") { attach_pid = args[2].toUInt(); } else if(args.size() >= 3 && args[1] == "--run") { run_app = args[2]; for(int i = 3; i < args.size(); ++i) { run_args.push_back(argv[i]); } } else if(args.size() == 2 && args[1] == "--version") { std::cout << "edb version: " << edb::version << std::endl; return 0; } else if(args.size() == 2 && args[1] == "--dump-version") { std::cout << edb::version << std::endl; return 0; } else { usage(); } } return start_debugger(attach_pid, run_app, run_args); }