Ejemplo n.º 1
0
void CmdVariable::onClient(DebuggerClient &client) {
  if (DebuggerCommand::displayedHelp(client)) return;

  String text;
  if (client.argCount() == 1) {
    text = client.argValue(1);
  } else if (client.argCount() != 0) {
    help(client);
    return;
  }

  if (client.isStackTraceAsync()) {
    m_type = KindOfVariableAsync;
  }

  m_frame = client.getFrame();

  auto cmd = client.xend<CmdVariable>(this);
  if (cmd->m_variables.empty()) {
    client.info("(no variable was defined)");
  } else {
    PrintVariables(client, cmd->m_variables, cmd->m_global ? -1 : m_frame,
        text, cmd->m_version);
  }
}
Ejemplo n.º 2
0
void CmdWhere::onClientImpl(DebuggerClient &client) {
    if (DebuggerCommand::displayedHelp(client)) return;
    if (client.argCount() > 1) {
        help(client);
        return;
    }

    Array st = fetchStackTrace(client);
    if (st.empty()) {
        client.info("(no stacktrace to display or in global scope)");
        client.info("if you hit serialization limit, consider do "
                    "\"set sa off\" and then get the stack without args");
        return;
    }

    // so list command can default to current frame
    client.moveToFrame(client.getFrame(), false);

    if (client.argCount() == 0) {
        int i = 0;
        for (ArrayIter iter(st); iter; ++iter) {
            client.printFrame(i, iter.second().toArray());
            ++i;
            if (!client.isApiMode() &&
                    i % DebuggerClient::ScrollBlockSize == 0 &&
                    client.ask("There are %zd more frames. Continue? [Y/n]",
                               st.size() - i) == 'n') {
                break;
            }
        }
    } else {
        string snum = client.argValue(1);
        int num = atoi(snum.c_str());
        if (snum[0] == '-') {
            snum = snum.substr(1);
        }
        if (!DebuggerClient::IsValidNumber(snum)) {
            client.error("The argument, if specified, has to be numeric.");
            return;
        }
        if (num > 0) {
            for (int i = 0; i < num && i < st.size(); i++) {
                client.printFrame(i, st[i].toArray());
            }
        } else if (num < 0) {
            for (int i = st.size() + num; i < st.size(); i++) {
                client.printFrame(i, st[i].toArray());
            }
        } else {
            client.error("0 was specified for the number of frames");
            client.tutorial(
                "The optional argument is the number of frames to print out. "
                "Use a positive number to print out innermost frames. Use a negative "
                "number to print out outermost frames."
            );
        }
    }
}
Ejemplo n.º 3
0
void CmdVariable::PrintVariable(DebuggerClient &client, const String& varName) {
  CmdVariable cmd(client.isStackTraceAsync()
                  ? KindOfVariableAsync : KindOfVariable);
  auto charCount = client.getDebuggerClientShortPrintCharCount();
  cmd.m_frame = client.getFrame();
  auto rcmd = client.xend<CmdVariable>(&cmd);

  always_assert(rcmd->m_version == 2);

  // Using the new protocol.  rcmd contains a list of variables only.  Fetch
  // value of varName only, so that we can recover nicely when its value is too
  // large to serialize.
  cmd.m_varName = varName;
  cmd.m_variables.reset();
  cmd.m_formatMaxLen = charCount;
  cmd.m_version = 2;
  rcmd = client.xend<CmdVariable>(&cmd);

  if (rcmd->m_variables.empty()) {
    // Perhaps the value is too large? See recvImpl.  Retry the command with
    // version 1, in which case values are omitted.
    cmd.m_version = 1;
    rcmd = client.xend<CmdVariable>(&cmd);
    if (!rcmd->m_variables.empty()) {
      // It's there without values, and gone with values, so it is too large.
      client.output(s_omitted);
    }
    return;
  }

  auto const get_var = [varName] (const CmdVariable& cmd) {
    assert(cmd.m_variables.size() == 1);
    assert(cmd.m_variables.exists(varName, true /* isKey */));
    assert(cmd.m_variables[varName].isString());
    return cmd.m_variables[varName].toString();
  };

  auto const value = get_var(*rcmd);
  if (charCount <= 0 || value.size() <= charCount) {
    client.output(value);
    return;
  }

  // Don't show the "omitted" suffix.
  client.output(StringSlice(value.data(), charCount));
  if (client.ask("There are more characters. Continue? [y/N]") == 'y') {
    // Now we get the full value, and show the rest.
    cmd.m_variables.reset();
    cmd.m_formatMaxLen = -1;
    rcmd = client.xend<CmdVariable>(&cmd);

    auto value = get_var(*rcmd);
    auto rest = StringSlice(value.data() + charCount, value.size() - charCount);
    client.output(rest);
    client.tutorial("You can use 'set cc n' to increase the character"
                    " limit. 'set cc -1' will remove the limit.");
  }
}
Ejemplo n.º 4
0
void CmdEval::onClient(DebuggerClient &client) {
  m_body = client.getCode();
  m_frame = client.getFrame();
  m_bypassAccessCheck = client.getDebuggerClientBypassCheck();
  auto res =
     client.xendWithNestedExecution<CmdEval>(this);
  res->handleReply(client);
  m_failed = res->m_failed;
}
Ejemplo n.º 5
0
void CmdPrint::onClientImpl(DebuggerClient &client) {
  if (DebuggerCommand::displayedHelp(client)) return;
  if (client.argCount() == 0) {
    help(client);
    return;
  }

  int index = 1;
  if (client.arg(1, "always")) {
    m_isForWatch = true;
    if (client.argCount() == 1) {
      client.error("'[p]rint [a]lways' needs an expression to watch.");
      return;
    }
    index++;
  } else if (client.arg(1, "list")) {
    m_isForWatch = true;
    processList(client);
    return;
  } else if (client.arg(1, "clear")) {
    m_isForWatch = true;
    processClear(client);
    return;
  }

  const char *format = nullptr;
  for (const char **fmt = Formats; *fmt; fmt++) {
    if (client.arg(index, *fmt)) {
      format = *fmt;
      index++;
      break;
    }
  }
  m_body = client.lineRest(index);
  if (m_isForWatch) {
    client.addWatch(format, m_body);
    return;
  }
  m_bypassAccessCheck = client.getDebuggerBypassCheck();
  m_printLevel = client.getDebuggerPrintLevel();
  assert(m_printLevel <= 0 || m_printLevel >= DebuggerClient::MinPrintLevel);
  m_frame = client.getFrame();
  CmdPrintPtr res = client.xend<CmdPrint>(this);
  if (!res->is(m_type)) {
    assert(client.isApiMode());
    m_incomplete = true;
    res->setClientOutput(client);
  } else {
    m_output = res->m_output;
    m_ret = res->m_ret;
    if (!m_output.empty()) {
      client.output(m_output);
    }
    client.output(FormatResult(format, m_ret));
  }
}
Ejemplo n.º 6
0
void CmdEval::onClient(DebuggerClient &client) {
  m_body = client.getCode();
  m_frame = client.getFrame();
  m_bypassAccessCheck = client.getDebuggerClientBypassCheck();
  auto res = client.xendWithNestedExecution<CmdEval>(this);
  assertx(res->is(DebuggerCommand::KindOfEval));
  auto eval = std::static_pointer_cast<CmdEval>(res);
  eval->handleReply(client);
  m_failed = eval->m_failed;
}
Ejemplo n.º 7
0
Variant CmdPrint::processWatch(DebuggerClient &client, const char *format,
                            const std::string &php) {
  m_body = php;
  m_frame = client.getFrame();
  m_noBreak = true;
  CmdPrintPtr res = client.xend<CmdPrint>(this);
  if (!res->m_output.empty()) {
    client.output(res->m_output);
  }
  return res->m_ret;
}
Ejemplo n.º 8
0
void CmdVariable::PrintVariable(DebuggerClient &client, CStrRef varName) {
  CmdVariable cmd;
  cmd.m_frame = client.getFrame();
  CmdVariablePtr rcmd = client.xend<CmdVariable>(&cmd);
  if (!rcmd->m_variables.empty()) {
    for (ArrayIter iter(rcmd->m_variables); iter; ++iter) {
      String name = iter.first().toString();
      if (!name.equal(varName)) continue;
      String value = DebuggerClient::FormatVariable(iter.second(), 200);
      client.print("%s", value.data());
    }
  }
}
Ejemplo n.º 9
0
void CmdEval::onClientImpl(DebuggerClient &client) {
  m_body = client.getCode();
  m_frame = client.getFrame();
  m_bypassAccessCheck = client.getDebuggerBypassCheck();
  DebuggerCommandPtr res =
    client.xendWithNestedExecution<DebuggerCommand>(this);
  if (!res->is(m_type)) {
    assert(client.isApiMode());
    m_incomplete = true;
    res->setClientOutput(client);
  } else {
    res->handleReply(client);
  }
}
Ejemplo n.º 10
0
void CmdDown::onClient(DebuggerClient &client) {
  if (DebuggerCommand::displayedHelp(client)) return;
  if (client.argCount() > 1) {
    help(client);
  } else {
    if (client.isStackTraceAsync()) {
      CmdWhere(KindOfWhereAsync).fetchStackTrace(client);
    } else {
      CmdWhere().fetchStackTrace(client);
    }

    client.moveToFrame(client.getFrame() - CmdUp::ParseNumber(client));
  }
}
Ejemplo n.º 11
0
void CmdEval::onClientImpl(DebuggerClient &client) {
  m_body = client.getCode();
  m_frame = client.getFrame();
  m_bypassAccessCheck = client.getDebuggerBypassCheck();
  client.sendToServer(this);
  DebuggerCommandPtr res = client.recvFromServer(m_type);
  if (!res->is(m_type)) {
    assert(client.isApiMode());
    m_incomplete = true;
    res->setClientOutput(client);
  } else {
    res->handleReply(client);
  }
}
Ejemplo n.º 12
0
void CmdVariable::PrintVariable(DebuggerClient &client, const String& varName) {
  CmdVariable cmd(client.isStackTraceAsync()
                  ? KindOfVariableAsync : KindOfVariable);
  auto charCount = client.getDebuggerClientShortPrintCharCount();
  cmd.m_frame = client.getFrame();
  auto rcmd = client.xend<CmdVariable>(&cmd);
  if (rcmd->m_version == 2) {
    // Using the new protocol. rcmd contains a list of variables only.
    // Fetch value of varName only, so that we can recover nicely when its
    // value is too large to serialize.
    cmd.m_varName = varName;
    cmd.m_variables.reset();
    cmd.m_version = 2;
    rcmd = client.xend<CmdVariable>(&cmd);
    if (rcmd->m_variables.empty()) {
      // Perhaps the value is too large? See recvImpl.
      // Retry the command with version 1, in which case values are omitted.
      cmd.m_version = 1;
      rcmd = client.xend<CmdVariable>(&cmd);
      if (!rcmd->m_variables.empty()) {
        // It's there without values, and gone with values, so it is too large.
        client.output("...(omitted)");
        return;
      }
    }
  }
  if (!rcmd->m_variables.empty()) {
    for (ArrayIter iter(rcmd->m_variables); iter; ++iter) {
      String name = iter.first().toString();
      if (!name.equal(varName)) continue;
      String value = DebuggerClient::FormatVariable(iter.second(), -1);
      auto excess = value.length() - charCount;
      if (charCount <= 0 || excess <= 0) {
        client.output("%s", value.data());
      } else {
        client.output("%s", value.substr(0, charCount).data());
        if (client.ask("There are %d more characters. Continue? [y/N]", excess)
            == 'y') {
          client.output("%s", value.substr(charCount).data());
          client.tutorial("You can use 'set cc n' to increase the character"
              " limit. 'set cc -1' will remove the limit.");
        }
      }
    }
  }
}
Ejemplo n.º 13
0
void CmdVariable::onClient(DebuggerClient &client) {
  if (DebuggerCommand::displayedHelp(client)) return;

  String text;
  if (client.argCount() == 1) {
    text = client.argValue(1);
  } else if (client.argCount() != 0) {
    help(client);
    return;
  }

  m_frame = client.getFrame();
  CmdVariablePtr cmd = client.xend<CmdVariable>(this);
  if (cmd->m_variables.empty()) {
    client.info("(no variable was defined)");
  } else {
    m_variables = cmd->m_variables;
    PrintVariables(client, cmd->m_variables, cmd->m_global, text);
  }
}
Ejemplo n.º 14
0
void CmdWhere::onClient(DebuggerClient &client) {
  if (DebuggerCommand::displayedHelp(client)) return;
  if (client.argCount() > 2) {
    help(client);
    return;
  }
  int argBase = 1;
  if ((client.argCount() > 0) && client.arg(argBase, "async")) {
    // We use a different command type for an async stack trace, so we
    // can both send and receive different data and still keep the
    // existing Where command unchanged. This ensures that old clients
    // can still get a stack trace from a newer server, and vice
    // versa.
    m_type = KindOfWhereAsync;
    argBase++;
    client.info("Fetching async stacktrace...");
  }

  Array st = fetchStackTrace(client);
  if (st.empty()) {
    if (m_type != KindOfWhereAsync) {
      client.info("(no stacktrace to display or in global scope)");
      client.info("If you hit the serialization limit, try "
                  "\"set sa off\" to get the stack without args");
    } else {
      client.info("(no async stacktrace to display)");
    }
    return;
  }

  // so list command can default to current frame
  client.moveToFrame(client.getFrame(), false);

  if (client.argCount() < argBase) {
    int i = 0;
    for (ArrayIter iter(st); iter; ++iter) {
      client.printFrame(i, iter.second().toArray());
      ++i;
      if (i % DebuggerClient::ScrollBlockSize == 0 &&
          client.ask("There are %zd more frames. Continue? [Y/n]",
                      st.size() - i) == 'n') {
        break;
      }
    }
  } else {
    std::string snum = client.argValue(argBase);
    int num = atoi(snum.c_str());
    if (snum[0] == '-') {
      snum = snum.substr(1);
    }
    if (!DebuggerClient::IsValidNumber(snum)) {
      client.error("The argument, if specified, has to be numeric.");
      return;
    }
    if (num > 0) {
      for (int i = 0; i < num && i < st.size(); i++) {
        client.printFrame(i, st[i].toArray());
      }
    } else if (num < 0) {
      for (int i = st.size() + num; i < st.size(); i++) {
        client.printFrame(i, st[i].toArray());
      }
    } else {
      client.error("0 was specified for the number of frames");
      client.tutorial(
        "The optional argument is the number of frames to print out. "
        "Use a positive number to print out innermost frames. Use a negative "
        "number to print out outermost frames."
      );
    }
  }
}