Ejemplo n.º 1
0
void CmdException::onClientImpl(DebuggerClient &client) {
  if (DebuggerCommand::displayedHelp(client)) return;
  if (client.argCount() == 0) {
    help(client);
    return;
  }

  bool regex = false;
  BreakPointInfo::State state = BreakPointInfo::Always;

  int index = 1;
  if (client.arg(1, "regex")) {
    regex = true;
    index++;
  } else if (client.arg(1, "once")) {
    state = BreakPointInfo::Once;
    index++;
  }

  BreakPointInfoPtr bpi(new BreakPointInfo(regex, state, ExceptionThrown,
                                           client.argValue(index), ""));
  if (!addToBreakpointListAndUpdateServer(client, bpi, index)) {
    client.tutorial(
      "This is the order of different arguments:\n"
      "\n"
      "\t[e]xception [r]egex|[o]nce {exp} if|&& {php}\n"
      "\n"
      "These are the components in an exception {exp}:\n"
      "\n"
      "\terror@{url}"
      "\t{namespace}::{cls}@{url}"
      "\n"
    );
  }
}
Ejemplo n.º 2
0
// If the first argument of the command is "help" or "?"
// this displays help text for the command and returns true.
// Otherwise it returns false.
bool DebuggerCommand::displayedHelp(DebuggerClient &client) {
  TRACE(2, "DebuggerCommand::displayedHelp\n");
  if (client.arg(1, "help") || client.arg(1, "?")) {
    help(client);
    return true;
  }
  return false;
}
Ejemplo n.º 3
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.º 4
0
void CmdPrint::list(DebuggerClient &client) {
  if (client.arg(1, "clear")) {
    client.addCompletion("all");
    return;
  }
  client.addCompletion(DebuggerClient::AutoCompleteCode);

  if (client.argCount() == 0) {
    client.addCompletion(Formats);
    client.addCompletion("always");
    client.addCompletion("list");
    client.addCompletion("clear");
  } else if (client.argCount() == 1 && client.arg(1, "always")) {
    client.addCompletion(Formats);
  }
}
Ejemplo n.º 5
0
void CmdHelp::onClientImpl(DebuggerClient &client) {
  if (DebuggerCommand::displayedHelp(client)) return;
  if (client.argCount() == 0) {
    HelpAll(client);
   } else if (client.arg(1, "start")) {
    HelpStarted(client);
  } else if (client.arg(1, "tutorial")) {
    if (!processTutorial(client)) {
      help(client);
    }
  } else {
    client.swapHelp();
    if (!client.process()) {
      help(client);
    }
  }
}
Ejemplo n.º 6
0
void CmdHelp::list(DebuggerClient &client) {
  if (client.argCount() == 0) {
    client.addCompletion(DebuggerClient::GetCommands());
    client.addCompletion("tutorial");
    client.addCompletion("start");
  } else if (client.arg(1, "tutorial")) {
    client.addCompletion("on");
    client.addCompletion("off");
    client.addCompletion("auto");
  }
}
Ejemplo n.º 7
0
void CmdMacro::onClientImpl(DebuggerClient &client) {
  if (DebuggerCommand::displayedHelp(client)) return;
  if (client.argCount() == 0) {
    help(client);
    return;
  }

  if (client.arg(1, "start")) {
    client.startMacro(client.argValue(2));
  } else if (client.arg(1, "end")) {
    client.endMacro();
  } else if (client.arg(1, "replay")) {
    if (!client.playMacro(client.argValue(2))) {
      client.error("Unable to find specified macro.");
      processList(client);
    }
  } else if (client.arg(1, "list")) {
    processList(client);
  } else if (client.arg(1, "clear")) {
    string snum = client.argValue(2);
    if (!DebuggerClient::IsValidNumber(snum)) {
      client.error("'& [c]lear' needs an {index} argument.");
      client.tutorial(
        "You will have to run '& [l]ist' first to see a list of valid "
        "numbers or indices to specify."
      );
      return;
    }

    int num = atoi(snum.c_str());
    if (!client.deleteMacro(num)) {
      client.error("\"%s\" is not a valid macro index. Choose one from "
                    "this list:", snum.c_str());
      processList(client);
      return;
    }
  }
}
void CmdInternalTesting::onClientImpl(DebuggerClient &client) {
  TRACE(2, "CmdInternalTesting::onClientImpl\n");
  if (DebuggerCommand::displayedHelp(client)) return;
  if (client.argCount() == 0) {
    help(client);
    return;
  }

  client.info("Executing internal test...");
  m_arg = client.argValue(1);

  if (client.arg(1, "badcmdtypesend")) {
    // Give the cmd a bad type and send it over. This should cause the proxy to
    // disconnect from us.
    m_type = KindOfInternalTestingBad;
    client.sendToServer(this);
    // Spin here and wait for the client to be marked as stopped
    // before going back to the event loop. This will give the local
    // proxy time to recgonize the bad cmd, terminate, and wait for
    // the client to stop. This will ensure that we always exit on the
    // same path on both proxy and client threads, and remove any
    // spurious output form ths test case.
    while (!client.internalTestingIsClientStopped()) {
      sleep(1);
    }
    throw DebuggerConsoleExitException(); // Expect no response
  } else if (client.arg(1, "badcmdtypereceive")) {
    client.xend<CmdInternalTesting>(this);
    return;
  } else if (client.arg(1, "shortcmdsend")) {
    m_arg = "shortcmd"; // Force send to drop a field.
    client.sendToServer(this);
    // See note above about this wait.
    while (!client.internalTestingIsClientStopped()) {
      sleep(1);
    }
    throw DebuggerConsoleExitException(); // Expect no response
  } else if (client.arg(1, "shortcmdreceive")) {
    client.xend<CmdInternalTesting>(this);
    return;
  } else if (client.arg(1, "segfaultClient")) {
    int *px = nullptr;
    *px = 42;
  } else if (client.arg(1, "segfaultServer")) {
    client.xend<CmdInternalTesting>(this);
    return;
  }

  help(client);
}
Ejemplo n.º 9
0
void CmdPrint::processClear(DebuggerClient &client) {
  DebuggerClient::WatchPtrVec &watches = client.getWatches();
  if (watches.empty()) {
    client.error("There is no watch expression to clear.");
    client.tutorial(
      "Use '[p]rint [a]lways ...' to set new watch expressions. "
      "Use '[p]rint ?|[h]elp' to read how to set them. "
    );
    return;
  }

  if (client.arg(2, "all")) {
    watches.clear();
    client.info("All watch expressions are cleared.");
    return;
  }

  string snum = client.argValue(2);
  if (!DebuggerClient::IsValidNumber(snum)) {
    client.error("'[p]rint [c]lear' needs an {index} argument.");
    client.tutorial(
      "You will have to run '[p]rint [l]ist' first to see a list of valid "
      "numbers or indices to specify."
    );
    return;
  }

  int num = atoi(snum.c_str()) - 1;
  if (num < 0 || num >= (int)watches.size()) {
    client.error("\"%s\" is not a valid index. Choose one from this list:",
                  snum.c_str());
    processList(client);
    return;
  }

  watches.erase(watches.begin() + num);
}
Ejemplo n.º 10
0
void CmdThread::onClient(DebuggerClient &client) {
  if (DebuggerCommand::displayedHelp(client)) return;
  if (client.argCount() > 1) {
    help(client);
    return;
  }

  if (client.argCount() == 0) {
    m_body = "info";
    auto res = client.xend<CmdThread>(this);
    client.print(res->m_out);
  } else if (client.arg(1, "list")) {
    processList(client);
  } else if (client.arg(1, "normal")) {
    m_body = "normal";
    client.sendToServer(this);
    client.info("Thread is running in normal mode now. Other threads will "
                 "interleave when they hit breakpoints as well.");
  } else if (client.arg(1, "sticky")) {
    m_body = "sticky";
    client.sendToServer(this);
    client.info("Thread is running in sticky mode now. All other threads "
                 "will wait until this thread finishes, when they hit "
                 "breakpoints.");
  } else if (client.arg(1, "exclusive")) {
    m_body = "exclusive";
    client.sendToServer(this);
    client.info("Thread is running in exclusive mode now. All other threads "
                 "will not break, even when they hit breakpoints.");
  } else {
    std::string snum = client.argValue(1);
    if (!DebuggerClient::IsValidNumber(snum)) {
      client.error("'[t]hread {index}' needs a numeric argument.");
      client.tutorial(
        "You will have to run '[t]hread [l]ist' first to see a list of valid "
        "numbers or indices to specify. Thread 1 is always your current "
        "thread. If that's the only thread on the list, you do not have "
        "another thread at break to switch to."
      );
      return;
    }

    int num = atoi(snum.c_str());
    DThreadInfoPtr thread = client.getThread(num);
    if (!thread) {
      processList(client, false);
      thread = client.getThread(num);
      if (!thread) {
        client.error("\"%s\" is not a valid thread index. Choose one from "
                      "this list:", snum.c_str());
        processList(client);
        return;
      }
    }

    if (thread->m_id == client.getCurrentThreadId()) {
      client.info("This is your current thread already.");
      return;
    }

    m_body = "switch";
    m_threads.push_back(thread);
    client.sendToServer(this);
    throw DebuggerConsoleExitException();
  }
}
Ejemplo n.º 11
0
void CmdMachine::onClientImpl(DebuggerClient &client) {
  if (DebuggerCommand::displayedHelp(client)) return;
  if (client.argCount() == 0) {
    help(client);
    return;
  }

  bool rpc = client.arg(1, "rpc");
  if (rpc || client.arg(1, "connect")) {
    if (client.argCount() != 2) {
      help(client);
      return;
    }
    string host = client.argValue(2);
    int port = 0;
    size_t pos = host.find(":");
    if (pos != string::npos) {
      if (!DebuggerClient::IsValidNumber(host.substr(pos + 1))) {
        client.error("Port needs to be a number");
        help(client);
        return;
      }
      port = atoi(host.substr(pos + 1).c_str());
      host = host.substr(0, pos);
    }

    if (rpc) {
      if (client.connectRPC(host, port)) {
        throw DebuggerConsoleExitException();
      }
    } else {
      if (client.connect(host, port)) {
        throw DebuggerConsoleExitException();
      }
    }
    if (!client.initializeMachine()) {
      throw DebuggerConsoleExitException();
    }
    return;
  }

  if (client.arg(1, "disconnect")) {
    if (client.disconnect()) {
      throw DebuggerConsoleExitException();
    }
    if (!client.initializeMachine()) {
      throw DebuggerConsoleExitException();
    }
    return;
  }

  if (client.arg(1, "list")) {
    processList(client);
    return;
  }

  if (client.arg(1, "attach")) {
    DSandboxInfoPtr sandbox;

    string snum = client.argValue(2);
    if (DebuggerClient::IsValidNumber(snum)) {
      int num = atoi(snum.c_str());
      sandbox = client.getSandbox(num);
      if (!sandbox) {
        processList(client, false);
        sandbox = client.getSandbox(num);
        if (!sandbox) {
          client.error("\"%s\" is not a valid sandbox index. Choose one from "
                        "this list:", snum.c_str());
          processList(client);
          return;
        }
      }
    } else {
      int argBase = 2;
      if (client.argCount() >= 2 && client.arg(2, "force")) {
        m_force = true;
        argBase++;
      }
      sandbox = DSandboxInfoPtr(new DSandboxInfo());
      if (client.argCount() < argBase) {
        sandbox->m_user = client.getCurrentUser();
        sandbox->m_name = "default";
      } else if (client.argCount() == argBase) {
        sandbox->m_user = client.getCurrentUser();
        sandbox->m_name = client.argValue(argBase);
      } else if (client.argCount() == argBase + 1) {
        sandbox->m_user = client.argValue(argBase);
        sandbox->m_name = client.argValue(argBase + 1);
      } else {
        help(client);
        return;
      }
    }
    if (AttachSandbox(client, sandbox, m_force)) {
      // Attach succeed, wait for next interrupt
      throw DebuggerConsoleExitException();
    }
    return;
  }

  help(client);
}
Ejemplo n.º 12
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."
      );
    }
  }
}