int wxLuaDebugData::EnumerateStackEntry(lua_State* L, int stack_frame, wxArrayInt& references) { wxCHECK_MSG(L, 0, wxT("Invalid lua_State")); wxCHECK_MSG(M_DEBUGREFDATA != NULL, 0, wxT("Invalid ref data")); lua_Debug luaDebug = INIT_LUA_DEBUG; int count = 0; if (lua_getstack(L, stack_frame, &luaDebug) != 0) { int stack_idx = 1; wxString name(lua2wx(lua_getlocal(L, &luaDebug, stack_idx))); while (!name.IsEmpty()) { //wxPrintf(wxT("%s lua_getlocal :%s\n"), lua_Debug_to_wxString(luaDebug).c_str(), name.c_str()); int wxl_valuetype = WXLUA_TNONE; wxString value; wxString source(lua2wx(luaDebug.source)); int lua_value_type = GetTypeValue(L, -1, &wxl_valuetype, value); int val_flag_type = 0; int val_ref = LUA_NOREF; if (lua_value_type == LUA_TTABLE) { val_ref = RefTable(L, -1, &val_flag_type, WXLUA_DEBUGITEM_VALUE_REF, references); } else if (lua_value_type == LUA_TUSERDATA) { if (lua_getmetatable(L, -1)) // doesn't push anything if nil { val_ref = RefTable(L, -1, &val_flag_type, WXLUA_DEBUGITEM_VALUE_REF, references); lua_pop(L, 1); } } Add(new wxLuaDebugItem(name, WXLUA_TNONE, value, wxl_valuetype, source, val_ref, 0, val_flag_type)); ++count; lua_pop(L, 1); // remove variable value name = lua2wx(lua_getlocal(L, &luaDebug, ++stack_idx)); } } return count; }
//获取数组类型变量的值 //只获取最多32个元素的值 std::wstring GetArrayTypeValue(int typeID, DWORD modBase, DWORD address, const BYTE* pData) { //获取元素个数,如果元素个数大于32,则设置为32 DWORD elemCount; SymGetTypeInfo( GetDebuggeeHandle(), modBase, typeID, TI_GET_COUNT, &elemCount); elemCount = elemCount > 32 ? 32 : elemCount; //获取数组元素的TypeID DWORD innerTypeID; SymGetTypeInfo( GetDebuggeeHandle(), modBase, typeID, TI_GET_TYPEID, &innerTypeID); //获取数组元素的长度 ULONG64 elemLen; SymGetTypeInfo( GetDebuggeeHandle(), modBase, innerTypeID, TI_GET_LENGTH, &elemLen); std::wostringstream valueBuilder; for (int index = 0; index != elemCount; ++index) { DWORD elemOffset = DWORD(index * elemLen); valueBuilder << TEXT(" [") << index << TEXT("] ") << GetTypeValue(innerTypeID, modBase, address + elemOffset, pData + index * elemLen); if (index != elemCount - 1) { valueBuilder << std::endl; } } return valueBuilder.str(); }
//将指定地址处的内存,并以相应类型的形式表现出来 std::wstring GetTypeValue(int typeID, DWORD modBase, DWORD address, const BYTE* pData) { DWORD typeTag; SymGetTypeInfo( GetDebuggeeHandle(), modBase, typeID, TI_GET_SYMTAG, &typeTag); switch (typeTag) { case SymTagBaseType: return GetBaseTypeValue(typeID, modBase, pData); case SymTagPointerType: return GetPointerTypeValue(typeID, modBase, pData); case SymTagEnum: return GetEnumTypeValue(typeID, modBase, pData); case SymTagArrayType: return GetArrayTypeValue(typeID, modBase, address, pData); case SymTagUDT: return GetUDTTypeValue(typeID, modBase, address, pData); case SymTagTypedef: //获取真正类型的ID DWORD actTypeID; SymGetTypeInfo( GetDebuggeeHandle(), modBase, typeID, TI_GET_TYPEID, &actTypeID); return GetTypeValue(actTypeID, modBase, address, pData); default: return L"??"; } }
int wxLuaDebugData::EnumerateTable(lua_State* L, int tableRef, int nIndex, wxArrayInt& references) { wxCHECK_MSG(L, 0, wxT("Invalid lua_State")); wxCHECK_MSG(M_DEBUGREFDATA != NULL, 0, wxT("Invalid ref data")); int count = 0; int wxl_keytype = WXLUA_TNONE; int wxl_valuetype = WXLUA_TNONE; wxString value; wxString name; if (tableRef == LUA_GLOBALSINDEX) { lua_pushglobaltable(L); GetTypeValue(L, -1, &wxl_valuetype, value); int flag_type = 0; int val_ref = RefTable(L, -1, &flag_type, WXLUA_DEBUGITEM_VALUE_REF, references); lua_pop(L, 1); // pop globals table Add(new wxLuaDebugItem(wxT("Globals"), WXLUA_TNONE, value, WXLUA_TTABLE, wxEmptyString, val_ref, 0, flag_type)); } #if LUA_VERSION_NUM < 502 // LUA_ENVIRONINDEX is no longer in 5.2 else if (tableRef == LUA_ENVIRONINDEX) { lua_pushvalue(L, LUA_ENVIRONINDEX); GetTypeValue(L, -1, &wxl_valuetype, value); int flag_type = 0; int val_ref = RefTable(L, -1, &flag_type, WXLUA_DEBUGITEM_VALUE_REF, references); lua_pop(L, 1); // pop environment table Add(new wxLuaDebugItem(wxT("Environment"), WXLUA_TNONE, value, WXLUA_TTABLE, wxEmptyString, val_ref, 0, flag_type)); } #endif // LUA_VERSION_NUM < 502 else if (tableRef == LUA_REGISTRYINDEX) { lua_pushvalue(L, LUA_REGISTRYINDEX); GetTypeValue(L, -1, &wxl_valuetype, value); int flag_type = 0; int val_ref = RefTable(L, -1, &flag_type, WXLUA_DEBUGITEM_VALUE_REF, references); lua_pop(L, 1); // pop registry table Add(new wxLuaDebugItem(wxT("Registry"), WXLUA_TNONE, value, WXLUA_TTABLE, wxEmptyString, val_ref, 0, flag_type)); } else { // push the table onto the stack to iterate through if (wxluaR_getref(L, tableRef, &wxlua_lreg_debug_refs_key)) { if (lua_isnil(L, -1)) { // assert so we don't crash mysteriously inside Lua on nil lua_pop(L, 1); // pop nil wxFAIL_MSG(wxT("Invalid wxLua debug reference")); return count; } // Check to see if this is a wxLua LUA_REGISTRYINDEX table void *lightuserdata_reg_key = NULL; lua_pushlightuserdata(L, &wxlua_lreg_regtable_key); // push key lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); // push value (table we're iterating) lua_rawget(L, -2); lightuserdata_reg_key = lua_touserdata(L, -1); // returns NULL for nil lua_pop(L, 2); // pop wxlua_lreg_regtable_key table and (nil or lightuserdata) // Check if this table/userdata has a metatable if (lua_getmetatable(L, -1)) // if no metatable then nothing is pushed { // get the type and value GetTypeValue(L, -1, &wxl_valuetype, value); int flag_type = 0; int val_ref = RefTable(L, -1, &flag_type, WXLUA_DEBUGITEM_VALUE_REF, references); // leading space so it's first when sorted Add(new wxLuaDebugItem(wxT(" __metatable"), WXLUA_TTABLE, value, wxl_valuetype, wxEmptyString, val_ref, nIndex, flag_type)); ++count; lua_pop(L, 1); // pop metatable } // start iterating if (lua_istable(L, -1)) { lua_pushnil(L); while (lua_next(L, -2) != 0) { // value at -1, key at -2, table at -3 // get the key type and value int lua_key_type = GetTypeValue(L, -2, &wxl_keytype, name); // get the value type and value int lua_value_type = GetTypeValue(L, -1, &wxl_valuetype, value); // Handle items within the wxLua LUA_REGISTRYINDEX tables to give more information if (lightuserdata_reg_key != NULL) { if (lightuserdata_reg_key == &wxlua_lreg_types_key) { value += wxString::Format(wxT(" (%s)"), wxluaT_typename(L, (int)lua_tonumber(L, -2)).c_str()); } else if (lightuserdata_reg_key == &wxlua_lreg_classes_key) { wxLuaBindClass* wxlClass = (wxLuaBindClass*)lua_touserdata(L, -1); value += wxLuaBindClassString(wxlClass); } else if (lightuserdata_reg_key == &wxlua_lreg_wxluabindings_key) { wxLuaBinding* binding = (wxLuaBinding*)lua_touserdata(L, -2); name = wxString::Format(wxT("wxLuaBinding(%s) -> %s"), name.c_str(), binding->GetBindingName().c_str()); value += wxT(" = ") + binding->GetLuaNamespace(); } else if (lightuserdata_reg_key == &wxlua_lreg_evtcallbacks_key) { wxLuaEventCallback* wxlCallback = (wxLuaEventCallback*)lua_touserdata(L, -2); wxCHECK_MSG(wxlCallback, count, wxT("Invalid wxLuaEventCallback")); wxString s(wxlCallback->GetInfo()); name = s.BeforeFirst(wxT('|')); value = s.AfterFirst(wxT('|')); } else if (lightuserdata_reg_key == &wxlua_lreg_windestroycallbacks_key) { // only handle t[wxWindow*] = wxLuaWinDestroyCallback* wxLuaWinDestroyCallback* wxlDestroyCallBack = (wxLuaWinDestroyCallback*)lua_touserdata(L, -1); wxCHECK_MSG(wxlDestroyCallBack, count, wxT("Invalid wxLuaWinDestroyCallback")); wxString s(wxlDestroyCallBack->GetInfo()); name = s.BeforeFirst(wxT('|')); value = s.AfterFirst(wxT('|')); } else if (lightuserdata_reg_key == &wxlua_lreg_topwindows_key) { wxWindow* win = (wxWindow*)lua_touserdata(L, -2); name += wxT(" ") + wxString(win->GetClassInfo()->GetClassName()); } else if (lightuserdata_reg_key == &wxlua_lreg_gcobjects_key) { int wxl_type_ = (int)lua_tonumber(L, -1); name = wxString::Format(wxT("%s(%s)"), wxluaT_typename(L, wxl_type_).c_str(), name.c_str()); } else if (lightuserdata_reg_key == &wxlua_lreg_weakobjects_key) { wxString names_weak; // iterate the table of userdata lua_pushnil(L); while (lua_next(L, -2) != 0) { // value = -1, key = -2, table = -3 int wxl_type_weak = (int)lua_tonumber(L, -2); if (!names_weak.IsEmpty()) names_weak += wxT(", "); names_weak += wxString::Format(wxT("%s(%d)"), wxluaT_typename(L, wxl_type_weak).c_str(), wxl_type_weak); lua_pop(L, 1); // pop value, lua_next will pop key at end } name = wxString::Format(wxT("%s (%s)"), names_weak.c_str(), name.c_str()); } } // For these keys we know what is in the value to give more information if (lua_key_type == LUA_TLIGHTUSERDATA) { void* key = lua_touserdata(L, -2); if (key == &wxlua_lreg_wxeventtype_key) { wxEventType eventType = (wxEventType)lua_tonumber(L, -1); const wxLuaBindEvent* wxlEvent = wxLuaBinding::FindBindEvent(eventType); if (wxlEvent != NULL) { value = wxString::Format(wxT("%d = %s : %s"), eventType, lua2wx(wxlEvent->name).c_str(), wxluaT_typename(L, *wxlEvent->wxluatype).c_str()); } } else if (key == &wxlua_metatable_type_key) { value += wxString::Format(wxT(" (%s)"), wxluaT_typename(L, (int)lua_tonumber(L, -1)).c_str()); } else if (key == &wxlua_metatable_wxluabindclass_key) { wxLuaBindClass* wxlClass = (wxLuaBindClass*)lua_touserdata(L, -1); value += wxLuaBindClassString(wxlClass); } else if (key == &wxlua_lreg_debug_refs_key) { value += wxT(" Note: You cannot traverse refed tables"); } } // ---------------------------------------------------------- // Handle the key int key_flag_type = 0; int key_ref = LUA_NOREF; // don't ref anything in this table since it's already refed if ((lua_key_type == LUA_TTABLE) && (lightuserdata_reg_key != &wxlua_lreg_debug_refs_key)) { key_ref = RefTable(L, -2, &key_flag_type, WXLUA_DEBUGITEM_KEY_REF, references); } else if (lua_key_type == LUA_TUSERDATA) { if (lua_getmetatable(L, -2)) // doesn't push anything if nil { key_ref = RefTable(L, -2, &key_flag_type, WXLUA_DEBUGITEM_KEY_REF, references); lua_pop(L, 1); } } // only add the key if we refed it so it can be viewed in the stack dialog if (key_flag_type != 0) { Add(new wxLuaDebugItem(name, wxl_keytype, value, wxl_valuetype, wxEmptyString, key_ref, nIndex, key_flag_type)); ++count; } // ---------------------------------------------------------- // Handle the value int val_flag_type = 0; int val_ref = LUA_NOREF; // don't ref anything in this table since it's already refed if ((lua_value_type == LUA_TTABLE) && (lightuserdata_reg_key != &wxlua_lreg_debug_refs_key)) { val_ref = RefTable(L, -1, &val_flag_type, WXLUA_DEBUGITEM_VALUE_REF, references); } else if (lua_value_type == LUA_TUSERDATA) { if (lua_getmetatable(L, -1)) // doesn't push anything if nil { val_ref = RefTable(L, -1, &val_flag_type, WXLUA_DEBUGITEM_VALUE_REF, references); lua_pop(L, 1); } } // Add the value, but not if the value doesn't expand and the key was already added if ((key_flag_type == 0) || ((key_flag_type != 0) && (val_flag_type != 0))) { Add(new wxLuaDebugItem(name, wxl_keytype, value, wxl_valuetype, wxEmptyString, val_ref, nIndex, val_flag_type)); ++count; } lua_pop(L, 1); // pop value, leave key } } lua_pop(L, 1); // remove reference } } return count; }
//获取数据成员的信息 //如果成员是数据成员,返回TRUE //否则返回FALSE BOOL GetDataMemberInfo(DWORD memberID, DWORD modBase, DWORD address, const BYTE* pData, std::wostringstream& valueBuilder) { DWORD memberTag; SymGetTypeInfo( GetDebuggeeHandle(), modBase, memberID, TI_GET_SYMTAG, &memberTag); if (memberTag != SymTagData && memberTag != SymTagBaseClass) { return FALSE; } valueBuilder << TEXT(" "); DWORD memberTypeID; SymGetTypeInfo( GetDebuggeeHandle(), modBase, memberID, TI_GET_TYPEID, &memberTypeID); //输出类型 valueBuilder << GetTypeName(memberTypeID, modBase); //输出名称 if (memberTag == SymTagData) { WCHAR* name; SymGetTypeInfo( GetDebuggeeHandle(), modBase, memberID, TI_GET_SYMNAME, &name); valueBuilder << TEXT(" ") << name; LocalFree(name); } else { valueBuilder << TEXT(" <base-class>"); } //输出长度 ULONG64 length; SymGetTypeInfo( GetDebuggeeHandle(), modBase, memberTypeID, TI_GET_LENGTH, &length); valueBuilder << TEXT(" ") << length; //输出地址 DWORD offset; SymGetTypeInfo( GetDebuggeeHandle(), modBase, memberID, TI_GET_OFFSET, &offset); DWORD childAddress = address + offset; valueBuilder << TEXT(" ") << std::hex << std::uppercase << std::setfill(TEXT('0')) << std::setw(8) << childAddress << std::dec; //输出值 if (IsSimpleType(memberTypeID, modBase) == TRUE) { valueBuilder << TEXT(" ") << GetTypeValue( memberTypeID, modBase, childAddress, pData + offset); } return TRUE; }