2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2017-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/ext/vsdebug/debugger.h"
18 #include "hphp/runtime/ext/vsdebug/debugger-request-info.h"
19 #include "hphp/runtime/ext/vsdebug/command.h"
20 #include "hphp/runtime/base/backtrace.h"
21 #include "hphp/runtime/base/tv-variant.h"
28 StackTraceCommand::StackTraceCommand(
30 folly::dynamic message
31 ) : VSCommand(debugger
, message
) {
34 StackTraceCommand::~StackTraceCommand() {
37 const StaticString
s_file("file");
38 const StaticString
s_line("line");
39 const StaticString
s_function("function");
41 bool StackTraceCommand::executeImpl(
42 DebuggerSession
* session
,
43 folly::dynamic
* responseMsg
45 // The request thread should not re-enter the debugger while
46 // processing this command.
47 DebuggerNoBreakContext
noBreak(m_debugger
);
49 const request_id_t requestId
= m_debugger
->getCurrentThreadId();
50 const folly::dynamic
& message
= getMessage();
51 const folly::dynamic
& args
= tryGetObject(message
, "arguments", s_emptyArgs
);
53 (*responseMsg
)["body"] = folly::dynamic::object
;
55 folly::dynamic
& stackTrace
= (*responseMsg
)["body"];
56 stackTrace
["stackFrames"] = folly::dynamic::array();
57 folly::dynamic
& frames
= stackTrace
["stackFrames"];
59 if (m_debugger
->getRequestInfo()->m_pauseRecurseCount
== 0) {
60 stackTrace
["stackFrames"] = frames
;
61 stackTrace
["totalFrames"] = 0;
62 (*responseMsg
)["body"] = stackTrace
;
66 int startFrame
= tryGetInt(args
, "startFrame", 0);
67 int levels
= tryGetInt(args
, "levels", INT_MAX
);
69 // Per protocol: if levels is 0, all frames should be returned.
74 // Respond with a stack trace!
75 auto backtraceArgs
= BacktraceArgs()
77 .setParserFrame(nullptr);
79 const Array backtrace
= createBacktrace(backtraceArgs
);
80 int backtraceSize
= backtrace
.size();
81 const ClientPreferences
& prefs
= m_debugger
->getClientPreferences();
83 for (int depth
= 0; depth
< backtraceSize
- 1; depth
++) {
84 if (depth
< startFrame
) {
88 if (levelsAdded
>= levels
) {
92 auto const parentFrame
= backtrace
.lookup(depth
+ 1);
94 tvCastToString(parentFrame
.val().parr
->get(s_function
)).data();
95 auto const frame
= backtrace
.lookup(depth
);
96 const auto file
= frame
.val().parr
->get(s_file
);
97 const auto line
= frame
.val().parr
->get(s_line
);
99 frames
.push_back(folly::dynamic::object
);
100 folly::dynamic
& stackFrame
= frames
[frames
.size() - 1];
101 stackFrame
["id"] = session
->generateFrameId(requestId
, depth
);
102 stackFrame
["name"] = funcName
;
104 int64_t lineNumber
= tvCastToInt64(line
);
105 if (!prefs
.linesStartAt1
) {
109 stackFrame
["line"] = lineNumber
;
110 stackFrame
["column"] = prefs
.columnsStartAt1
? 1 : 0;
112 std::string fileName
= tvCastToString(file
).toCppString();
113 if (!fileName
.empty()) {
114 stackFrame
["source"] = folly::dynamic::object
;
115 folly::dynamic
& source
= stackFrame
["source"];
116 source
["name"] = std::filesystem::path
{fileName
}.stem().native();
117 source
["path"] = fileName
;
123 if (backtrace
.size() == 0) {
124 // The backtrace will be empty if the request is just starting up and hasn't
125 // invoked anything yet.
126 frames
.push_back(folly::dynamic::object
);
127 folly::dynamic
& stackFrame
= frames
[frames
.size() - 1];
128 stackFrame
["id"] = -1;
129 stackFrame
["name"] = "{request initializing}";
130 stackFrame
["line"] = 0;
131 stackFrame
["column"] = 0;
133 folly::dynamic source
= folly::dynamic::object
;
134 source
["name"] = "<unknown>";
135 source
["path"] = "<unknown>";
136 stackFrame
["source"] = source
;
139 stackTrace
["totalFrames"] = backtraceSize
== 0 ? 0 : backtraceSize
- 1;
141 // Completion of this command does not resume the target.