std::pair<bool,Variant> DebuggerProxy::ExecutePHP(const std::string &php, String &output, int frame, int flags) { TRACE(2, "DebuggerProxy::ExecutePHP\n"); // Wire up stdout and stderr to our own string buffer so we can pass // any output back to the client. StringBuffer sb; StringBuffer *save = g_context->swapOutputBuffer(nullptr); DebuggerStdoutHook stdout_hook(sb); DebuggerLoggerHook stderr_hook(sb); auto const previousEvalOutputHook = m_evalOutputHook; if (previousEvalOutputHook != nullptr) { g_context->removeStdoutHook(previousEvalOutputHook); } m_evalOutputHook = &stdout_hook; g_context->addStdoutHook(&stdout_hook); if (flags & ExecutePHPFlagsLog) { Logger::SetThreadHook(&stderr_hook); } SCOPE_EXIT { g_context->removeStdoutHook(&stdout_hook); g_context->swapOutputBuffer(save); if (flags & ExecutePHPFlagsLog) { Logger::SetThreadHook(nullptr); } if (previousEvalOutputHook != nullptr) { g_context->addStdoutHook(previousEvalOutputHook); } m_evalOutputHook = previousEvalOutputHook; }; String code(php.c_str(), php.size(), CopyString); // We're about to start executing more PHP. This is typically done // in response to commands from the client, and the client expects // those commands to send more interrupts since, of course, the // user might want to debug the code we're about to run. If we're // already processing an interrupt, enable signal polling around // the execution of the new PHP to ensure that we can handle // signals while doing so. // // Note: we must switch the thread mode to Sticky so we block // other threads which may hit interrupts while we're running, // since nested processInterrupt() calls would normally release // other threads on the way out. assertx(m_thread == (int64_t)Process::GetThreadId()); ThreadMode origThreadMode = m_threadMode; switchThreadMode(Sticky, m_thread); if (flags & ExecutePHPFlagsAtInterrupt) enableSignalPolling(); SCOPE_EXIT { if (flags & ExecutePHPFlagsAtInterrupt) disableSignalPolling(); switchThreadMode(origThreadMode, m_thread); }; auto const ret = g_context->evalPHPDebugger(code.get(), frame); output = sb.detach(); return {ret.failed, ret.result}; }
/** * Fake vfs */ ssize_t vfs_console_write(struct _reent *r, int fd, const char *src, size_t len) { if (stdout_hook) stdout_hook(src, len); size_t i; for (i = 0; i < len; ++i) putch(((const char*) src)[i]); return len; }
ssize_t vfs_console_write(struct vfs_file_s *file, const void *src, size_t len) { if (stdout_hook) stdout_hook(src, len); size_t i; for (i = 0; i < len; ++i) putch(((const char*)src)[i]); return len; }
unsigned int debug_routine_stub(unsigned int code, CONTEXT *context) { if(code != EXCEPT_CODE_DEBUG_PRINT) return 0; size_t i; size_t len = context->Gpr[4]; char * src = (char*)context->Gpr[3]; if (stdout_hook) stdout_hook(src, len); for (i = 0; i < len; ++i) putch(((const char*)src)[i]); // Skip over the trap context->Iar += 4; return 1; }