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]); } }
// 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); }
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); }
static xdebug_monitored_function_entry *xdebug_monitored_function_init(char *func_name, char *filename, int lineno) { xdebug_monitored_function_entry *tmp = xdmalloc(sizeof(xdebug_monitored_function_dtor)); tmp->func_name = xdstrdup(func_name); tmp->filename = xdstrdup(filename); tmp->lineno = lineno; return tmp; }
char *xdebug_sprintf(const char* fmt, ...) { char *new_str; int size = 1; va_list args; char *orig_locale; orig_locale = xdstrdup(setlocale(LC_ALL, NULL)); setlocale(LC_ALL, "C"); new_str = (char *) xdmalloc(size); for (;;) { int n; va_start(args, fmt); n = vsnprintf(new_str, size, fmt, args); va_end(args); if (n > -1 && n < size) { break; } if (n < 0) { size *= 2; } else { size = n + 1; } new_str = (char *) xdrealloc(new_str, size); } setlocale(LC_ALL, orig_locale); xdfree(orig_locale); return new_str; }
// 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; }
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); }
xdebug_coverage_function *xdebug_coverage_function_ctor(char *function_name) { xdebug_coverage_function *function; function = xdmalloc(sizeof(xdebug_coverage_function)); function->name = xdstrdup(function_name); function->branch_info = NULL; return function; }
void xdebug_xml_char_handler(void *ctx, const xmlChar *ch, int len) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; xdebug_xml_reader_priv *data = (xdebug_xml_reader_priv *) ctxt->_private; char *tmp; tmp = strndup(ch, len); xdebug_xml_add_text(data->current, xdstrdup(tmp)); free(tmp); }
static void init_function_monitor_hash(xdebug_hash *internal, HashTable *functions_to_monitor) { zval *val; ZEND_HASH_FOREACH_VAL(functions_to_monitor, val) { if (Z_TYPE_P(val) == IS_STRING) { xdebug_hash_add(internal, Z_STRVAL_P(val), Z_STRLEN_P(val), xdstrdup(Z_STRVAL_P(val))); } } ZEND_HASH_FOREACH_END(); }
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 */ 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); } } }
xdebug_coverage_file *xdebug_coverage_file_ctor(char *filename) { xdebug_coverage_file *file; file = xdmalloc(sizeof(xdebug_coverage_file)); file->name = xdstrdup(filename); file->lines = xdebug_hash_alloc(128, xdebug_coverage_line_dtor); file->functions = xdebug_hash_alloc(128, xdebug_coverage_function_dtor); file->has_branch_info = 0; return file; }
static void init_function_monitor_hash(xdebug_hash *internal, HashTable *functions_to_monitor) { HashPosition pos; zval **val; zend_hash_internal_pointer_reset_ex(functions_to_monitor, &pos); while (zend_hash_get_current_data_ex(functions_to_monitor, (void **) &val, &pos) != FAILURE) { if (Z_TYPE_PP(val) == IS_STRING) { xdebug_hash_add(internal, Z_STRVAL_PP(val), Z_STRLEN_PP(val), xdstrdup(Z_STRVAL_PP(val))); } zend_hash_move_forward_ex(functions_to_monitor, &pos); } }
char* xdebug_error_type(int type) { switch (type) { case E_ERROR: case E_CORE_ERROR: case E_COMPILE_ERROR: case E_USER_ERROR: return xdstrdup("Fatal error"); break; #if PHP_VERSION_ID >= 50200 case E_RECOVERABLE_ERROR: return xdstrdup("Catchable fatal error"); break; #endif case E_WARNING: case E_CORE_WARNING: case E_COMPILE_WARNING: case E_USER_WARNING: return xdstrdup("Warning"); break; case E_PARSE: return xdstrdup("Parse error"); break; case E_NOTICE: case E_USER_NOTICE: return xdstrdup("Notice"); break; case E_STRICT: return xdstrdup("Strict standards"); break; #if PHP_VERSION_ID >= 50300 case E_DEPRECATED: return xdstrdup("Deprecated"); break; #endif default: return xdstrdup("Unknown error"); break; } }
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; }
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); }
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; }