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/command.h"
19 #include "hphp/runtime/base/backtrace.h"
20 #include "hphp/runtime/base/tv-variant.h"
25 StackTraceCommand::StackTraceCommand(
27 folly::dynamic message
28 ) : VSCommand(debugger
, message
) {
31 StackTraceCommand::~StackTraceCommand() {
34 const StaticString
s_file("file");
35 const StaticString
s_line("line");
36 const StaticString
s_function("function");
38 bool StackTraceCommand::executeImpl(
39 DebuggerSession
* session
,
40 folly::dynamic
* responseMsg
42 const request_id_t requestId
= m_debugger
->getCurrentThreadId();
43 const folly::dynamic
& message
= getMessage();
44 const folly::dynamic
& args
= tryGetObject(message
, "arguments", s_emptyArgs
);
46 (*responseMsg
)["body"] = folly::dynamic::object
;
48 folly::dynamic
& stackTrace
= (*responseMsg
)["body"];
49 stackTrace
["stackFrames"] = folly::dynamic::array();
50 folly::dynamic
& frames
= stackTrace
["stackFrames"];
52 if (m_debugger
->getRequestInfo()->m_pauseRecurseCount
== 0) {
53 stackTrace
["stackFrames"] = frames
;
54 stackTrace
["totalFrames"] = 0;
55 (*responseMsg
)["body"] = stackTrace
;
59 int startFrame
= tryGetInt(args
, "startFrame", 0);
60 int levels
= tryGetInt(args
, "levels", INT_MAX
);
62 // Per protocol: if levels is 0, all frames should be returned.
67 // Respond with a stack trace!
68 auto backtraceArgs
= BacktraceArgs()
71 .setParserFrame(nullptr);
73 const Array backtrace
= createBacktrace(backtraceArgs
);
74 int backtraceSize
= backtrace
.size();
75 const ClientPreferences
& prefs
= m_debugger
->getClientPreferences();
77 for (int depth
= 0; depth
< backtraceSize
- 1; depth
++) {
78 if (depth
< startFrame
) {
82 if (levelsAdded
>= levels
) {
86 auto const parentFrame
= backtrace
.rvalAt(depth
+ 1).unboxed();
88 tvCastToString(parentFrame
.val().parr
->get(s_function
).tv()).data();
89 auto const frame
= backtrace
.rvalAt(depth
).unboxed();
90 const auto file
= frame
.val().parr
->get(s_file
);
91 const auto line
= frame
.val().parr
->get(s_line
);
93 frames
.push_back(folly::dynamic::object
);
94 folly::dynamic
& stackFrame
= frames
[frames
.size() - 1];
95 stackFrame
["id"] = session
->generateFrameId(requestId
, depth
);
96 stackFrame
["name"] = funcName
;
98 int64_t lineNumber
= tvCastToInt64(line
.tv());
99 if (!prefs
.linesStartAt1
) {
103 stackFrame
["line"] = lineNumber
;
104 stackFrame
["column"] = 0;
105 stackFrame
["source"] = folly::dynamic::object
;
107 folly::dynamic
& source
= stackFrame
["source"];
108 std::string fileName
= tvCastToString(file
.tv()).toCppString();
110 if (fileName
.empty()) {
111 // Some routines like builtins and native extensions do not have
112 // a PHP file path in their frame's file name field.
113 fileName
= std::string("<unknown>");
116 source
["name"] = fileName
;
117 source
["path"] = fileName
;
122 if (backtrace
.size() == 0) {
123 // The backtrace will be empty if the request is just starting up and hasn't
124 // invoked anything yet.
125 frames
.push_back(folly::dynamic::object
);
126 folly::dynamic
& stackFrame
= frames
[frames
.size() - 1];
127 stackFrame
["id"] = -1;
128 stackFrame
["name"] = "{request initializing}";
129 stackFrame
["line"] = 0;
130 stackFrame
["column"] = 0;
132 folly::dynamic source
= folly::dynamic::object
;
133 source
["name"] = "<unknown>";
134 source
["path"] = "<unknown>";
135 stackFrame
["source"] = source
;
138 stackTrace
["totalFrames"] = backtraceSize
== 0 ? 0 : backtraceSize
- 1;
140 // Completion of this command does not resume the target.