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 */
33typedef 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 */
42JERRY_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 */
69void
70jerry_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 */
96static bool
97jerry_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 */
110static void
111jerry_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 */
207static void
208jerry_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 */
278static uint8_t
279jerry_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 */
331static bool
332jerry_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 */
422static void
423jerry_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 */
538static bool
539jerry_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 */
648static inline bool JERRY_ATTR_ALWAYS_INLINE
649jerry_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 */
1099bool
1100jerry_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 */
1158void
1159jerry_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 */
1204void
1205jerry_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 */
1222bool
1223jerry_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 */
1256void
1257jerry_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 */
1277bool
1278jerry_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 */
1331bool
1332jerry_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 */
1354bool
1355jerry_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 */
1372void
1373jerry_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 */
1410static ecma_string_t *
1411jerry_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 */
1510bool
1511jerry_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