Skip to content

Commit 434fb3b

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 e0e6363 commit 434fb3b

File tree

14 files changed

+905
-13
lines changed

14 files changed

+905
-13
lines changed

jerry-core/debugger/debugger.c

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

851+
case JERRY_DEBUGGER_GET_SCOPE_CHAIN:
852+
{
853+
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
854+
855+
jerry_debugger_send_scope_chain ();
856+
857+
return true;
858+
}
859+
860+
case JERRY_DEBUGGER_GET_SCOPE_VARIABLES:
861+
{
862+
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_get_scope_variables_t);
863+
864+
jerry_debugger_send_scope_variables (recv_buffer_p);
865+
866+
return true;
867+
}
868+
528869
case JERRY_DEBUGGER_EXCEPTION_CONFIG:
529870
{
530871
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_exception_config_t);

0 commit comments

Comments
 (0)