Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/object/script_backtrace.cpp
9903 views
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
31
#include "script_backtrace.h"
32
33
#include "core/object/script_language.h"
34
35
void ScriptBacktrace::_store_variables(const List<String> &p_names, const List<Variant> &p_values, LocalVector<StackVariable> &r_variables) {
36
r_variables.reserve(p_names.size());
37
38
const List<String>::Element *name = p_names.front();
39
const List<Variant>::Element *value = p_values.front();
40
41
for (int i = 0; i < p_names.size(); i++) {
42
StackVariable variable;
43
variable.name = name->get();
44
variable.value = value->get();
45
r_variables.push_back(std::move(variable));
46
47
name = name->next();
48
value = value->next();
49
}
50
}
51
52
void ScriptBacktrace::_bind_methods() {
53
ClassDB::bind_method(D_METHOD("get_language_name"), &ScriptBacktrace::get_language_name);
54
55
ClassDB::bind_method(D_METHOD("is_empty"), &ScriptBacktrace::is_empty);
56
ClassDB::bind_method(D_METHOD("get_frame_count"), &ScriptBacktrace::get_frame_count);
57
ClassDB::bind_method(D_METHOD("get_frame_function", "index"), &ScriptBacktrace::get_frame_function);
58
ClassDB::bind_method(D_METHOD("get_frame_file", "index"), &ScriptBacktrace::get_frame_file);
59
ClassDB::bind_method(D_METHOD("get_frame_line", "index"), &ScriptBacktrace::get_frame_line);
60
61
ClassDB::bind_method(D_METHOD("get_global_variable_count"), &ScriptBacktrace::get_global_variable_count);
62
ClassDB::bind_method(D_METHOD("get_global_variable_name", "variable_index"), &ScriptBacktrace::get_global_variable_name);
63
ClassDB::bind_method(D_METHOD("get_global_variable_value", "variable_index"), &ScriptBacktrace::get_global_variable_value);
64
65
ClassDB::bind_method(D_METHOD("get_local_variable_count", "frame_index"), &ScriptBacktrace::get_local_variable_count);
66
ClassDB::bind_method(D_METHOD("get_local_variable_name", "frame_index", "variable_index"), &ScriptBacktrace::get_local_variable_name);
67
ClassDB::bind_method(D_METHOD("get_local_variable_value", "frame_index", "variable_index"), &ScriptBacktrace::get_local_variable_value);
68
69
ClassDB::bind_method(D_METHOD("get_member_variable_count", "frame_index"), &ScriptBacktrace::get_member_variable_count);
70
ClassDB::bind_method(D_METHOD("get_member_variable_name", "frame_index", "variable_index"), &ScriptBacktrace::get_member_variable_name);
71
ClassDB::bind_method(D_METHOD("get_member_variable_value", "frame_index", "variable_index"), &ScriptBacktrace::get_member_variable_value);
72
73
ClassDB::bind_method(D_METHOD("format", "indent_all", "indent_frames"), &ScriptBacktrace::format, DEFVAL(0), DEFVAL(4));
74
}
75
76
ScriptBacktrace::ScriptBacktrace(ScriptLanguage *p_language, bool p_include_variables) {
77
language_name = p_language->get_name();
78
79
Vector<ScriptLanguage::StackInfo> stack_infos = p_language->debug_get_current_stack_info();
80
stack_frames.reserve(stack_infos.size());
81
82
if (p_include_variables) {
83
List<String> globals_names;
84
List<Variant> globals_values;
85
p_language->debug_get_globals(&globals_names, &globals_values);
86
_store_variables(globals_names, globals_values, global_variables);
87
}
88
89
for (int i = 0; i < stack_infos.size(); i++) {
90
const ScriptLanguage::StackInfo &stack_info = stack_infos[i];
91
92
StackFrame stack_frame;
93
stack_frame.function = stack_info.func;
94
stack_frame.file = stack_info.file;
95
stack_frame.line = stack_info.line;
96
97
if (p_include_variables) {
98
List<String> locals_names;
99
List<Variant> locals_values;
100
p_language->debug_get_stack_level_locals(i, &locals_names, &locals_values);
101
_store_variables(locals_names, locals_values, stack_frame.local_variables);
102
103
List<String> members_names;
104
List<Variant> members_values;
105
p_language->debug_get_stack_level_members(i, &members_names, &members_values);
106
_store_variables(members_names, members_values, stack_frame.member_variables);
107
}
108
109
stack_frames.push_back(std::move(stack_frame));
110
}
111
}
112
113
String ScriptBacktrace::get_frame_function(int p_index) const {
114
ERR_FAIL_INDEX_V(p_index, (int)stack_frames.size(), String());
115
return stack_frames[p_index].function;
116
}
117
118
String ScriptBacktrace::get_frame_file(int p_index) const {
119
ERR_FAIL_INDEX_V(p_index, (int)stack_frames.size(), String());
120
return stack_frames[p_index].file;
121
}
122
123
int ScriptBacktrace::get_frame_line(int p_index) const {
124
ERR_FAIL_INDEX_V(p_index, (int)stack_frames.size(), -1);
125
return stack_frames[p_index].line;
126
}
127
128
String ScriptBacktrace::get_global_variable_name(int p_variable_index) const {
129
ERR_FAIL_INDEX_V(p_variable_index, (int)global_variables.size(), String());
130
return global_variables[p_variable_index].name;
131
}
132
133
Variant ScriptBacktrace::get_global_variable_value(int p_variable_index) const {
134
ERR_FAIL_INDEX_V(p_variable_index, (int)global_variables.size(), String());
135
return global_variables[p_variable_index].value;
136
}
137
138
int ScriptBacktrace::get_local_variable_count(int p_frame_index) const {
139
ERR_FAIL_INDEX_V(p_frame_index, (int)stack_frames.size(), 0);
140
return (int)stack_frames[p_frame_index].local_variables.size();
141
}
142
143
String ScriptBacktrace::get_local_variable_name(int p_frame_index, int p_variable_index) const {
144
ERR_FAIL_INDEX_V(p_frame_index, (int)stack_frames.size(), String());
145
const LocalVector<StackVariable> &local_variables = stack_frames[p_frame_index].local_variables;
146
ERR_FAIL_INDEX_V(p_variable_index, (int)local_variables.size(), String());
147
return local_variables[p_variable_index].name;
148
}
149
150
Variant ScriptBacktrace::get_local_variable_value(int p_frame_index, int p_variable_index) const {
151
ERR_FAIL_INDEX_V(p_frame_index, (int)stack_frames.size(), String());
152
const LocalVector<StackVariable> &variables = stack_frames[p_frame_index].local_variables;
153
ERR_FAIL_INDEX_V(p_variable_index, (int)variables.size(), String());
154
return variables[p_variable_index].value;
155
}
156
157
int ScriptBacktrace::get_member_variable_count(int p_frame_index) const {
158
ERR_FAIL_INDEX_V(p_frame_index, (int)stack_frames.size(), 0);
159
return (int)stack_frames[p_frame_index].member_variables.size();
160
}
161
162
String ScriptBacktrace::get_member_variable_name(int p_frame_index, int p_variable_index) const {
163
ERR_FAIL_INDEX_V(p_frame_index, (int)stack_frames.size(), String());
164
const LocalVector<StackVariable> &variables = stack_frames[p_frame_index].member_variables;
165
ERR_FAIL_INDEX_V(p_variable_index, (int)variables.size(), String());
166
return variables[p_variable_index].name;
167
}
168
169
Variant ScriptBacktrace::get_member_variable_value(int p_frame_index, int p_variable_index) const {
170
ERR_FAIL_INDEX_V(p_frame_index, (int)stack_frames.size(), String());
171
const LocalVector<StackVariable> &variables = stack_frames[p_frame_index].member_variables;
172
ERR_FAIL_INDEX_V(p_variable_index, (int)variables.size(), String());
173
return variables[p_variable_index].value;
174
}
175
176
String ScriptBacktrace::format(int p_indent_all, int p_indent_frames) const {
177
if (is_empty()) {
178
return String();
179
}
180
181
static const String space = String::chr(U' ');
182
String indent_all = space.repeat(p_indent_all);
183
String indent_frames = space.repeat(p_indent_frames);
184
String indent_total = indent_all + indent_frames;
185
186
String result = indent_all + language_name + " backtrace (most recent call first):";
187
for (int i = 0; i < (int)stack_frames.size(); i++) {
188
const StackFrame &stack_frame = stack_frames[i];
189
result += "\n" + indent_total + "[" + itos(i) + "] " + stack_frame.function;
190
191
if (!stack_frame.file.is_empty()) {
192
result += " (" + stack_frame.file + ":" + itos(stack_frame.line) + ")";
193
}
194
}
195
196
return result;
197
}
198
199