Пример #1
0
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);
}
Пример #2
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();
}
Пример #3
0
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);
}
Пример #4
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);
  }
}
Пример #5
0
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]);
	}
}
Пример #6
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);
}
Пример #7
0
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();
}
Пример #8
0
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);
}
Пример #9
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;
}
Пример #10
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();
}