static int create_file_link(char **filename, const char *error_filename, int error_lineno TSRMLS_DC) { xdebug_str fname = {0, 0, NULL}; char *format = XG(file_link_format); while (*format) { if (*format != '%') { xdebug_str_addl(&fname, (char *) format, 1, 0); } else { format++; switch (*format) { case 'f': /* filename */ xdebug_str_add(&fname, xdebug_sprintf("%s", error_filename), 1); break; case 'l': /* line number */ xdebug_str_add(&fname, xdebug_sprintf("%d", error_lineno), 1); break; case '%': /* literal % */ xdebug_str_addl(&fname, "%", 1, 0); break; } } format++; } *filename = fname.d; return fname.l; }
xdebug_xml_node* xdebug_get_value_xml_node(const char* name, const Variant& val, XDebugVarType type /* = XDebugVarType::Normal */, XDebugExporter& exporter) { // Compute the short and full name of the passed value char* short_name = nullptr; char* full_name = nullptr; if (name) { switch (type) { case XDebugVarType::Normal: { char* tmp_name = prepare_variable_name(name); short_name = xdstrdup(tmp_name); full_name = xdstrdup(tmp_name); xdfree(tmp_name); break; } case XDebugVarType::Static: short_name = xdebug_sprintf("::%s", name); full_name = xdebug_sprintf("::%s", name); break; case XDebugVarType::Constant: short_name = xdstrdup(name); full_name = xdstrdup(name); break; default: throw Exception("Invalid variable type"); } } // Recursively construct the xml return xdebug_var_export_xml_node(short_name, full_name, nullptr, val, exporter); }
void xdebug_append_error_description(xdebug_str *str, int html, const char *error_type_str, char *buffer, const char *error_filename, const int error_lineno TSRMLS_DC) { char **formats = select_formats(html TSRMLS_CC); char *escaped; #if PHP_VERSION_ID >= 50400 size_t newlen; #else int newlen; #endif if (html) { escaped = php_escape_html_entities_ex(buffer, strlen(buffer), &newlen, 0, 0, NULL, 1 TSRMLS_CC); } else { escaped = estrdup(buffer); } if (strlen(XG(file_link_format)) > 0 && html) { char *file_link; create_file_link(&file_link, error_filename, error_lineno TSRMLS_CC); xdebug_str_add(str, xdebug_sprintf(formats[11], error_type_str, escaped, file_link, error_filename, error_lineno), 1); xdfree(file_link); } else { xdebug_str_add(str, xdebug_sprintf(formats[1], error_type_str, escaped, error_filename, error_lineno), 1); } efree(escaped); }
void xdebug_log_stack(const char *error_type_str, char *buffer, const char *error_filename, const int error_lineno TSRMLS_DC) { xdebug_llist_element *le; function_stack_entry *i; char *tmp_log_message; tmp_log_message = xdebug_sprintf( "PHP %s: %s in %s on line %d", error_type_str, buffer, error_filename, error_lineno); php_log_err(tmp_log_message TSRMLS_CC); xdfree(tmp_log_message); if (XG(stack) && XG(stack)->size) { php_log_err("PHP Stack trace:" TSRMLS_CC); for (le = XDEBUG_LLIST_HEAD(XG(stack)); le != NULL; le = XDEBUG_LLIST_NEXT(le)) { int c = 0; /* Comma flag */ unsigned int j = 0; /* Counter */ char *tmp_name; xdebug_str log_buffer = {0, 0, NULL}; i = XDEBUG_LLIST_VALP(le); tmp_name = xdebug_show_fname(i->function, 0, 0 TSRMLS_CC); xdebug_str_add(&log_buffer, xdebug_sprintf("PHP %3d. %s(", i->level, tmp_name), 1); xdfree(tmp_name); /* Printing vars */ for (j = 0; j < i->varc; j++) { char *tmp_varname, *tmp_value; if (c) { xdebug_str_addl(&log_buffer, ", ", 2, 0); } else { c = 1; } tmp_varname = i->var[j].name ? xdebug_sprintf("$%s = ", i->var[j].name) : xdstrdup(""); xdebug_str_add(&log_buffer, tmp_varname, 0); xdfree(tmp_varname); if (i->var[j].addr) { tmp_value = xdebug_get_zval_value(i->var[j].addr, 0, NULL); xdebug_str_add(&log_buffer, tmp_value, 0); xdfree(tmp_value); } else { xdebug_str_addl(&log_buffer, "*uninitialized*", 15, 0); } } xdebug_str_add(&log_buffer, xdebug_sprintf(") %s:%d", i->filename, i->lineno), 1); php_log_err(log_buffer.d TSRMLS_CC); xdebug_str_free(&log_buffer); } } }
static void dump_used_var_with_contents(void *htmlq, xdebug_hash_element* he, void *argument) { int html = *(int *)htmlq; int len; zval *zvar; char *contents; char *name = (char*) he->ptr; HashTable *tmp_ht; char **formats; xdebug_str *str = (xdebug_str *) argument; TSRMLS_FETCH(); if (!he->ptr) { return; } /* Bail out on $this and $GLOBALS */ if (strcmp(name, "this") == 0 || strcmp(name, "GLOBALS") == 0) { return; } #if PHP_VERSION_ID >= 50300 if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); } #endif tmp_ht = XG(active_symbol_table); XG(active_symbol_table) = EG(active_symbol_table); zvar = xdebug_get_php_symbol(name, strlen(name) + 1); XG(active_symbol_table) = tmp_ht; formats = select_formats(PG(html_errors) TSRMLS_CC); if (!zvar) { xdebug_str_add(str, xdebug_sprintf(formats[9], name), 1); return; } if (html) { contents = xdebug_get_zval_value_fancy(NULL, zvar, &len, 0, NULL TSRMLS_CC); } else { contents = xdebug_get_zval_value(zvar, 0, NULL); } if (contents) { xdebug_str_add(str, xdebug_sprintf(formats[8], name, contents), 1); } else { xdebug_str_add(str, xdebug_sprintf(formats[9], name), 1); } xdfree(contents); }
void xdebug_append_error_description(xdebug_str *str, int html, const char *error_type_str, char *buffer, const char *error_filename, const int error_lineno TSRMLS_DC) { char **formats = select_formats(html TSRMLS_CC); if (strlen(XG(file_link_format)) > 0 && html) { char *file_link; create_file_link(&file_link, error_filename, error_lineno TSRMLS_CC); xdebug_str_add(str, xdebug_sprintf(formats[11], error_type_str, buffer, file_link, error_filename, error_lineno), 1); xdfree(file_link); } else { xdebug_str_add(str, xdebug_sprintf(formats[1], error_type_str, buffer, error_filename, error_lineno), 1); } }
// TODO(#3704) Clean this up-- this was taken from php5 xdebug char* XDebugUtils::pathToUrl(const char* fileurl) { int l, i, new_len; char *tmp = nullptr; char *encoded_fileurl; /* encode the url */ encoded_fileurl = xdebug_raw_url_encode(fileurl, strlen(fileurl), &new_len, 1); if (strncmp(fileurl, "phar://", 7) == 0) { /* ignore, phar is cool */ tmp = xdstrdup(fileurl); } else if (fileurl[0] != '/' && fileurl[0] != '\\' && fileurl[1] != ':') { String path(fileurl, CopyString); Variant realpath = HHVM_FN(realpath)(path); if (realpath.isString()) { char* realpath_str = realpath.toString().get()->mutableData(); tmp = xdebug_sprintf("file://%s", realpath_str); } else { // Couldn't convert, use raw path tmp = xdstrdup(encoded_fileurl); } } else if (fileurl[1] == '/' || fileurl[1] == '\\') { // convert UNC paths (eg. \\server\sharepath) // http://blogs.msdn.com/ie/archive/2006/12/06/file-uris-in-windows.aspx tmp = xdebug_sprintf("file:%s", encoded_fileurl); } else if (fileurl[0] == '/' || fileurl[0] == '\\') { /* convert *nix paths (eg. /path) */ tmp = xdebug_sprintf("file://%s", encoded_fileurl); } else if (fileurl[1] == ':') { /* convert windows drive paths (eg. c:\path) */ tmp = xdebug_sprintf("file:///%s", encoded_fileurl); } else { /* no clue about it, use it raw */ tmp = xdstrdup(encoded_fileurl); } l = strlen(tmp); /* convert '\' to '/' */ for (i = 0; i < l; i++) { if (tmp[i] == '\\') { tmp[i]='/'; } } xdfree(encoded_fileurl); // Needs to be free return tmp; }
static char* prepare_variable_name(const char* name) { const char* prefix = (name[0] == '$' || name[0] == ':') ? "" : "$"; char* tmp_name = xdebug_sprintf("%s%s", prefix, name); if (tmp_name[strlen(tmp_name) - 2] == ':' && tmp_name[strlen(tmp_name) - 1] == ':') { tmp_name[strlen(tmp_name) - 2] = '\0'; } return tmp_name; }
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(); }
char* xdebug_return_trace_assignment(function_stack_entry *i, char *varname, zval *retval, char *op, char *filename, int lineno TSRMLS_DC) { int j = 0; xdebug_str str = {0, 0, NULL}; char *tmp_value; if (XG(trace_format) != 0) { return xdstrdup(""); } xdebug_str_addl(&str, " ", 20, 0); if (XG(show_mem_delta)) { xdebug_str_addl(&str, " ", 8, 0); } for (j = 0; j <= i->level; j++) { xdebug_str_addl(&str, " ", 2, 0); } xdebug_str_addl(&str, " => ", 6, 0); xdebug_str_add(&str, varname, 0); if (op[0] != '\0' ) { /* pre/post inc/dec ops are special */ xdebug_str_add(&str, xdebug_sprintf(" %s ", op), 1); tmp_value = xdebug_get_zval_value(retval, 0, NULL); if (tmp_value) { xdebug_str_add(&str, tmp_value, 1); } else { xdebug_str_addl(&str, "NULL", 4, 0); } } xdebug_str_add(&str, xdebug_sprintf(" %s:%d\n", filename, lineno), 1); return str.d; }
void XDebugServer::sendMessage(xdebug_xml_node& xml) { // Convert xml to an xdebug_str xdebug_str xml_message = {0, 0, nullptr}; xdebug_xml_return_node(&xml, &xml_message); size_t msg_len = xml_message.l + sizeof(XML_MSG_HEADER) - 1; // Log the message log("-> %s\n\n", xml_message.d); logFlush(); // Format the message xdebug_str* message; xdebug_str_ptr_init(message); xdebug_str_add(message, xdebug_sprintf("%d", msg_len, 1), 1); xdebug_str_addl(message, "\0", 1, 0); xdebug_str_add(message, XML_MSG_HEADER, 0); xdebug_str_add(message, xml_message.d, 0); xdebug_str_addl(message, "\0", 1, 0); xdebug_str_dtor(xml_message); // Write the message write(m_socket, message->d, message->l); xdebug_str_ptr_dtor(message); }
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); }
void xdebug_append_printable_stack(xdebug_str *str, int html TSRMLS_DC) { xdebug_llist_element *le; function_stack_entry *i; int len; char **formats = select_formats(html TSRMLS_CC); if (XG(stack) && XG(stack)->size) { i = XDEBUG_LLIST_VALP(XDEBUG_LLIST_HEAD(XG(stack))); xdebug_str_add(str, formats[2], 0); for (le = XDEBUG_LLIST_HEAD(XG(stack)); le != NULL; le = XDEBUG_LLIST_NEXT(le)) { int c = 0; /* Comma flag */ int j = 0; /* Counter */ char *tmp_name; i = XDEBUG_LLIST_VALP(le); tmp_name = xdebug_show_fname(i->function, html, 0 TSRMLS_CC); if (html) { #if HAVE_PHP_MEMORY_USAGE xdebug_str_add(str, xdebug_sprintf(formats[3], i->level, i->time - XG(start_time), i->memory, tmp_name), 1); #else xdebug_str_add(str, xdebug_sprintf(formats[3], i->level, i->time - XG(start_time), tmp_name), 1); #endif } else { #if HAVE_PHP_MEMORY_USAGE xdebug_str_add(str, xdebug_sprintf(formats[3], i->time - XG(start_time), i->memory, i->level, tmp_name), 1); #else xdebug_str_add(str, xdebug_sprintf(formats[3], i->time - XG(start_time), i->level, tmp_name), 1); #endif } xdfree(tmp_name); /* Printing vars */ for (j = 0; j < i->varc; j++) { char *tmp_value, *tmp_fancy_value, *tmp_fancy_synop_value; int newlen; if (c) { xdebug_str_addl(str, ", ", 2, 0); } else { c = 1; } if (i->var[j].name && XG(collect_params) >= 4) { if (html) { xdebug_str_add(str, xdebug_sprintf("<span>$%s = </span>", i->var[j].name), 1); } else { xdebug_str_add(str, xdebug_sprintf("$%s = ", i->var[j].name), 1); } } if (i->var[j].addr) { if (html) { tmp_value = xdebug_get_zval_value(i->var[j].addr, 0, NULL); tmp_fancy_value = xdebug_xmlize(tmp_value, strlen(tmp_value), &newlen); tmp_fancy_synop_value = xdebug_get_zval_synopsis_fancy("", i->var[j].addr, &len, 0, NULL TSRMLS_CC); switch (XG(collect_params)) { case 1: // synopsis xdebug_str_add(str, xdebug_sprintf("<span>%s</span>", tmp_fancy_synop_value), 1); break; case 2: // synopsis + full in tooltip xdebug_str_add(str, xdebug_sprintf("<span title='%s'>%s</span>", tmp_fancy_value, tmp_fancy_synop_value), 1); break; case 3: // full default: xdebug_str_add(str, xdebug_sprintf("<span>%s</span>", tmp_fancy_value), 1); break; } xdfree(tmp_value); efree(tmp_fancy_value); xdfree(tmp_fancy_synop_value); } else { switch (XG(collect_params)) { case 1: // synopsis case 2: tmp_value = xdebug_get_zval_synopsis(i->var[j].addr, 0, NULL); break; case 3: default: tmp_value = xdebug_get_zval_value(i->var[j].addr, 0, NULL); break; } if (tmp_value) { xdebug_str_add(str, xdebug_sprintf("%s", tmp_value), 1); xdfree(tmp_value); } else { xdebug_str_addl(str, "???", 3, 0); } } } else { xdebug_str_addl(str, "???", 3, 0); } } if (i->include_filename) { xdebug_str_add(str, xdebug_sprintf(formats[4], i->include_filename), 1); } if (html) { if (strlen(XG(file_link_format)) > 0) { char *just_filename = strrchr(i->filename, DEFAULT_SLASH); char *file_link; create_file_link(&file_link, i->filename, i->lineno TSRMLS_CC); xdebug_str_add(str, xdebug_sprintf(formats[10], i->filename, file_link, just_filename, i->lineno), 1); xdfree(file_link); } else { char *just_filename = strrchr(i->filename, DEFAULT_SLASH); xdebug_str_add(str, xdebug_sprintf(formats[5], i->filename, just_filename, i->lineno), 1); } } else { xdebug_str_add(str, xdebug_sprintf(formats[5], i->filename, i->lineno), 1); } } if (XG(dump_globals) && !(XG(dump_once) && XG(dumped))) { char *tmp = xdebug_get_printable_superglobals(html TSRMLS_CC); if (tmp) { xdebug_str_add(str, tmp, 1); } XG(dumped) = 1; } if (XG(show_local_vars) && XG(stack) && XDEBUG_LLIST_TAIL(XG(stack))) { int scope_nr = XG(stack)->size; i = XDEBUG_LLIST_VALP(XDEBUG_LLIST_TAIL(XG(stack))); if (i->user_defined == XDEBUG_INTERNAL && XDEBUG_LLIST_PREV(XDEBUG_LLIST_TAIL(XG(stack))) && XDEBUG_LLIST_VALP(XDEBUG_LLIST_PREV(XDEBUG_LLIST_TAIL(XG(stack))))) { i = XDEBUG_LLIST_VALP(XDEBUG_LLIST_PREV(XDEBUG_LLIST_TAIL(XG(stack)))); scope_nr--; } if (i->used_vars && i->used_vars->size) { xdebug_hash *tmp_hash; xdebug_str_add(str, xdebug_sprintf(formats[6], scope_nr), 1); tmp_hash = xdebug_used_var_hash_from_llist(i->used_vars); xdebug_hash_apply_with_argument(tmp_hash, (void*) &html, dump_used_var_with_contents, (void *) str); xdebug_hash_destroy(tmp_hash); } } } }
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; }
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(); }