Skip to content

Commit 34c5e22

Browse files
robertsipkaakosthekiss
authored andcommitted
List scope chain levels and their variables to the selected stack frame. (#2557)
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 7120b8e commit 34c5e22

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)