"Fossies" - the Fresh Open Source Software Archive

Member "AutoHotkey_L-1.1.33.09/source/Debugger.h" (8 May 2021, 14404 Bytes) of package /windows/misc/AutoHotkey_L-1.1.33.09.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Debugger.h" see the Fossies "Dox" file reference documentation.

    1 /*
    2 Debugger.h
    3 
    4 Original code by Steve Gray.
    5 
    6 This software is provided 'as-is', without any express or implied
    7 warranty. In no event will the authors be held liable for any damages
    8 arising from the use of this software.
    9 
   10 Permission is granted to anyone to use this software for any purpose,
   11 including commercial applications, and to alter it and redistribute it
   12 freely, without restriction.
   13 */
   14 
   15 #pragma once
   16 
   17 #ifndef CONFIG_DEBUGGER
   18 
   19 #define DEBUGGER_STACK_PUSH(...)
   20 #define DEBUGGER_STACK_POP()
   21 
   22 #else
   23 
   24 #ifndef Debugger_h
   25 #define Debugger_h
   26 
   27 #include <winsock2.h>
   28 #include "script_object.h"
   29 
   30 
   31 #define DEBUGGER_INITIAL_BUFFER_SIZE 2048
   32 
   33 #define DEBUGGER_XML_TAG "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
   34 #define DEBUGGER_XML_TAG_SIZE (_countof(DEBUGGER_XML_TAG)-1)
   35 
   36 #define DEBUGGER_LANG_NAME AHK_NAME
   37 
   38 // DBGp Error Codes
   39 #define DEBUGGER_E_OK                   0
   40 #define DEBUGGER_E_PARSE_ERROR          1
   41 #define DEBUGGER_E_INVALID_OPTIONS      3
   42 #define DEBUGGER_E_UNIMPL_COMMAND       4
   43 #define DEBUGGER_E_COMMAND_UNAVAIL      5
   44 
   45 #define DEBUGGER_E_CAN_NOT_OPEN_FILE    100
   46 
   47 #define DEBUGGER_E_BREAKPOINT_TYPE      201 // Breakpoint type not supported.
   48 #define DEBUGGER_E_BREAKPOINT_INVALID   202 // Invalid line number or filename.
   49 #define DEBUGGER_E_BREAKPOINT_NO_CODE   203 // No code on breakpoint line.
   50 #define DEBUGGER_E_BREAKPOINT_STATE     204 // Invalid breakpoint state.
   51 #define DEBUGGER_E_BREAKPOINT_NOT_FOUND 205 // No such breakpoint.
   52 
   53 #define DEBUGGER_E_UNKNOWN_PROPERTY     300
   54 #define DEBUGGER_E_INVALID_STACK_DEPTH  301
   55 #define DEBUGGER_E_INVALID_CONTEXT      302
   56 
   57 #define DEBUGGER_E_INTERNAL_ERROR       998 // Unrecoverable internal error, usually the result of a Winsock error.
   58 
   59 #define DEBUGGER_E_CONTINUE             -1 // Internal code used by continuation commands.
   60 
   61 // Error messages: these are shown directly to the user, so are in the native string format.
   62 #define DEBUGGER_ERR_INTERNAL           _T("An internal error has occurred in the debugger engine.")
   63 #define DEBUGGER_ERR_DISCONNECT_PROMPT  _T("\nContinue running the script without the debugger?")
   64 #define DEBUGGER_ERR_FAILEDTOCONNECT    _T("Failed to connect to an active debugger client.")
   65 
   66 // Buffer size required for a given XML message size, plus protocol overhead.
   67 // Format: data_length NULL xml_tag data NULL
   68 //#define DEBUGGER_XML_SIZE_REQUIRED(xml_size) (MAX_NUMBER_LENGTH + DEBUGGER_XML_TAG_SIZE + xml_size + 2)
   69 #define DEBUGGER_RESPONSE_OVERHEAD (MAX_INTEGER_LENGTH + DEBUGGER_XML_TAG_SIZE + 2)
   70 
   71 class Debugger;
   72 
   73 extern Debugger g_Debugger;
   74 // jackieku: modified to hold the buffer.
   75 extern CStringA g_DebuggerHost;
   76 extern CStringA g_DebuggerPort;
   77 
   78 
   79 enum BreakpointTypeType {BT_Line, BT_Call, BT_Return, BT_Exception, BT_Conditional, BT_Watch};
   80 enum BreakpointStateType {BS_Disabled=0, BS_Enabled};
   81 
   82 class Breakpoint
   83 {
   84 public:
   85     int id;
   86     char type;
   87     char state;
   88     bool temporary;
   89     
   90     // Not yet supported: function, hit_count, hit_value, hit_condition, exception
   91 
   92     Breakpoint() : id(++sMaxId), type(BT_Line), state(BS_Enabled), temporary(false)
   93     {
   94     }
   95 
   96 private:
   97     static int sMaxId; // Highest used breakpoint ID.
   98 };
   99 
  100 
  101 // Forward-declarations (this file is included in script.h before these are declared).
  102 class Line;
  103 class Func;
  104 struct UDFCallInfo;
  105 class Label;
  106 
  107 
  108 struct DbgStack
  109 {
  110     enum StackEntryType {SE_Thread, SE_Sub, SE_UDF};
  111     struct Entry
  112     {
  113         Line *line;
  114         union
  115         {
  116             TCHAR *desc; // SE_Thread -- "auto-exec", hotkey/hotstring name, "timer", etc.
  117             Label *sub; // SE_Sub
  118             UDFCallInfo *udf; // SE_UDF
  119         };
  120         StackEntryType type;
  121     };
  122 
  123     Entry *mBottom, *mTop, *mTopBound;
  124     size_t mSize; // i.e. capacity.
  125 
  126     DbgStack()
  127     {
  128         // We don't want to set the following too low since the stack would need to be reallocated,
  129         // but also don't want to set it too high since the average script mightn't recurse deeply;
  130         // if the stack size never approaches its maximum, there'll be wasted memory:
  131         mSize = 128;
  132         mBottom = (Entry *)malloc(mSize * sizeof(Entry));
  133         mTop = mBottom - 1; // ++mTop will be the first entry.
  134         mTopBound = mTop + mSize; // Topmost valid position.
  135     }
  136 
  137     int Depth()
  138     {
  139         return (int)(mTop + 1 - mBottom);
  140     }
  141 
  142     // noinline currently seems to have a slight effect on benchmarks.
  143     // Since it should be called very rarely, we don't want it inlined.
  144     void __declspec(noinline) Expand()
  145     {
  146         mSize *= 2;
  147         // To keep the design as simple as possible, assume the allocation will never fail.
  148         // These reallocations should be very rare: if size starts at 128 and doubles each
  149         // time, three expansions would bring it to 1024 entries, which is probably larger
  150         // than any script could need.  (Generally the program's stack will run out before
  151         // script recursion gets anywhere near that deep.)
  152         Entry *new_bottom = (Entry *)realloc(mBottom, mSize * sizeof(Entry));
  153         // Recalculate top of stack.
  154         mTop = mTop - mBottom + new_bottom;
  155         mBottom = new_bottom; // After using its old value.
  156         // Pre-calculate upper bound to keep Push() simple.
  157         mTopBound = mBottom - 1 + mSize;
  158     }
  159 
  160     Entry *Push();
  161 
  162     void Pop()
  163     {
  164         ASSERT(mTop >= mBottom);
  165         --mTop;
  166     }
  167 
  168     void Push(TCHAR *aDesc);
  169     void Push(Label *aSub);
  170     void Push(Func *aFunc);
  171     void Push(UDFCallInfo *aRecurse);
  172 
  173     void GetLocalVars(int aDepth, Var **&aVar, Var **&aVarEnd, VarBkp *&aBkp, VarBkp *&aBkpEnd);
  174 };
  175 
  176 #define DEBUGGER_STACK_PUSH(aWhat)  g_Debugger.mStack.Push(aWhat);
  177 #define DEBUGGER_STACK_POP()        g_Debugger.mStack.Pop();
  178 
  179 
  180 enum PropertyContextType {PC_Local=0, PC_Global};
  181 
  182 
  183 class Debugger
  184 {
  185 public:
  186     int Connect(const char *aAddress, const char *aPort);
  187     int Disconnect();
  188     void Exit(ExitReasons aExitReason, char *aCommandName=NULL); // Called when exiting AutoHotkey.
  189     inline bool IsConnected() { return mSocket != INVALID_SOCKET; }
  190     inline bool IsStepping() { return mInternalState >= DIS_StepInto; }
  191     inline bool HasStdErrHook() { return mStdErrMode != SR_Disabled; }
  192     inline bool HasStdOutHook() { return mStdOutMode != SR_Disabled; }
  193 
  194     inline void PostExecFunctionCall(Line *aExpressionLine)
  195     {
  196         // If the debugger is stepping into/over/out from a function call, we want to
  197         // break at the line which called that function, since the next line to execute
  198         // might be a line in some other function (i.e. because the line which called
  199         // the function is "return func()" or calls another function after this one).
  200         if ((mInternalState == DIS_StepInto
  201             || ((mInternalState == DIS_StepOut || mInternalState == DIS_StepOver)
  202                 // Always '<' since '<=' (for StepOver) shouldn't be possible,
  203                 // since we just returned from a function call:
  204                 && mStack.Depth() < mContinuationDepth))
  205             // The final check ensures we don't repeatedly break at a line containing
  206             // multiple built-in function calls; i.e. don't break unless some script
  207             // has been executed since we began evaluating aExpressionLine.  Something
  208             // like "return recursivefunc()" should work if this is StepInto or StepOver
  209             // since mCurrLine would probably be the '}' of that function:
  210             && mCurrLine != aExpressionLine)
  211             PreExecLine(aExpressionLine);
  212     }
  213 
  214     // Code flow notification functions:
  215     int PreExecLine(Line *aLine); // Called before executing each line.
  216     
  217     // Receive and process commands. Returns when a continuation command is received.
  218     int ProcessCommands();
  219     int Break();
  220     
  221     bool HasPendingCommand();
  222 
  223     // Streams
  224     int WriteStreamPacket(LPCTSTR aText, LPCSTR aType);
  225     bool OutputStdErr(LPCTSTR aText);
  226     bool OutputStdOut(LPCTSTR aText);
  227 
  228     #define DEBUGGER_COMMAND(cmd)   int cmd(char **aArgV, int aArgCount, char *aTransactionId)
  229     
  230     //
  231     // Debugger commands.
  232     //
  233     DEBUGGER_COMMAND(status);
  234 
  235     DEBUGGER_COMMAND(feature_get);
  236     DEBUGGER_COMMAND(feature_set);
  237     
  238     DEBUGGER_COMMAND(run);
  239     DEBUGGER_COMMAND(step_into);
  240     DEBUGGER_COMMAND(step_over);
  241     DEBUGGER_COMMAND(step_out);
  242     DEBUGGER_COMMAND(_break);
  243     DEBUGGER_COMMAND(stop);
  244     DEBUGGER_COMMAND(detach);
  245     
  246     DEBUGGER_COMMAND(breakpoint_set);
  247     DEBUGGER_COMMAND(breakpoint_get);
  248     DEBUGGER_COMMAND(breakpoint_update);
  249     DEBUGGER_COMMAND(breakpoint_remove);
  250     DEBUGGER_COMMAND(breakpoint_list);
  251     
  252     DEBUGGER_COMMAND(stack_depth);
  253     DEBUGGER_COMMAND(stack_get);
  254     DEBUGGER_COMMAND(context_names);
  255     DEBUGGER_COMMAND(context_get);
  256 
  257     DEBUGGER_COMMAND(typemap_get);
  258     DEBUGGER_COMMAND(property_get);
  259     DEBUGGER_COMMAND(property_set);
  260     DEBUGGER_COMMAND(property_value);
  261     
  262     DEBUGGER_COMMAND(source);
  263 
  264     DEBUGGER_COMMAND(redirect_stdout);
  265     DEBUGGER_COMMAND(redirect_stderr);
  266 
  267 
  268     Debugger() : mSocket(INVALID_SOCKET), mInternalState(DIS_Starting)
  269         , mMaxPropertyData(1024), mContinuationTransactionId(""), mStdErrMode(SR_Disabled), mStdOutMode(SR_Disabled)
  270         , mMaxChildren(20), mMaxDepth(2), mDisabledHooks(0)
  271     {
  272     }
  273 
  274     
  275     // Stack - keeps track of threads, function calls and gosubs.
  276     DbgStack mStack;
  277 
  278 private:
  279     SOCKET mSocket;
  280     Line *mCurrLine; // Similar to g_script.mCurrLine, but may be different when breaking post-function-call, before continuing expression evaluation.
  281 
  282     class Buffer
  283     {
  284     public:
  285         int Write(char *aData, size_t aDataSize=-1);
  286         int WriteF(const char *aFormat, ...);
  287         int WriteFileURI(const char *aPath);
  288         int WriteEncodeBase64(const char *aData, size_t aDataSize, bool aSkipBufferSizeCheck = false);
  289         int Expand();
  290         int ExpandIfNecessary(size_t aRequiredSize);
  291         void Remove(size_t aDataSize);
  292         void Clear();
  293 
  294         Buffer() : mData(NULL), mDataSize(0), mDataUsed(0), mFailed(FALSE) {}
  295     
  296         char *mData;
  297         size_t mDataSize;
  298         size_t mDataUsed;
  299         BOOL mFailed;
  300 
  301         ~Buffer() {
  302             if (mData)
  303                 free(mData);
  304         }
  305     } mCommandBuf, mResponseBuf;
  306 
  307     enum DebuggerInternalStateType {
  308         DIS_None = 0,
  309         DIS_Starting = DIS_None,
  310         DIS_Run,
  311         DIS_Break,
  312         DIS_StepInto,
  313         DIS_StepOver,
  314         DIS_StepOut
  315     } mInternalState;
  316 
  317     enum StreamRedirectType {
  318         SR_Disabled = 0,
  319         SR_Copy = 1,
  320         SR_Redirect = 2
  321     } mStdErrMode, mStdOutMode;
  322 
  323     int mContinuationDepth; // Stack depth at last continuation command, for step_into/step_over.
  324     CStringA mContinuationTransactionId; // transaction_id of last continuation command.
  325 
  326     int mMaxPropertyData, mMaxChildren, mMaxDepth;
  327 
  328     HookType mDisabledHooks;
  329 
  330 
  331     enum PropertyType
  332     {
  333         PropNone = 0,
  334         PropVar,
  335         PropVarBkp,
  336         PropField,
  337         PropValue // Read-only pseudo-property (ExprTokenType)
  338     };
  339 
  340     struct PropertySource
  341     {
  342         PropertyType kind;
  343         Var *var;
  344         VarBkp *bkp;
  345         Object::FieldType *field;
  346         ExprTokenType value;
  347     };
  348 
  349     struct PropertyInfo : PropertySource
  350     {
  351         LPCSTR name;
  352         CStringA &fullname;
  353         LPSTR facet; // Initialised during writing.
  354         bool is_alias, is_builtin, is_static, is_binaryclip; // Facets.
  355         int page, pagesize; // Attributes which are also parameters.
  356         int max_data; // Parameters.
  357         int max_depth;
  358 
  359         PropertyInfo(CStringA &aNameBuf)
  360             : is_alias(false), is_builtin(false), is_static(false), is_binaryclip(false)
  361             , page(0), fullname(aNameBuf) {}
  362     };
  363 
  364     
  365     struct PropertyWriter : public IDebugProperties
  366     {
  367         Debugger &mDbg;
  368         PropertyInfo &mProp;
  369         IObject *mObject;
  370         size_t mNameLength;
  371         int mDepth;
  372         int mError;
  373 
  374         PropertyWriter(Debugger &aDbg, PropertyInfo &aProp, IObject *aObject)
  375             : mDbg(aDbg)
  376             , mProp(aProp)
  377             , mObject(aObject)
  378             , mNameLength(aProp.fullname.GetLength())
  379             , mDepth(0)
  380             , mError(0)
  381         {
  382         }
  383 
  384         void WriteProperty(LPCSTR aName, ExprTokenType &aValue);
  385         void WriteProperty(ExprTokenType &aKey, ExprTokenType &aValue);
  386 
  387         void _WriteProperty(ExprTokenType &aValue);
  388 
  389         void BeginProperty(LPCSTR aName, LPCSTR aType, int aNumChildren, DebugCookie &aCookie);
  390         void EndProperty(DebugCookie aCookie);
  391     };
  392 
  393 
  394     // Receive next command from debugger UI:
  395     int ReceiveCommand(int *aCommandSize=NULL);
  396 
  397     // Send XML response to debugger UI:
  398     int SendResponse();
  399     int SendErrorResponse(char *aCommandName, char *aTransactionId, int aError=999, char *aExtraAttributes=NULL);
  400     int SendStandardResponse(char *aCommandName, char *aTransactionId);
  401     int SendContinuationResponse(char *aCommand=NULL, char *aStatus="break", char *aReason="ok");
  402 
  403     int EnterBreakState();
  404     void ExitBreakState();
  405 
  406     int WriteBreakpointXml(Breakpoint *aBreakpoint, Line *aLine);
  407 
  408     void AppendKeyName(CStringA &aNameBuf, size_t aParentNameLength, const char *aName);
  409 
  410     int GetPropertyInfo(Var &aVar, PropertyInfo &aProp, LPTSTR &aValueBuf);
  411     int GetPropertyInfo(VarBkp &aBkp, PropertyInfo &aProp, LPTSTR &aValueBuf);
  412     int GetPropertyInfo(Object::FieldType &aField, PropertyInfo &aProp);
  413     
  414     int GetPropertyValue(Var &aVar, PropertyInfo &aProp, LPTSTR &aValueBuf);
  415 
  416     int WritePropertyXml(PropertyInfo &aProp);
  417     int WritePropertyXml(PropertyInfo &aProp, LPTSTR aName);
  418     int WritePropertyXml(PropertyInfo &aProp, IObject *aObject);
  419 
  420     int WritePropertyData(LPCTSTR aData, size_t aDataSize, int aMaxEncodedSize);
  421     int WritePropertyData(ExprTokenType &aValue, int aMaxEncodedSize);
  422 
  423     int ParsePropertyName(LPCSTR aFullName, int aDepth, int aVarScope, bool aVarMustExist
  424         , PropertySource &aResult);
  425     int property_get_or_value(char **aArgV, int aArgCount, char *aTransactionId, bool aIsPropertyGet);
  426     int redirect_std(char **aArgV, int aArgCount, char *aTransactionId, char *aCommandName);
  427     int run_step(char **aArgV, int aArgCount, char *aTransactionId, char *aCommandName, DebuggerInternalStateType aNewState);
  428 
  429     // Decode a file URI in-place.
  430     void DecodeURI(char *aUri);
  431     
  432     static const char *sBase64Chars;
  433     static size_t Base64Encode(char *aBuf, const char *aInput, size_t aInputSize = -1);
  434     static size_t Base64Decode(char *aBuf, const char *aInput, size_t aInputSize = -1);
  435 
  436 
  437     //typedef int (Debugger::*CommandFunc)(char **aArgV, int aArgCount, char *aTransactionId);
  438     typedef DEBUGGER_COMMAND((Debugger::*CommandFunc));
  439     
  440     struct CommandDef
  441     {
  442         const char *mName;
  443         CommandFunc mFunc;
  444     };
  445 
  446     static CommandDef sCommands[];
  447     
  448 
  449     // Debugger::ParseArgs
  450     //
  451     // Returns DEBUGGER_E_OK on success, or a DBGp error code otherwise.
  452     //
  453     // The Xdebug/DBGp documentation is very vague about command line rules,
  454     // so this function has no special treatment of quotes, backslash, etc.
  455     // There is currently no way to include a literal " -" in an arg as it
  456     // would be recognized as the beginning of the next arg.
  457     //
  458     int ParseArgs(char *aArgs, char **aArgV, int &aArgCount, char *&aTransactionId);
  459     
  460     // Caller must verify that aArg is within bounds:
  461     inline char *ArgValue(char **aArgV, int aArg) { return aArgV[aArg] + 1; }
  462     inline char  ArgChar(char **aArgV, int aArg) { return *aArgV[aArg]; }
  463 
  464     // Fatal debugger error. Prompt user to terminate script or only disconnect debugger.
  465     static int FatalError(LPCTSTR aMessage = DEBUGGER_ERR_INTERNAL DEBUGGER_ERR_DISCONNECT_PROMPT);
  466 };
  467 
  468 #endif
  469 #endif