Skip to content

Commit aa64635

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 1302887 commit aa64635

File tree

13 files changed

+868
-13
lines changed

13 files changed

+868
-13
lines changed

jerry-core/debugger/debugger.c

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

828+
case JERRY_DEBUGGER_GET_SCOPE_CHAIN:
829+
{
830+
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
831+
832+
jerry_debugger_send_scope_chain ();
833+
834+
return true;
835+
}
836+
837+
case JERRY_DEBUGGER_GET_SCOPE_VARIABLES:
838+
{
839+
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_get_scope_variables_t);
840+
841+
jerry_debugger_send_scope_variables (recv_buffer_p);
842+
843+
return true;
844+
}
845+
528846
case JERRY_DEBUGGER_EXCEPTION_CONFIG:
529847
{
530848
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_exception_config_t);

0 commit comments

Comments
 (0)