2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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 #ifndef incl_HPHP_EVAL_DEBUGGER_CLIENT_H_
18 #define incl_HPHP_EVAL_DEBUGGER_CLIENT_H_
20 #include <boost/smart_ptr/shared_array.hpp>
27 #include "hphp/runtime/debugger/debugger.h"
28 #include "hphp/runtime/debugger/debugger_client_settings.h"
29 #include "hphp/runtime/base/debuggable.h"
30 #include "hphp/util/text-color.h"
31 #include "hphp/util/hdf.h"
32 #include "hphp/util/mutex.h"
40 ///////////////////////////////////////////////////////////////////////////////
42 struct DebuggerCommand
;
45 using DebuggerCommandPtr
= std::shared_ptr
<DebuggerCommand
>;
47 class DebuggerClient
{
50 static int CodeBlockSize
;
51 static int ScrollBlockSize
;
52 static const char *LineNoFormat
;
53 static const char *LineNoFormatWithStar
;
54 static const char *LocalPrompt
;
55 static const char *ConfigFileName
;
56 static const char *LegacyConfigFileName
;
57 static const char *HistoryFileName
;
58 static std::string HomePrefix
;
59 static std::string SourceRoot
;
63 static const char *HelpColor
;
64 static const char *InfoColor
;
65 static const char *OutputColor
;
66 static const char *ErrorColor
;
67 static const char *ItemNameColor
;
68 static const char *HighlightForeColor
;
69 static const char *HighlightBgColor
;
70 static const char *DefaultCodeColors
[];
71 static const int MinPrintLevel
= 1;
74 static void LoadColors(const IniSetting::Map
& ini
, Hdf hdf
);
75 static const char *LoadColor(const IniSetting::Map
& ini
, Hdf hdf
,
76 const char *defaultName
);
77 static const char *LoadBgColor(const IniSetting::Map
& ini
, Hdf hdf
,
78 const char *defaultName
);
79 static void LoadCodeColor(CodeColor index
, const IniSetting::Map
& ini
,
80 Hdf hdf
, const char *defaultName
);
83 * Starts/stops a debugger client.
85 static SmartPtr
<Socket
> Start(const DebuggerClientOptions
&options
);
89 * Pre-defined auto-complete lists. Append-only, as they will be used in
90 * binary communication protocol.
93 AutoCompleteFileNames
,
94 AutoCompleteVariables
,
95 AutoCompleteConstants
,
97 AutoCompleteFunctions
,
98 AutoCompleteClassMethods
,
99 AutoCompleteClassProperties
,
100 AutoCompleteClassConstants
,
106 static const char **GetCommands();
108 typedef std::vector
<std::string
> LiveList
;
109 typedef boost::shared_array
<LiveList
> LiveListsPtr
;
110 static LiveListsPtr
CreateNewLiveLists() {
111 return LiveListsPtr(new LiveList
[DebuggerClient::AutoCompleteCount
]);
113 std::vector
<std::string
> getAllCompletions(std::string
const &text
);
118 static void AdjustScreenMetrics();
119 static bool Match(const char *input
, const char *cmd
);
120 static bool IsValidNumber(const std::string
&arg
);
121 static String
FormatVariable(const Variant
& v
, int maxlen
= 80,
123 static String
FormatInfoVec(const IDebuggable::InfoVec
&info
,
124 int *nameLen
= nullptr);
125 static String
FormatTitle(const char *title
);
128 explicit DebuggerClient();
132 * Main processing functions.
135 // Carries out the current command and returns true if the command completed.
138 void onSignal(int sig
);
144 void print (const char *fmt
, ...) ATTRIBUTE_PRINTF(2,3);
145 void help (const char *fmt
, ...) ATTRIBUTE_PRINTF(2,3);
146 void info (const char *fmt
, ...) ATTRIBUTE_PRINTF(2,3);
147 void output (const char *fmt
, ...) ATTRIBUTE_PRINTF(2,3);
148 void error (const char *fmt
, ...) ATTRIBUTE_PRINTF(2,3);
150 void print (const std::string
&s
);
151 void help (const std::string
&s
);
152 void info (const std::string
&s
);
153 void output (const std::string
&s
);
154 void error (const std::string
&s
);
156 void print (const String
& s
);
157 void help (const String
& s
);
158 void info (const String
& s
);
159 void output (const String
& s
);
160 void error (const String
& s
);
162 bool code(const String
& source
, int lineFocus
= 0, int line1
= 0,
164 int charFocus0
= 0, int lineFocus1
= 0, int charFocus1
= 0);
165 void shortCode(BreakPointInfoPtr bp
);
166 char ask(const char *fmt
, ...) ATTRIBUTE_PRINTF(2,3);
168 std::string
wrap(const std::string
&s
);
169 void helpTitle(const char *title
);
170 void helpCmds(const char *cmd
, const char *desc
, ...);
171 void helpCmds(const std::vector
<const char *> &cmds
);
172 void helpBody(const std::string
&s
);
173 void helpSection(const std::string
&s
);
175 void tutorial(const char *text
);
176 void setTutorial(int mode
);
178 // Returns the source code string that the debugger is currently
180 const std::string
&getCode() const { return m_code
;}
184 * Test if argument matches specified. "index" is 1-based.
186 const std::string
&getCommand() const { return m_command
;}
187 bool arg(int index
, const char *s
);
188 int argCount() { return m_args
.size();}
189 std::string
argValue(int index
);
190 // The entire line after that argument, un-escaped.
191 std::string
lineRest(int index
);
192 std::vector
<std::string
> *args() { return &m_args
;}
195 * Send the commmand to server's DebuggerProxy and expect same type of command
196 * back. The WithNestedExecution version supports commands that cause the
197 * server to run PHP on send when we want to be able to debug that PHP before
198 * completing the command.
200 template<typename T
> std::shared_ptr
<T
> xend(DebuggerCommand
*cmd
) {
201 return std::static_pointer_cast
<T
>(xend(cmd
, Nested
));
203 template<typename T
> std::shared_ptr
<T
>
204 xendWithNestedExecution(DebuggerCommand
*cmd
) {
205 return std::static_pointer_cast
<T
>(xend(cmd
, NestedWithExecution
));
208 void sendToServer(DebuggerCommand
*cmd
);
211 * Machine functions. True if we're switching to a machine that's not
212 * interrupting, therefore, we need to throw DebuggerConsoleExitException
213 * to pump more interrupts. False if we're switching to a machine that
214 * was already interrupting, OR, there was a failure to switch. We then
215 * need to call initializeMachine() immediately without waiting.
217 bool connect(const std::string
&host
, int port
);
218 bool connectRPC(const std::string
&host
, int port
);
221 bool initializeMachine();
227 void updateSandboxes(std::vector
<DSandboxInfoPtr
> &sandboxes
) {
228 m_sandboxes
= sandboxes
;
230 DSandboxInfoPtr
getSandbox(int index
) const;
231 void setSandbox(DSandboxInfoPtr sandbox
);
232 std::string
getSandboxId();
237 void updateThreads(std::vector
<DThreadInfoPtr
> threads
);
238 DThreadInfoPtr
getThread(int index
) const;
239 int64_t getCurrentThreadId() const { return m_threadId
;}
242 * Current source location and breakpoints.
244 BreakPointInfoPtr
getCurrentLocation() const { return m_breakpoint
;}
245 std::vector
<BreakPointInfoPtr
> *getBreakPoints() { return &m_breakpoints
;}
246 void setMatchedBreakPoints(std::vector
<BreakPointInfoPtr
> breakpoints
);
247 void setCurrentLocation(int64_t threadId
, BreakPointInfoPtr breakpoint
);
248 std::vector
<BreakPointInfoPtr
> *getMatchedBreakPoints() { return &m_matched
;}
250 // Retrieves a source location that is the current focus of the
251 // debugger. The current focus is initially determined by the
252 // breakpoint where the debugger is currently stopped and can
253 // thereafter be modified by list commands and by switching the
255 void getListLocation(std::string
&file
, int &line
, int &lineFocus0
,
256 int &charFocus0
, int &lineFocus1
, int &charFocus1
);
258 void setListLocation(const std::string
&file
, int line
, bool center
);
259 void setSourceRoot(const std::string
&sourceRoot
);
264 typedef std::pair
<const char *, std::string
> Watch
;
265 typedef std::shared_ptr
<Watch
> WatchPtr
;
266 typedef std::vector
<WatchPtr
> WatchPtrVec
;
267 WatchPtrVec
&getWatches() { return m_watches
;}
268 void addWatch(const char *fmt
, const std::string
&php
);
273 Array
getStackTrace() { return m_stacktrace
; }
274 void setStackTrace(const Array
& stacktrace
, bool isAsync
);
275 bool isStackTraceAsync() { return m_stacktraceAsync
; }
276 void moveToFrame(int index
, bool display
= true);
277 void printFrame(int index
, const Array
& frame
);
278 void setFrame(int frame
) { m_frame
= frame
; }
279 int getFrame() const { return m_frame
; }
284 bool setCompletion(const char *text
, int start
, int end
);
285 char *getCompletion(const char *text
, int state
);
286 void addCompletion(AutoComplete type
);
287 void addCompletion(const char **list
);
288 void addCompletion(const char *name
);
289 void addCompletion(const std::vector
<std::string
> &items
);
290 void setLiveLists(LiveListsPtr liveLists
) { m_acLiveLists
= liveLists
; }
292 void init(const DebuggerClientOptions
&options
);
293 void clearCachedLocal() {
294 m_stacktrace
.reset();
300 void startMacro(std::string name
);
302 bool playMacro(std::string name
);
303 const std::vector
<std::shared_ptr
<Macro
>> &getMacros() const {
306 bool deleteMacro(int index
);
308 DECLARE_DBG_CLIENT_SETTING_ACCESSORS
310 std::string
getLogFile () const { return m_logFile
; }
311 void setLogFile (std::string inLogFile
) { m_logFile
= inLogFile
; }
312 FILE* getLogFileHandler () const { return m_logFileHandler
; }
313 void setLogFileHandler (FILE* inLogFileHandler
) {
314 m_logFileHandler
= inLogFileHandler
;
316 std::string
getCurrentUser() const { return m_options
.user
; }
319 void usageLogCommand(const std::string
&cmd
, const std::string
&data
);
320 void usageLogEvent(const std::string
&eventName
,
321 const std::string
&data
= "");
323 std::string
getZendExecutable() const { return m_zendExe
; }
325 // Internal testing helpers. Only used by internal tests!!!
326 bool internalTestingIsClientStopped() const { return m_stopped
; }
328 bool unknownCmdReceived() const { return m_unknownCmd
; }
336 std::string m_configFileName
;
338 std::set
<std::string
> m_tutorialVisited
;
339 bool m_scriptMode
; // Is this client being scripted by a test?
340 bool m_neverSaveConfig
; // So that tests can avoid clobbering the config file
341 bool m_neverSaveConfigOverride
;
343 DECLARE_DBG_CLIENT_SETTING
345 std::string m_logFile
;
346 FILE* m_logFileHandler
;
348 DebuggerClientOptions m_options
;
349 AsyncFunc
<DebuggerClient
> m_mainThread
;
352 InputState m_inputState
;
353 int m_sigNum
; // Set when ctrl-c is pressed, used by signal polling
354 int m_sigCount
; // Number of times ctrl-c pressed since last interrupt
356 // auto-completion states
360 std::vector
<const char **> m_acLists
;
361 std::vector
<const char *> m_acStrings
;
362 std::vector
<std::string
> m_acItems
;
363 bool m_acLiveListsDirty
;
364 LiveListsPtr m_acLiveLists
;
365 bool m_acProtoTypePrompted
;
368 // The current command to process.
369 std::string m_command
;
370 std::string m_commandCanonical
;
371 std::string m_prevCmd
;
372 std::vector
<std::string
> m_args
;
373 // m_args[i]'s last character is m_line[m_argIdx[i]]
374 std::vector
<int> m_argIdx
;
377 std::vector
<std::shared_ptr
<Macro
>> m_macros
;
378 std::shared_ptr
<Macro
> m_macroRecording
;
379 std::shared_ptr
<Macro
> m_macroPlaying
;
381 std::vector
<std::shared_ptr
<DMachineInfo
>>
382 m_machines
; // All connected machines. 0th is local.
383 std::shared_ptr
<DMachineInfo
> m_machine
; // Current machine
384 std::string m_rpcHost
; // Current RPC host
386 std::vector
<DSandboxInfoPtr
> m_sandboxes
;
387 std::vector
<DThreadInfoPtr
> m_threads
;
389 std::map
<int64_t, int> m_threadIdMap
; // maps threadId to index
391 std::vector
<BreakPointInfoPtr
> m_breakpoints
;
392 BreakPointInfoPtr m_breakpoint
;
393 std::vector
<BreakPointInfoPtr
> m_matched
;
395 // list command's current location, which may be different from m_breakpoint
397 // The file currently being listed. Set implicitly by breakpoints and
398 // explicitly by list commands issued to the client by a user.
399 std::string m_listFile
;
401 // The first line to list
405 WatchPtrVec m_watches
;
408 bool m_stacktraceAsync
;
411 std::string m_sourceRoot
;
413 void start(const DebuggerClientOptions
&options
);
417 std::string
getPrompt();
418 void addToken(std::string
&token
, int idx
);
419 void parseCommand(const char *line
);
421 bool parse(const char *line
);
422 bool match(const char *cmd
);
424 void processTakeCode();
426 DebuggerCommand
*createCommand();
428 void updateLiveLists();
429 void promptFunctionPrototype();
430 char *getCompletion(const std::vector
<std::string
> &items
,
432 char *getCompletion(const std::vector
<const char *> &items
,
436 void defineColors(const Hdf
&config
);
439 void record(const char *line
);
442 void closeAllConnections();
443 void switchMachine(std::shared_ptr
<DMachineInfo
> machine
);
444 SmartPtr
<Socket
> connectLocal();
445 bool connectRemote(const std::string
&host
, int port
);
446 bool tryConnect(const std::string
&host
, int port
, bool clearmachines
);
449 TopLevel
, // The top-level event loop, called from run().
450 Nested
, // A nested loop where we expect a cmd back with no PHP executed.
451 NestedWithExecution
// A nested loop where more PHP may execute.
454 DebuggerCommandPtr
xend(DebuggerCommand
*cmd
, EventLoopKind loopKind
);
455 DebuggerCommandPtr
eventLoop(EventLoopKind loopKind
, int expectedCmd
,
458 // Zend executable for CmdZend, overridable via config.
459 std::string m_zendExe
= "php";
464 ///////////////////////////////////////////////////////////////////////////////
467 #endif // incl_HPHP_EVAL_DEBUGGER_CLIENT_H_