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;
}
예제 #2
0
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);
}
예제 #3
0
파일: xdebug_stack.c 프로젝트: bjori/xdebug
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);
}
예제 #6
0
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);
	}
}
예제 #7
0
// 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;
}
예제 #8
0
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;
}
예제 #9
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();
}
예제 #10
0
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;
}
예제 #11
0
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);
}
예제 #12
0
파일: xdebug_xml.cpp 프로젝트: Fermi/hhvm
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);
}
예제 #13
0
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);
			}
		}
	}
}
예제 #14
0
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;
}
예제 #15
0
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);
}
예제 #16
0
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();
}