Skip to content

Commit 87a55a4

Browse files
committed
List scope chain levels and their variables to the selected stack frame.
It supports to list the scope chain of the current execution context and see which variables are available. JerryScript-DCO-1.0-Signed-off-by: Robert Sipka rsipka.uszeged@partner.samsung.com
1 parent 93567fb commit 87a55a4

File tree

14 files changed

+914
-13
lines changed

14 files changed

+914
-13
lines changed

jerry-core/debugger/debugger.c

Lines changed: 348 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "ecma-builtin-helpers.h"
1919
#include "ecma-conversion.h"
2020
#include "ecma-eval.h"
21+
#include "ecma-function-object.h"
2122
#include "ecma-objects.h"
2223
#include "jcontext.h"
2324
#include "jerryscript-port.h"
@@ -37,9 +38,9 @@ typedef struct
3738
* The number of message types in the debugger should reflect the
3839
* debugger versioning.
3940
*/
40-
JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 28
41-
&& JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 19
42-
&& JERRY_DEBUGGER_VERSION == 6,
41+
JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 32
42+
&& JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 21
43+
&& JERRY_DEBUGGER_VERSION == 7,
4344
debugger_version_correlates_to_message_type_count);
4445

4546
/**
@@ -195,6 +196,332 @@ jerry_debugger_send_backtrace (const uint8_t *recv_buffer_p) /**< pointer to the
195196
jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + message_size);
196197
} /* jerry_debugger_send_backtrace */
197198

