void XDebugServer::addStatus(xdebug_xml_node& node) { // TODO(#4489053) Change this when xml api is changed char* status = const_cast<char*>(getStatusString(m_status)); char* reason = const_cast<char*>(getReasonString(m_reason)); xdebug_xml_add_attribute_ex(&node, "status", status, 0, 0); xdebug_xml_add_attribute_ex(&node, "reason", reason, 0, 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(); }
void XDebugServer::addCmdAndTrans(xdebug_xml_node& node) { // lastcmd and lasttransid are not always set (for example when the // connection is severed before the first command is sent) if (m_lastCommand == Command::NONE || m_lastTransactionId == nullptr) { return; } // TODO(#4489053) Change this when xml api is changed char* command = const_cast<char*>(getCommandStr(m_lastCommand)); xdebug_xml_add_attribute_ex(&node, "command", command, 0, 0); xdebug_xml_add_attribute_ex(&node, "transaction_id", m_lastTransactionId, 0, 0); }
void xdebug_xml_return_node(xdebug_xml_node* node, struct xdebug_str *output) { xdebug_str_addl(output, "<", 1, 0); xdebug_str_add(output, node->tag, 0); if (node->text && node->text->encode) { xdebug_xml_add_attribute_ex(node, "encoding", "base64", 0, 0); } if (node->attribute) { xdebug_xml_return_attribute(node->attribute, output); } xdebug_str_addl(output, ">", 1, 0); if (node->child) { xdebug_xml_return_node(node->child, output); } if (node->text) { xdebug_xml_return_text_node(node->text, output); } xdebug_str_addl(output, "</", 2, 0); xdebug_str_add(output, node->tag, 0); xdebug_str_addl(output, ">", 1, 0); if (node->next) { xdebug_xml_return_node(node->next, output); } }
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]); } }
void xdebug_xml_add_attribute_dup( xdebug_xml_node* xml, const char* attr, const char* val ) { // const-cast is okay since we are not freeing the passed attribute. auto const cattr = const_cast<char*>(attr); xdebug_xml_add_attribute_ex(xml, cattr, xdstrdup(val), 0, 1); }
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(); }
void xdebug_xml_add_attribute(xdebug_xml_node* xml, const char* attr, int val) { // const-cast is okay since we are not freeing the passed attribute. auto const cattr = const_cast<char*>(attr); xdebug_xml_add_attribute_ex(xml, cattr, xdebug_sprintf("%d", val), 0, 1); }
xdebug_xml_node* xdebug_var_export_xml_node(const char* name, const char* fullName, const char* facet, const Variant& var, XDebugExporter& exporter) { // Setup the node. Each const cast is necessary due to xml api xdebug_xml_node* node = xdebug_xml_node_init("property"); if (name != nullptr) { xdebug_xml_add_attribute_ex(node, "name", const_cast<char*>(name), 0, 1); } if (fullName != nullptr) { xdebug_xml_add_attribute_ex(node, "fullname", const_cast<char*>(fullName), 0, 1); } if (facet != nullptr) { xdebug_xml_add_attribute_ex(node, "facet", const_cast<char*>(facet), 0, 1); } xdebug_xml_add_attribute_ex(node, "address", xdebug_sprintf("%ld", (long) &var), 0, 1); // Case on the type for the rest if (var.isBoolean()) { xdebug_xml_add_attribute(node, "type", "bool"); xdebug_xml_add_text(node, xdebug_sprintf("%d", var.toBoolean())); } else if (var.isNull()) { xdebug_xml_add_attribute(node, "type", "null"); } else if (var.isInteger()) { xdebug_xml_add_attribute(node, "type", "int"); xdebug_xml_add_text(node, xdebug_sprintf("%ld", var.toInt64())); } else if (var.isDouble()) { xdebug_xml_add_attribute(node, "type", "float"); xdebug_xml_add_text(node, xdebug_sprintf("%lG", var.toDouble())); } else if (var.isString()) { // Add the type and the original size String str = var.toString(); xdebug_xml_add_attribute(node, "type", "string"); xdebug_xml_add_attribute_ex(node, "size", xdebug_sprintf("%d", str.size()), 0, 1); // Possibly shrink the string, then add it to the node if (exporter.max_data != 0 && str.size() > exporter.max_data) { str = str.substr(0, exporter.max_data); } xdebug_xml_add_text_encodel(node, xdstrdup(str.data()), str.size()); } else if (var.isArray()) { Array arr = var.toArray(); xdebug_xml_add_attribute(node, "type", "array"); xdebug_xml_add_attribute(node, "children", const_cast<char*>(arr.size() > 0 ? "1" : "0")); // If we've already seen this object, return if (exporter.counts[arr.get()]++ > 0) { xdebug_xml_add_attribute(node, "recursive", "1"); return node; } // Write the # of children then short-circuit if we are too deep xdebug_xml_add_attribute_ex(node, "numchildren", xdebug_sprintf("%d", arr.size()), 0, 1); if (exporter.level++ >= exporter.max_depth) { return node; } // Compute the page and the start/end indices // Note that php xdebug doesn't support pages except for at the top level uint32_t page = exporter.level == 1 ? exporter.page : 0; uint32_t start = page * exporter.max_children; uint32_t end = (page + 1) * exporter.max_children; xdebug_xml_add_attribute_ex(node, "page", xdebug_sprintf("%d", page), 0, 1); xdebug_xml_add_attribute_ex(node, "pagesize", xdebug_sprintf("%d", exporter.max_children), 0, 1); // Add each child ArrayIter iter(arr); iter.setPos(start); for (uint32_t i = start; i < end && iter; i++, ++iter) { xdebug_array_element_export_xml_node(*node, name, iter.first(), iter.second(), exporter); } // Done at this level exporter.level--; exporter.counts[arr.get()]--; } else if (var.isObject()) { // TODO(#3704) This could be merged into the above array code. For now, // it's separate as this was pulled originally from xdebug ObjectData* obj = var.toObject().get(); Class* cls = obj->getVMClass(); Array props = get_object_props(obj); // Add object info xdebug_xml_add_attribute(node, "type", "object"); xdebug_xml_add_attribute_ex(node, "classname", xdstrdup(cls->name()->data()), 0, 1); xdebug_xml_add_attribute(node, "children", const_cast<char*>(props.size() ? "1" : "0")); // If we've already seen this object, return if (exporter.counts[obj]++ > 0) { xdebug_xml_add_attribute(node, "recursive", "1"); return node; } // Add the # of props then short circuit if we are too deep xdebug_xml_add_attribute_ex(node, "numchildren", xdebug_sprintf("%d", props.size()), 0, 1); if (exporter.level++ >= exporter.max_depth) { return node; } // Compute the page and the start/end indices // Note that php xdebug doesn't support pages except for at the top level uint32_t page = exporter.level == 1 ? exporter.page : 0; uint32_t start = page * exporter.max_children; uint32_t end = (page + 1) * exporter.max_children; xdebug_xml_add_attribute_ex(node, "page", xdebug_sprintf("%d", page), 0, 1); xdebug_xml_add_attribute_ex(node, "pagesize", xdebug_sprintf("%d", exporter.max_children), 0, 1); // Add each property ArrayIter iter(props); iter.setPos(start); for (uint32_t i = start; i < end && iter; i++, ++iter) { xdebug_object_element_export_xml_node(*node, name, obj, iter.first(), iter.second(), exporter); } // Done at this level exporter.level--; exporter.counts[(void*) obj]--; } else if (var.isResource()) { ResourceData* res = var.toResource().get(); xdebug_xml_add_attribute(node, "type", "resource"); const char* text = xdebug_sprintf("resource id='%ld' type='%s'", res->o_getId(), res->o_getResourceName().data()); xdebug_xml_add_text(node, const_cast<char*>(text)); } else { xdebug_xml_add_attribute(node, "type", "null"); } return node; }
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(); }