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 "byte-code.h" |
17 | #include "debugger.h" |
18 | #include "ecma-array-object.h" |
19 | #include "ecma-builtin-helpers.h" |
20 | #include "ecma-conversion.h" |
21 | #include "ecma-eval.h" |
22 | #include "ecma-function-object.h" |
23 | #include "ecma-objects.h" |
24 | #include "jcontext.h" |
25 | #include "jerryscript-port.h" |
26 | #include "lit-char-helpers.h" |
27 | |
28 | #if ENABLED (JERRY_DEBUGGER) |
29 | |
30 | /** |
31 | * Incoming message: next message of string data. |
32 | */ |
33 | typedef struct |
34 | { |
35 | uint8_t type; /**< type of the message */ |
36 | } jerry_debugger_receive_uint8_data_part_t; |
37 | |
38 | /** |
39 | * The number of message types in the debugger should reflect the |
40 | * debugger versioning. |
41 | */ |
42 | JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 33 |
43 | && JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 21 |
44 | && JERRY_DEBUGGER_VERSION == 9, |
45 | debugger_version_correlates_to_message_type_count); |
46 | |
47 | /** |
48 | * Waiting for data from the client. |
49 | */ |
50 | #define JERRY_DEBUGGER_RECEIVE_DATA_MODE \ |
51 | (JERRY_DEBUGGER_BREAKPOINT_MODE | JERRY_DEBUGGER_CLIENT_SOURCE_MODE) |
52 | |
53 | /** |
54 | * Type cast the debugger send buffer into a specific type. |
55 | */ |
56 | #define JERRY_DEBUGGER_SEND_BUFFER_AS(type, name_p) \ |
57 | type *name_p = (type *) (JERRY_CONTEXT (debugger_send_buffer_payload_p)) |
58 | |
59 | /** |
60 | * Type cast the debugger receive buffer into a specific type. |
61 | */ |
62 | #define JERRY_DEBUGGER_RECEIVE_BUFFER_AS(type, name_p) \ |
63 | type *name_p = ((type *) recv_buffer_p) |
64 | |
65 | /** |
66 | * Free all unreferenced byte code structures which |
67 | * were not acknowledged by the debugger client. |
68 | */ |
69 | void |
70 | jerry_debugger_free_unreferenced_byte_code (void) |
71 | { |
72 | jerry_debugger_byte_code_free_t *byte_code_free_p; |
73 | |
74 | byte_code_free_p = JMEM_CP_GET_POINTER (jerry_debugger_byte_code_free_t, |
75 | JERRY_CONTEXT (debugger_byte_code_free_tail)); |
76 | |
77 | while (byte_code_free_p != NULL) |
78 | { |
79 | jerry_debugger_byte_code_free_t *prev_byte_code_free_p; |
80 | prev_byte_code_free_p = JMEM_CP_GET_POINTER (jerry_debugger_byte_code_free_t, |
81 | byte_code_free_p->prev_cp); |
82 | |
83 | jmem_heap_free_block (byte_code_free_p, |
84 | ((size_t) byte_code_free_p->size) << JMEM_ALIGNMENT_LOG); |
85 | |
86 | byte_code_free_p = prev_byte_code_free_p; |
87 | } |
88 | } /* jerry_debugger_free_unreferenced_byte_code */ |
89 | |
90 | /** |
91 | * Send data over an active connection. |
92 | * |
93 | * @return true - if the data was sent successfully |
94 | * false - otherwise |
95 | */ |
96 | static bool |
97 | jerry_debugger_send (size_t message_length) /**< message length in bytes */ |
98 | { |
99 | JERRY_ASSERT (message_length <= JERRY_CONTEXT (debugger_max_send_size)); |
100 | |
101 | jerry_debugger_transport_header_t *header_p = JERRY_CONTEXT (debugger_transport_header_p); |
102 | uint8_t *payload_p = JERRY_CONTEXT (debugger_send_buffer_payload_p); |
103 | |
104 | return header_p->send (header_p, payload_p, message_length); |
105 | } /* jerry_debugger_send */ |
106 | |
107 | /** |
108 | * Send backtrace. |
109 | */ |
110 | static void |
111 | jerry_debugger_send_backtrace (const uint8_t *recv_buffer_p) /**< pointer to the received data */ |
112 | { |
113 | JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_get_backtrace_t, get_backtrace_p); |
114 | |
115 | uint32_t min_depth; |
116 | memcpy (&min_depth, get_backtrace_p->min_depth, sizeof (uint32_t)); |
117 | uint32_t max_depth; |
118 | memcpy (&max_depth, get_backtrace_p->max_depth, sizeof (uint32_t)); |
119 | |
120 | if (max_depth == 0) |
121 | { |
122 | max_depth = UINT32_MAX; |
123 | } |
124 | |
125 | if (get_backtrace_p->get_total_frame_count != 0) |
126 | { |
127 | JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_backtrace_total_t, backtrace_total_p); |
128 | backtrace_total_p->type = JERRY_DEBUGGER_BACKTRACE_TOTAL; |
129 | |
130 | vm_frame_ctx_t *iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p); |
131 | uint32_t frame_count = 0; |
132 | while (iter_frame_ctx_p != NULL) |
133 | { |
134 | if (!(iter_frame_ctx_p->shared_p->bytecode_header_p->status_flags & (CBC_CODE_FLAGS_STATIC_FUNCTION))) |
135 | { |
136 | frame_count++; |
137 | } |
138 | iter_frame_ctx_p = iter_frame_ctx_p->prev_context_p; |
139 | } |
140 | memcpy (backtrace_total_p->frame_count, &frame_count, sizeof (frame_count)); |
141 | |
142 | jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + sizeof (frame_count)); |
143 | } |
144 | |
145 | JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_backtrace_t, backtrace_p); |
146 | |
147 | backtrace_p->type = JERRY_DEBUGGER_BACKTRACE; |
148 | |
149 | vm_frame_ctx_t *frame_ctx_p = JERRY_CONTEXT (vm_top_context_p); |
150 | |
151 | size_t current_frame = 0; |
152 | const size_t max_frame_count = JERRY_DEBUGGER_SEND_MAX (jerry_debugger_frame_t); |
153 | const size_t max_message_size = JERRY_DEBUGGER_SEND_SIZE (max_frame_count, jerry_debugger_frame_t); |
154 | |
155 | if (min_depth <= max_depth) |
156 | { |
157 | uint32_t min_depth_offset = 0; |
158 | |
159 | while (frame_ctx_p != NULL && min_depth_offset < min_depth) |
160 | { |
161 | frame_ctx_p = frame_ctx_p->prev_context_p; |
162 | min_depth_offset++; |
163 | } |
164 | |
165 | while (frame_ctx_p != NULL && min_depth_offset++ < max_depth) |
166 | { |
167 | if (frame_ctx_p->shared_p->bytecode_header_p->status_flags |
168 | & (CBC_CODE_FLAGS_DEBUGGER_IGNORE | CBC_CODE_FLAGS_STATIC_FUNCTION)) |
169 | { |
170 | frame_ctx_p = frame_ctx_p->prev_context_p; |
171 | continue; |
172 | } |
173 | |
174 | if (current_frame >= max_frame_count) |
175 | { |
176 | if (!jerry_debugger_send (max_message_size)) |
177 | { |
178 | return; |
179 | } |
180 | current_frame = 0; |
181 | } |
182 | |
183 | jerry_debugger_frame_t *frame_p = backtrace_p->frames + current_frame; |
184 | |
185 | jmem_cpointer_t byte_code_cp; |
186 | JMEM_CP_SET_NON_NULL_POINTER (byte_code_cp, frame_ctx_p->shared_p->bytecode_header_p); |
187 | memcpy (frame_p->byte_code_cp, &byte_code_cp, sizeof (jmem_cpointer_t)); |
188 | |
189 | uint32_t offset = (uint32_t) (frame_ctx_p->byte_code_p - (uint8_t *) frame_ctx_p->shared_p->bytecode_header_p); |
190 | memcpy (frame_p->offset, &offset, sizeof (uint32_t)); |
191 | |
192 | frame_ctx_p = frame_ctx_p->prev_context_p; |
193 | current_frame++; |
194 | } |
195 | } |
196 | |
197 | size_t message_size = current_frame * sizeof (jerry_debugger_frame_t); |
198 | |
199 | backtrace_p->type = JERRY_DEBUGGER_BACKTRACE_END; |
200 | |
201 | jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + message_size); |
202 | } /* jerry_debugger_send_backtrace */ |
203 | |
204 | /** |
205 | * Send the scope chain types. |
206 | */ |
207 | static void |
208 | jerry_debugger_send_scope_chain (void) |
209 | { |
210 | vm_frame_ctx_t *iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p); |
211 | |
212 | const size_t max_byte_count = JERRY_DEBUGGER_SEND_MAX (uint8_t); |
213 | const size_t max_message_size = JERRY_DEBUGGER_SEND_SIZE (max_byte_count, uint8_t); |
214 | |
215 | JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t, message_type_p); |
216 | message_type_p->type = JERRY_DEBUGGER_SCOPE_CHAIN; |
217 | |
218 | size_t buffer_pos = 0; |
219 | bool next_func_is_local = true; |
220 | ecma_object_t *lex_env_p = iter_frame_ctx_p->lex_env_p; |
221 | |
222 | while (true) |
223 | { |
224 | JERRY_ASSERT (ecma_is_lexical_environment (lex_env_p)); |
225 | |
226 | if (buffer_pos == max_byte_count) |
227 | { |
228 | if (!jerry_debugger_send (max_message_size)) |
229 | { |
230 | return; |
231 | } |
232 | |
233 | buffer_pos = 0; |
234 | } |
235 | |
236 | if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) |
237 | { |
238 | if ((lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) != 0) |
239 | { |
240 | message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_NON_CLOSURE; |
241 | } |
242 | else if (next_func_is_local) |
243 | { |
244 | message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_LOCAL; |
245 | next_func_is_local = false; |
246 | } |
247 | else |
248 | { |
249 | message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_CLOSURE; |
250 | } |
251 | } |
252 | else if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND) |
253 | { |
254 | if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL) |
255 | { |
256 | message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_GLOBAL; |
257 | break; |
258 | } |
259 | else |
260 | { |
261 | message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_WITH; |
262 | } |
263 | } |
264 | |
265 | JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); |
266 | lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); |
267 | } |
268 | |
269 | message_type_p->type = JERRY_DEBUGGER_SCOPE_CHAIN_END; |
270 | |
271 | jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + buffer_pos); |
272 | } /* jerry_debugger_send_scope_chain */ |
273 | |
274 | /** |
275 | * Get type of the scope variable property. |
276 | * @return (jerry_debugger_scope_variable_type_t) |
277 | */ |
278 | static uint8_t |
279 | jerry_debugger_get_variable_type (ecma_value_t value) /**< input ecma value */ |
280 | { |
281 | uint8_t ret_value = JERRY_DEBUGGER_VALUE_NONE; |
282 | |
283 | if (ecma_is_value_undefined (value)) |
284 | { |
285 | ret_value = JERRY_DEBUGGER_VALUE_UNDEFINED; |
286 | } |
287 | else if (ecma_is_value_null (value)) |
288 | { |
289 | ret_value = JERRY_DEBUGGER_VALUE_NULL; |
290 | } |
291 | else if (ecma_is_value_boolean (value)) |
292 | { |
293 | ret_value = JERRY_DEBUGGER_VALUE_BOOLEAN; |
294 | } |
295 | else if (ecma_is_value_number (value)) |
296 | { |
297 | ret_value = JERRY_DEBUGGER_VALUE_NUMBER; |
298 | } |
299 | else if (ecma_is_value_string (value)) |
300 | { |
301 | ret_value = JERRY_DEBUGGER_VALUE_STRING; |
302 | } |
303 | else |
304 | { |
305 | JERRY_ASSERT (ecma_is_value_object (value)); |
306 | |
307 | if (ecma_get_object_type (ecma_get_object_from_value (value)) == ECMA_OBJECT_TYPE_ARRAY) |
308 | { |
309 | ret_value = JERRY_DEBUGGER_VALUE_ARRAY; |
310 | } |
311 | else |
312 | { |
313 | ret_value = ecma_op_is_callable (value) ? JERRY_DEBUGGER_VALUE_FUNCTION : JERRY_DEBUGGER_VALUE_OBJECT; |
314 | } |
315 | } |
316 | |
317 | JERRY_ASSERT (ret_value != JERRY_DEBUGGER_VALUE_NONE); |
318 | |
319 | return ret_value; |
320 | } /* jerry_debugger_get_variable_type */ |
321 | |
322 | /** |
323 | * Helper function for jerry_debugger_send_scope_variables. |
324 | * |
325 | * It will copies the given scope values type, length and value into the outgoing message string. |
326 | * |
327 | * @param variable_type type (jerry_debugger_scope_variable_type_t) |
328 | * @return true - if the copy was successfully |
329 | * false - otherwise |
330 | */ |
331 | static bool |
332 | jerry_debugger_copy_variables_to_string_message (uint8_t variable_type, /**< type */ |
333 | ecma_string_t *value_str, /**< property name or value string */ |
334 | jerry_debugger_send_string_t *message_string_p, /**< msg pointer */ |
335 | size_t *buffer_pos) /**< string data position of the message */ |
336 | { |
337 | const size_t max_byte_count = JERRY_DEBUGGER_SEND_MAX (uint8_t); |
338 | const size_t max_message_size = JERRY_DEBUGGER_SEND_SIZE (max_byte_count, uint8_t); |
339 | |
340 | ECMA_STRING_TO_UTF8_STRING (value_str, str_buff, str_buff_size); |
341 | |
342 | size_t str_size = 0; |
343 | size_t str_limit = 255; |
344 | bool result = true; |
345 | |
346 | bool type_processed = false; |
347 | |
348 | while (true) |
349 | { |
350 | if (*buffer_pos == max_byte_count) |
351 | { |
352 | if (!jerry_debugger_send (max_message_size)) |
353 | { |
354 | result = false; |
355 | break; |
356 | } |
357 | |
358 | *buffer_pos = 0; |
359 | } |
360 | |
361 | if (!type_processed) |
362 | { |
363 | if (variable_type != JERRY_DEBUGGER_VALUE_NONE) |
364 | { |
365 | message_string_p->string[*buffer_pos] = variable_type; |
366 | *buffer_pos += 1; |
367 | } |
368 | type_processed = true; |
369 | continue; |
370 | } |
371 | |
372 | if (variable_type == JERRY_DEBUGGER_VALUE_FUNCTION) |
373 | { |
374 | str_size = 0; // do not copy function values |
375 | } |
376 | else |
377 | { |
378 | str_size = (str_buff_size > str_limit) ? str_limit : str_buff_size; |
379 | } |
380 | |
381 | message_string_p->string[*buffer_pos] = (uint8_t) str_size; |
382 | *buffer_pos += 1; |
383 | break; |
384 | } |
385 | |
386 | if (result) |
387 | { |
388 | size_t free_bytes = max_byte_count - *buffer_pos; |
389 | const uint8_t *string_p = str_buff; |
390 | |
391 | while (str_size > free_bytes) |
392 | { |
393 | memcpy (message_string_p->string + *buffer_pos, string_p, free_bytes); |
394 | |
395 | if (!jerry_debugger_send (max_message_size)) |
396 | { |
397 | result = false; |
398 | break; |
399 | } |
400 | |
401 | string_p += free_bytes; |
402 | str_size -= free_bytes; |
403 | free_bytes = max_byte_count; |
404 | *buffer_pos = 0; |
405 | } |
406 | |
407 | if (result) |
408 | { |
409 | memcpy (message_string_p->string + *buffer_pos, string_p, str_size); |
410 | *buffer_pos += str_size; |
411 | } |
412 | } |
413 | |
414 | ECMA_FINALIZE_UTF8_STRING (str_buff, str_buff_size); |
415 | |
416 | return result; |
417 | } /* jerry_debugger_copy_variables_to_string_message */ |
418 | |
419 | /** |
420 | * Send variables of the given scope chain level. |
421 | */ |
422 | static void |
423 | jerry_debugger_send_scope_variables (const uint8_t *recv_buffer_p) /**< pointer to the received data */ |
424 | { |
425 | JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_get_scope_variables_t, get_scope_variables_p); |
426 | |
427 | uint32_t chain_index; |
428 | memcpy (&chain_index, get_scope_variables_p->chain_index, sizeof (uint32_t)); |
429 | |
430 | vm_frame_ctx_t *iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p); |
431 | ecma_object_t *lex_env_p = iter_frame_ctx_p->lex_env_p; |
432 | |
433 | while (chain_index != 0) |
434 | { |
435 | if (JERRY_UNLIKELY (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL)) |
436 | { |
437 | jerry_debugger_send_type (JERRY_DEBUGGER_SCOPE_VARIABLES_END); |
438 | return; |
439 | } |
440 | |
441 | lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); |
442 | |
443 | if ((ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND) |
444 | || (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)) |
445 | { |
446 | chain_index--; |
447 | } |
448 | } |
449 | |
450 | jmem_cpointer_t prop_iter_cp; |
451 | |
452 | if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) |
453 | { |
454 | prop_iter_cp = lex_env_p->u1.property_list_cp; |
455 | } |
456 | else |
457 | { |
458 | JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); |
459 | ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); |
460 | |
461 | if (JERRY_UNLIKELY (ecma_op_object_is_fast_array (binding_obj_p))) |
462 | { |
463 | ecma_fast_array_convert_to_normal (binding_obj_p); |
464 | } |
465 | |
466 | prop_iter_cp = binding_obj_p->u1.property_list_cp; |
467 | } |
468 | |
469 | JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t, message_string_p); |
470 | message_string_p->type = JERRY_DEBUGGER_SCOPE_VARIABLES; |
471 | |
472 | size_t buffer_pos = 0; |
473 | |
474 | while (prop_iter_cp != JMEM_CP_NULL) |
475 | { |
476 | ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); |
477 | JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); |
478 | |
479 | ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; |
480 | |
481 | for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) |
482 | { |
483 | if (ECMA_PROPERTY_IS_NAMED_PROPERTY (prop_iter_p->types[i])) |
484 | { |
485 | if (ECMA_PROPERTY_GET_NAME_TYPE (prop_iter_p->types[i]) == ECMA_DIRECT_STRING_MAGIC |
486 | && prop_pair_p->names_cp[i] >= LIT_NON_INTERNAL_MAGIC_STRING__COUNT) |
487 | { |
488 | continue; |
489 | } |
490 | |
491 | ecma_string_t *prop_name = ecma_string_from_property_name (prop_iter_p->types[i], |
492 | prop_pair_p->names_cp[i]); |
493 | |
494 | if (!jerry_debugger_copy_variables_to_string_message (JERRY_DEBUGGER_VALUE_NONE, |
495 | prop_name, |
496 | message_string_p, |
497 | &buffer_pos)) |
498 | { |
499 | ecma_deref_ecma_string (prop_name); |
500 | return; |
501 | } |
502 | |
503 | ecma_deref_ecma_string (prop_name); |
504 | |
505 | ecma_property_value_t prop_value_p = prop_pair_p->values[i]; |
506 | |
507 | uint8_t variable_type = jerry_debugger_get_variable_type (prop_value_p.value); |
508 | |
509 | ecma_string_t *str_p = ecma_op_to_string (prop_value_p.value); |
510 | JERRY_ASSERT (str_p != NULL); |
511 | |
512 | if (!jerry_debugger_copy_variables_to_string_message (variable_type, |
513 | str_p, |
514 | message_string_p, |
515 | &buffer_pos)) |
516 | { |
517 | ecma_deref_ecma_string (str_p); |
518 | return; |
519 | } |
520 | |
521 | ecma_deref_ecma_string (str_p); |
522 | } |
523 | } |
524 | |
525 | prop_iter_cp = prop_iter_p->next_property_cp; |
526 | } |
527 | |
528 | message_string_p->type = JERRY_DEBUGGER_SCOPE_VARIABLES_END; |
529 | jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + buffer_pos); |
530 | } /* jerry_debugger_send_scope_variables */ |
531 | |
532 | /** |
533 | * Send result of evaluated expression or throw an error. |
534 | * |
535 | * @return true - if execution should be resumed |
536 | * false - otherwise |
537 | */ |
538 | static bool |
539 | jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated string */ |
540 | size_t eval_string_size) /**< evaluated string size */ |
541 | { |
542 | JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); |
543 | JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE)); |
544 | |
545 | JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_IGNORE); |
546 | |
547 | uint32_t chain_index; |
548 | memcpy (&chain_index, eval_string_p, sizeof (uint32_t)); |
549 | uint32_t parse_opts = ECMA_PARSE_DIRECT_EVAL | (chain_index << ECMA_PARSE_CHAIN_INDEX_SHIFT); |
550 | |
551 | ecma_value_t result = ecma_op_eval_chars_buffer (eval_string_p + 5, eval_string_size - 5, parse_opts); |
552 | JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE); |
553 | |
554 | if (!ECMA_IS_VALUE_ERROR (result)) |
555 | { |
556 | if (eval_string_p[4] != JERRY_DEBUGGER_EVAL_EVAL) |
557 | { |
558 | JERRY_ASSERT (eval_string_p[4] == JERRY_DEBUGGER_EVAL_THROW || eval_string_p[4] == JERRY_DEBUGGER_EVAL_ABORT); |
559 | JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); |
560 | |
561 | /* Stop where the error is caught. */ |
562 | JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); |
563 | JERRY_CONTEXT (debugger_stop_context) = NULL; |
564 | |
565 | jcontext_raise_exception (result); |
566 | jcontext_set_abort_flag (eval_string_p[4] == JERRY_DEBUGGER_EVAL_ABORT); |
567 | |
568 | return true; |
569 | } |
570 | |
571 | if (!ecma_is_value_string (result)) |
572 | { |
573 | ecma_string_t *str_p = ecma_op_to_string (result); |
574 | ecma_value_t to_string_value = ecma_make_string_value (str_p); |
575 | ecma_free_value (result); |
576 | result = to_string_value; |
577 | } |
578 | } |
579 | |
580 | ecma_value_t message = result; |
581 | uint8_t type = JERRY_DEBUGGER_EVAL_OK; |
582 | |
583 | if (ECMA_IS_VALUE_ERROR (result)) |
584 | { |
585 | type = JERRY_DEBUGGER_EVAL_ERROR; |
586 | result = JERRY_CONTEXT (error_value); |
587 | |
588 | if (ecma_is_value_object (result)) |
589 | { |
590 | message = ecma_op_object_find (ecma_get_object_from_value (result), |
591 | ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE)); |
592 | |
593 | if (!ecma_is_value_string (message) |
594 | || ecma_string_is_empty (ecma_get_string_from_value (message))) |
595 | { |
596 | ecma_free_value (message); |
597 | lit_magic_string_id_t id = ecma_object_get_class_name (ecma_get_object_from_value (result)); |
598 | ecma_free_value (result); |
599 | |
600 | const lit_utf8_byte_t *string_p = lit_get_magic_string_utf8 (id); |
601 | jerry_debugger_send_string (JERRY_DEBUGGER_EVAL_RESULT, |
602 | type, |
603 | string_p, |
604 | strlen ((const char *) string_p)); |
605 | return false; |
606 | } |
607 | } |
608 | else |
609 | { |
610 | /* Primitive type. */ |
611 | ecma_string_t *str_p = ecma_op_to_string (result); |
612 | JERRY_ASSERT (str_p != NULL); |
613 | |
614 | message = ecma_make_string_value (str_p); |
615 | } |
616 | |
617 | ecma_free_value (result); |
618 | } |
619 | |
620 | ecma_string_t *string_p = ecma_get_string_from_value (message); |
621 | |
622 | ECMA_STRING_TO_UTF8_STRING (string_p, buffer_p, buffer_size); |
623 | jerry_debugger_send_string (JERRY_DEBUGGER_EVAL_RESULT, type, buffer_p, buffer_size); |
624 | ECMA_FINALIZE_UTF8_STRING (buffer_p, buffer_size); |
625 | |
626 | ecma_free_value (message); |
627 | |
628 | return false; |
629 | } /* jerry_debugger_send_eval */ |
630 | |
631 | /** |
632 | * Check received packet size. |
633 | */ |
634 | #define JERRY_DEBUGGER_CHECK_PACKET_SIZE(type) \ |
635 | if (message_size != sizeof (type)) \ |
636 | { \ |
637 | JERRY_ERROR_MSG ("Invalid message size\n"); \ |
638 | jerry_debugger_transport_close (); \ |
639 | return false; \ |
640 | } |
641 | |
642 | /** |
643 | * Receive message from the client. |
644 | * |
645 | * @return true - if message is processed successfully |
646 | * false - otherwise |
647 | */ |
648 | static inline bool JERRY_ATTR_ALWAYS_INLINE |
649 | jerry_debugger_process_message (const uint8_t *recv_buffer_p, /**< pointer to the received data */ |
650 | uint32_t message_size, /**< message size */ |
651 | bool *resume_exec_p, /**< pointer to the resume exec flag */ |
652 | uint8_t *expected_message_type_p, /**< message type */ |
653 | jerry_debugger_uint8_data_t **message_data_p) /**< custom message data */ |
654 | { |
655 | /* Process the received message. */ |
656 | |
657 | if (recv_buffer_p[0] >= JERRY_DEBUGGER_CONTINUE |
658 | && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE)) |
659 | { |
660 | JERRY_ERROR_MSG ("Message requires breakpoint mode\n" ); |
661 | jerry_debugger_transport_close (); |
662 | return false; |
663 | } |
664 | |
665 | if (*expected_message_type_p != 0) |
666 | { |
667 | JERRY_ASSERT (*expected_message_type_p == JERRY_DEBUGGER_EVAL_PART |
668 | || *expected_message_type_p == JERRY_DEBUGGER_CLIENT_SOURCE_PART); |
669 | |
670 | jerry_debugger_uint8_data_t *uint8_data_p = (jerry_debugger_uint8_data_t *) *message_data_p; |
671 | |
672 | if (recv_buffer_p[0] != *expected_message_type_p) |
673 | { |
674 | jmem_heap_free_block (uint8_data_p, uint8_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t)); |
675 | JERRY_ERROR_MSG ("Unexpected message\n" ); |
676 | jerry_debugger_transport_close (); |
677 | return false; |
678 | } |
679 | |
680 | JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_uint8_data_part_t, uint8_data_part_p); |
681 | |
682 | if (message_size < sizeof (jerry_debugger_receive_uint8_data_part_t) + 1) |
683 | { |
684 | jmem_heap_free_block (uint8_data_p, uint8_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t)); |
685 | JERRY_ERROR_MSG ("Invalid message size\n" ); |
686 | jerry_debugger_transport_close (); |
687 | return false; |
688 | } |
689 | |
690 | uint32_t expected_data = uint8_data_p->uint8_size - uint8_data_p->uint8_offset; |
691 | |
692 | message_size -= (uint32_t) sizeof (jerry_debugger_receive_uint8_data_part_t); |
693 | |
694 | if (message_size > expected_data) |
695 | { |
696 | jmem_heap_free_block (uint8_data_p, uint8_data_p->uint8_size + sizeof (jerry_debugger_uint8_data_t)); |
697 | JERRY_ERROR_MSG ("Invalid message size\n" ); |
698 | jerry_debugger_transport_close (); |
699 | return false; |
700 | } |
701 | |
702 | lit_utf8_byte_t *string_p = (lit_utf8_byte_t *) (uint8_data_p + 1); |
703 | memcpy (string_p + uint8_data_p->uint8_offset, |
704 | (lit_utf8_byte_t *) (uint8_data_part_p + 1), |
705 | message_size); |
706 | |
707 | if (message_size < expected_data) |
708 | { |
709 | uint8_data_p->uint8_offset += message_size; |
710 | return true; |
711 | } |
712 | |
713 | bool result; |
714 | |
715 | if (*expected_message_type_p == JERRY_DEBUGGER_EVAL_PART) |
716 | { |
717 | if (jerry_debugger_send_eval (string_p, uint8_data_p->uint8_size)) |
718 | { |
719 | *resume_exec_p = true; |
720 | } |
721 | result = (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) != 0; |
722 | } |
723 | else |
724 | { |
725 | result = true; |
726 | JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_CLIENT_SOURCE_MODE); |
727 | *resume_exec_p = true; |
728 | } |
729 | |
730 | *expected_message_type_p = 0; |
731 | return result; |
732 | } |
733 | |
734 | switch (recv_buffer_p[0]) |
735 | { |
736 | case JERRY_DEBUGGER_FREE_BYTE_CODE_CP: |
737 | { |
738 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_byte_code_cp_t); |
739 | |
740 | JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_byte_code_cp_t, byte_code_p); |
741 | |
742 | jmem_cpointer_t byte_code_free_cp; |
743 | memcpy (&byte_code_free_cp, byte_code_p->byte_code_cp, sizeof (jmem_cpointer_t)); |
744 | |
745 | if (byte_code_free_cp != JERRY_CONTEXT (debugger_byte_code_free_tail)) |
746 | { |
747 | JERRY_ERROR_MSG ("Invalid byte code free order\n" ); |
748 | jerry_debugger_transport_close (); |
749 | return false; |
750 | } |
751 | |
752 | jerry_debugger_byte_code_free_t *byte_code_free_p; |
753 | byte_code_free_p = JMEM_CP_GET_NON_NULL_POINTER (jerry_debugger_byte_code_free_t, |
754 | byte_code_free_cp); |
755 | |
756 | if (byte_code_free_p->prev_cp != ECMA_NULL_POINTER) |
757 | { |
758 | JERRY_CONTEXT (debugger_byte_code_free_tail) = byte_code_free_p->prev_cp; |
759 | } |
760 | else |
761 | { |
762 | JERRY_CONTEXT (debugger_byte_code_free_head) = ECMA_NULL_POINTER; |
763 | JERRY_CONTEXT (debugger_byte_code_free_tail) = ECMA_NULL_POINTER; |
764 | } |
765 | |
766 | #if ENABLED (JERRY_MEM_STATS) |
767 | jmem_stats_free_byte_code_bytes (((size_t) byte_code_free_p->size) << JMEM_ALIGNMENT_LOG); |
768 | #endif /* ENABLED (JERRY_MEM_STATS) */ |
769 | |
770 | jmem_heap_free_block (byte_code_free_p, |
771 | ((size_t) byte_code_free_p->size) << JMEM_ALIGNMENT_LOG); |
772 | return true; |
773 | } |
774 | |
775 | case JERRY_DEBUGGER_UPDATE_BREAKPOINT: |
776 | { |
777 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_update_breakpoint_t); |
778 | |
779 | JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_update_breakpoint_t, update_breakpoint_p); |
780 | |
781 | jmem_cpointer_t byte_code_cp; |
782 | memcpy (&byte_code_cp, update_breakpoint_p->byte_code_cp, sizeof (jmem_cpointer_t)); |
783 | uint8_t *byte_code_p = JMEM_CP_GET_NON_NULL_POINTER (uint8_t, byte_code_cp); |
784 | |
785 | uint32_t offset; |
786 | memcpy (&offset, update_breakpoint_p->offset, sizeof (uint32_t)); |
787 | byte_code_p += offset; |
788 | |
789 | JERRY_ASSERT (*byte_code_p == CBC_BREAKPOINT_ENABLED || *byte_code_p == CBC_BREAKPOINT_DISABLED); |
790 | |
791 | *byte_code_p = update_breakpoint_p->is_set_breakpoint ? CBC_BREAKPOINT_ENABLED : CBC_BREAKPOINT_DISABLED; |
792 | return true; |
793 | } |
794 | |
795 | case JERRY_DEBUGGER_MEMSTATS: |
796 | { |
797 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); |
798 | |
799 | jerry_debugger_send_memstats (); |
800 | return true; |
801 | } |
802 | |
803 | case JERRY_DEBUGGER_STOP: |
804 | { |
805 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); |
806 | |
807 | JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); |
808 | JERRY_CONTEXT (debugger_stop_context) = NULL; |
809 | *resume_exec_p = false; |
810 | return true; |
811 | } |
812 | |
813 | case JERRY_DEBUGGER_CONTINUE: |
814 | { |
815 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); |
816 | |
817 | JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_STOP); |
818 | JERRY_CONTEXT (debugger_stop_context) = NULL; |
819 | *resume_exec_p = true; |
820 | return true; |
821 | } |
822 | |
823 | case JERRY_DEBUGGER_STEP: |
824 | { |
825 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); |
826 | |
827 | JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); |
828 | JERRY_CONTEXT (debugger_stop_context) = NULL; |
829 | *resume_exec_p = true; |
830 | return true; |
831 | } |
832 | |
833 | case JERRY_DEBUGGER_NEXT: |
834 | { |
835 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); |
836 | |
837 | JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); |
838 | JERRY_CONTEXT (debugger_stop_context) = JERRY_CONTEXT (vm_top_context_p); |
839 | *resume_exec_p = true; |
840 | return true; |
841 | } |
842 | |
843 | case JERRY_DEBUGGER_FINISH: |
844 | { |
845 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); |
846 | |
847 | JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); |
848 | |
849 | /* This will point to the current context's parent (where the function was called) |
850 | * and in case of NULL the result will the same as in case of STEP. */ |
851 | JERRY_CONTEXT (debugger_stop_context) = JERRY_CONTEXT (vm_top_context_p->prev_context_p); |
852 | *resume_exec_p = true; |
853 | return true; |
854 | } |
855 | |
856 | case JERRY_DEBUGGER_GET_BACKTRACE: |
857 | { |
858 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_get_backtrace_t); |
859 | |
860 | jerry_debugger_send_backtrace (recv_buffer_p); |
861 | return true; |
862 | } |
863 | |
864 | case JERRY_DEBUGGER_GET_SCOPE_CHAIN: |
865 | { |
866 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); |
867 | |
868 | jerry_debugger_send_scope_chain (); |
869 | |
870 | return true; |
871 | } |
872 | |
873 | case JERRY_DEBUGGER_GET_SCOPE_VARIABLES: |
874 | { |
875 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_get_scope_variables_t); |
876 | |
877 | jerry_debugger_send_scope_variables (recv_buffer_p); |
878 | |
879 | return true; |
880 | } |
881 | |
882 | case JERRY_DEBUGGER_EXCEPTION_CONFIG: |
883 | { |
884 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_exception_config_t); |
885 | JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_exception_config_t, exception_config_p); |
886 | |
887 | if (exception_config_p->enable == 0) |
888 | { |
889 | JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION); |
890 | JERRY_DEBUG_MSG ("Stop at exception disabled\n" ); |
891 | } |
892 | else |
893 | { |
894 | JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION); |
895 | JERRY_DEBUG_MSG ("Stop at exception enabled\n" ); |
896 | } |
897 | |
898 | return true; |
899 | } |
900 | |
901 | case JERRY_DEBUGGER_PARSER_CONFIG: |
902 | { |
903 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_parser_config_t); |
904 | JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_parser_config_t, parser_config_p); |
905 | |
906 | if (parser_config_p->enable_wait != 0) |
907 | { |
908 | JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_PARSER_WAIT); |
909 | JERRY_DEBUG_MSG ("Waiting after parsing enabled\n" ); |
910 | } |
911 | else |
912 | { |
913 | JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_PARSER_WAIT); |
914 | JERRY_DEBUG_MSG ("Waiting after parsing disabled\n" ); |
915 | } |
916 | |
917 | return true; |
918 | } |
919 | |
920 | case JERRY_DEBUGGER_PARSER_RESUME: |
921 | { |
922 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); |
923 | |
924 | if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_PARSER_WAIT_MODE)) |
925 | { |
926 | JERRY_ERROR_MSG ("Not in parser wait mode\n" ); |
927 | jerry_debugger_transport_close (); |
928 | return false; |
929 | } |
930 | |
931 | JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_PARSER_WAIT_MODE); |
932 | return true; |
933 | } |
934 | |
935 | case JERRY_DEBUGGER_EVAL: |
936 | { |
937 | if (message_size < sizeof (jerry_debugger_receive_eval_first_t) + 5) |
938 | { |
939 | JERRY_ERROR_MSG ("Invalid message size\n" ); |
940 | jerry_debugger_transport_close (); |
941 | return false; |
942 | } |
943 | |
944 | JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_eval_first_t, eval_first_p); |
945 | |
946 | uint32_t eval_size; |
947 | memcpy (&eval_size, eval_first_p->eval_size, sizeof (uint32_t)); |
948 | |
949 | if (eval_size <= JERRY_CONTEXT (debugger_max_receive_size) - sizeof (jerry_debugger_receive_eval_first_t)) |
950 | { |
951 | if (eval_size != message_size - sizeof (jerry_debugger_receive_eval_first_t)) |
952 | { |
953 | JERRY_ERROR_MSG ("Invalid message size\n" ); |
954 | jerry_debugger_transport_close (); |
955 | return false; |
956 | } |
957 | |
958 | if (jerry_debugger_send_eval ((lit_utf8_byte_t *) (eval_first_p + 1), eval_size)) |
959 | { |
960 | *resume_exec_p = true; |
961 | } |
962 | |
963 | return (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) != 0; |
964 | } |
965 | |
966 | jerry_debugger_uint8_data_t *eval_uint8_data_p; |
967 | size_t eval_data_size = sizeof (jerry_debugger_uint8_data_t) + eval_size; |
968 | |
969 | eval_uint8_data_p = (jerry_debugger_uint8_data_t *) jmem_heap_alloc_block (eval_data_size); |
970 | |
971 | eval_uint8_data_p->uint8_size = eval_size; |
972 | eval_uint8_data_p->uint8_offset = (uint32_t) (message_size - sizeof (jerry_debugger_receive_eval_first_t)); |
973 | |
974 | lit_utf8_byte_t *eval_string_p = (lit_utf8_byte_t *) (eval_uint8_data_p + 1); |
975 | memcpy (eval_string_p, |
976 | (lit_utf8_byte_t *) (eval_first_p + 1), |
977 | message_size - sizeof (jerry_debugger_receive_eval_first_t)); |
978 | |
979 | *message_data_p = eval_uint8_data_p; |
980 | *expected_message_type_p = JERRY_DEBUGGER_EVAL_PART; |
981 | |
982 | return true; |
983 | } |
984 | |
985 | case JERRY_DEBUGGER_CLIENT_SOURCE: |
986 | { |
987 | if (message_size <= sizeof (jerry_debugger_receive_client_source_first_t)) |
988 | { |
989 | JERRY_ERROR_MSG ("Invalid message size\n" ); |
990 | jerry_debugger_transport_close (); |
991 | return false; |
992 | } |
993 | |
994 | if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE)) |
995 | { |
996 | JERRY_ERROR_MSG ("Not in client source mode\n" ); |
997 | jerry_debugger_transport_close (); |
998 | return false; |
999 | } |
1000 | |
1001 | JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_client_source_first_t, client_source_first_p); |
1002 | |
1003 | uint32_t client_source_size; |
1004 | memcpy (&client_source_size, client_source_first_p->code_size, sizeof (uint32_t)); |
1005 | |
1006 | uint32_t header_size = sizeof (jerry_debugger_receive_client_source_first_t); |
1007 | |
1008 | if (client_source_size <= JERRY_CONTEXT (debugger_max_receive_size) - header_size |
1009 | && client_source_size != message_size - header_size) |
1010 | { |
1011 | JERRY_ERROR_MSG ("Invalid message size\n" ); |
1012 | jerry_debugger_transport_close (); |
1013 | return false; |
1014 | } |
1015 | |
1016 | jerry_debugger_uint8_data_t *client_source_data_p; |
1017 | size_t client_source_data_size = sizeof (jerry_debugger_uint8_data_t) + client_source_size; |
1018 | |
1019 | client_source_data_p = (jerry_debugger_uint8_data_t *) jmem_heap_alloc_block (client_source_data_size); |
1020 | |
1021 | client_source_data_p->uint8_size = client_source_size; |
1022 | client_source_data_p->uint8_offset = (uint32_t) (message_size |
1023 | - sizeof (jerry_debugger_receive_client_source_first_t)); |
1024 | |
1025 | lit_utf8_byte_t *client_source_string_p = (lit_utf8_byte_t *) (client_source_data_p + 1); |
1026 | memcpy (client_source_string_p, |
1027 | (lit_utf8_byte_t *) (client_source_first_p + 1), |
1028 | message_size - sizeof (jerry_debugger_receive_client_source_first_t)); |
1029 | |
1030 | *message_data_p = client_source_data_p; |
1031 | |
1032 | if (client_source_data_p->uint8_size != client_source_data_p->uint8_offset) |
1033 | { |
1034 | *expected_message_type_p = JERRY_DEBUGGER_CLIENT_SOURCE_PART; |
1035 | } |
1036 | else |
1037 | { |
1038 | JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_CLIENT_SOURCE_MODE); |
1039 | *resume_exec_p = true; |
1040 | } |
1041 | return true; |
1042 | } |
1043 | |
1044 | case JERRY_DEBUGGER_NO_MORE_SOURCES: |
1045 | { |
1046 | if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE)) |
1047 | { |
1048 | JERRY_ERROR_MSG ("Not in client source mode\n" ); |
1049 | jerry_debugger_transport_close (); |
1050 | return false; |
1051 | } |
1052 | |
1053 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); |
1054 | |
1055 | JERRY_DEBUGGER_UPDATE_FLAGS (JERRY_DEBUGGER_CLIENT_NO_SOURCE, JERRY_DEBUGGER_CLIENT_SOURCE_MODE); |
1056 | |
1057 | *resume_exec_p = true; |
1058 | |
1059 | return true; |
1060 | } |
1061 | |
1062 | case JERRY_DEBUGGER_CONTEXT_RESET: |
1063 | { |
1064 | if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_SOURCE_MODE)) |
1065 | { |
1066 | JERRY_ERROR_MSG ("Not in client source mode\n" ); |
1067 | jerry_debugger_transport_close (); |
1068 | return false; |
1069 | } |
1070 | |
1071 | JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); |
1072 | |
1073 | JERRY_DEBUGGER_UPDATE_FLAGS (JERRY_DEBUGGER_CONTEXT_RESET_MODE, JERRY_DEBUGGER_CLIENT_SOURCE_MODE); |
1074 | |
1075 | *resume_exec_p = true; |
1076 | |
1077 | return true; |
1078 | } |
1079 | |
1080 | default: |
1081 | { |
1082 | JERRY_ERROR_MSG ("Unexpected message." ); |
1083 | jerry_debugger_transport_close (); |
1084 | return false; |
1085 | } |
1086 | } |
1087 | } /* jerry_debugger_process_message */ |
1088 | |
1089 | /** |
1090 | * Receive message from the client. |
1091 | * |
1092 | * Note: |
1093 | * If the function returns with true, the value of |
1094 | * JERRY_DEBUGGER_VM_STOP flag should be ignored. |
1095 | * |
1096 | * @return true - if execution should be resumed, |
1097 | * false - otherwise |
1098 | */ |
1099 | bool |
1100 | jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p) /**< [out] data received from client */ |
1101 | { |
1102 | JERRY_ASSERT (jerry_debugger_transport_is_connected ()); |
1103 | |
1104 | JERRY_ASSERT (message_data_p != NULL ? !!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE) |
1105 | : !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE)); |
1106 | |
1107 | JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY; |
1108 | |
1109 | bool resume_exec = false; |
1110 | uint8_t expected_message_type = 0; |
1111 | |
1112 | while (true) |
1113 | { |
1114 | jerry_debugger_transport_receive_context_t context; |
1115 | if (!jerry_debugger_transport_receive (&context)) |
1116 | { |
1117 | JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)); |
1118 | return true; |
1119 | } |
1120 | |
1121 | if (context.message_p == NULL) |
1122 | { |
1123 | JERRY_CONTEXT (debugger_received_length) = (uint16_t) context.received_length; |
1124 | |
1125 | if (expected_message_type != 0) |
1126 | { |
1127 | jerry_debugger_transport_sleep (); |
1128 | continue; |
1129 | } |
1130 | |
1131 | return resume_exec; |
1132 | } |
1133 | |
1134 | /* Only datagram packets are supported. */ |
1135 | JERRY_ASSERT (context.message_total_length > 0); |
1136 | |
1137 | /* The jerry_debugger_process_message function is inlined |
1138 | * so passing these arguments is essentially free. */ |
1139 | if (!jerry_debugger_process_message (context.message_p, |
1140 | (uint32_t) context.message_length, |
1141 | &resume_exec, |
1142 | &expected_message_type, |
1143 | message_data_p)) |
1144 | { |
1145 | JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)); |
1146 | return true; |
1147 | } |
1148 | |
1149 | jerry_debugger_transport_receive_completed (&context); |
1150 | } |
1151 | } /* jerry_debugger_receive */ |
1152 | |
1153 | #undef JERRY_DEBUGGER_CHECK_PACKET_SIZE |
1154 | |
1155 | /** |
1156 | * Tell the client that a breakpoint has been hit and wait for further debugger commands. |
1157 | */ |
1158 | void |
1159 | jerry_debugger_breakpoint_hit (uint8_t message_type) /**< message type */ |
1160 | { |
1161 | JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); |
1162 | |
1163 | JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_breakpoint_hit_t, breakpoint_hit_p); |
1164 | |
1165 | breakpoint_hit_p->type = message_type; |
1166 | |
1167 | vm_frame_ctx_t *frame_ctx_p = JERRY_CONTEXT (vm_top_context_p); |
1168 | |
1169 | jmem_cpointer_t byte_code_header_cp; |
1170 | JMEM_CP_SET_NON_NULL_POINTER (byte_code_header_cp, frame_ctx_p->shared_p->bytecode_header_p); |
1171 | memcpy (breakpoint_hit_p->byte_code_cp, &byte_code_header_cp, sizeof (jmem_cpointer_t)); |
1172 | |
1173 | uint32_t offset = (uint32_t) (frame_ctx_p->byte_code_p - (uint8_t *) frame_ctx_p->shared_p->bytecode_header_p); |
1174 | memcpy (breakpoint_hit_p->offset, &offset, sizeof (uint32_t)); |
1175 | |
1176 | if (!jerry_debugger_send (sizeof (jerry_debugger_send_breakpoint_hit_t))) |
1177 | { |
1178 | return; |
1179 | } |
1180 | |
1181 | JERRY_DEBUGGER_UPDATE_FLAGS (JERRY_DEBUGGER_BREAKPOINT_MODE, JERRY_DEBUGGER_VM_EXCEPTION_THROWN); |
1182 | |
1183 | jerry_debugger_uint8_data_t *uint8_data = NULL; |
1184 | |
1185 | while (!jerry_debugger_receive (&uint8_data)) |
1186 | { |
1187 | jerry_debugger_transport_sleep (); |
1188 | } |
1189 | |
1190 | if (uint8_data != NULL) |
1191 | { |
1192 | jmem_heap_free_block (uint8_data, |
1193 | uint8_data->uint8_size + sizeof (jerry_debugger_uint8_data_t)); |
1194 | } |
1195 | |
1196 | JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_BREAKPOINT_MODE); |
1197 | |
1198 | JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY; |
1199 | } /* jerry_debugger_breakpoint_hit */ |
1200 | |
1201 | /** |
1202 | * Send the type signal to the client. |
1203 | */ |
1204 | void |
1205 | jerry_debugger_send_type (jerry_debugger_header_type_t type) /**< message type */ |
1206 | { |
1207 | JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); |
1208 | |
1209 | JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_type_t, message_type_p); |
1210 | |
1211 | message_type_p->type = (uint8_t) type; |
1212 | |
1213 | jerry_debugger_send (sizeof (jerry_debugger_send_type_t)); |
1214 | } /* jerry_debugger_send_type */ |
1215 | |
1216 | /** |
1217 | * Send the type signal to the client. |
1218 | * |
1219 | * @return true - if the data sent successfully to the debugger client, |
1220 | * false - otherwise |
1221 | */ |
1222 | bool |
1223 | jerry_debugger_send_configuration (uint8_t max_message_size) /**< maximum message size */ |
1224 | { |
1225 | JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_configuration_t, configuration_p); |
1226 | |
1227 | /* Helper structure for endianness check. */ |
1228 | union |
1229 | { |
1230 | uint16_t uint16_value; /**< a 16-bit value */ |
1231 | uint8_t uint8_value[2]; /**< lower and upper byte of a 16-bit value */ |
1232 | } endian_data; |
1233 | |
1234 | endian_data.uint16_value = 1; |
1235 | |
1236 | configuration_p->type = JERRY_DEBUGGER_CONFIGURATION; |
1237 | configuration_p->configuration = 0; |
1238 | |
1239 | if (endian_data.uint8_value[0] == 1) |
1240 | { |
1241 | configuration_p->configuration |= (uint8_t) JERRY_DEBUGGER_LITTLE_ENDIAN; |
1242 | } |
1243 | |
1244 | uint32_t version = JERRY_DEBUGGER_VERSION; |
1245 | memcpy (configuration_p->version, &version, sizeof (uint32_t)); |
1246 | |
1247 | configuration_p->max_message_size = max_message_size; |
1248 | configuration_p->cpointer_size = sizeof (jmem_cpointer_t); |
1249 | |
1250 | return jerry_debugger_send (sizeof (jerry_debugger_send_configuration_t)); |
1251 | } /* jerry_debugger_send_configuration */ |
1252 | |
1253 | /** |
1254 | * Send raw data to the debugger client. |
1255 | */ |
1256 | void |
1257 | jerry_debugger_send_data (jerry_debugger_header_type_t type, /**< message type */ |
1258 | const void *data, /**< raw data */ |
1259 | size_t size) /**< size of data */ |
1260 | { |
1261 | JERRY_ASSERT (size <= JERRY_DEBUGGER_SEND_MAX (uint8_t)); |
1262 | |
1263 | JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_type_t, message_type_p); |
1264 | |
1265 | message_type_p->type = (uint8_t) type; |
1266 | memcpy (message_type_p + 1, data, size); |
1267 | |
1268 | jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + size); |
1269 | } /* jerry_debugger_send_data */ |
1270 | |
1271 | /** |
1272 | * Send string to the debugger client. |
1273 | * |
1274 | * @return true - if the data sent successfully to the debugger client, |
1275 | * false - otherwise |
1276 | */ |
1277 | bool |
1278 | jerry_debugger_send_string (uint8_t message_type, /**< message type */ |
1279 | uint8_t sub_type, /**< subtype of the string */ |
1280 | const uint8_t *string_p, /**< string data */ |
1281 | size_t string_length) /**< length of string */ |
1282 | { |
1283 | JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); |
1284 | |
1285 | const size_t max_byte_count = JERRY_DEBUGGER_SEND_MAX (uint8_t); |
1286 | const size_t max_message_size = JERRY_DEBUGGER_SEND_SIZE (max_byte_count, uint8_t); |
1287 | |
1288 | JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t, message_string_p); |
1289 | |
1290 | message_string_p->type = message_type; |
1291 | |
1292 | if (sub_type != JERRY_DEBUGGER_NO_SUBTYPE) |
1293 | { |
1294 | string_length += 1; |
1295 | } |
1296 | |
1297 | while (string_length > max_byte_count) |
1298 | { |
1299 | memcpy (message_string_p->string, string_p, max_byte_count); |
1300 | |
1301 | if (!jerry_debugger_send (max_message_size)) |
1302 | { |
1303 | return false; |
1304 | } |
1305 | |
1306 | string_length -= max_byte_count; |
1307 | string_p += max_byte_count; |
1308 | } |
1309 | |
1310 | message_string_p->type = (uint8_t) (message_type + 1); |
1311 | |
1312 | if (sub_type != JERRY_DEBUGGER_NO_SUBTYPE) |
1313 | { |
1314 | memcpy (message_string_p->string, string_p, string_length - 1); |
1315 | message_string_p->string[string_length - 1] = sub_type; |
1316 | } |
1317 | else |
1318 | { |
1319 | memcpy (message_string_p->string, string_p, string_length); |
1320 | } |
1321 | |
1322 | return jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + string_length); |
1323 | } /* jerry_debugger_send_string */ |
1324 | |
1325 | /** |
1326 | * Send the function compressed pointer to the debugger client. |
1327 | * |
1328 | * @return true - if the data was sent successfully to the debugger client, |
1329 | * false - otherwise |
1330 | */ |
1331 | bool |
1332 | jerry_debugger_send_function_cp (jerry_debugger_header_type_t type, /**< message type */ |
1333 | ecma_compiled_code_t *compiled_code_p) /**< byte code pointer */ |
1334 | { |
1335 | JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); |
1336 | |
1337 | JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_byte_code_cp_t, byte_code_cp_p); |
1338 | |
1339 | byte_code_cp_p->type = (uint8_t) type; |
1340 | |
1341 | jmem_cpointer_t compiled_code_cp; |
1342 | JMEM_CP_SET_NON_NULL_POINTER (compiled_code_cp, compiled_code_p); |
1343 | memcpy (byte_code_cp_p->byte_code_cp, &compiled_code_cp, sizeof (jmem_cpointer_t)); |
1344 | |
1345 | return jerry_debugger_send (sizeof (jerry_debugger_send_byte_code_cp_t)); |
1346 | } /* jerry_debugger_send_function_cp */ |
1347 | |
1348 | /** |
1349 | * Send function data to the debugger client. |
1350 | * |
1351 | * @return true - if the data sent successfully to the debugger client, |
1352 | * false - otherwise |
1353 | */ |
1354 | bool |
1355 | jerry_debugger_send_parse_function (uint32_t line, /**< line */ |
1356 | uint32_t column) /**< column */ |
1357 | { |
1358 | JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); |
1359 | |
1360 | JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_parse_function_t, message_parse_function_p); |
1361 | |
1362 | message_parse_function_p->type = JERRY_DEBUGGER_PARSE_FUNCTION; |
1363 | memcpy (message_parse_function_p->line, &line, sizeof (uint32_t)); |
1364 | memcpy (message_parse_function_p->column, &column, sizeof (uint32_t)); |
1365 | |
1366 | return jerry_debugger_send (sizeof (jerry_debugger_send_parse_function_t)); |
1367 | } /* jerry_debugger_send_parse_function */ |
1368 | |
1369 | /** |
1370 | * Send memory statistics to the debugger client. |
1371 | */ |
1372 | void |
1373 | jerry_debugger_send_memstats (void) |
1374 | { |
1375 | JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); |
1376 | |
1377 | JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_memstats_t, memstats_p); |
1378 | |
1379 | memstats_p->type = JERRY_DEBUGGER_MEMSTATS_RECEIVE; |
1380 | |
1381 | #if ENABLED (JERRY_MEM_STATS) /* if memory statistics feature is enabled */ |
1382 | jmem_heap_stats_t *heap_stats = &JERRY_CONTEXT (jmem_heap_stats); |
1383 | |
1384 | uint32_t allocated_bytes = (uint32_t) heap_stats->allocated_bytes; |
1385 | memcpy (memstats_p->allocated_bytes, &allocated_bytes, sizeof (uint32_t)); |
1386 | uint32_t byte_code_bytes = (uint32_t) heap_stats->byte_code_bytes; |
1387 | memcpy (memstats_p->byte_code_bytes, &byte_code_bytes, sizeof (uint32_t)); |
1388 | uint32_t string_bytes = (uint32_t) heap_stats->string_bytes; |
1389 | memcpy (memstats_p->string_bytes, &string_bytes, sizeof (uint32_t)); |
1390 | uint32_t object_bytes = (uint32_t) heap_stats->object_bytes; |
1391 | memcpy (memstats_p->object_bytes, &object_bytes, sizeof (uint32_t)); |
1392 | uint32_t property_bytes = (uint32_t) heap_stats->property_bytes; |
1393 | memcpy (memstats_p->property_bytes, &property_bytes, sizeof (uint32_t)); |
1394 | #else /* !ENABLED (JERRY_MEM_STATS) if not, just put zeros */ |
1395 | memset (memstats_p->allocated_bytes, 0, sizeof (uint32_t)); |
1396 | memset (memstats_p->byte_code_bytes, 0, sizeof (uint32_t)); |
1397 | memset (memstats_p->string_bytes, 0, sizeof (uint32_t)); |
1398 | memset (memstats_p->object_bytes, 0, sizeof (uint32_t)); |
1399 | memset (memstats_p->property_bytes, 0, sizeof (uint32_t)); |
1400 | #endif /* ENABLED (JERRY_MEM_STATS) */ |
1401 | |
1402 | jerry_debugger_send (sizeof (jerry_debugger_send_memstats_t)); |
1403 | } /* jerry_debugger_send_memstats */ |
1404 | |
1405 | /* |
1406 | * Converts an standard error into a string. |
1407 | * |
1408 | * @return standard error string |
1409 | */ |
1410 | static ecma_string_t * |
1411 | jerry_debugger_exception_object_to_string (ecma_value_t exception_obj_value) /**< exception object */ |
1412 | { |
1413 | ecma_object_t *object_p = ecma_get_object_from_value (exception_obj_value); |
1414 | |
1415 | jmem_cpointer_t prototype_cp = object_p->u2.prototype_cp; |
1416 | |
1417 | if (prototype_cp == JMEM_CP_NULL) |
1418 | { |
1419 | return NULL; |
1420 | } |
1421 | |
1422 | ecma_object_t *prototype_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, prototype_cp); |
1423 | |
1424 | if (ecma_get_object_type (prototype_p) != ECMA_OBJECT_TYPE_GENERAL |
1425 | || !ecma_get_object_is_builtin (prototype_p)) |
1426 | { |
1427 | return NULL; |
1428 | } |
1429 | |
1430 | lit_magic_string_id_t string_id; |
1431 | |
1432 | switch (((ecma_extended_object_t *) prototype_p)->u.built_in.id) |
1433 | { |
1434 | #if ENABLED (JERRY_BUILTIN_ERRORS) |
1435 | case ECMA_BUILTIN_ID_EVAL_ERROR_PROTOTYPE: |
1436 | { |
1437 | string_id = LIT_MAGIC_STRING_EVAL_ERROR_UL; |
1438 | break; |
1439 | } |
1440 | case ECMA_BUILTIN_ID_RANGE_ERROR_PROTOTYPE: |
1441 | { |
1442 | string_id = LIT_MAGIC_STRING_RANGE_ERROR_UL; |
1443 | break; |
1444 | } |
1445 | case ECMA_BUILTIN_ID_REFERENCE_ERROR_PROTOTYPE: |
1446 | { |
1447 | string_id = LIT_MAGIC_STRING_REFERENCE_ERROR_UL; |
1448 | break; |
1449 | } |
1450 | case ECMA_BUILTIN_ID_SYNTAX_ERROR_PROTOTYPE: |
1451 | { |
1452 | string_id = LIT_MAGIC_STRING_SYNTAX_ERROR_UL; |
1453 | break; |
1454 | } |
1455 | case ECMA_BUILTIN_ID_TYPE_ERROR_PROTOTYPE: |
1456 | { |
1457 | string_id = LIT_MAGIC_STRING_TYPE_ERROR_UL; |
1458 | break; |
1459 | } |
1460 | case ECMA_BUILTIN_ID_URI_ERROR_PROTOTYPE: |
1461 | { |
1462 | string_id = LIT_MAGIC_STRING_URI_ERROR_UL; |
1463 | break; |
1464 | } |
1465 | #endif /* ENABLED (JERRY_BUILTIN_ERRORS) */ |
1466 | case ECMA_BUILTIN_ID_ERROR_PROTOTYPE: |
1467 | { |
1468 | string_id = LIT_MAGIC_STRING_ERROR_UL; |
1469 | break; |
1470 | } |
1471 | default: |
1472 | { |
1473 | return NULL; |
1474 | } |
1475 | } |
1476 | |
1477 | ecma_stringbuilder_t builder = ecma_stringbuilder_create (); |
1478 | |
1479 | ecma_stringbuilder_append_magic (&builder, string_id); |
1480 | |
1481 | ecma_property_t *property_p; |
1482 | property_p = ecma_find_named_property (ecma_get_object_from_value (exception_obj_value), |
1483 | ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE)); |
1484 | |
1485 | if (property_p == NULL || !(*property_p & ECMA_PROPERTY_FLAG_DATA)) |
1486 | { |
1487 | return ecma_stringbuilder_finalize (&builder); |
1488 | } |
1489 | |
1490 | ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); |
1491 | |
1492 | if (!ecma_is_value_string (prop_value_p->value)) |
1493 | { |
1494 | return ecma_stringbuilder_finalize (&builder); |
1495 | } |
1496 | |
1497 | ecma_stringbuilder_append_byte (&builder, LIT_CHAR_COLON); |
1498 | ecma_stringbuilder_append_byte (&builder, LIT_CHAR_SP); |
1499 | ecma_stringbuilder_append (&builder, ecma_get_string_from_value (prop_value_p->value)); |
1500 | |
1501 | return ecma_stringbuilder_finalize (&builder); |
1502 | } /* jerry_debugger_exception_object_to_string */ |
1503 | |
1504 | /** |
1505 | * Send string representation of exception to the client. |
1506 | * |
1507 | * @return true - if the data sent successfully to the debugger client, |
1508 | * false - otherwise |
1509 | */ |
1510 | bool |
1511 | jerry_debugger_send_exception_string (ecma_value_t exception_value) |
1512 | { |
1513 | JERRY_ASSERT (jcontext_has_pending_exception ()); |
1514 | ecma_string_t *string_p = NULL; |
1515 | |
1516 | if (ecma_is_value_object (exception_value)) |
1517 | { |
1518 | string_p = jerry_debugger_exception_object_to_string (exception_value); |
1519 | |
1520 | if (string_p == NULL) |
1521 | { |
1522 | string_p = ecma_get_string_from_value (ecma_builtin_helper_object_to_string (exception_value)); |
1523 | } |
1524 | } |
1525 | else if (ecma_is_value_string (exception_value)) |
1526 | { |
1527 | string_p = ecma_get_string_from_value (exception_value); |
1528 | ecma_ref_ecma_string (string_p); |
1529 | } |
1530 | else |
1531 | { |
1532 | string_p = ecma_op_to_string (exception_value); |
1533 | } |
1534 | |
1535 | ECMA_STRING_TO_UTF8_STRING (string_p, string_data_p, string_size); |
1536 | |
1537 | bool result = jerry_debugger_send_string (JERRY_DEBUGGER_EXCEPTION_STR, |
1538 | JERRY_DEBUGGER_NO_SUBTYPE, |
1539 | string_data_p, |
1540 | string_size); |
1541 | |
1542 | ECMA_FINALIZE_UTF8_STRING (string_data_p, string_size); |
1543 | |
1544 | ecma_deref_ecma_string (string_p); |
1545 | return result; |
1546 | } /* jerry_debugger_send_exception_string */ |
1547 | |
1548 | #endif /* ENABLED (JERRY_DEBUGGER) */ |
1549 | |