script_backtrace.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /**************************************************************************/
  2. /* script_backtrace.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "script_backtrace.h"
  31. #include "core/object/script_language.h"
  32. void ScriptBacktrace::_store_variables(const List<String> &p_names, const List<Variant> &p_values, LocalVector<StackVariable> &r_variables) {
  33. r_variables.reserve(p_names.size());
  34. const List<String>::Element *name = p_names.front();
  35. const List<Variant>::Element *value = p_values.front();
  36. for (int i = 0; i < p_names.size(); i++) {
  37. StackVariable variable;
  38. variable.name = name->get();
  39. variable.value = value->get();
  40. r_variables.push_back(std::move(variable));
  41. name = name->next();
  42. value = value->next();
  43. }
  44. }
  45. void ScriptBacktrace::_bind_methods() {
  46. ClassDB::bind_method(D_METHOD("get_language_name"), &ScriptBacktrace::get_language_name);
  47. ClassDB::bind_method(D_METHOD("is_empty"), &ScriptBacktrace::is_empty);
  48. ClassDB::bind_method(D_METHOD("get_frame_count"), &ScriptBacktrace::get_frame_count);
  49. ClassDB::bind_method(D_METHOD("get_frame_function", "index"), &ScriptBacktrace::get_frame_function);
  50. ClassDB::bind_method(D_METHOD("get_frame_file", "index"), &ScriptBacktrace::get_frame_file);
  51. ClassDB::bind_method(D_METHOD("get_frame_line", "index"), &ScriptBacktrace::get_frame_line);
  52. ClassDB::bind_method(D_METHOD("get_global_variable_count"), &ScriptBacktrace::get_global_variable_count);
  53. ClassDB::bind_method(D_METHOD("get_global_variable_name", "variable_index"), &ScriptBacktrace::get_global_variable_name);
  54. ClassDB::bind_method(D_METHOD("get_global_variable_value", "variable_index"), &ScriptBacktrace::get_global_variable_value);
  55. ClassDB::bind_method(D_METHOD("get_local_variable_count", "frame_index"), &ScriptBacktrace::get_local_variable_count);
  56. ClassDB::bind_method(D_METHOD("get_local_variable_name", "frame_index", "variable_index"), &ScriptBacktrace::get_local_variable_name);
  57. ClassDB::bind_method(D_METHOD("get_local_variable_value", "frame_index", "variable_index"), &ScriptBacktrace::get_local_variable_value);
  58. ClassDB::bind_method(D_METHOD("get_member_variable_count", "frame_index"), &ScriptBacktrace::get_member_variable_count);
  59. ClassDB::bind_method(D_METHOD("get_member_variable_name", "frame_index", "variable_index"), &ScriptBacktrace::get_member_variable_name);
  60. ClassDB::bind_method(D_METHOD("get_member_variable_value", "frame_index", "variable_index"), &ScriptBacktrace::get_member_variable_value);
  61. ClassDB::bind_method(D_METHOD("format", "indent_all", "indent_frames"), &ScriptBacktrace::format, DEFVAL(0), DEFVAL(4));
  62. }
  63. ScriptBacktrace::ScriptBacktrace(ScriptLanguage *p_language, bool p_include_variables) {
  64. language_name = p_language->get_name();
  65. Vector<ScriptLanguage::StackInfo> stack_infos = p_language->debug_get_current_stack_info();
  66. stack_frames.reserve(stack_infos.size());
  67. if (p_include_variables) {
  68. List<String> globals_names;
  69. List<Variant> globals_values;
  70. p_language->debug_get_globals(&globals_names, &globals_values);
  71. _store_variables(globals_names, globals_values, global_variables);
  72. }
  73. for (int i = 0; i < stack_infos.size(); i++) {
  74. const ScriptLanguage::StackInfo &stack_info = stack_infos[i];
  75. StackFrame stack_frame;
  76. stack_frame.function = stack_info.func;
  77. stack_frame.file = stack_info.file;
  78. stack_frame.line = stack_info.line;
  79. if (p_include_variables) {
  80. List<String> locals_names;
  81. List<Variant> locals_values;
  82. p_language->debug_get_stack_level_locals(i, &locals_names, &locals_values);
  83. _store_variables(locals_names, locals_values, stack_frame.local_variables);
  84. List<String> members_names;
  85. List<Variant> members_values;
  86. p_language->debug_get_stack_level_members(i, &members_names, &members_values);
  87. _store_variables(members_names, members_values, stack_frame.member_variables);
  88. }
  89. stack_frames.push_back(std::move(stack_frame));
  90. }
  91. }
  92. String ScriptBacktrace::get_frame_function(int p_index) const {
  93. ERR_FAIL_INDEX_V(p_index, (int)stack_frames.size(), String());
  94. return stack_frames[p_index].function;
  95. }
  96. String ScriptBacktrace::get_frame_file(int p_index) const {
  97. ERR_FAIL_INDEX_V(p_index, (int)stack_frames.size(), String());
  98. return stack_frames[p_index].file;
  99. }
  100. int ScriptBacktrace::get_frame_line(int p_index) const {
  101. ERR_FAIL_INDEX_V(p_index, (int)stack_frames.size(), -1);
  102. return stack_frames[p_index].line;
  103. }
  104. String ScriptBacktrace::get_global_variable_name(int p_variable_index) const {
  105. ERR_FAIL_INDEX_V(p_variable_index, (int)global_variables.size(), String());
  106. return global_variables[p_variable_index].name;
  107. }
  108. Variant ScriptBacktrace::get_global_variable_value(int p_variable_index) const {
  109. ERR_FAIL_INDEX_V(p_variable_index, (int)global_variables.size(), String());
  110. return global_variables[p_variable_index].value;
  111. }
  112. int ScriptBacktrace::get_local_variable_count(int p_frame_index) const {
  113. ERR_FAIL_INDEX_V(p_frame_index, (int)stack_frames.size(), 0);
  114. return (int)stack_frames[p_frame_index].local_variables.size();
  115. }
  116. String ScriptBacktrace::get_local_variable_name(int p_frame_index, int p_variable_index) const {
  117. ERR_FAIL_INDEX_V(p_frame_index, (int)stack_frames.size(), String());
  118. const LocalVector<StackVariable> &local_variables = stack_frames[p_frame_index].local_variables;
  119. ERR_FAIL_INDEX_V(p_variable_index, (int)local_variables.size(), String());
  120. return local_variables[p_variable_index].name;
  121. }
  122. Variant ScriptBacktrace::get_local_variable_value(int p_frame_index, int p_variable_index) const {
  123. ERR_FAIL_INDEX_V(p_frame_index, (int)stack_frames.size(), String());
  124. const LocalVector<StackVariable> &variables = stack_frames[p_frame_index].local_variables;
  125. ERR_FAIL_INDEX_V(p_variable_index, (int)variables.size(), String());
  126. return variables[p_variable_index].value;
  127. }
  128. int ScriptBacktrace::get_member_variable_count(int p_frame_index) const {
  129. ERR_FAIL_INDEX_V(p_frame_index, (int)stack_frames.size(), 0);
  130. return (int)stack_frames[p_frame_index].member_variables.size();
  131. }
  132. String ScriptBacktrace::get_member_variable_name(int p_frame_index, int p_variable_index) const {
  133. ERR_FAIL_INDEX_V(p_frame_index, (int)stack_frames.size(), String());
  134. const LocalVector<StackVariable> &variables = stack_frames[p_frame_index].member_variables;
  135. ERR_FAIL_INDEX_V(p_variable_index, (int)variables.size(), String());
  136. return variables[p_variable_index].name;
  137. }
  138. Variant ScriptBacktrace::get_member_variable_value(int p_frame_index, int p_variable_index) const {
  139. ERR_FAIL_INDEX_V(p_frame_index, (int)stack_frames.size(), String());
  140. const LocalVector<StackVariable> &variables = stack_frames[p_frame_index].member_variables;
  141. ERR_FAIL_INDEX_V(p_variable_index, (int)variables.size(), String());
  142. return variables[p_variable_index].value;
  143. }
  144. String ScriptBacktrace::format(int p_indent_all, int p_indent_frames) const {
  145. if (is_empty()) {
  146. return String();
  147. }
  148. static const String space = String::chr(U' ');
  149. String indent_all = space.repeat(p_indent_all);
  150. String indent_frames = space.repeat(p_indent_frames);
  151. String indent_total = indent_all + indent_frames;
  152. String result = indent_all + language_name + " backtrace (most recent call first):";
  153. for (int i = 0; i < (int)stack_frames.size(); i++) {
  154. const StackFrame &stack_frame = stack_frames[i];
  155. result += "\n" + indent_total + "[" + itos(i) + "] " + stack_frame.function;
  156. if (!stack_frame.file.is_empty()) {
  157. result += " (" + stack_frame.file + ":" + itos(stack_frame.line) + ")";
  158. }
  159. }
  160. return result;
  161. }