1 | /* Copyright JS Foundation and other contributors, http://js.foundation |
2 | * |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
4 | * you may not use this file except in compliance with the License. |
5 | * You may obtain a copy of the License at |
6 | * |
7 | * http://www.apache.org/licenses/LICENSE-2.0 |
8 | * |
9 | * Unless required by applicable law or agreed to in writing, software |
10 | * distributed under the License is distributed on an "AS IS" BASIS |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | * See the License for the specific language governing permissions and |
13 | * limitations under the License. |
14 | */ |
15 | |
16 | #include "debugger.h" |
17 | #include "jcontext.h" |
18 | #include "jerryscript.h" |
19 | |
20 | /** |
21 | * Checks whether the debugger is connected. |
22 | * |
23 | * @return true - if the debugger is connected |
24 | * false - otherwise |
25 | */ |
26 | bool |
27 | jerry_debugger_is_connected (void) |
28 | { |
29 | #if ENABLED (JERRY_DEBUGGER) |
30 | return JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED; |
31 | #else /* !ENABLED (JERRY_DEBUGGER) */ |
32 | return false; |
33 | #endif /* ENABLED (JERRY_DEBUGGER) */ |
34 | } /* jerry_debugger_is_connected */ |
35 | |
36 | /** |
37 | * Stop execution at the next available breakpoint. |
38 | */ |
39 | void |
40 | jerry_debugger_stop (void) |
41 | { |
42 | #if ENABLED (JERRY_DEBUGGER) |
43 | if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) |
44 | && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE)) |
45 | { |
46 | JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); |
47 | JERRY_CONTEXT (debugger_stop_context) = NULL; |
48 | } |
49 | #endif /* ENABLED (JERRY_DEBUGGER) */ |
50 | } /* jerry_debugger_stop */ |
51 | |
52 | /** |
53 | * Continue execution. |
54 | */ |
55 | void |
56 | jerry_debugger_continue (void) |
57 | { |
58 | #if ENABLED (JERRY_DEBUGGER) |
59 | if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) |
60 | && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE)) |
61 | { |
62 | JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_STOP); |
63 | JERRY_CONTEXT (debugger_stop_context) = NULL; |
64 | } |
65 | #endif /* ENABLED (JERRY_DEBUGGER) */ |
66 | } /* jerry_debugger_continue */ |
67 | |
68 | /** |
69 | * Sets whether the engine should stop at breakpoints. |
70 | */ |
71 | void |
72 | jerry_debugger_stop_at_breakpoint (bool enable_stop_at_breakpoint) /**< enable/disable stop at breakpoint */ |
73 | { |
74 | #if ENABLED (JERRY_DEBUGGER) |
75 | if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED |
76 | && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE)) |
77 | { |
78 | if (enable_stop_at_breakpoint) |
79 | { |
80 | JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_IGNORE); |
81 | } |
82 | else |
83 | { |
84 | JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE); |
85 | } |
86 | } |
87 | #else /* !ENABLED (JERRY_DEBUGGER) */ |
88 | JERRY_UNUSED (enable_stop_at_breakpoint); |
89 | #endif /* ENABLED (JERRY_DEBUGGER) */ |
90 | } /* jerry_debugger_stop_at_breakpoint */ |
91 | |
92 | /** |
93 | * Sets whether the engine should wait and run a source. |
94 | * |
95 | * @return enum JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED - if the source is not received |
96 | * JERRY_DEBUGGER_SOURCE_RECEIVED - if a source code received |
97 | * JERRY_DEBUGGER_SOURCE_END - the end of the source codes |
98 | * JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED - the end of the context |
99 | */ |
100 | jerry_debugger_wait_for_source_status_t |
101 | jerry_debugger_wait_for_client_source (jerry_debugger_wait_for_source_callback_t callback_p, /**< callback function */ |
102 | void *user_p, /**< user pointer passed to the callback */ |
103 | jerry_value_t *return_value) /**< [out] parse and run return value */ |
104 | { |
105 | *return_value = jerry_create_undefined (); |
106 | |
107 | #if ENABLED (JERRY_DEBUGGER) |
108 | if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) |
109 | && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE)) |
110 | { |
111 | JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_CLIENT_SOURCE_MODE); |
112 | jerry_debugger_uint8_data_t *client_source_data_p = NULL; |
113 | jerry_debugger_wait_for_source_status_t ret_type = JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED; |
114 | |
115 | /* Notify the client about that the engine is waiting for a source. */ |
116 | jerry_debugger_send_type (JERRY_DEBUGGER_WAIT_FOR_SOURCE); |
117 | |
118 | while (true) |
119 | { |
120 | if (jerry_debugger_receive (&client_source_data_p)) |
121 | { |
122 | if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)) |
123 | { |
124 | break; |
125 | } |
126 | |
127 | /* Stop executing the current context. */ |
128 | if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONTEXT_RESET_MODE)) |
129 | { |
130 | ret_type = JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED; |
131 | JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_CONTEXT_RESET_MODE); |
132 | break; |
133 | } |
134 | |
135 | /* Stop waiting for a new source file. */ |
136 | if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_NO_SOURCE)) |
137 | { |
138 | ret_type = JERRY_DEBUGGER_SOURCE_END; |
139 | JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_CLIENT_SOURCE_MODE); |
140 | break; |
141 | } |
142 | |
143 | /* The source arrived. */ |
144 | if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE)) |
145 | { |
146 | JERRY_ASSERT (client_source_data_p != NULL); |
147 | |
148 | jerry_char_t *resource_name_p = (jerry_char_t *) (client_source_data_p + 1); |
149 | size_t resource_name_size = strlen ((const char *) resource_name_p); |
150 | |
151 | *return_value = callback_p (resource_name_p, |
152 | resource_name_size, |
153 | resource_name_p + resource_name_size + 1, |
154 | client_source_data_p->uint8_size - resource_name_size - 1, |
155 | user_p); |
156 | |
157 | ret_type = JERRY_DEBUGGER_SOURCE_RECEIVED; |
158 | break; |
159 | } |
160 | } |
161 | |
162 | jerry_debugger_transport_sleep (); |
163 | } |
164 | |
165 | JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE) |
166 | || !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)); |
167 | |
168 | if (client_source_data_p != NULL) |
169 | { |
170 | /* The data may partly arrived. */ |
171 | jmem_heap_free_block (client_source_data_p, |
172 | client_source_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t)); |
173 | } |
174 | |
175 | return ret_type; |
176 | } |
177 | |
178 | return JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED; |
179 | #else /* !ENABLED (JERRY_DEBUGGER) */ |
180 | JERRY_UNUSED (callback_p); |
181 | JERRY_UNUSED (user_p); |
182 | |
183 | return JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED; |
184 | #endif /* ENABLED (JERRY_DEBUGGER) */ |
185 | } /* jerry_debugger_wait_for_client_source */ |
186 | |
187 | /** |
188 | * Send the output of the program to the debugger client. |
189 | * Currently only sends print output. |
190 | */ |
191 | void |
192 | jerry_debugger_send_output (const jerry_char_t *buffer, /**< buffer */ |
193 | jerry_size_t str_size) /**< string size */ |
194 | { |
195 | #if ENABLED (JERRY_DEBUGGER) |
196 | if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) |
197 | { |
198 | jerry_debugger_send_string (JERRY_DEBUGGER_OUTPUT_RESULT, |
199 | JERRY_DEBUGGER_OUTPUT_OK, |
200 | (const uint8_t *) buffer, |
201 | sizeof (uint8_t) * str_size); |
202 | } |
203 | #else /* !ENABLED (JERRY_DEBUGGER) */ |
204 | JERRY_UNUSED (buffer); |
205 | JERRY_UNUSED (str_size); |
206 | #endif /* ENABLED (JERRY_DEBUGGER) */ |
207 | } /* jerry_debugger_send_output */ |
208 | |
209 | /** |
210 | * Send the log of the program to the debugger client. |
211 | */ |
212 | void |
213 | jerry_debugger_send_log (jerry_log_level_t level, /**< level of the diagnostics message */ |
214 | const jerry_char_t *buffer, /**< buffer */ |
215 | jerry_size_t str_size) /**< string size */ |
216 | { |
217 | #if ENABLED (JERRY_DEBUGGER) |
218 | if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) |
219 | { |
220 | jerry_debugger_send_string (JERRY_DEBUGGER_OUTPUT_RESULT, |
221 | (uint8_t) (level + 2), |
222 | (const uint8_t *) buffer, |
223 | sizeof (uint8_t) * str_size); |
224 | } |
225 | #else /* !ENABLED (JERRY_DEBUGGER) */ |
226 | JERRY_UNUSED (level); |
227 | JERRY_UNUSED (buffer); |
228 | JERRY_UNUSED (str_size); |
229 | #endif /* ENABLED (JERRY_DEBUGGER) */ |
230 | } /* jerry_debugger_send_log */ |
231 | |