199+
/**
200+
* Send the scope chain types.
201+
*/
202+
static void
203+
jerry_debugger_send_scope_chain (void)
204+
{
205+
vm_frame_ctx_t *iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p);
206+
207+
const size_t max_byte_count = JERRY_DEBUGGER_SEND_MAX (uint8_t);
208+
const size_t max_message_size = JERRY_DEBUGGER_SEND_SIZE (max_byte_count, uint8_t);
209+
210+
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t, message_type_p);
211+
message_type_p->type = JERRY_DEBUGGER_SCOPE_CHAIN;
212+
213+
size_t buffer_pos = 0;
214+
bool next_func_is_local = true;
215+
ecma_object_t *lex_env_p = iter_frame_ctx_p->lex_env_p;
216+
217+
while (true)
218+
{
219+
JERRY_ASSERT (ecma_is_lexical_environment (lex_env_p));
220+
221+
if (buffer_pos == max_byte_count)
222+
{
223+
if (!jerry_debugger_send (max_message_size))
224+
{
225+
return;
226+
}
227+
228+
buffer_pos = 0;
229+
}
230+
231+
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
232+
{
233+
if ((lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_NON_CLOSURE) != 0)
234+
{
235+
message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_NON_CLOSURE;
236+
}
237+
else if (next_func_is_local)
238+
{
239+
message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_LOCAL;
240+
next_func_is_local = false;
241+
}
242+
else
243+
{
244+
message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_CLOSURE;
245+
}
246+
}
247+
else if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND)
248+
{
249+
if (ecma_get_lex_env_outer_reference (lex_env_p) == NULL)
250+
{
251+
message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_GLOBAL;
252+
break;
253+
}
254+
else
255+
{
256+
message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_WITH;
257+
}
258+
}
259+
260+
lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
261+
}
262+
263+
message_type_p->type = JERRY_DEBUGGER_SCOPE_CHAIN_END;
264+
265+
jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + buffer_pos);
266+
} /* jerry_debugger_send_scope_chain */
267+
268+
/**
269+
* Get type of the scope variable property.
270+
*/
271+
static jerry_debugger_scope_variable_type_t
272+
jerry_debugger_get_variable_type (ecma_value_t value) /**< input ecma value */
273+
{
274+
jerry_debugger_scope_variable_type_t ret_value = JERRY_DEBUGGER_VALUE_NONE;
275+
276+
if (ecma_is_value_undefined (value))
277+
{
278+
ret_value = JERRY_DEBUGGER_VALUE_UNDEFINED;
279+
}
280+
else if (ecma_is_value_null (value))
281+
{
282+
ret_value = JERRY_DEBUGGER_VALUE_NULL;
283+
}
284+
else if (ecma_is_value_boolean (value))
285+
{
286+
ret_value = JERRY_DEBUGGER_VALUE_BOOLEAN;
287+
}
288+
else if (ecma_is_value_number (value))
289+
{
290+
ret_value = JERRY_DEBUGGER_VALUE_NUMBER;
291+
}
292+
else if (ecma_is_value_string (value))
293+
{
294+
ret_value = JERRY_DEBUGGER_VALUE_STRING;
295+
}
296+
else
297+
{
298+
JERRY_ASSERT (ecma_is_value_object (value));
299+
300+
if (ecma_object_get_class_name (ecma_get_object_from_value (value)) == LIT_MAGIC_STRING_ARRAY_UL)
301+
{
302+
ret_value = JERRY_DEBUGGER_VALUE_ARRAY;
303+
}
304+
else
305+
{
306+
ret_value = ecma_op_is_callable (value) ? JERRY_DEBUGGER_VALUE_FUNCTION : JERRY_DEBUGGER_VALUE_OBJECT;
307+
}
308+
}
309+
310+
JERRY_ASSERT (ret_value != JERRY_DEBUGGER_VALUE_NONE);
311+
312+
return ret_value;
313+
} /* jerry_debugger_get_variable_type */
314+
315+
/**
316+
* Helper function for jerry_debugger_send_scope_variables.
317+
*
318+
* It will copies the given scope values type, length and value into the outgoing message string.
319+
*
320+
* @return true - if the copy was successfully
321+
* false - otherwise
322+
*/
323+
static bool
324+
jerry_debugger_copy_variables_to_string_message (jerry_debugger_scope_variable_type_t variable_type, /**< type */
325+
ecma_string_t *value_str, /**< property name or value string */
326+
jerry_debugger_send_string_t *message_string_p, /**< msg pointer */
327+
size_t *buffer_pos) /**< string data position of the message */
328+
{
329+
const size_t max_byte_count = JERRY_DEBUGGER_SEND_MAX (uint8_t);
330+
const size_t max_message_size = JERRY_DEBUGGER_SEND_SIZE (max_byte_count, uint8_t);
331+
332+
ECMA_STRING_TO_UTF8_STRING (value_str, str_buff, str_buff_size);
333+
334+
size_t str_size = 0;
335+
size_t str_limit = 255;
336+
bool result = true;
337+
338+
bool type_processed = false;
339+
340+
while (true)
341+
{
342+
if (*buffer_pos == max_byte_count)
343+
{
344+
if (!jerry_debugger_send (max_message_size))
345+
{
346+
result = false;
347+
break;
348+
}
349+
350+
*buffer_pos = 0;
351+
}
352+
353+
if (!type_processed)
354+
{
355+
if (variable_type != JERRY_DEBUGGER_VALUE_NONE)
356+
{
357+
message_string_p->string[*buffer_pos] = variable_type;
358+
*buffer_pos += 1;
359+
}
360+
type_processed = true;
361+
continue;
362+
}
363+
364+
if (variable_type == JERRY_DEBUGGER_VALUE_FUNCTION)
365+
{
366+
str_size = 0; // do not copy function values
367+
}
368+
else
369+
{
370+
str_size = (str_buff_size > str_limit) ? str_limit : str_buff_size;
371+
}
372+
373+
message_string_p->string[*buffer_pos] = (uint8_t) str_size;
374+
*buffer_pos += 1;
375+
break;
376+
}
377+
378+
if (result)
379+
{
380+
size_t free_bytes = max_byte_count - *buffer_pos;
381+
const uint8_t *string_p = str_buff;
382+
383+
while (str_size > free_bytes)
384+
{
385+
memcpy (message_string_p->string + *buffer_pos, string_p, free_bytes);
386+
387+
if (!jerry_debugger_send (max_message_size))
388+
{
389+
result = false;
390+
break;
391+
}
392+
393+
string_p += free_bytes;
394+
str_size -= free_bytes;
395+
free_bytes = max_byte_count;
396+
*buffer_pos = 0;
397+
}
398+
399+
if (result)
400+
{
401+
memcpy (message_string_p->string + *buffer_pos, string_p, str_size);
402+
*buffer_pos += str_size;
403+
}
404+
}
405+
406+
ECMA_FINALIZE_UTF8_STRING (str_buff, str_buff_size);
407+
408+
return result;
409+
} /* jerry_debugger_copy_variables_to_string_message */
410+
411+
/**
412+
* Send variables of the given scope chain level.
413+
*/
414+
static void
415+
jerry_debugger_send_scope_variables (const uint8_t *recv_buffer_p) /**< pointer to the received data */
416+
{
417+
JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_get_scope_variables_t, get_scope_variables_p);
418+
419+
uint32_t chain_index;
420+
memcpy (&chain_index, get_scope_variables_p->chain_index, sizeof (uint32_t));
421+
422+
vm_frame_ctx_t *iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p);
423+
ecma_object_t *lex_env_p = iter_frame_ctx_p->lex_env_p;
424+
425+
while (chain_index != 0)
426+
{
427+
lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
428+
429+
if (JERRY_UNLIKELY (lex_env_p == NULL))
430+
{
431+
jerry_debugger_send_type (JERRY_DEBUGGER_SCOPE_VARIABLES_END);
432+
return;
433+
}
434+
435+
if ((ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND)
436+
|| (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE))
437+
{
438+
chain_index--;
439+
}
440+
}
441+
442+
ecma_property_header_t *prop_iter_p;
443+
444+
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
445+
{
446+
prop_iter_p = ecma_get_property_list (lex_env_p);
447+
}
448+
else
449+
{
450+
JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
451+
ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
452+
prop_iter_p = ecma_get_property_list (binding_obj_p);
453+
}
454+
455+
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t, message_string_p);
456+
message_string_p->type = JERRY_DEBUGGER_SCOPE_VARIABLES;
457+
458+
size_t buffer_pos = 0;
459+
460+
while (prop_iter_p != NULL)
461+
{
462+
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
463+
464+
ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;
465+
466+
for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
467+
{
468+
if (ECMA_PROPERTY_IS_NAMED_PROPERTY (prop_iter_p->types[i]))
469+
{
470+
if (ECMA_PROPERTY_GET_NAME_TYPE (prop_iter_p->types[i]) == ECMA_DIRECT_STRING_MAGIC
471+
&& prop_pair_p->names_cp[i] >= LIT_NON_INTERNAL_MAGIC_STRING__COUNT)
472+
{
473+
continue;
474+
}
475+
476+
ecma_string_t *prop_name = ecma_string_from_property_name (prop_iter_p->types[i],
477+
prop_pair_p->names_cp[i]);
478+
479+
if (!jerry_debugger_copy_variables_to_string_message (JERRY_DEBUGGER_VALUE_NONE,
480+
prop_name,
481+
message_string_p,
482+
&buffer_pos))
483+
{
484+
ecma_deref_ecma_string (prop_name);
485+
return;
486+
}
487+
488+
ecma_deref_ecma_string (prop_name);
489+
490+
ecma_property_value_t prop_value_p = prop_pair_p->values[i];
491+
ecma_value_t property_value;
492+
493+
jerry_debugger_scope_variable_type_t variable_type = jerry_debugger_get_variable_type (prop_value_p.value);
494+
495+
if (variable_type == JERRY_DEBUGGER_VALUE_OBJECT)
496+
{
497+
property_value = ecma_builtin_json_string_from_object (prop_value_p.value);
498+
}
499+
else
500+
{
501+
property_value = ecma_op_to_string (prop_value_p.value);
502+
}
503+
504+
if (!jerry_debugger_copy_variables_to_string_message (variable_type,
505+
ecma_get_string_from_value (property_value),
506+
message_string_p,
507+
&buffer_pos))
508+
{
509+
ecma_free_value (property_value);
510+
return;
511+
}
512+
513+
ecma_free_value (property_value);
514+
}
515+
}
516+
517+
prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
518+
prop_iter_p->next_property_cp);
519+
}
520+
521+
message_string_p->type = JERRY_DEBUGGER_SCOPE_VARIABLES_END;
522+
jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + buffer_pos);
523+
} /* jerry_debugger_send_scope_variables */
524+
198525
/**
199526
* Send result of evaluated expression or throw an error.
200527
*
@@ -525,6 +852,24 @@ jerry_debugger_process_message (const uint8_t *recv_buffer_p, /**< pointer to th
525852
return true;
526853
}
527854

855+
case JERRY_DEBUGGER_GET_SCOPE_CHAIN:
856+
{
857+
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
858+
859+
jerry_debugger_send_scope_chain ();
860+
861+
return true;
862+
}
863+
864+
case JERRY_DEBUGGER_GET_SCOPE_VARIABLES:
865+
{
866+
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_get_scope_variables_t);
867+
868+
jerry_debugger_send_scope_variables (recv_buffer_p);
869+
870+
return true;
871+
}
872+
528873
case JERRY_DEBUGGER_EXCEPTION_CONFIG:
529874
{
530875
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_exception_config_t);

0 commit comments

Comments
 (0)