Initial version of JerryScript debugger (#1557)
The debugger supports setting breakpoints, execution control (step, next, continue) and getting backtrace. The communication is WebSocket-based, so a browser can communicate with JerryScript without any intermediate application. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com JerryScript-DCO-1.0-Signed-off-by: Levente Orban orbanl@inf.u-szeged.hu
This commit is contained in:
committed by
Tilmann Scheller
parent
453066fcf1
commit
025a99ccbb
@@ -0,0 +1,547 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "jerry-api.h"
|
||||
|
||||
#ifdef JERRY_DEBUGGER
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "jcontext.h"
|
||||
#include "jerry-debugger.h"
|
||||
#include "jerry-port.h"
|
||||
|
||||
/**
|
||||
* Debugger socket communication port.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_PORT 5001
|
||||
|
||||
/**
|
||||
* Masking-key is available.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_WEBSOCKET_MASK_BIT 0x80
|
||||
|
||||
/**
|
||||
* Opcode type mask.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK 0x0fu
|
||||
|
||||
/**
|
||||
* Packet length mask.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK 0x7fu
|
||||
|
||||
/**
|
||||
* Payload mask size in bytes of a websocket package.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE 4
|
||||
|
||||
/**
|
||||
* Header for incoming packets.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t ws_opcode; /**< websocket opcode */
|
||||
uint8_t size; /**< size of the message */
|
||||
uint8_t mask[4]; /**< mask bytes */
|
||||
} jerry_debugger_receive_header_t;
|
||||
|
||||
/**
|
||||
* Close the socket connection to the client.
|
||||
*/
|
||||
static void
|
||||
jerry_debugger_close_connection_tcp (bool log_error) /**< log error */
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (jerry_init_flags) & JERRY_INIT_DEBUGGER);
|
||||
|
||||
JERRY_CONTEXT (jerry_init_flags) &= (uint32_t) ~JERRY_INIT_DEBUGGER;
|
||||
|
||||
if (log_error)
|
||||
{
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", strerror (errno));
|
||||
}
|
||||
|
||||
jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Debugger client connection closed.\n");
|
||||
|
||||
close (JERRY_CONTEXT (debugger_connection));
|
||||
JERRY_CONTEXT (debugger_connection) = -1;
|
||||
|
||||
jerry_debugger_free_unreferenced_byte_code ();
|
||||
} /* jerry_debugger_close_connection_tcp */
|
||||
|
||||
/**
|
||||
* Send message to the client side.
|
||||
*
|
||||
* @return true - if the data was sent successfully to the client side
|
||||
* false - otherwise
|
||||
*/
|
||||
static bool
|
||||
jerry_debugger_send_tcp (const uint8_t *data_p, /**< data pointer */
|
||||
size_t data_size) /**< data size */
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (jerry_init_flags) & JERRY_INIT_DEBUGGER);
|
||||
|
||||
do
|
||||
{
|
||||
ssize_t sent_bytes = send (JERRY_CONTEXT (debugger_connection), data_p, data_size, 0);
|
||||
|
||||
if (sent_bytes < 0)
|
||||
{
|
||||
if (errno == EWOULDBLOCK)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
jerry_debugger_close_connection_tcp (true);
|
||||
return false;
|
||||
}
|
||||
|
||||
data_size -= (size_t) sent_bytes;
|
||||
data_p += sent_bytes;
|
||||
}
|
||||
while (data_size > 0);
|
||||
|
||||
return true;
|
||||
} /* jerry_debugger_send_tcp */
|
||||
|
||||
/**
|
||||
* Convert a 6-bit value to a Base64 character.
|
||||
*
|
||||
* @return Base64 character
|
||||
*/
|
||||
static uint8_t
|
||||
jerry_to_base64_character (uint8_t value) /**< 6-bit value */
|
||||
{
|
||||
if (value < 26)
|
||||
{
|
||||
return (uint8_t) (value + 'A');
|
||||
}
|
||||
|
||||
if (value < 52)
|
||||
{
|
||||
return (uint8_t) (value - 26 + 'a');
|
||||
}
|
||||
|
||||
if (value < 62)
|
||||
{
|
||||
return (uint8_t) (value - 52 + '0');
|
||||
}
|
||||
|
||||
if (value == 62)
|
||||
{
|
||||
return (uint8_t) '+';
|
||||
}
|
||||
|
||||
return (uint8_t) '/';
|
||||
} /* jerry_to_base64_character */
|
||||
|
||||
/**
|
||||
* Encode a byte sequence into Base64 string.
|
||||
*/
|
||||
static void
|
||||
jerry_to_base64 (const uint8_t *source_p, /**< source data */
|
||||
uint8_t *destination_p, /**< destination buffer */
|
||||
size_t length) /**< length of source, must be divisible by 3 */
|
||||
{
|
||||
while (length >= 3)
|
||||
{
|
||||
uint8_t value = (source_p[0] >> 2);
|
||||
destination_p[0] = jerry_to_base64_character (value);
|
||||
|
||||
value = (uint8_t) (((source_p[0] << 4) | (source_p[1] >> 4)) & 0x3f);
|
||||
destination_p[1] = jerry_to_base64_character (value);
|
||||
|
||||
value = (uint8_t) (((source_p[1] << 2) | (source_p[2] >> 6)) & 0x3f);
|
||||
destination_p[2] = jerry_to_base64_character (value);
|
||||
|
||||
value = (uint8_t) (source_p[2] & 0x3f);
|
||||
destination_p[3] = jerry_to_base64_character (value);
|
||||
|
||||
source_p += 3;
|
||||
destination_p += 4;
|
||||
length -= 3;
|
||||
}
|
||||
} /* jerry_to_base64 */
|
||||
|
||||
/**
|
||||
* Process WebSocket handshake.
|
||||
*
|
||||
* @return true - if the handshake was completed successfully
|
||||
* false - otherwise
|
||||
*/
|
||||
static bool
|
||||
jerry_process_handshake (int client_socket, /**< client socket */
|
||||
uint8_t *request_buffer_p) /**< temporary buffer */
|
||||
{
|
||||
size_t request_buffer_size = 1024;
|
||||
uint8_t *request_end_p = request_buffer_p;
|
||||
|
||||
/* Buffer request text until the double newlines are received. */
|
||||
while (true)
|
||||
{
|
||||
size_t length = request_buffer_size - 1u - (size_t) (request_end_p - request_buffer_p);
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Handshake buffer too small.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t size = recv (client_socket, request_end_p, length, 0);
|
||||
|
||||
if (size < 0)
|
||||
{
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", strerror (errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
request_end_p += (size_t) size;
|
||||
*request_end_p = 0;
|
||||
|
||||
if (request_end_p > request_buffer_p + 4
|
||||
&& memcmp (request_end_p - 4, "\r\n\r\n", 4) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check protocol. */
|
||||
const char *text_p = "GET /jerry-debugger";
|
||||
size_t text_len = strlen (text_p);
|
||||
|
||||
if ((size_t) (request_end_p - request_buffer_p) < text_len
|
||||
|| memcmp (request_buffer_p, text_p, text_len) != 0)
|
||||
{
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid handshake format.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *websocket_key_p = request_buffer_p + text_len;
|
||||
|
||||
text_p = "Sec-WebSocket-Key:";
|
||||
text_len = strlen (text_p);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if ((size_t) (request_end_p - websocket_key_p) < text_len)
|
||||
{
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Sec-WebSocket-Key not found.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (websocket_key_p[0] == 'S'
|
||||
&& websocket_key_p[-1] == '\n'
|
||||
&& websocket_key_p[-2] == '\r'
|
||||
&& memcmp (websocket_key_p, text_p, text_len) == 0)
|
||||
{
|
||||
websocket_key_p += text_len;
|
||||
break;
|
||||
}
|
||||
|
||||
websocket_key_p++;
|
||||
}
|
||||
|
||||
/* String terminated by double newlines. */
|
||||
|
||||
while (*websocket_key_p == ' ')
|
||||
{
|
||||
websocket_key_p++;
|
||||
}
|
||||
|
||||
uint8_t *websocket_key_end_p = websocket_key_p;
|
||||
|
||||
while (*websocket_key_end_p > ' ')
|
||||
{
|
||||
websocket_key_end_p++;
|
||||
}
|
||||
|
||||
/* Since the request_buffer_p is not needed anymore it can
|
||||
* be reused for storing the SHA-1 key and Base64 string. */
|
||||
|
||||
const size_t sha1_length = 20;
|
||||
|
||||
jerry_debugger_compute_sha1 (websocket_key_p,
|
||||
(size_t) (websocket_key_end_p - websocket_key_p),
|
||||
(const uint8_t *) "258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
|
||||
36,
|
||||
request_buffer_p);
|
||||
|
||||
/* The SHA-1 key is 20 bytes long but jerry_to_base64 expects
|
||||
* a length divisible by 3 so an extra 0 is appended at the end. */
|
||||
request_buffer_p[sha1_length] = 0;
|
||||
|
||||
jerry_to_base64 (request_buffer_p, request_buffer_p + sha1_length + 1, sha1_length + 1);
|
||||
|
||||
/* Last value must be replaced by equal sign. */
|
||||
|
||||
text_p = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ";
|
||||
|
||||
if (!jerry_debugger_send_tcp ((const uint8_t *) text_p, strlen (text_p))
|
||||
|| !jerry_debugger_send_tcp (request_buffer_p + sha1_length + 1, 27))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
text_p = "=\r\n\r\n";
|
||||
return jerry_debugger_send_tcp ((const uint8_t *) text_p, strlen (text_p));
|
||||
} /* jerry_process_handshake */
|
||||
|
||||
/**
|
||||
* Initialize the socket connection.
|
||||
*
|
||||
* @return true - if the connection succeeded
|
||||
* false - otherwise
|
||||
*/
|
||||
bool
|
||||
jerry_debugger_accept_connection ()
|
||||
{
|
||||
int server_socket;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t sin_size = sizeof (struct sockaddr_in);
|
||||
|
||||
JERRY_ASSERT (JERRY_CONTEXT (jerry_init_flags) & JERRY_INIT_DEBUGGER);
|
||||
|
||||
/* Disable debugger flag temporarily. */
|
||||
JERRY_CONTEXT (jerry_init_flags) &= (uint32_t) ~JERRY_INIT_DEBUGGER;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons (JERRY_DEBUGGER_PORT);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if ((server_socket = socket (AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
{
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", strerror (errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
int opt_value = 1;
|
||||
|
||||
if (setsockopt (server_socket, SOL_SOCKET, SO_REUSEADDR, &opt_value, sizeof (int)) == -1)
|
||||
{
|
||||
close (server_socket);
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", strerror (errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bind (server_socket, (struct sockaddr *)&addr, sizeof (struct sockaddr)) == -1)
|
||||
{
|
||||
close (server_socket);
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", strerror (errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (listen (server_socket, 1) == -1)
|
||||
{
|
||||
close (server_socket);
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", strerror (errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Waiting for client connection\n");
|
||||
|
||||
JERRY_CONTEXT (debugger_connection) = accept (server_socket, (struct sockaddr *)&addr, &sin_size);
|
||||
|
||||
if (JERRY_CONTEXT (debugger_connection) == -1)
|
||||
{
|
||||
close (server_socket);
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", strerror (errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
close (server_socket);
|
||||
|
||||
/* Enable debugger flag again. */
|
||||
JERRY_CONTEXT (jerry_init_flags) |= JERRY_INIT_DEBUGGER;
|
||||
|
||||
bool is_handshake_ok = false;
|
||||
|
||||
JMEM_DEFINE_LOCAL_ARRAY (request_buffer_p, 1024, uint8_t);
|
||||
|
||||
is_handshake_ok = jerry_process_handshake (JERRY_CONTEXT (debugger_connection),
|
||||
request_buffer_p);
|
||||
|
||||
JMEM_FINALIZE_LOCAL_ARRAY (request_buffer_p);
|
||||
|
||||
if (!is_handshake_ok)
|
||||
{
|
||||
jerry_debugger_close_connection ();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!jerry_debugger_send_configuration (JERRY_DEBUGGER_MAX_BUFFER_SIZE - sizeof (jerry_debugger_receive_header_t)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set non-blocking mode. */
|
||||
int socket_flags = fcntl (JERRY_CONTEXT (debugger_connection), F_GETFL, 0);
|
||||
|
||||
if (socket_flags < 0)
|
||||
{
|
||||
jerry_debugger_close_connection_tcp (true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fcntl (JERRY_CONTEXT (debugger_connection), F_SETFL, socket_flags | O_NONBLOCK) == -1)
|
||||
{
|
||||
jerry_debugger_close_connection_tcp (true);
|
||||
return false;
|
||||
}
|
||||
|
||||
jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Connected from: %s\n", inet_ntoa (addr.sin_addr));
|
||||
|
||||
JERRY_CONTEXT (debugger_stop_exec) = true;
|
||||
JERRY_CONTEXT (debugger_stop_context) = NULL;
|
||||
|
||||
return true;
|
||||
} /* jerry_debugger_accept_connection */
|
||||
|
||||
/**
|
||||
* Close the socket connection to the client.
|
||||
*/
|
||||
inline void __attr_always_inline___
|
||||
jerry_debugger_close_connection (void)
|
||||
{
|
||||
jerry_debugger_close_connection_tcp (false);
|
||||
} /* jerry_debugger_close_connection */
|
||||
|
||||
/**
|
||||
* Send message to the client side
|
||||
*
|
||||
* @return true - if the data was sent successfully to the debugger client,
|
||||
* false - otherwise
|
||||
*/
|
||||
inline bool __attr_always_inline___
|
||||
jerry_debugger_send (size_t data_size) /**< data size */
|
||||
{
|
||||
return jerry_debugger_send_tcp (JERRY_CONTEXT (debugger_send_buffer), data_size);
|
||||
} /* jerry_debugger_send */
|
||||
|
||||
/**
|
||||
* Receive message from the client.
|
||||
*
|
||||
* Note:
|
||||
* If the function returns with true, the value of
|
||||
* JERRY_CONTEXT (debugger_stop_exec) should be ignored.
|
||||
*
|
||||
* @return true - if execution should be resumed,
|
||||
* false - otherwise
|
||||
*/
|
||||
bool
|
||||
jerry_debugger_receive (void)
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (jerry_init_flags) & JERRY_INIT_DEBUGGER);
|
||||
|
||||
JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY;
|
||||
|
||||
uint8_t *recv_buffer_p = JERRY_CONTEXT (debugger_receive_buffer);
|
||||
bool resume_exec = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
uint32_t offset = JERRY_CONTEXT (debugger_receive_buffer_offset);
|
||||
ssize_t byte_recv = recv (JERRY_CONTEXT (debugger_connection),
|
||||
recv_buffer_p + offset,
|
||||
JERRY_DEBUGGER_MAX_BUFFER_SIZE - offset,
|
||||
0);
|
||||
|
||||
if (byte_recv <= 0)
|
||||
{
|
||||
if (byte_recv < 0 && errno != EWOULDBLOCK)
|
||||
{
|
||||
jerry_debugger_close_connection_tcp (true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return resume_exec;
|
||||
}
|
||||
|
||||
JERRY_CONTEXT (debugger_receive_buffer_offset) += (uint32_t) byte_recv;
|
||||
|
||||
if (JERRY_CONTEXT (debugger_receive_buffer_offset) < sizeof (jerry_debugger_receive_header_t))
|
||||
{
|
||||
return resume_exec;
|
||||
}
|
||||
|
||||
const size_t max_packet_size = JERRY_DEBUGGER_MAX_BUFFER_SIZE - sizeof (jerry_debugger_receive_header_t);
|
||||
|
||||
JERRY_ASSERT (max_packet_size < 126);
|
||||
|
||||
if ((recv_buffer_p[0] & ~JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRY_DEBUGGER_WEBSOCKET_FIN_BIT
|
||||
|| (recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK) >= max_packet_size
|
||||
|| !(recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_MASK_BIT))
|
||||
{
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unsupported Websocket message.\n");
|
||||
jerry_debugger_close_connection ();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((recv_buffer_p[0] & JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME)
|
||||
{
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unsupported Websocket opcode.\n");
|
||||
jerry_debugger_close_connection ();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t message_size = (uint32_t) (recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK);
|
||||
uint32_t message_total_size = (uint32_t) (message_size + sizeof (jerry_debugger_receive_header_t));
|
||||
|
||||
if (JERRY_CONTEXT (debugger_receive_buffer_offset) < message_total_size)
|
||||
{
|
||||
return resume_exec;
|
||||
}
|
||||
|
||||
/* Unmask data bytes. */
|
||||
uint8_t *data_p = recv_buffer_p + sizeof (jerry_debugger_receive_header_t);
|
||||
const uint8_t *mask_p = data_p - JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE;
|
||||
const uint8_t *mask_end_p = data_p;
|
||||
const uint8_t *data_end_p = data_p + message_size;
|
||||
|
||||
while (data_p < data_end_p)
|
||||
{
|
||||
/* Invert certain bits with xor operation. */
|
||||
*data_p = *data_p ^ *mask_p;
|
||||
|
||||
data_p++;
|
||||
mask_p++;
|
||||
|
||||
if (mask_p >= mask_end_p)
|
||||
{
|
||||
mask_p -= JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!jerry_debugger_process_message (recv_buffer_p + sizeof (jerry_debugger_receive_header_t),
|
||||
message_size,
|
||||
&resume_exec))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (message_total_size < JERRY_CONTEXT (debugger_receive_buffer_offset))
|
||||
{
|
||||
memcpy (recv_buffer_p,
|
||||
recv_buffer_p + message_total_size,
|
||||
JERRY_CONTEXT (debugger_receive_buffer_offset) - message_total_size);
|
||||
}
|
||||
|
||||
JERRY_CONTEXT (debugger_receive_buffer_offset) -= message_total_size;
|
||||
}
|
||||
} /* jerry_debugger_receive */
|
||||
|
||||
#endif /* JERRY_DEBUGGER */
|
||||
@@ -0,0 +1,86 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef JERRY_DEBUGGER_WS_H
|
||||
#define JERRY_DEBUGGER_WS_H
|
||||
|
||||
#ifdef JERRY_DEBUGGER
|
||||
|
||||
#include "ecma-globals.h"
|
||||
|
||||
/* JerryScript debugger protocol is a simplified version of RFC-6455 (WebSockets). */
|
||||
|
||||
/**
|
||||
* Maximum number of bytes transmitted or received.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_MAX_BUFFER_SIZE 128
|
||||
|
||||
/**
|
||||
* Last fragment of a Websocket package.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_WEBSOCKET_FIN_BIT 0x80
|
||||
|
||||
/**
|
||||
* WebSocket opcode types.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
JERRY_DEBUGGER_WEBSOCKET_TEXT_FRAME = 1, /**< text frame */
|
||||
JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME = 2, /**< binary frame */
|
||||
JERRY_DEBUGGER_WEBSOCKET_CLOSE_CONNECTION = 8, /**< close connection */
|
||||
JERRY_DEBUGGER_WEBSOCKET_PING = 9, /**< ping (keep alive) frame */
|
||||
JERRY_DEBUGGER_WEBSOCKET_PONG = 10, /**< reply to ping frame */
|
||||
} jerry_websocket_opcode_type_t;
|
||||
|
||||
/**
|
||||
* Header for outgoing packets.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t ws_opcode; /**< Websocket opcode */
|
||||
uint8_t size; /**< size of the message */
|
||||
} jerry_debugger_send_header_t;
|
||||
|
||||
/**
|
||||
* Initialize the header of an outgoing message.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_INIT_SEND_MESSAGE(message_p) \
|
||||
(message_p)->header.ws_opcode = JERRY_DEBUGGER_WEBSOCKET_FIN_BIT | JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME;
|
||||
|
||||
/**
|
||||
* Set the size of an outgoing message from type.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE(message_p, type) \
|
||||
(message_p)->header.size = (uint8_t) (sizeof (type) - sizeof (jerry_debugger_send_header_t));
|
||||
|
||||
/**
|
||||
* Set the size of an outgoing message.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE(message_p, byte_size) \
|
||||
(message_p)->header.size = (uint8_t) (byte_size);
|
||||
|
||||
bool jerry_debugger_accept_connection (void);
|
||||
void jerry_debugger_close_connection (void);
|
||||
|
||||
bool jerry_debugger_send (size_t data_size);
|
||||
bool jerry_debugger_receive (void);
|
||||
|
||||
void jerry_debugger_compute_sha1 (const uint8_t *input1, size_t input1_len,
|
||||
const uint8_t *input2, size_t input2_len,
|
||||
uint8_t output[20]);
|
||||
|
||||
#endif /* JERRY_DEBUGGER */
|
||||
|
||||
#endif /* JERRY_DEBUGGER_WS_H */
|
||||
@@ -0,0 +1,446 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "jerry-api.h"
|
||||
|
||||
#ifdef JERRY_DEBUGGER
|
||||
|
||||
#include "byte-code.h"
|
||||
#include "jcontext.h"
|
||||
#include "jerry-debugger.h"
|
||||
#include "jerry-port.h"
|
||||
|
||||
/**
|
||||
* Type cast the debugger send buffer into a specific type.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_SEND_BUFFER_AS(type, name_p) \
|
||||
type *name_p = (type *) (&JERRY_CONTEXT (debugger_send_buffer))
|
||||
|
||||
/**
|
||||
* Type cast the debugger receive buffer into a specific type.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_RECEIVE_BUFFER_AS(type, name_p) \
|
||||
type *name_p = ((type *) recv_buffer_p)
|
||||
|
||||
/**
|
||||
* Free all unreferenced byte code structures which
|
||||
* were not acknowledged by the debugger client.
|
||||
*/
|
||||
void
|
||||
jerry_debugger_free_unreferenced_byte_code (void)
|
||||
{
|
||||
jerry_debugger_byte_code_free_t *byte_code_free_p;
|
||||
|
||||
byte_code_free_p = JMEM_CP_GET_POINTER (jerry_debugger_byte_code_free_t,
|
||||
JERRY_CONTEXT (debugger_byte_code_free_head));
|
||||
|
||||
while (byte_code_free_p != NULL)
|
||||
{
|
||||
jerry_debugger_byte_code_free_t *next_byte_code_free_p;
|
||||
next_byte_code_free_p = JMEM_CP_GET_POINTER (jerry_debugger_byte_code_free_t,
|
||||
byte_code_free_p->next_cp);
|
||||
|
||||
jmem_heap_free_block (byte_code_free_p,
|
||||
((size_t) byte_code_free_p->size) << JMEM_ALIGNMENT_LOG);
|
||||
|
||||
byte_code_free_p = next_byte_code_free_p;
|
||||
}
|
||||
} /* jerry_debugger_free_unreferenced_byte_code */
|
||||
|
||||
/**
|
||||
* Send backtrace.
|
||||
*/
|
||||
static void
|
||||
jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer the the received data */
|
||||
{
|
||||
JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_get_backtrace_t, get_backtrace_p);
|
||||
|
||||
uint32_t max_depth;
|
||||
memcpy (&max_depth, get_backtrace_p->max_depth, sizeof (uint32_t));
|
||||
|
||||
if (max_depth == 0)
|
||||
{
|
||||
max_depth = UINT32_MAX;
|
||||
}
|
||||
|
||||
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_backtrace_t, backtrace_p);
|
||||
|
||||
JERRY_DEBUGGER_INIT_SEND_MESSAGE (backtrace_p);
|
||||
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (backtrace_p, jerry_debugger_send_backtrace_t);
|
||||
backtrace_p->type = JERRY_DEBUGGER_BACKTRACE;
|
||||
|
||||
vm_frame_ctx_t *frame_ctx_p = JERRY_CONTEXT (vm_top_context_p);
|
||||
|
||||
uint32_t current_frame = 0;
|
||||
|
||||
while (frame_ctx_p != NULL && max_depth > 0)
|
||||
{
|
||||
if (current_frame >= JERRY_DEBUGGER_MAX_SIZE (jerry_debugger_frame_t))
|
||||
{
|
||||
if (!jerry_debugger_send (sizeof (jerry_debugger_send_backtrace_t)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
current_frame = 0;
|
||||
}
|
||||
|
||||
jerry_debugger_frame_t *frame_p = backtrace_p->frames + current_frame;
|
||||
|
||||
jmem_cpointer_t byte_code_cp;
|
||||
JMEM_CP_SET_NON_NULL_POINTER (byte_code_cp, frame_ctx_p->bytecode_header_p);
|
||||
memcpy (frame_p->byte_code_cp, &byte_code_cp, sizeof (jmem_cpointer_t));
|
||||
|
||||
uint32_t offset = (uint32_t) (frame_ctx_p->byte_code_p - (uint8_t *) frame_ctx_p->bytecode_header_p);
|
||||
memcpy (frame_p->offset, &offset, sizeof (uint32_t));
|
||||
|
||||
frame_ctx_p = frame_ctx_p->prev_context_p;
|
||||
current_frame++;
|
||||
max_depth--;
|
||||
}
|
||||
|
||||
size_t message_size = current_frame * sizeof (jerry_debugger_frame_t);
|
||||
|
||||
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE (backtrace_p, 1 + message_size);
|
||||
backtrace_p->type = JERRY_DEBUGGER_BACKTRACE_END;
|
||||
|
||||
jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + message_size);
|
||||
} /* jerry_debugger_send_backtrace */
|
||||
|
||||
/**
|
||||
* Check received packet size.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_CHECK_PACKET_SIZE(type) \
|
||||
if (message_size != sizeof (type)) \
|
||||
{ \
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n"); \
|
||||
jerry_debugger_close_connection (); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive message from the client.
|
||||
*
|
||||
* @return true - if message is processed successfully
|
||||
* false - otherwise
|
||||
*/
|
||||
inline bool __attr_always_inline___
|
||||
jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the received data */
|
||||
uint32_t message_size, /**< message size */
|
||||
bool *resume_exec_p) /**< pointer to the resume exec flag */
|
||||
{
|
||||
/* Process the received message. */
|
||||
switch (recv_buffer_p[0])
|
||||
{
|
||||
case JERRY_DEBUGGER_FREE_BYTE_CODE_CP:
|
||||
{
|
||||
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_byte_code_cp_t);
|
||||
|
||||
JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_byte_code_cp_t, byte_code_p);
|
||||
|
||||
jmem_cpointer_t byte_code_free_cp;
|
||||
memcpy (&byte_code_free_cp, byte_code_p->byte_code_cp, sizeof (jmem_cpointer_t));
|
||||
|
||||
jerry_debugger_byte_code_free_t *byte_code_free_p;
|
||||
byte_code_free_p = JMEM_CP_GET_NON_NULL_POINTER (jerry_debugger_byte_code_free_t,
|
||||
byte_code_free_cp);
|
||||
|
||||
if (JERRY_CONTEXT (debugger_byte_code_free_head) == byte_code_free_cp)
|
||||
{
|
||||
JERRY_CONTEXT (debugger_byte_code_free_head) = byte_code_free_p->next_cp;
|
||||
}
|
||||
|
||||
if (byte_code_free_p->prev_cp != ECMA_NULL_POINTER)
|
||||
{
|
||||
jerry_debugger_byte_code_free_t *prev_byte_code_free_p;
|
||||
prev_byte_code_free_p = JMEM_CP_GET_NON_NULL_POINTER (jerry_debugger_byte_code_free_t,
|
||||
byte_code_free_p->prev_cp);
|
||||
|
||||
prev_byte_code_free_p->next_cp = byte_code_free_p->next_cp;
|
||||
}
|
||||
|
||||
if (byte_code_free_p->next_cp != ECMA_NULL_POINTER)
|
||||
{
|
||||
jerry_debugger_byte_code_free_t *next_byte_code_free_p;
|
||||
next_byte_code_free_p = JMEM_CP_GET_NON_NULL_POINTER (jerry_debugger_byte_code_free_t,
|
||||
byte_code_free_p->next_cp);
|
||||
|
||||
next_byte_code_free_p->prev_cp = byte_code_free_p->prev_cp;
|
||||
}
|
||||
|
||||
jmem_heap_free_block (byte_code_free_p,
|
||||
((size_t) byte_code_free_p->size) << JMEM_ALIGNMENT_LOG);
|
||||
return true;
|
||||
}
|
||||
|
||||
case JERRY_DEBUGGER_UPDATE_BREAKPOINT:
|
||||
{
|
||||
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_update_breakpoint_t);
|
||||
|
||||
JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_update_breakpoint_t, update_breakpoint_p);
|
||||
|
||||
jmem_cpointer_t byte_code_cp;
|
||||
memcpy (&byte_code_cp, update_breakpoint_p->byte_code_cp, sizeof (jmem_cpointer_t));
|
||||
uint8_t *byte_code_p = JMEM_CP_GET_NON_NULL_POINTER (uint8_t, byte_code_cp);
|
||||
|
||||
uint32_t offset;
|
||||
memcpy (&offset, update_breakpoint_p->offset, sizeof (uint32_t));
|
||||
byte_code_p += offset;
|
||||
|
||||
JERRY_ASSERT (*byte_code_p == CBC_BREAKPOINT_ENABLED || *byte_code_p == CBC_BREAKPOINT_DISABLED);
|
||||
|
||||
*byte_code_p = update_breakpoint_p->is_set_breakpoint ? CBC_BREAKPOINT_ENABLED : CBC_BREAKPOINT_DISABLED;
|
||||
return true;
|
||||
}
|
||||
|
||||
case JERRY_DEBUGGER_STOP:
|
||||
{
|
||||
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
|
||||
|
||||
JERRY_CONTEXT (debugger_stop_exec) = true;
|
||||
JERRY_CONTEXT (debugger_stop_context) = NULL;
|
||||
*resume_exec_p = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
case JERRY_DEBUGGER_CONTINUE:
|
||||
{
|
||||
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
|
||||
|
||||
JERRY_CONTEXT (debugger_stop_exec) = false;
|
||||
JERRY_CONTEXT (debugger_stop_context) = NULL;
|
||||
|
||||
*resume_exec_p = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
case JERRY_DEBUGGER_STEP:
|
||||
{
|
||||
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
|
||||
|
||||
JERRY_CONTEXT (debugger_stop_exec) = true;
|
||||
JERRY_CONTEXT (debugger_stop_context) = NULL;
|
||||
*resume_exec_p = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
case JERRY_DEBUGGER_NEXT:
|
||||
{
|
||||
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
|
||||
|
||||
JERRY_CONTEXT (debugger_stop_exec) = true;
|
||||
JERRY_CONTEXT (debugger_stop_context) = JERRY_CONTEXT (vm_top_context_p);
|
||||
*resume_exec_p = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
case JERRY_DEBUGGER_GET_BACKTRACE:
|
||||
{
|
||||
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_get_backtrace_t);
|
||||
|
||||
jerry_debugger_send_backtrace (recv_buffer_p);
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unexpected message.");
|
||||
jerry_debugger_close_connection ();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} /* jerry_debugger_process_message */
|
||||
|
||||
#undef JERRY_DEBUGGER_CHECK_PACKET_SIZE
|
||||
|
||||
/**
|
||||
* Tell the client that a breakpoint has been hit and wait for further debugger commands.
|
||||
*/
|
||||
void
|
||||
jerry_debugger_breakpoint_hit (void)
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (jerry_init_flags) & JERRY_INIT_DEBUGGER);
|
||||
|
||||
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_breakpoint_hit_t, breakpoint_hit_p);
|
||||
|
||||
JERRY_DEBUGGER_INIT_SEND_MESSAGE (breakpoint_hit_p);
|
||||
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (breakpoint_hit_p, jerry_debugger_send_breakpoint_hit_t);
|
||||
breakpoint_hit_p->type = (uint8_t) JERRY_DEBUGGER_BREAKPOINT_HIT;
|
||||
|
||||
vm_frame_ctx_t *frame_ctx_p = JERRY_CONTEXT (vm_top_context_p);
|
||||
|
||||
jmem_cpointer_t byte_code_header_cp;
|
||||
JMEM_CP_SET_NON_NULL_POINTER (byte_code_header_cp, frame_ctx_p->bytecode_header_p);
|
||||
memcpy (breakpoint_hit_p->byte_code_cp, &byte_code_header_cp, sizeof (jmem_cpointer_t));
|
||||
|
||||
uint32_t offset = (uint32_t) (frame_ctx_p->byte_code_p - (uint8_t *) frame_ctx_p->bytecode_header_p);
|
||||
memcpy (breakpoint_hit_p->offset, &offset, sizeof (uint32_t));
|
||||
|
||||
if (!jerry_debugger_send (sizeof (jerry_debugger_send_breakpoint_hit_t)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (!jerry_debugger_receive ())
|
||||
{
|
||||
}
|
||||
|
||||
JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY;
|
||||
} /* jerry_debugger_breakpoint_hit */
|
||||
|
||||
/**
|
||||
* Send the type signal to the client.
|
||||
*/
|
||||
void
|
||||
jerry_debugger_send_type (jerry_debugger_header_type_t type) /**< message type */
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (jerry_init_flags) & JERRY_INIT_DEBUGGER);
|
||||
|
||||
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_type_t, message_type_p);
|
||||
|
||||
JERRY_DEBUGGER_INIT_SEND_MESSAGE (message_type_p);
|
||||
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (message_type_p, jerry_debugger_send_type_t)
|
||||
message_type_p->type = (uint8_t) type;
|
||||
|
||||
jerry_debugger_send (sizeof (jerry_debugger_send_type_t));
|
||||
} /* jerry_debugger_send_type */
|
||||
|
||||
|
||||
/**
|
||||
* Send the type signal to the client.
|
||||
*
|
||||
* @return true - if the data sent successfully to the debugger client,
|
||||
* false - otherwise
|
||||
*/
|
||||
bool
|
||||
jerry_debugger_send_configuration (uint8_t max_message_size) /**< maximum message size */
|
||||
{
|
||||
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_configuration_t, configuration_p);
|
||||
|
||||
/* Helper structure for endianness check. */
|
||||
union
|
||||
{
|
||||
uint16_t uint16_value; /**< a 16-bit value */
|
||||
uint8_t uint8_value[2]; /**< lower and upper byte of a 16-bit value */
|
||||
} endian_data;
|
||||
|
||||
endian_data.uint16_value = 1;
|
||||
|
||||
JERRY_DEBUGGER_INIT_SEND_MESSAGE (configuration_p);
|
||||
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (configuration_p, jerry_debugger_send_configuration_t);
|
||||
configuration_p->type = JERRY_DEBUGGER_CONFIGURATION;
|
||||
configuration_p->max_message_size = max_message_size;
|
||||
configuration_p->cpointer_size = sizeof (jmem_cpointer_t);
|
||||
configuration_p->little_endian = (endian_data.uint8_value[0] == 1);
|
||||
|
||||
return jerry_debugger_send (sizeof (jerry_debugger_send_configuration_t));
|
||||
} /* jerry_debugger_send_configuration */
|
||||
|
||||
/**
|
||||
* Send raw data to the debugger client.
|
||||
*/
|
||||
void
|
||||
jerry_debugger_send_data (jerry_debugger_header_type_t type, /**< message type */
|
||||
const void *data, /**< raw data */
|
||||
size_t size) /**< size of data */
|
||||
{
|
||||
JERRY_ASSERT (size < JERRY_DEBUGGER_MAX_SIZE (uint8_t));
|
||||
|
||||
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_type_t, message_type_p);
|
||||
|
||||
JERRY_DEBUGGER_INIT_SEND_MESSAGE (message_type_p);
|
||||
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE (message_type_p, 1 + size);
|
||||
message_type_p->type = type;
|
||||
memcpy (message_type_p + 1, data, size);
|
||||
|
||||
jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + size);
|
||||
} /* jerry_debugger_send_data */
|
||||
|
||||
/**
|
||||
* Send string to the debugger client.
|
||||
*/
|
||||
void
|
||||
jerry_debugger_send_string (uint8_t message_type, /**< message type */
|
||||
const jerry_char_t *string_p, /**< string data */
|
||||
size_t string_length) /**< length of string */
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (jerry_init_flags) & JERRY_INIT_DEBUGGER);
|
||||
|
||||
const size_t max_fragment_len = JERRY_DEBUGGER_MAX_SIZE (char);
|
||||
|
||||
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t, message_string_p);
|
||||
|
||||
JERRY_DEBUGGER_INIT_SEND_MESSAGE (message_string_p);
|
||||
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (message_string_p, jerry_debugger_send_string_t);
|
||||
message_string_p->type = message_type;
|
||||
|
||||
while (string_length > max_fragment_len)
|
||||
{
|
||||
memcpy (message_string_p->string, string_p, max_fragment_len);
|
||||
|
||||
if (!jerry_debugger_send (sizeof (jerry_debugger_send_string_t)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string_length -= max_fragment_len;
|
||||
string_p += max_fragment_len;
|
||||
}
|
||||
|
||||
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE (message_string_p, 1 + string_length);
|
||||
message_string_p->type = (uint8_t) (message_type + 1);
|
||||
|
||||
memcpy (message_string_p->string, string_p, string_length);
|
||||
|
||||
jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + string_length);
|
||||
} /* jerry_debugger_send_string */
|
||||
|
||||
/**
|
||||
* Send the function name to the debugger client.
|
||||
*/
|
||||
void
|
||||
jerry_debugger_send_function_name (const jerry_char_t *function_name_p, /**< function name */
|
||||
size_t function_name_length) /**< length of function name */
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (jerry_init_flags) & JERRY_INIT_DEBUGGER);
|
||||
|
||||
jerry_debugger_send_string (JERRY_DEBUGGER_FUNCTION_NAME, function_name_p, function_name_length);
|
||||
} /* jerry_debugger_send_function_name */
|
||||
|
||||
/**
|
||||
* Send the function compressed pointer to the debugger client.
|
||||
*
|
||||
* @return true - if the data was sent successfully to the debugger client,
|
||||
* false - otherwise
|
||||
*/
|
||||
bool
|
||||
jerry_debugger_send_function_cp (jerry_debugger_header_type_t type, /**< message type */
|
||||
ecma_compiled_code_t *compiled_code_p) /**< byte code pointer */
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (jerry_init_flags) & JERRY_INIT_DEBUGGER);
|
||||
|
||||
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_byte_code_cp_t, byte_code_cp_p);
|
||||
|
||||
JERRY_DEBUGGER_INIT_SEND_MESSAGE (byte_code_cp_p);
|
||||
JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (byte_code_cp_p, jerry_debugger_send_byte_code_cp_t);
|
||||
byte_code_cp_p->type = (uint8_t) type;
|
||||
|
||||
jmem_cpointer_t compiled_code_cp;
|
||||
JMEM_CP_SET_NON_NULL_POINTER (compiled_code_cp, compiled_code_p);
|
||||
memcpy (byte_code_cp_p->byte_code_cp, &compiled_code_cp, sizeof (jmem_cpointer_t));
|
||||
|
||||
return jerry_debugger_send (sizeof (jerry_debugger_send_byte_code_cp_t));
|
||||
} /* jerry_debugger_send_function_cp */
|
||||
|
||||
#endif /* JERRY_DEBUGGER */
|
||||
@@ -0,0 +1,210 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef JERRY_DEBUGGER_H
|
||||
#define JERRY_DEBUGGER_H
|
||||
|
||||
#ifdef JERRY_DEBUGGER
|
||||
|
||||
#include "jerry-debugger-ws.h"
|
||||
#include "ecma-globals.h"
|
||||
|
||||
/* JerryScript debugger protocol is a simplified version of RFC-6455 (WebSockets). */
|
||||
|
||||
/**
|
||||
* Frequency of calling jerry_debugger_receive() by the VM.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_MESSAGE_FREQUENCY 5
|
||||
|
||||
/**
|
||||
* Limited resources available for the engine, so it is important to
|
||||
* check the maximum buffer size. It needs to be between 64 and 256 bytes.
|
||||
*/
|
||||
#if JERRY_DEBUGGER_MAX_BUFFER_SIZE < 64 || JERRY_DEBUGGER_MAX_BUFFER_SIZE > 256
|
||||
#error Please define the MAX_BUFFER_SIZE between 64 and 256 bytes.
|
||||
#endif /* JERRY_DEBUGGER_MAX_BUFFER_SIZE < 64 || JERRY_DEBUGGER_MAX_BUFFER_SIZE > 256 */
|
||||
|
||||
/**
|
||||
* Calculate the maximum number of items for a given type
|
||||
* which can be transmitted by one message.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_MAX_SIZE(type) \
|
||||
((JERRY_DEBUGGER_MAX_BUFFER_SIZE - sizeof (jerry_debugger_send_header_t) - 1) / sizeof (type))
|
||||
|
||||
/**
|
||||
* Types for the package.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
/* Messages sent by the server to client. */
|
||||
JERRY_DEBUGGER_CONFIGURATION = 1, /**< debugger configuration */
|
||||
JERRY_DEBUGGER_PARSE_ERROR = 2, /**< parse error */
|
||||
JERRY_DEBUGGER_BYTE_CODE_CP = 3, /**< byte code compressed pointer */
|
||||
JERRY_DEBUGGER_PARSE_FUNCTION = 4, /**< parsing a new function */
|
||||
JERRY_DEBUGGER_BREAKPOINT_LIST = 5, /**< list of line offsets */
|
||||
JERRY_DEBUGGER_BREAKPOINT_OFFSET_LIST = 6, /**< list of byte code offsets */
|
||||
JERRY_DEBUGGER_RESOURCE_NAME = 7, /**< resource name fragment */
|
||||
JERRY_DEBUGGER_RESOURCE_NAME_END = 8, /**< resource name fragment */
|
||||
JERRY_DEBUGGER_FUNCTION_NAME = 9, /**< function name fragment */
|
||||
JERRY_DEBUGGER_FUNCTION_NAME_END = 10, /**< function name fragment */
|
||||
JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 11, /**< invalidate byte code compressed pointer */
|
||||
JERRY_DEBUGGER_BREAKPOINT_HIT = 12, /**< notify breakpoint hit */
|
||||
JERRY_DEBUGGER_BACKTRACE = 13, /**< backtrace data */
|
||||
JERRY_DEBUGGER_BACKTRACE_END = 14, /**< last backtrace data */
|
||||
|
||||
/* Messages sent by the client to server. */
|
||||
JERRY_DEBUGGER_FREE_BYTE_CODE_CP = 1, /**< free byte code compressed pointer */
|
||||
JERRY_DEBUGGER_UPDATE_BREAKPOINT = 2, /**< update breakpoint status */
|
||||
JERRY_DEBUGGER_STOP = 3, /**< stop execution */
|
||||
JERRY_DEBUGGER_CONTINUE = 4, /**< continue execution */
|
||||
JERRY_DEBUGGER_STEP = 5, /**< next breakpoint, step into functions */
|
||||
JERRY_DEBUGGER_NEXT = 6, /**< next breakpoint in the same context */
|
||||
JERRY_DEBUGGER_GET_BACKTRACE = 7, /**< get backtrace */
|
||||
} jerry_debugger_header_type_t;
|
||||
|
||||
/**
|
||||
* Delayed free of byte code data.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint16_t size;
|
||||
jmem_cpointer_t prev_cp;
|
||||
jmem_cpointer_t next_cp;
|
||||
} jerry_debugger_byte_code_free_t;
|
||||
|
||||
/**
|
||||
* Outgoing message: JerryScript configuration.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
jerry_debugger_send_header_t header; /**< message header */
|
||||
uint8_t type; /**< type of the message */
|
||||
uint8_t max_message_size; /**< maximum incoming message size */
|
||||
uint8_t cpointer_size; /**< size of compressed pointers */
|
||||
uint8_t little_endian; /**< little endian machine */
|
||||
} jerry_debugger_send_configuration_t;
|
||||
|
||||
/**
|
||||
* Outgoing message: message without arguments.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
jerry_debugger_send_header_t header; /**< message header */
|
||||
uint8_t type; /**< type of the message */
|
||||
} jerry_debugger_send_type_t;
|
||||
|
||||
/**
|
||||
* Incoming message: message without arguments.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t type; /**< type of the message */
|
||||
} jerry_debugger_receive_type_t;
|
||||
|
||||
/**
|
||||
* Outgoing message: string (Source file name or function name).
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
jerry_debugger_send_header_t header; /**< message header */
|
||||
uint8_t type; /**< type of the message */
|
||||
uint8_t string[JERRY_DEBUGGER_MAX_SIZE (uint8_t)]; /**< string data */
|
||||
} jerry_debugger_send_string_t;
|
||||
|
||||
/**
|
||||
* Outgoing message: byte code compressed pointer.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
jerry_debugger_send_header_t header; /**< message header */
|
||||
uint8_t type; /**< type of the message */
|
||||
uint8_t byte_code_cp[sizeof (jmem_cpointer_t)]; /**< byte code compressed pointer */
|
||||
} jerry_debugger_send_byte_code_cp_t;
|
||||
|
||||
/**
|
||||
* Incoming message: byte code compressed pointer.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t type; /**< type of the message */
|
||||
uint8_t byte_code_cp[sizeof (jmem_cpointer_t)]; /**< byte code compressed pointer */
|
||||
} jerry_debugger_receive_byte_code_cp_t;
|
||||
|
||||
/**
|
||||
* Incoming message: update (enable/disable) breakpoint status.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t type; /**< type of the message */
|
||||
uint8_t is_set_breakpoint; /**< set or clear breakpoint */
|
||||
uint8_t byte_code_cp[sizeof (jmem_cpointer_t)]; /**< byte code compressed pointer */
|
||||
uint8_t offset[sizeof (uint32_t)]; /**< breakpoint offset */
|
||||
} jerry_debugger_receive_update_breakpoint_t;
|
||||
|
||||
/**
|
||||
* Outgoing message: notify breakpoint hit.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
jerry_debugger_send_header_t header; /**< message header */
|
||||
uint8_t type; /**< type of the message */
|
||||
uint8_t byte_code_cp[sizeof (jmem_cpointer_t)]; /**< byte code compressed pointer */
|
||||
uint8_t offset[sizeof (uint32_t)]; /**< breakpoint offset */
|
||||
} jerry_debugger_send_breakpoint_hit_t;
|
||||
|
||||
/**
|
||||
* Stack frame descriptor for sending backtrace information.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t byte_code_cp[sizeof (jmem_cpointer_t)]; /**< byte code compressed pointer */
|
||||
uint8_t offset[sizeof (uint32_t)]; /**< last breakpoint offset */
|
||||
} jerry_debugger_frame_t;
|
||||
|
||||
/**
|
||||
* Outgoing message: backtrace information.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
jerry_debugger_send_header_t header; /**< message header */
|
||||
uint8_t type; /**< type of the message */
|
||||
jerry_debugger_frame_t frames[JERRY_DEBUGGER_MAX_SIZE (jerry_debugger_frame_t)]; /**< frames */
|
||||
} jerry_debugger_send_backtrace_t;
|
||||
|
||||
/**
|
||||
* Incoming message: get backtrace.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t type; /**< type of the message */
|
||||
uint8_t max_depth[sizeof (uint32_t)]; /**< maximum depth (0 - unlimited) */
|
||||
} jerry_debugger_receive_get_backtrace_t;
|
||||
|
||||
void jerry_debugger_free_unreferenced_byte_code (void);
|
||||
|
||||
bool jerry_debugger_process_message (uint8_t *recv_buffer_p, uint32_t message_size, bool *resume_exec_p);
|
||||
void jerry_debugger_breakpoint_hit (void);
|
||||
|
||||
void jerry_debugger_send_type (jerry_debugger_header_type_t type);
|
||||
bool jerry_debugger_send_configuration (uint8_t max_message_size);
|
||||
void jerry_debugger_send_data (jerry_debugger_header_type_t type, const void *data, size_t size);
|
||||
void jerry_debugger_send_string (uint8_t message_type, const jerry_char_t *string_p, size_t string_length);
|
||||
void jerry_debugger_send_function_name (const jerry_char_t *function_name_p, size_t function_name_length);
|
||||
bool jerry_debugger_send_function_cp (jerry_debugger_header_type_t type, ecma_compiled_code_t *compiled_code_p);
|
||||
void jerry_debugger_send_source_file_name (const jerry_char_t *file_name_p, size_t file_name_length);
|
||||
|
||||
#endif /* JERRY_DEBUGGER */
|
||||
|
||||
#endif /* JERRY_DEBUGGER_H */
|
||||
@@ -0,0 +1,370 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* FIPS-180-1 compliant SHA-1 implementation
|
||||
*
|
||||
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is part of mbed TLS (https://tls.mbed.org)
|
||||
*/
|
||||
|
||||
/*
|
||||
* The SHA-1 standard was published by NIST in 1993.
|
||||
*
|
||||
* http://www.itl.nist.gov/fipspubs/fip180-1.htm
|
||||
*/
|
||||
|
||||
#ifdef JERRY_DEBUGGER
|
||||
|
||||
#include "jerry-debugger.h"
|
||||
|
||||
/**
|
||||
* SHA-1 context structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t total[2]; /**< number of bytes processed */
|
||||
uint32_t state[5]; /**< intermediate digest state */
|
||||
uint8_t buffer[64]; /**< data block being processed */
|
||||
} jerry_sha1_context;
|
||||
|
||||
/* 32-bit integer manipulation macros (big endian). */
|
||||
|
||||
#define JERRY_SHA1_GET_UINT32_BE(n, b, i) \
|
||||
{ \
|
||||
(n) = (((uint32_t) (b)[(i) + 0]) << 24) \
|
||||
| (((uint32_t) (b)[(i) + 1]) << 16) \
|
||||
| (((uint32_t) (b)[(i) + 2]) << 8) \
|
||||
| ((uint32_t) (b)[(i) + 3]); \
|
||||
}
|
||||
|
||||
#define JERRY_SHA1_PUT_UINT32_BE(n, b, i) \
|
||||
{ \
|
||||
(b)[(i) + 0] = (uint8_t) ((n) >> 24); \
|
||||
(b)[(i) + 1] = (uint8_t) ((n) >> 16); \
|
||||
(b)[(i) + 2] = (uint8_t) ((n) >> 8); \
|
||||
(b)[(i) + 3] = (uint8_t) ((n)); \
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize SHA-1 context.
|
||||
*/
|
||||
static void
|
||||
jerry_sha1_init (jerry_sha1_context *sha1_context_p) /**< SHA-1 context */
|
||||
{
|
||||
memset (sha1_context_p, 0, sizeof (jerry_sha1_context));
|
||||
|
||||
sha1_context_p->total[0] = 0;
|
||||
sha1_context_p->total[1] = 0;
|
||||
|
||||
sha1_context_p->state[0] = 0x67452301;
|
||||
sha1_context_p->state[1] = 0xEFCDAB89;
|
||||
sha1_context_p->state[2] = 0x98BADCFE;
|
||||
sha1_context_p->state[3] = 0x10325476;
|
||||
sha1_context_p->state[4] = 0xC3D2E1F0;
|
||||
} /* jerry_sha1_init */
|
||||
|
||||
#define JERRY_SHA1_P(a, b, c, d, e, x) \
|
||||
do { \
|
||||
e += JERRY_SHA1_SHIFT (a, 5) + JERRY_SHA1_F (b, c, d) + K + x; \
|
||||
b = JERRY_SHA1_SHIFT (b, 30); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Update SHA-1 internal buffer status.
|
||||
*/
|
||||
static void
|
||||
jerry_sha1_process (jerry_sha1_context *sha1_context_p, /**< SHA-1 context */
|
||||
const uint8_t data[64]) /**< data buffer */
|
||||
{
|
||||
uint32_t temp, W[16], A, B, C, D, E;
|
||||
|
||||
JERRY_SHA1_GET_UINT32_BE (W[0], data, 0);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[1], data, 4);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[2], data, 8);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[3], data, 12);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[4], data, 16);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[5], data, 20);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[6], data, 24);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[7], data, 28);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[8], data, 32);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[9], data, 36);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[10], data, 40);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[11], data, 44);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[12], data, 48);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[13], data, 52);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[14], data, 56);
|
||||
JERRY_SHA1_GET_UINT32_BE (W[15], data, 60);
|
||||
|
||||
#define JERRY_SHA1_SHIFT(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
||||
|
||||
#define JERRY_SHA1_R(t) \
|
||||
( \
|
||||
temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ W[t & 0x0F], \
|
||||
W[t & 0x0F] = JERRY_SHA1_SHIFT (temp, 1) \
|
||||
)
|
||||
|
||||
A = sha1_context_p->state[0];
|
||||
B = sha1_context_p->state[1];
|
||||
C = sha1_context_p->state[2];
|
||||
D = sha1_context_p->state[3];
|
||||
E = sha1_context_p->state[4];
|
||||
|
||||
uint32_t K = 0x5A827999;
|
||||
|
||||
#define JERRY_SHA1_F(x, y, z) (z ^ (x & (y ^ z)))
|
||||
|
||||
JERRY_SHA1_P (A, B, C, D, E, W[0]);
|
||||
JERRY_SHA1_P (E, A, B, C, D, W[1]);
|
||||
JERRY_SHA1_P (D, E, A, B, C, W[2]);
|
||||
JERRY_SHA1_P (C, D, E, A, B, W[3]);
|
||||
JERRY_SHA1_P (B, C, D, E, A, W[4]);
|
||||
JERRY_SHA1_P (A, B, C, D, E, W[5]);
|
||||
JERRY_SHA1_P (E, A, B, C, D, W[6]);
|
||||
JERRY_SHA1_P (D, E, A, B, C, W[7]);
|
||||
JERRY_SHA1_P (C, D, E, A, B, W[8]);
|
||||
JERRY_SHA1_P (B, C, D, E, A, W[9]);
|
||||
JERRY_SHA1_P (A, B, C, D, E, W[10]);
|
||||
JERRY_SHA1_P (E, A, B, C, D, W[11]);
|
||||
JERRY_SHA1_P (D, E, A, B, C, W[12]);
|
||||
JERRY_SHA1_P (C, D, E, A, B, W[13]);
|
||||
JERRY_SHA1_P (B, C, D, E, A, W[14]);
|
||||
JERRY_SHA1_P (A, B, C, D, E, W[15]);
|
||||
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (16));
|
||||
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (17));
|
||||
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (18));
|
||||
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (19));
|
||||
|
||||
#undef JERRY_SHA1_F
|
||||
|
||||
K = 0x6ED9EBA1;
|
||||
|
||||
#define JERRY_SHA1_F(x, y, z) (x ^ y ^ z)
|
||||
|
||||
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (20));
|
||||
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (21));
|
||||
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (22));
|
||||
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (23));
|
||||
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (24));
|
||||
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (25));
|
||||
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (26));
|
||||
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (27));
|
||||
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (28));
|
||||
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (29));
|
||||
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (30));
|
||||
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (31));
|
||||
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (32));
|
||||
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (33));
|
||||
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (34));
|
||||
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (35));
|
||||
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (36));
|
||||
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (37));
|
||||
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (38));
|
||||
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (39));
|
||||
|
||||
#undef JERRY_SHA1_F
|
||||
|
||||
K = 0x8F1BBCDC;
|
||||
|
||||
#define JERRY_SHA1_F(x, y, z) ((x & y) | (z & (x | y)))
|
||||
|
||||
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (40));
|
||||
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (41));
|
||||
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (42));
|
||||
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (43));
|
||||
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (44));
|
||||
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (45));
|
||||
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (46));
|
||||
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (47));
|
||||
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (48));
|
||||
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (49));
|
||||
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (50));
|
||||
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (51));
|
||||
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (52));
|
||||
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (53));
|
||||
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (54));
|
||||
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (55));
|
||||
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (56));
|
||||
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (57));
|
||||
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (58));
|
||||
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (59));
|
||||
|
||||
#undef JERRY_SHA1_F
|
||||
|
||||
K = 0xCA62C1D6;
|
||||
|
||||
#define JERRY_SHA1_F(x, y, z) (x ^ y ^ z)
|
||||
|
||||
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (60));
|
||||
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (61));
|
||||
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (62));
|
||||
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (63));
|
||||
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (64));
|
||||
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (65));
|
||||
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (66));
|
||||
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (67));
|
||||
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (68));
|
||||
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (69));
|
||||
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (70));
|
||||
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (71));
|
||||
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (72));
|
||||
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (73));
|
||||
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (74));
|
||||
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (75));
|
||||
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (76));
|
||||
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (77));
|
||||
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (78));
|
||||
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (79));
|
||||
|
||||
#undef JERRY_SHA1_F
|
||||
|
||||
sha1_context_p->state[0] += A;
|
||||
sha1_context_p->state[1] += B;
|
||||
sha1_context_p->state[2] += C;
|
||||
sha1_context_p->state[3] += D;
|
||||
sha1_context_p->state[4] += E;
|
||||
|
||||
#undef JERRY_SHA1_SHIFT
|
||||
#undef JERRY_SHA1_R
|
||||
} /* jerry_sha1_process */
|
||||
|
||||
#undef JERRY_SHA1_P
|
||||
|
||||
/**
|
||||
* SHA-1 update buffer.
|
||||
*/
|
||||
static void
|
||||
jerry_sha1_update (jerry_sha1_context *sha1_context_p, /**< SHA-1 context */
|
||||
const uint8_t *source_p, /**< source buffer */
|
||||
size_t source_length) /**< length of source buffer */
|
||||
{
|
||||
size_t fill;
|
||||
uint32_t left;
|
||||
|
||||
if (source_length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
left = sha1_context_p->total[0] & 0x3F;
|
||||
fill = 64 - left;
|
||||
|
||||
sha1_context_p->total[0] += (uint32_t) source_length;
|
||||
|
||||
/* Check overflow. */
|
||||
if (sha1_context_p->total[0] < (uint32_t) source_length)
|
||||
{
|
||||
sha1_context_p->total[1]++;
|
||||
}
|
||||
|
||||
if (left && source_length >= fill)
|
||||
{
|
||||
memcpy ((void *) (sha1_context_p->buffer + left), source_p, fill);
|
||||
jerry_sha1_process (sha1_context_p, sha1_context_p->buffer);
|
||||
source_p += fill;
|
||||
source_length -= fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while (source_length >= 64)
|
||||
{
|
||||
jerry_sha1_process (sha1_context_p, source_p);
|
||||
source_p += 64;
|
||||
source_length -= 64;
|
||||
}
|
||||
|
||||
if (source_length > 0)
|
||||
{
|
||||
memcpy ((void *) (sha1_context_p->buffer + left), source_p, source_length);
|
||||
}
|
||||
} /* jerry_sha1_update */
|
||||
|
||||
/**
|
||||
* SHA-1 final digest.
|
||||
*/
|
||||
static void
|
||||
jerry_sha1_finish (jerry_sha1_context *sha1_context_p, /**< SHA-1 context */
|
||||
uint8_t destination_p[20]) /**< result */
|
||||
{
|
||||
uint8_t buffer[16];
|
||||
|
||||
uint32_t high = (sha1_context_p->total[0] >> 29) | (sha1_context_p->total[1] << 3);
|
||||
uint32_t low = (sha1_context_p->total[0] << 3);
|
||||
|
||||
uint32_t last = sha1_context_p->total[0] & 0x3F;
|
||||
uint32_t padn = (last < 56) ? (56 - last) : (120 - last);
|
||||
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
buffer[0] = 0x80;
|
||||
|
||||
while (padn > sizeof (buffer))
|
||||
{
|
||||
jerry_sha1_update (sha1_context_p, buffer, sizeof (buffer));
|
||||
buffer[0] = 0;
|
||||
padn -= (uint32_t) sizeof (buffer);
|
||||
}
|
||||
|
||||
jerry_sha1_update (sha1_context_p, buffer, padn);
|
||||
|
||||
JERRY_SHA1_PUT_UINT32_BE (high, buffer, 0);
|
||||
JERRY_SHA1_PUT_UINT32_BE (low, buffer, 4);
|
||||
|
||||
jerry_sha1_update (sha1_context_p, buffer, 8);
|
||||
|
||||
JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[0], destination_p, 0);
|
||||
JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[1], destination_p, 4);
|
||||
JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[2], destination_p, 8);
|
||||
JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[3], destination_p, 12);
|
||||
JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[4], destination_p, 16);
|
||||
} /* jerry_sha1_finish */
|
||||
|
||||
#undef JERRY_SHA1_GET_UINT32_BE
|
||||
#undef JERRY_SHA1_PUT_UINT32_BE
|
||||
|
||||
/**
|
||||
* Computes the SHA-1 value of the combination of the two input buffers.
|
||||
*/
|
||||
void
|
||||
jerry_debugger_compute_sha1 (const uint8_t *source1_p, /**< first part of the input */
|
||||
size_t source1_length, /**< length of the first part */
|
||||
const uint8_t *source2_p, /**< second part of the input */
|
||||
size_t source2_length, /**< length of the second part */
|
||||
uint8_t destination_p[20]) /**< result */
|
||||
{
|
||||
JMEM_DEFINE_LOCAL_ARRAY (sha1_context_p, 1, jerry_sha1_context);
|
||||
|
||||
jerry_sha1_init (sha1_context_p);
|
||||
jerry_sha1_update (sha1_context_p, source1_p, source1_length);
|
||||
jerry_sha1_update (sha1_context_p, source2_p, source2_length);
|
||||
jerry_sha1_finish (sha1_context_p, destination_p);
|
||||
|
||||
JMEM_FINALIZE_LOCAL_ARRAY (sha1_context_p);
|
||||
} /* jerry_debugger_compute_sha1 */
|
||||
|
||||
#endif /* JERRY_DEBUGGER */
|
||||
Reference in New Issue
Block a user