void XDebugServer::addError(xdebug_xml_node& node, XDebugError code) { // Create the error node auto error = xdebug_xml_node_init("error"); xdebug_xml_add_attribute(error, "code", static_cast<int>(code)); xdebug_xml_add_child(&node, error); // Add the error code's error message auto message = xdebug_xml_node_init("message"); xdebug_xml_add_text(message, const_cast<char*>(xdebug_error_str(code)), 0); xdebug_xml_add_child(error, message); }
// Exports the given xml key value pair as an xml child of the given parent node static void xdebug_array_element_export_xml_node(xdebug_xml_node& parent, const char* parentName, const Variant& key, const Variant& val, XDebugExporter& exporter) { String key_str = key.toString(); Variant full_name = init_null(); // Construct the full name StringBuffer buf; if (parentName != nullptr) { if (key.isInteger()) { buf.printf("%s[%s]", parentName, key_str.data()); } else { buf.printf("%s['%s']", parentName, key_str.data()); } full_name = buf.detach(); } const char* full_name_str = full_name.isNull() ? nullptr : full_name.toString().data(); // Recursively add the child xdebug_xml_node* child = xdebug_var_export_xml_node(xdstrdup(key_str.data()), xdstrdup(full_name_str), nullptr, val, exporter); xdebug_xml_add_child(&parent, child); }
void xdebug_xml_start_element_handler(void *ctx, const xmlChar *name, const xmlChar **atts) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; xdebug_xml_reader_priv *data = (xdebug_xml_reader_priv *) ctxt->_private; xdebug_xml_node *child; data->stack[data->level] = data->current; data->level++; child = xdebug_xml_node_init_ex(xdstrdup(name), 1); if (data->current) { xdebug_xml_add_child(data->current, child); } data->current = child; if (!data->xml) { data->xml = child; } if (atts) { do { xdebug_xml_add_attribute_ex(child, xdstrdup(atts[0]), xdstrdup(atts[1]), 1, 1); atts = &atts[2]; } while (atts[0]); } }
bool XDebugServer::breakpoint(const Variant& filename, const Variant& exception, const Variant& message, int line) { log("Hit breakpoint at %s:%d", filename.toString().data(), line); setStatus(Status::Break, Reason::Ok); // Initialize the response node auto response = xdebug_xml_node_init("response"); addXmlns(*response); addStatus(*response); if (m_lastCommand != nullptr) { addCommand(*response, *m_lastCommand); } // Grab the c strings auto to_c_str = [] (const Variant& var) { return !var.isString() ? nullptr : var.toString().data(); }; auto filename_str = to_c_str(filename); auto exception_str = to_c_str(exception); auto message_str = to_c_str(message); auto line_str = xdebug_sprintf("%d", line); // Create the message node auto msg = xdebug_xml_node_init("xdebug:message"); xdebug_xml_add_attribute_ex(msg, "lineno", line_str, 0, 1); if (filename_str != nullptr) { filename_str = XDebugUtils::pathToUrl(filename_str); // output file format xdebug_xml_add_attribute_ex( msg, "filename", filename_str, 0 /* freeAttr */, 1 /* freeVal */ ); } if (exception_str != nullptr) { xdebug_xml_add_attribute(msg, "exception", exception_str); } if (message_str != nullptr) { xdebug_xml_add_text(msg, message_str, 0); } // Add the message node then send the response xdebug_xml_add_child(response, msg); sendMessage(*response); xdebug_xml_node_dtor(response); // Wait for a resonse from the user return doCommandLoop(); }
bool XDebugServer::initDbgp() { // Initialize the status and reason switch (m_mode) { case Mode::REQ: setStatus(Status::Starting, Reason::Ok); break; case Mode::JIT: setStatus(Status::Break, Reason::Error); break; } // Create the response auto response = xdebug_xml_node_init("init"); addXmlns(*response); // Add the engine info auto child = xdebug_xml_node_init("engine"); xdebug_xml_add_attribute(child, "version", XDEBUG_VERSION); xdebug_xml_add_text(child, XDEBUG_NAME, 0); xdebug_xml_add_child(response, child); // Add the author child = xdebug_xml_node_init("author"); xdebug_xml_add_text(child, XDEBUG_AUTHOR, 0); xdebug_xml_add_child(response, child); // Add the url child = xdebug_xml_node_init("url"); xdebug_xml_add_text(child, XDEBUG_URL, 0); xdebug_xml_add_child(response, child); // Add the copyright child = xdebug_xml_node_init("copyright"); xdebug_xml_add_text(child, XDEBUG_COPYRIGHT, 0); xdebug_xml_add_child(response, child); // Grab the absolute path of the script filename auto globals = get_global_variables()->asArrayData(); Variant scriptname_var = globals->get(s_SERVER).toArray()[s_SCRIPT_FILENAME]; assert(scriptname_var.isString()); auto scriptname = scriptname_var.toString().get()->mutableData(); auto fileuri = XDebugUtils::pathToUrl(scriptname); // Add attributes to the root init node xdebug_xml_add_attribute_ex(response, "fileuri", fileuri, 0, 1); xdebug_xml_add_attribute(response, "language", "PHP"); xdebug_xml_add_attribute(response, "protocol_version", DBGP_VERSION); xdebug_xml_add_attribute(response, "appid", getpid()); // Add the DBGP_COOKIE environment variable const String dbgp_cookie = g_context->getenv(s_DBGP_COOKIE); if (!dbgp_cookie.empty()) { xdebug_xml_add_attribute(response, "session", dbgp_cookie.data()); } // Add the idekey if (XDEBUG_GLOBAL(IdeKey).size() > 0) { xdebug_xml_add_attribute(response, "idekey", XDEBUG_GLOBAL(IdeKey).c_str()); } // Sent the response sendMessage(*response); xdebug_xml_node_dtor(response); // Wait for a response from the client return doCommandLoop(); }
static void xdebug_object_element_export_xml_node(xdebug_xml_node& parent, const char* parentName, const ObjectData* obj, const Variant& key, const Variant& val, XDebugExporter& exporter) { auto const prop_str = key.toString(); auto const cls = obj->getVMClass(); auto const cls_name = cls->name()->data(); // Compute whether the properity is static. auto const sLookup = cls->getSProp(nullptr, prop_str.get()); auto const is_static = sLookup.prop != nullptr; bool visible = is_static; bool accessible = sLookup.accessible; // If the property is not static, we know it's a member, but need to grab the // visibility if (!is_static) { bool unset; obj->getProp(nullptr, prop_str.get(), visible, accessible, unset); } // This is public if it is visible and accessible from the nullptr context bool is_public = visible && accessible; // Compute the property name and full name const char* name; const char* full_name = nullptr; if (!val.isInteger()) { // Compute the property name if (is_public) { name = xdstrdup(prop_str.data()); } else { name = xdebug_sprintf("*%s*%s", cls_name, prop_str.data()); } // Compute the property full name if we have a parent name if (parentName != nullptr) { if (is_public && is_static) { full_name = xdebug_sprintf("%s::%s", parentName, prop_str.data()); } else if (is_public && !is_static) { full_name = xdebug_sprintf("%s->%s", parentName, prop_str.data()); } else if (!is_public && is_static) { full_name = xdebug_sprintf("%s::*%s*%s", parentName, "::", cls_name, prop_str.data()); } else if (!is_public && !is_static) { full_name = xdebug_sprintf("%s->*%s*%s", parentName, "->", cls_name, prop_str.data()); } } } else { // Compute the name + full name if we have a parent name name = xdebug_sprintf("%ld", key.toInt64()); if (parentName != nullptr) { if (is_static) { full_name = xdebug_sprintf("%s::%ld", parentName, key.toInt64()); } else { full_name = xdebug_sprintf("%s->%ld", parentName, key.toInt64()); } } } // Compute the facet (static/non-static + public/private) const char* facet = xdebug_sprintf("%s%s", is_static ? "static " : "", is_public ? "public" : "private"); // Recursively write the this property. The duplications are necessary due to // the xdebug xml api xdebug_xml_node* child = xdebug_var_export_xml_node(xdstrdup(name), xdstrdup(full_name), xdstrdup(facet), val, exporter); xdebug_xml_add_child(&parent, child); }
void XDebugServer::initDbgp() { // Initialize the status and reason switch (m_mode) { case Mode::REQ: setStatus(Status::STARTING, Reason::OK); break; case Mode::JIT: setStatus(Status::BREAK, Reason::ERROR); break; } // Create the response xdebug_xml_node* response = xdebug_xml_node_init("init"); addXmnls(*response); // Add the engine info xdebug_xml_node* child = xdebug_xml_node_init("engine"); xdebug_xml_add_attribute(child, "version", XDEBUG_VERSION); xdebug_xml_add_text(child, XDEBUG_NAME, 0); xdebug_xml_add_child(response, child); // Add the author child = xdebug_xml_node_init("author"); xdebug_xml_add_text(child, XDEBUG_AUTHOR, 0); xdebug_xml_add_child(response, child); // Add the url child = xdebug_xml_node_init("url"); xdebug_xml_add_text(child, XDEBUG_URL, 0); xdebug_xml_add_child(response, child); // Add the copyright child = xdebug_xml_node_init("copyright"); xdebug_xml_add_text(child, XDEBUG_COPYRIGHT, 0); xdebug_xml_add_child(response, child); // Grab the absolute path of the script filename const ArrayData* globals = get_global_variables()->asArrayData(); Variant scriptname_var = globals->get(s_SERVER).toArray()[s_SCRIPT_FILENAME]; assert(scriptname_var.isString()); char* scriptname = scriptname_var.toString().get()->mutableData(); char* fileuri = XDebugUtils::pathToUrl(scriptname); // Grab the app id (pid) // TODO(#4489053) Specification mentions the parent app id as well, xdebug // doesn't include it. char* appid = xdebug_sprintf("%d", getpid()); // Add attributes to the root init node xdebug_xml_add_attribute_ex(response, "fileuri", fileuri, 0, 1); xdebug_xml_add_attribute_ex(response, "language", "PHP", 0, 0); xdebug_xml_add_attribute_ex(response, "protocol_version", DBGP_VERSION, 0, 0); xdebug_xml_add_attribute_ex(response, "appid", appid, 0, 1); // Add the DBGP_COOKIE environment variable char* dbgp_cookie = getenv("DBGP_COOKIE"); if (dbgp_cookie != nullptr) { xdebug_xml_add_attribute_ex(response, "session", dbgp_cookie, 0, 0); } // Add the idekey if (XDEBUG_GLOBAL(IdeKey).size() > 0) { // TODO(#4489053) Change this when xml api is changed char* idekey = const_cast<char*>(XDEBUG_GLOBAL(IdeKey).c_str()); xdebug_xml_add_attribute_ex(response, "idekey", idekey, 0, 0); } // Sent the response sendMessage(*response); xdebug_xml_node_dtor(response); // Wait for a response from the client doCommandLoop(); }