improve fscript to support debugger

This commit is contained in:
lixianjing 2022-01-16 18:15:14 +08:00
parent c2553a5a28
commit 0ba781528c
34 changed files with 3887 additions and 52 deletions

View File

@ -1,4 +1,8 @@
# 最新动态
2022/01/16
* 完善fscript支持调试器。
2022/01/13
* 优化tk\_object\_get\_child\_object感谢雨欣提供补丁

View File

@ -13,6 +13,7 @@ TOOLS_NAME = os.environ['TOOLS_NAME']
BASE_SOURCES = Glob('layouters/*.c') + \
Glob('base/*.c') + \
Glob('debugger/*.c') + \
Glob('ui_loader/*.c') + \
Glob('svg/*.c') + \
Glob('clip_board/*.c') + \

6
src/debugger/README.md Normal file
View File

@ -0,0 +1,6 @@
# fscript 调试器
## TODO
* step in/step out
* hot reload(update code)

12
src/debugger/SConscript Normal file
View File

@ -0,0 +1,12 @@
import os
import copy
import awtk_config as awtk
BIN_DIR=os.environ['BIN_DIR'];
LIB_DIR=os.environ['LIB_DIR'];
sources = Glob('*.c')
env=DefaultEnvironment().Clone()
env.Library(os.path.join(LIB_DIR, 'debugger'), sources, LIBS=['tkc'])

180
src/debugger/debugger.c Normal file
View File

@ -0,0 +1,180 @@
/**
* File: debugger.c
* Author: AWTK Develop Team
* Brief: debugger
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-11 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "debugger/debugger.h"
ret_t debugger_lock(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->lock != NULL, RET_BAD_PARAMS);
return debugger->vt->lock(debugger);
}
ret_t debugger_unlock(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->unlock != NULL, RET_BAD_PARAMS);
return debugger->vt->unlock(debugger);
}
ret_t debugger_stop(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->stop != NULL, RET_BAD_PARAMS);
return debugger->vt->stop(debugger);
}
ret_t debugger_pause(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->pause != NULL, RET_BAD_PARAMS);
return debugger->vt->pause(debugger);
}
bool_t debugger_is_paused(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, FALSE);
return_value_if_fail(debugger->vt->is_paused != NULL, FALSE);
return debugger->vt->is_paused(debugger);
}
bool_t debugger_match(debugger_t* debugger, const char* code_id) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, FALSE);
return_value_if_fail(debugger->vt->match != NULL && code_id != NULL, FALSE);
return debugger->vt->match(debugger, code_id);
}
ret_t debugger_next(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->next != NULL, RET_BAD_PARAMS);
return debugger->vt->next(debugger);
}
ret_t debugger_step_in(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->step_in != NULL, RET_BAD_PARAMS);
return debugger->vt->step_in(debugger);
}
ret_t debugger_step_out(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->step_out != NULL, RET_BAD_PARAMS);
return debugger->vt->step_out(debugger);
}
ret_t debugger_step_over(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->step_over != NULL, RET_BAD_PARAMS);
return debugger->vt->step_over(debugger);
}
ret_t debugger_continue(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->continve != NULL, RET_BAD_PARAMS);
return debugger->vt->continve(debugger);
}
tk_object_t* debugger_get_local(debugger_t* debugger, uint32_t frame_index) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, NULL);
return_value_if_fail(debugger->vt->get_local != NULL, NULL);
return debugger->vt->get_local(debugger, frame_index);
}
tk_object_t* debugger_get_self(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, NULL);
return_value_if_fail(debugger->vt->get_self != NULL, NULL);
return debugger->vt->get_self(debugger);
}
tk_object_t* debugger_get_global(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, NULL);
return_value_if_fail(debugger->vt->get_global != NULL, NULL);
return debugger->vt->get_global(debugger);
}
ret_t debugger_get_callstack(debugger_t* debugger, binary_data_t* callstack) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->get_callstack != NULL, RET_BAD_PARAMS);
return_value_if_fail(callstack != NULL, RET_BAD_PARAMS);
return debugger->vt->get_callstack(debugger, callstack);
}
ret_t debugger_clear_break_points(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->clear_break_points != NULL, RET_BAD_PARAMS);
return debugger->vt->clear_break_points(debugger);
}
ret_t debugger_set_break_point(debugger_t* debugger, uint32_t line) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->set_break_point != NULL, RET_BAD_PARAMS);
return debugger->vt->set_break_point(debugger, line);
}
ret_t debugger_remove_break_point(debugger_t* debugger, uint32_t line) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->remove_break_point != NULL, RET_BAD_PARAMS);
return debugger->vt->remove_break_point(debugger, line);
}
ret_t debugger_init(debugger_t* debugger, const char* lang, const char* code_id) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->init != NULL, RET_BAD_PARAMS);
return_value_if_fail(lang != NULL && code_id != NULL, RET_BAD_PARAMS);
return debugger->vt->init(debugger, lang, code_id);
}
ret_t debugger_get_code(debugger_t* debugger, binary_data_t* code) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->get_code != NULL, RET_BAD_PARAMS);
return_value_if_fail(code != NULL, RET_BAD_PARAMS);
return debugger->vt->get_code(debugger, code);
}
ret_t debugger_update_code(debugger_t* debugger, const binary_data_t* code) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->update_code != NULL, RET_BAD_PARAMS);
return_value_if_fail(code != NULL && code->data != NULL, RET_BAD_PARAMS);
return debugger->vt->update_code(debugger, code);
}
ret_t debugger_deinit(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger->vt->deinit != NULL, RET_BAD_PARAMS);
return debugger->vt->deinit(debugger);
}

322
src/debugger/debugger.h Normal file
View File

@ -0,0 +1,322 @@
/**
* File: debugger.h
* Author: AWTK Develop Team
* Brief: debugger
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-11 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_DEBUGGER_H
#define TK_DEBUGGER_H
#include "tkc/event.h"
#include "tkc/object.h"
#include "tkc/types_def.h"
#include "debugger/debugger_const.h"
BEGIN_C_DECLS
struct _debugger_t;
typedef struct _debugger_t debugger_t;
typedef ret_t (*debugger_lock_t)(debugger_t* debugger);
typedef ret_t (*debugger_unlock_t)(debugger_t* debugger);
typedef ret_t (*debugger_stop_t)(debugger_t* debugger);
typedef ret_t (*debugger_pause_t)(debugger_t* debugger);
typedef bool_t (*debugger_match_t)(debugger_t* debugger, const char* code_id);
typedef bool_t (*debugger_is_paused_t)(debugger_t* debugger);
typedef ret_t (*debugger_next_t)(debugger_t* debugger);
typedef ret_t (*debugger_step_in_t)(debugger_t* debugger);
typedef ret_t (*debugger_step_out_t)(debugger_t* debugger);
typedef ret_t (*debugger_step_over_t)(debugger_t* debugger);
typedef ret_t (*debugger_continue_t)(debugger_t* debugger);
typedef tk_object_t* (*debugger_get_local_t)(debugger_t* debugger, uint32_t frame_index);
typedef tk_object_t* (*debugger_get_self_t)(debugger_t* debugger);
typedef tk_object_t* (*debugger_get_global_t)(debugger_t* debugger);
typedef ret_t (*debugger_get_callstack_t)(debugger_t* debugger, binary_data_t* callstack);
typedef ret_t (*debugger_clear_break_points_t)(debugger_t* debugger);
typedef ret_t (*debugger_set_break_point_t)(debugger_t* debugger, uint32_t line);
typedef ret_t (*debugger_remove_break_point_t)(debugger_t* debugger, uint32_t line);
typedef ret_t (*debugger_get_code_t)(debugger_t* debugger, binary_data_t* code);
typedef ret_t (*debugger_update_code_t)(debugger_t* debugger, const binary_data_t* code);
typedef ret_t (*debugger_init_t)(debugger_t* debugger, const char* lang, const char* code_id);
typedef ret_t (*debugger_deinit_t)(debugger_t* debugger);
typedef debugger_t* (*debugger_fscript_create_t)(void);
typedef struct _debugger_vtable_t {
const char* lang;
debugger_init_t init;
debugger_lock_t lock;
debugger_unlock_t unlock;
debugger_stop_t stop;
debugger_pause_t pause;
debugger_match_t match;
debugger_is_paused_t is_paused;
debugger_next_t next;
debugger_step_in_t step_in;
debugger_step_out_t step_out;
debugger_step_over_t step_over;
debugger_continue_t continve;
debugger_get_local_t get_local;
debugger_get_self_t get_self;
debugger_get_global_t get_global;
debugger_get_callstack_t get_callstack;
debugger_get_code_t get_code;
debugger_update_code_t update_code;
debugger_set_break_point_t set_break_point;
debugger_remove_break_point_t remove_break_point;
debugger_clear_break_points_t clear_break_points;
debugger_deinit_t deinit;
} debugger_vtable_t;
/**
* @class debugger_t
*
*
*/
struct _debugger_t {
tk_object_t object;
const debugger_vtable_t* vt;
};
/**
* @method debugger_lock
* debugger对象
* @param {debugger_t*} debugger debugger对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_lock(debugger_t* debugger);
/**
* @method debugger_unlock
* debugger对象
* @param {debugger_t*} debugger debugger对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_unlock(debugger_t* debugger);
/**
* @method debugger_stop
*
* @param {debugger_t*} debugger debugger对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_stop(debugger_t* debugger);
/**
* @method debugger_pause
*
* > next/step_xxx等函数
*
* @param {debugger_t*} debugger debugger对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_pause(debugger_t* debugger);
/**
* @method debugger_is_paused
*
*
* @param {debugger_t*} debugger debugger对象
*
* @return {bool_t} TRUE表示处于暂停运行状态
*/
bool_t debugger_is_paused(debugger_t* debugger);
/**
* @method debugger_match
* code_id是否与当前debugger匹配
*
* @param {debugger_t*} debugger debugger对象
* @param {const char*} code_id ID
*
* @return {bool_t} TRUE表示匹配到
*/
bool_t debugger_match(debugger_t* debugger, const char* code_id);
/**
* @method debugger_next
*
* >
* @param {debugger_t*} debugger debugger对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_next(debugger_t* debugger);
/**
* @method debugger_step_in
*
* >
* @param {debugger_t*} debugger debugger对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_step_in(debugger_t* debugger);
/**
* @method debugger_step_out
*
* >
* @param {debugger_t*} debugger debugger对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_step_out(debugger_t* debugger);
/**
* @method debugger_step_over
* ()
* >
* @param {debugger_t*} debugger debugger对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_step_over(debugger_t* debugger);
/**
* @method debugger_continue
*
* >
* @param {debugger_t*} debugger debugger对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_continue(debugger_t* debugger);
/**
* @method debugger_get_local
*
* >
* @param {debugger_t*} debugger debugger对象
* @param {uint32_t} frame_index frame序数(0)
*
* @return {tk_object_t*}
*/
tk_object_t* debugger_get_local(debugger_t* debugger, uint32_t frame_index);
/**
* @method debugger_get_self
* self对象
* >
* @param {debugger_t*} debugger debugger对象
*
* @return {tk_object_t*} self对象
*/
tk_object_t* debugger_get_self(debugger_t* debugger);
/**
* @method debugger_get_global
*
* >
* @param {debugger_t*} debugger debugger对象
*
* @return {tk_object_t*}
*/
tk_object_t* debugger_get_global(debugger_t* debugger);
/**
* @method debugger_get_callstack
* callstack
* @param {debugger_t*} debugger debugger对象
* @param {binary_data_t*} callstack callstack
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_get_callstack(debugger_t* debugger, binary_data_t* callstack);
/**
* @method debugger_clear_break_points
*
* @param {debugger_t*} debugger debugger对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_clear_break_points(debugger_t* debugger);
/**
* @method debugger_set_break_point
*
* @param {debugger_t*} debugger debugger对象
* @param {uint32_t} line
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_set_break_point(debugger_t* debugger, uint32_t line);
/**
* @method debugger_remove_break_point
*
* @param {debugger_t*} debugger debugger对象
* @param {uint32_t} line
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_remove_break_point(debugger_t* debugger, uint32_t line);
/**
* @method debugger_init
*
* @param {debugger_t*} debugger debugger对象
* @param {const char*} lang
* @param {const char*} code_id ID
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_init(debugger_t* debugger, const char* lang, const char* code_id);
/**
* @method debugger_deinit
*
* @param {debugger_t*} debugger debugger对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_deinit(debugger_t* debugger);
/**
* @method debugger_update_code
*
* @param {debugger_t*} debugger debugger对象
* @param {const binary_data_t*} code
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_update_code(debugger_t* debugger, const binary_data_t* code);
/**
* @method debugger_get_code
*
* @param {debugger_t*} debugger debugger对象
* @param {binary_data_t*} code
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_get_code(debugger_t* debugger, binary_data_t* code);
#define DEBUGGER(debugger) ((debugger_t*)(debugger))
END_C_DECLS
#endif /*TK_DEBUGGER_H*/

View File

@ -0,0 +1,407 @@
/**
* File: debugger.c
* Author: AWTK Develop Team
* Brief: debugger
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-11 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "ubjson/ubjson_parser.h"
#include "debugger/debugger_message.h"
#include "debugger/debugger_client.h"
static ret_t debugger_client_lock(debugger_t* debugger) {
return RET_OK;
}
static ret_t debugger_client_unlock(debugger_t* debugger) {
return RET_OK;
}
static ret_t debugger_client_write_data(tk_ostream_t* out, const void* data, uint32_t size) {
return tk_ostream_write_len(out, data, size, DEBUGGER_IO_WRITE_TIMEOUT) == size ? RET_OK : RET_IO;
}
static ret_t debugger_client_read_data(tk_istream_t* in, void* data, uint32_t size) {
return tk_istream_read_len(in, data, size, DEBUGGER_IO_READ_TIMEOUT) == size ? RET_OK : RET_IO;
}
static ret_t debugger_client_extend_buff(debugger_t* debugger, uint32_t size) {
ret_t ret = RET_OK;
debugger_client_t* client = DEBUGGER_CLIENT(debugger);
if (client->capacity < size) {
void* buff = TKMEM_REALLOC(client->buff, size);
if (buff != NULL) {
client->buff = buff;
client->capacity = size;
} else {
ret = RET_OOM;
}
}
return ret;
}
static ret_t debugger_client_dispatch_message(debugger_t* debugger, debugger_resp_t* resp) {
debugger_client_t* client = DEBUGGER_CLIENT(debugger);
switch (resp->code) {
case DEBUGGER_RESP_MSG_BREAKED: {
uint32_t line = 0;
debugger_breaked_event_t event;
tk_object_t* obj = ubjson_to_object(client->buff, resp->size);
return_value_if_fail(obj != NULL, RET_BAD_PARAMS);
line = tk_object_get_prop_int(obj, STR_DEBUGGER_EVENT_PROP_LINE, 0);
emitter_dispatch(EMITTER(debugger), debugger_breaked_event_init(&event, line));
TK_OBJECT_UNREF(obj);
break;
}
case DEBUGGER_RESP_MSG_LOG: {
uint32_t line = 0;
const char* message = NULL;
debugger_log_event_t event;
tk_object_t* obj = ubjson_to_object(client->buff, resp->size);
return_value_if_fail(obj != NULL, RET_BAD_PARAMS);
line = tk_object_get_prop_int(obj, STR_DEBUGGER_EVENT_PROP_LINE, 0);
message = tk_object_get_prop_str(obj, STR_DEBUGGER_EVENT_PROP_MESSAGE);
emitter_dispatch(EMITTER(debugger), debugger_log_event_init(&event, line, message));
TK_OBJECT_UNREF(obj);
break;
}
case DEBUGGER_RESP_MSG_ERROR: {
uint32_t line = 0;
const char* message = NULL;
debugger_error_event_t event;
tk_object_t* obj = ubjson_to_object(client->buff, resp->size);
return_value_if_fail(obj != NULL, RET_BAD_PARAMS);
line = tk_object_get_prop_int(obj, STR_DEBUGGER_EVENT_PROP_LINE, 0);
message = tk_object_get_prop_str(obj, STR_DEBUGGER_EVENT_PROP_MESSAGE);
emitter_dispatch(EMITTER(debugger), debugger_error_event_init(&event, line, message));
TK_OBJECT_UNREF(obj);
break;
}
case DEBUGGER_RESP_MSG_COMPLETED: {
client->program_completed = TRUE;
emitter_dispatch_simple_event(EMITTER(debugger), DEBUGGER_RESP_MSG_COMPLETED);
break;
}
default: {
break;
}
}
return RET_OK;
}
static ret_t debugger_client_dispatch_one(debugger_t* debugger, debugger_resp_t* resp) {
debugger_client_t* client = DEBUGGER_CLIENT(debugger);
tk_istream_t* in = tk_iostream_get_istream(client->io);
return_value_if_fail(in != NULL, RET_BAD_PARAMS);
return_value_if_fail(debugger_client_read_data(in, resp, sizeof(*resp)) == RET_OK, RET_IO);
assert(DEBUGGER_VERSION == resp->version);
return_value_if_fail(debugger_client_extend_buff(debugger, resp->size) == RET_OK, RET_OOM);
if (resp->size > 0) {
return_value_if_fail(debugger_client_read_data(in, client->buff, resp->size) == RET_OK, RET_IO);
}
return debugger_client_dispatch_message(debugger, resp);
}
ret_t debugger_client_dispatch(debugger_t* debugger) {
debugger_resp_t resp;
return_value_if_fail(debugger != NULL, RET_BAD_PARAMS);
memset(&resp, 0x00, sizeof(resp));
return debugger_client_dispatch_one(debugger, &resp);
}
ret_t debugger_client_wait_for_completed(debugger_t* debugger) {
debugger_resp_t resp;
debugger_client_t* client = DEBUGGER_CLIENT(debugger);
memset(&resp, 0x00, sizeof(resp));
while (!(client->program_completed)) {
break_if_fail(debugger_client_dispatch_one(debugger, &resp) == RET_OK);
if (resp.code == DEBUGGER_RESP_MSG_COMPLETED) {
break;
}
}
return RET_OK;
}
static ret_t debugger_client_read_packet(debugger_t* debugger, uint32_t resp_code, void** data,
uint32_t* size, ret_t* ret) {
debugger_resp_t resp;
debugger_client_t* client = DEBUGGER_CLIENT(debugger);
memset(&resp, 0x00, sizeof(resp));
while (TRUE) {
break_if_fail(debugger_client_dispatch_one(debugger, &resp) == RET_OK);
if (resp.code == resp_code) {
*data = client->buff;
*size = resp.size;
*ret = resp.error;
break;
}
}
return RET_OK;
}
static ret_t debugger_client_read_simple(debugger_t* debugger, uint32_t resp_code) {
void* data = NULL;
uint32_t size = 0;
ret_t ret = RET_FAIL;
debugger_client_read_packet(debugger, resp_code, &data, &size, &ret);
return ret;
}
static tk_object_t* debugger_client_read_object(debugger_t* debugger, uint32_t resp_code) {
void* data = NULL;
uint32_t size = 0;
ret_t ret = RET_FAIL;
if (debugger_client_read_packet(debugger, resp_code, &data, &size, &ret) == RET_OK &&
ret == RET_OK) {
assert(data != NULL && size > 0);
return ubjson_to_object(data, size);
}
return NULL;
}
static ret_t debugger_client_read_binary(debugger_t* debugger, uint32_t resp_code,
binary_data_t* data) {
ret_t ret = RET_FAIL;
debugger_client_read_packet(debugger, resp_code, &(data->data), &(data->size), &ret);
return ret;
}
static ret_t debugger_client_write_binary(debugger_t* debugger, uint32_t code, const void* data,
uint32_t size) {
debugger_req_t req;
debugger_client_t* client = DEBUGGER_CLIENT(debugger);
tk_ostream_t* out = tk_iostream_get_ostream(client->io);
memset(&req, 0x00, sizeof(req));
req.code = code;
req.size = size;
req.version = DEBUGGER_VERSION;
debugger_client_write_data(out, &req, sizeof(req));
if (req.size > 0) {
return debugger_client_write_data(out, data, size);
} else {
return RET_OK;
}
}
static ret_t debugger_client_write_simple(debugger_t* debugger, uint32_t code, uint32_t data) {
debugger_req_t req;
debugger_client_t* client = DEBUGGER_CLIENT(debugger);
tk_ostream_t* out = tk_iostream_get_ostream(client->io);
memset(&req, 0x00, sizeof(req));
req.code = code;
req.data = data;
req.size = 0;
req.version = DEBUGGER_VERSION;
return debugger_client_write_data(out, &req, sizeof(req));
}
static ret_t debugger_client_request_simple(debugger_t* debugger, uint32_t code, uint32_t data) {
return_value_if_fail(debugger_client_write_simple(debugger, code, data) == RET_OK, RET_FAIL);
return debugger_client_read_simple(debugger, code);
}
static ret_t debugger_client_request_binary(debugger_t* debugger, uint32_t code, const void* data,
uint32_t size) {
return_value_if_fail(debugger_client_write_binary(debugger, code, data, size) == RET_OK,
RET_FAIL);
return debugger_client_read_simple(debugger, code);
}
static ret_t debugger_client_stop(debugger_t* debugger) {
return debugger_client_request_simple(debugger, DEBUGGER_REQ_STOP, 0);
}
static ret_t debugger_client_pause(debugger_t* debugger) {
return debugger_client_request_simple(debugger, DEBUGGER_REQ_PAUSE, 0);
}
static bool_t debugger_client_is_paused(debugger_t* debugger) {
return debugger_client_request_simple(debugger, DEBUGGER_REQ_IS_PAUSED, 0) == RET_OK;
}
static ret_t debugger_client_next(debugger_t* debugger) {
return debugger_client_request_simple(debugger, DEBUGGER_REQ_NEXT, 0);
}
static ret_t debugger_client_step_in(debugger_t* debugger) {
return debugger_client_request_simple(debugger, DEBUGGER_REQ_STEP_IN, 0);
}
static ret_t debugger_client_step_out(debugger_t* debugger) {
return debugger_client_request_simple(debugger, DEBUGGER_REQ_STEP_OUT, 0);
}
static ret_t debugger_client_step_over(debugger_t* debugger) {
return debugger_client_request_simple(debugger, DEBUGGER_REQ_STEP_OVER, 0);
}
static ret_t debugger_client_continue(debugger_t* debugger) {
return debugger_client_request_simple(debugger, DEBUGGER_REQ_CONTINUE, 0);
}
static tk_object_t* debugger_client_get_local(debugger_t* debugger, uint32_t frame_index) {
if (debugger_client_write_simple(debugger, DEBUGGER_REQ_GET_LOCAL, frame_index) == RET_OK) {
return debugger_client_read_object(debugger, DEBUGGER_RESP_GET_LOCAL);
} else {
return NULL;
}
}
static tk_object_t* debugger_client_get_self(debugger_t* debugger) {
if (debugger_client_write_simple(debugger, DEBUGGER_REQ_GET_SELF, 0) == RET_OK) {
return debugger_client_read_object(debugger, DEBUGGER_RESP_GET_SELF);
} else {
return NULL;
}
}
static tk_object_t* debugger_client_get_global(debugger_t* debugger) {
if (debugger_client_write_simple(debugger, DEBUGGER_REQ_GET_GLOBAL, 0) == RET_OK) {
return debugger_client_read_object(debugger, DEBUGGER_RESP_GET_GLOBAL);
} else {
return NULL;
}
}
static ret_t debugger_client_get_callstack(debugger_t* debugger, binary_data_t* callstack) {
if (debugger_client_write_simple(debugger, DEBUGGER_REQ_GET_CALLSTACK, 0) == RET_OK) {
return debugger_client_read_binary(debugger, DEBUGGER_RESP_GET_CALLSTACK, callstack);
} else {
return RET_FAIL;
}
}
static ret_t debugger_client_clear_break_points(debugger_t* debugger) {
return debugger_client_request_simple(debugger, DEBUGGER_REQ_CLEAR_BREAK_POINTS, 0);
}
static ret_t debugger_client_set_break_point(debugger_t* debugger, uint32_t line) {
return debugger_client_request_simple(debugger, DEBUGGER_REQ_SET_BREAK_POINT, line);
}
static ret_t debugger_client_remove_break_point(debugger_t* debugger, uint32_t line) {
return debugger_client_request_simple(debugger, DEBUGGER_REQ_REMOVE_BREAK_POINT, line);
}
static ret_t debugger_client_init(debugger_t* debugger, const char* lang, const char* code_id) {
char data[256];
tk_snprintf(data, sizeof(data) - 1, "%s:%s", lang, code_id);
return debugger_client_request_binary(debugger, DEBUGGER_REQ_INIT, data, strlen(data) + 1);
}
static ret_t debugger_client_deinit(debugger_t* debugger) {
return debugger_client_request_simple(debugger, DEBUGGER_REQ_DEINIT, 0);
}
static ret_t debugger_client_update_code(debugger_t* debugger, const binary_data_t* code) {
return debugger_client_request_binary(debugger, DEBUGGER_REQ_UPDATE_CODE, code->data, code->size);
}
static ret_t debugger_client_get_code(debugger_t* debugger, binary_data_t* code) {
if (debugger_client_write_simple(debugger, DEBUGGER_REQ_GET_CODE, 0) == RET_OK) {
return debugger_client_read_binary(debugger, DEBUGGER_RESP_GET_CODE, code);
} else {
return RET_FAIL;
}
}
static const debugger_vtable_t s_debugger_client_vtable = {
.init = debugger_client_init,
.lang = "client",
.lock = debugger_client_lock,
.unlock = debugger_client_unlock,
.stop = debugger_client_stop,
.pause = debugger_client_pause,
.is_paused = debugger_client_is_paused,
.next = debugger_client_next,
.step_in = debugger_client_step_in,
.step_out = debugger_client_step_out,
.step_over = debugger_client_step_over,
.continve = debugger_client_continue,
.get_local = debugger_client_get_local,
.get_self = debugger_client_get_self,
.get_global = debugger_client_get_global,
.get_code = debugger_client_get_code,
.get_callstack = debugger_client_get_callstack,
.update_code = debugger_client_update_code,
.set_break_point = debugger_client_set_break_point,
.remove_break_point = debugger_client_remove_break_point,
.clear_break_points = debugger_client_clear_break_points,
.deinit = debugger_client_deinit,
};
debugger_client_t* debugger_client_cast(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt == &s_debugger_client_vtable, NULL);
return (debugger_client_t*)debugger;
}
static ret_t debugger_client_on_destroy(tk_object_t* obj) {
debugger_client_t* debugger = DEBUGGER_CLIENT(obj);
return_value_if_fail(debugger != NULL, RET_BAD_PARAMS);
TKMEM_FREE(debugger->buff);
TK_OBJECT_UNREF(debugger->io);
return RET_OK;
}
static const object_vtable_t s_object_debugger_client_vtable = {
.type = "object_debugger_client",
.desc = "object_debugger_client",
.size = sizeof(debugger_client_t),
.is_collection = FALSE,
.on_destroy = debugger_client_on_destroy};
debugger_t* debugger_client_create(tk_iostream_t* io) {
debugger_client_t* debugger = NULL;
return_value_if_fail(io != NULL, NULL);
debugger = (debugger_client_t*)tk_object_create(&s_object_debugger_client_vtable);
return_value_if_fail(debugger != NULL, NULL);
debugger->io = io;
TK_OBJECT_REF(debugger->io);
debugger->debugger.vt = &s_debugger_client_vtable;
debugger->capacity = 10 * 1024;
debugger->buff = TKMEM_ALLOC(debugger->capacity);
return (debugger_t*)debugger;
}

View File

@ -0,0 +1,94 @@
/**
* File: debugger_client.h
* Author: AWTK Develop Team
* Brief: debugger_client
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-12 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_DEBUGGER_CLIENT_H
#define TK_DEBUGGER_CLIENT_H
#include "tkc/mem.h"
#include "tkc/iostream.h"
#include "debugger/debugger.h"
BEGIN_C_DECLS
/**
* @class debugger_client_t
*
*
*/
typedef struct _debugger_client_t {
debugger_t debugger;
/**
* @property {tk_iostream_t*} io
* @annotation ["readable"]
* stream对象
*/
tk_iostream_t* io;
/*private*/
/*读取包的缓冲区*/
void* buff;
uint32_t capacity;
/*程序执行完成*/
bool_t program_completed;
} debugger_client_t;
/**
* @method debugger_client_create
*
* @param {tk_iostream_t*} io io对象
*
* @return {debugger_t*} debugger对象
*/
debugger_t* debugger_client_create(tk_iostream_t* io);
/**
* @method debugger_client_cast
*
* @param {debugger_t*} debugger debugger对象
*
* @return {debugger_client_t*} debugger对象
*/
debugger_client_t* debugger_client_cast(debugger_t* debugger);
/**
* @method debugger_client_dispatch
*
* @param {debugger_t*} debugger debugger对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_client_dispatch(debugger_t* debugger);
/**
* @method debugger_client_wait_for_completed
*
* @param {debugger_t*} debugger debugger对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_client_wait_for_completed(debugger_t* debugger);
#define DEBUGGER_CLIENT(debugger) debugger_client_cast((debugger_t*)debugger);
END_C_DECLS
#endif /*TK_DEBUGGER_CLIENT_H*/

View File

@ -0,0 +1,44 @@
/**
* File: debugger_server.h
* Author: AWTK Develop Team
* Brief: debugger server
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-14 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "tkc/socket_helper.h"
#include "streams/inet/iostream_tcp.h"
#include "debugger/debugger_client_tcp.h"
debugger_t* debugger_client_tcp_create(const char* host, uint32_t port) {
int32_t sock = 0;
tk_iostream_t* io = NULL;
debugger_t* debugger = NULL;
return_value_if_fail(host != NULL, NULL);
sock = tk_tcp_connect(host, port);
return_value_if_fail(sock >= 0, NULL);
io = tk_iostream_tcp_create(sock);
if (io != NULL) {
debugger = debugger_client_create(io);
TK_OBJECT_UNREF(io);
} else {
socket_close(sock);
}
return debugger;
}

View File

@ -0,0 +1,50 @@
/**
* File: debugger_client_tcp.h
* Author: AWTK Develop Team
* Brief: debugger client_tcp
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-14 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_DEBUGGER_CLIENT_TCP_H
#define TK_DEBUGGER_CLIENT_TCP_H
#include "tkc/iostream.h"
#include "debugger/debugger.h"
#include "debugger/debugger_client.h"
BEGIN_C_DECLS
/**
* @class debugger_client_tcp_t
* @annotation ["fake"]
* TCP客户端
*
*/
/**
* @method debugger_client_tcp_create
* TCP客户端对象
* @param {const char*} host
* @param {uint32_t} port
*
* @return {debugger_t*} debugger对象
*/
debugger_t* debugger_client_tcp_create(const char* host, uint32_t port);
END_C_DECLS
#endif /*TK_DEBUGGER_CLIENT_TCP_H*/

View File

@ -0,0 +1,33 @@
/**
* File: debugger_const.h
* Author: AWTK Develop Team
* Brief: debugger constant
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-16 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_DEBUGGER_CONST_H
#define TK_DEBUGGER_CONST_H
#define DEBUGGER_VERSION 0x0100
#define STR_DEBUGGER_EVENT_PROP_LINE "line"
#define STR_DEBUGGER_EVENT_PROP_MESSAGE "message"
#define DEBUGGER_IO_READ_TIMEOUT 10000
#define DEBUGGER_IO_WRITE_TIMEOUT 5000
#endif /*TK_DEBUGGER_CONST_H*/

View File

@ -0,0 +1,63 @@
/**
* File: debugger_factory.c
* Author: AWTK Develop Team
* Brief: debugger factory
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-14 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "tkc/general_factory.h"
#include "debugger/debugger_factory.h"
static general_factory_t* s_debugger_factory = NULL;
ret_t debugger_factory_init(void) {
return_value_if_fail(s_debugger_factory == NULL, RET_BAD_PARAMS);
s_debugger_factory = general_factory_create();
return s_debugger_factory != NULL ? RET_OK : RET_FAIL;
}
ret_t debugger_factory_reg(const char* lang, debugger_fscript_create_t create) {
return_value_if_fail(s_debugger_factory != NULL, RET_BAD_PARAMS);
return_value_if_fail(lang != NULL && create != NULL, RET_BAD_PARAMS);
return general_factory_register(s_debugger_factory, lang, (tk_create_t)create);
}
debugger_t* debugger_factory_create_debugger(const char* lang, const char* code_id) {
debugger_t* debugger = NULL;
debugger_fscript_create_t create = NULL;
return_value_if_fail(s_debugger_factory != NULL, NULL);
return_value_if_fail(lang != NULL && code_id != NULL, NULL);
create = (debugger_fscript_create_t)general_factory_find(s_debugger_factory, lang);
return_value_if_fail(create != NULL, NULL);
debugger = create();
return_value_if_fail(debugger != NULL, NULL);
debugger_init(debugger, lang, code_id);
return debugger;
}
ret_t debugger_factory_deinit(void) {
return_value_if_fail(s_debugger_factory != NULL, RET_BAD_PARAMS);
general_factory_destroy(s_debugger_factory);
s_debugger_factory = NULL;
return RET_OK;
}

View File

@ -0,0 +1,73 @@
/**
* File: debugger_factory.h
* Author: AWTK Develop Team
* Brief: debugger factory
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-14 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_DEBUGGER_FACTORY_H
#define TK_DEBUGGER_FACTORY_H
#include "debugger/debugger.h"
BEGIN_C_DECLS
/**
* @class debugger_factory_t
* @annotaion ["fake"]
*
*/
/**
* @method debugger_factory_init
*
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_factory_init(void);
/**
* @method debugger_factory_reg
*
* @param {const char*} lang
* @param {debugger_fscript_create_t} create
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_factory_reg(const char* lang, debugger_fscript_create_t create);
/**
* @method debugger_factory_create_debugger
*
* @param {const char*} lang
* @param {const char*} code_id ID
*
* @return {debugger_t*}
*/
debugger_t* debugger_factory_create_debugger(const char* lang, const char* code_id);
/**
* @method debugger_factory_deinit
*
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_factory_deinit(void);
END_C_DECLS
#endif /*TK_DEBUGGER_FACTORY_H*/

View File

@ -0,0 +1,486 @@
/**
* File: debugger.c
* Author: AWTK Develop Team
* Brief: debugger
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-11 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "debugger/debugger_server.h"
#include "debugger/debugger_message.h"
#include "debugger/debugger_fscript.h"
static ret_t debugger_fscript_lock(debugger_t* debugger) {
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL, RET_BAD_PARAMS);
log_debug("debugger_fscript_lock\n");
return tk_mutex_nest_lock(d->mutex);
}
static ret_t debugger_fscript_unlock(debugger_t* debugger) {
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL, RET_BAD_PARAMS);
log_debug("debugger_fscript_unlock\n");
return tk_mutex_nest_unlock(d->mutex);
}
static ret_t debugger_fscript_stop(debugger_t* debugger) {
ret_t ret = RET_FAIL;
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL, RET_BAD_PARAMS);
if (debugger_fscript_lock(debugger) == RET_OK) {
if (d->fscript != NULL) {
/*TODO*/
}
debugger_fscript_unlock(debugger);
}
return ret;
}
static ret_t debugger_fscript_pause(debugger_t* debugger) {
ret_t ret = RET_FAIL;
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL, RET_BAD_PARAMS);
if (debugger_fscript_lock(debugger) == RET_OK) {
if (d->fscript != NULL && d->paused == FALSE) {
ret = RET_OK;
/*停止到下一行要执行的代码*/
d->next_stop_executed_line = d->executed_lines + 1;
}
ret = d->paused == TRUE ? RET_OK : RET_FAIL;
debugger_fscript_unlock(debugger);
}
return ret;
}
static bool_t debugger_fscript_match(debugger_t* debugger, const char* code_id) {
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL, FALSE);
return tk_str_eq(d->code_id, code_id);
}
static bool_t debugger_fscript_is_paused(debugger_t* debugger) {
bool_t ret = FALSE;
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL, FALSE);
if (debugger_fscript_lock(debugger) == RET_OK) {
ret = d->paused;
debugger_fscript_unlock(debugger);
}
return ret;
}
static ret_t debugger_fscript_next(debugger_t* debugger) {
ret_t ret = RET_FAIL;
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL, RET_BAD_PARAMS);
if (debugger_fscript_lock(debugger) == RET_OK) {
if (d->fscript != NULL && d->paused) {
ret = RET_OK;
d->next_stop_executed_line = d->executed_lines + 1;
}
debugger_fscript_unlock(debugger);
if (ret == RET_OK) {
tk_cond_var_awake(d->cond_var);
}
}
return ret;
}
static ret_t debugger_fscript_step_in(debugger_t* debugger) {
/*TODO*/
return debugger_fscript_next(debugger);
}
static ret_t debugger_fscript_step_out(debugger_t* debugger) {
/*TODO*/
return debugger_fscript_next(debugger);
}
static ret_t debugger_fscript_step_over(debugger_t* debugger) {
/*TODO*/
return debugger_fscript_next(debugger);
}
static ret_t debugger_fscript_continue(debugger_t* debugger) {
ret_t ret = RET_FAIL;
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL, RET_BAD_PARAMS);
if (debugger_fscript_lock(debugger) == RET_OK) {
if (d->fscript != NULL && d->paused) {
ret = RET_OK;
d->next_stop_line = -1;
d->next_stop_executed_line = -1;
}
debugger_fscript_unlock(debugger);
if (ret == RET_OK) {
tk_cond_var_awake(d->cond_var);
}
}
return ret;
}
static ret_t debugger_fscript_get_code(debugger_t* debugger, binary_data_t* code) {
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL && d->fscript != NULL, RET_BAD_PARAMS);
code->data = d->code.str;
code->size = d->code.size + 1;
return RET_OK;
}
tk_object_t* debugger_fscript_get_local(debugger_t* debugger, uint32_t frame_index) {
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL && d->fscript != NULL, NULL);
/*FIXME: 目前只支持当前*/
return TK_OBJECT_REF(d->fscript->locals);
}
tk_object_t* debugger_fscript_get_self(debugger_t* debugger) {
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL && d->fscript != NULL, NULL);
return TK_OBJECT_REF(d->fscript->obj);
}
tk_object_t* debugger_fscript_get_global(debugger_t* debugger) {
return TK_OBJECT_REF(fscript_get_global_object());
}
static ret_t debugger_fscript_get_callstack(debugger_t* debugger, binary_data_t* callstack) {
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL && d->fscript != NULL, RET_BAD_PARAMS);
callstack->data = d->callstack.str;
callstack->size = d->callstack.size + 1;
return RET_OK;
}
static ret_t debugger_fscript_clear_break_points(debugger_t* debugger) {
ret_t ret = RET_FAIL;
bool_t paused = FALSE;
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL, RET_BAD_PARAMS);
if (debugger_fscript_lock(debugger) == RET_OK) {
d->next_stop_line = -1;
d->next_stop_executed_line = -1;
ret = darray_clear(&(d->break_points));
paused = d->paused;
debugger_fscript_unlock(debugger);
}
if (paused) {
tk_cond_var_awake(d->cond_var);
}
return ret;
}
static ret_t debugger_fscript_set_break_point(debugger_t* debugger, uint32_t line) {
ret_t ret = RET_FAIL;
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL, RET_BAD_PARAMS);
if (debugger_fscript_lock(debugger) == RET_OK) {
ret = darray_push_unique(&(d->break_points), tk_pointer_from_int(line));
debugger_fscript_unlock(debugger);
}
return ret;
}
static ret_t debugger_fscript_remove_break_point(debugger_t* debugger, uint32_t line) {
ret_t ret = RET_FAIL;
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL, RET_BAD_PARAMS);
if (debugger_fscript_lock(debugger) == RET_OK) {
ret = darray_remove(&(d->break_points), tk_pointer_from_int(line));
debugger_fscript_unlock(debugger);
}
return ret;
}
static ret_t debugger_fscript_init(debugger_t* debugger, const char* lang, const char* code_id) {
ret_t ret = RET_FAIL;
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL, RET_BAD_PARAMS);
if (debugger_fscript_lock(debugger) == RET_OK) {
ret = RET_OK;
d->code_id = tk_str_copy(d->code_id, code_id);
debugger_fscript_unlock(debugger);
}
return ret;
}
static ret_t debugger_fscript_deinit(debugger_t* debugger) {
debugger_fscript_clear_break_points(debugger);
return RET_OK;
}
static ret_t debugger_fscript_update_code(debugger_t* debugger, const binary_data_t* code) {
ret_t ret = RET_FAIL;
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL, RET_BAD_PARAMS);
if (debugger_fscript_lock(debugger) == RET_OK) {
ret = RET_OK;
str_set_with_len(&(d->code), (char*)(code->data), code->size);
/*TODO*/
debugger_fscript_unlock(debugger);
}
return ret;
}
static const debugger_vtable_t s_debugger_fscript_vtable = {
.lang = DEBUGGER_LANG_FSCRIPT,
.init = debugger_fscript_init,
.lock = debugger_fscript_lock,
.unlock = debugger_fscript_unlock,
.stop = debugger_fscript_stop,
.pause = debugger_fscript_pause,
.match = debugger_fscript_match,
.is_paused = debugger_fscript_is_paused,
.next = debugger_fscript_next,
.step_in = debugger_fscript_step_in,
.step_out = debugger_fscript_step_out,
.step_over = debugger_fscript_step_over,
.continve = debugger_fscript_continue,
.get_local = debugger_fscript_get_local,
.get_self = debugger_fscript_get_self,
.get_global = debugger_fscript_get_global,
.get_callstack = debugger_fscript_get_callstack,
.get_code = debugger_fscript_get_code,
.update_code = debugger_fscript_update_code,
.set_break_point = debugger_fscript_set_break_point,
.remove_break_point = debugger_fscript_remove_break_point,
.clear_break_points = debugger_fscript_clear_break_points,
.deinit = debugger_fscript_deinit,
};
debugger_fscript_t* debugger_fscript_cast(debugger_t* debugger) {
return_value_if_fail(debugger != NULL && debugger->vt == &s_debugger_fscript_vtable, NULL);
return (debugger_fscript_t*)debugger;
}
static ret_t debugger_fscript_on_destroy(tk_object_t* obj) {
debugger_fscript_t* debugger = DEBUGGER_FSCRIPT(obj);
return_value_if_fail(debugger != NULL, RET_BAD_PARAMS);
tk_mutex_nest_destroy(debugger->mutex);
debugger->mutex = NULL;
tk_cond_var_destroy(debugger->cond_var);
debugger->cond_var = NULL;
TKMEM_FREE(debugger->code_id);
str_reset(&(debugger->code));
str_reset(&(debugger->callstack));
darray_deinit(&(debugger->break_points));
return RET_OK;
}
static const object_vtable_t s_object_debugger_fscript_vtable = {
.type = "object_debugger_fscript",
.desc = "object_debugger_fscript",
.size = sizeof(debugger_fscript_t),
.is_collection = FALSE,
.on_destroy = debugger_fscript_on_destroy};
debugger_t* debugger_fscript_create(void) {
debugger_fscript_t* debugger = NULL;
debugger = (debugger_fscript_t*)tk_object_create(&s_object_debugger_fscript_vtable);
return_value_if_fail(debugger != NULL, NULL);
debugger->mutex = tk_mutex_nest_create();
debugger->cond_var = tk_cond_var_create();
debugger->debugger.vt = &s_debugger_fscript_vtable;
str_init(&(debugger->code), 100);
str_init(&(debugger->callstack), 100);
darray_init(&(debugger->break_points), 10, NULL, NULL);
return (debugger_t*)debugger;
}
ret_t debugger_fscript_print_func(fscript_t* fscript, fscript_args_t* args, value_t* result) {
str_t str;
char buff[32];
uint32_t i = 0;
debugger_log_event_t event;
debugger_t* debugger = NULL;
if (fscript != NULL && fscript->code_id != NULL) {
debugger = debugger_server_find_debugger(fscript->code_id);
}
if (debugger != NULL) {
uint32_t line = fscript->curr->row;
value_set_bool(result, TRUE);
str_init(&str, 100);
for (i = 0; i < args->size; i++) {
str_append(&str, value_str_ex(args->args + i, buff, sizeof(buff) - 1));
}
debugger_log_event_init(&event, line, str.str);
emitter_dispatch(EMITTER(debugger), (event_t*)&event);
str_reset(&str);
}
return RET_OK;
}
static ret_t debugger_fscript_on_error(void* ctx, fscript_t* fscript) {
debugger_error_event_t event;
debugger_t* debugger = DEBUGGER(ctx);
debugger_error_event_init(&event, fscript->error_row, fscript->error_message);
emitter_dispatch(EMITTER(debugger), (event_t*)&event);
return RET_OK;
}
ret_t debugger_fscript_set_fscript(debugger_t* debugger, fscript_t* fscript) {
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
return_value_if_fail(d != NULL, RET_BAD_PARAMS);
d->fscript = fscript;
if (fscript) {
d->executed_lines = 0;
d->last_executed_line = 0;
d->next_stop_line = -1;
d->prev_breaked_line = -1;
d->next_stop_executed_line = -1;
str_set(&(d->callstack), "<root>\n");
fscript_set_print_func(fscript, debugger_fscript_print_func);
fscript_set_on_error(fscript, debugger_fscript_on_error, d);
} else {
emitter_dispatch_simple_event(EMITTER(debugger), DEBUGGER_RESP_MSG_COMPLETED);
}
return RET_OK;
}
static ret_t debugger_fscript_before_exec_func(debugger_t* debugger, int32_t line) {
bool_t paused = FALSE;
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
if (debugger_fscript_lock(debugger) == RET_OK) {
bool_t bp = darray_find_index(&(d->break_points), tk_pointer_from_int(line)) >= 0;
d->paused = bp || line == d->next_stop_line || d->executed_lines == d->next_stop_executed_line;
paused = d->paused && (d->prev_breaked_line != line);
if (paused) {
debugger_breaked_event_t event;
debugger_breaked_event_init(&event, line);
emitter_dispatch(EMITTER(debugger), (event_t*)&event);
d->prev_breaked_line = line;
}
debugger_fscript_unlock(debugger);
if (paused) {
log_debug("debugger wait for instruction\n");
tk_cond_var_wait(d->cond_var, 0xffffff);
}
}
return RET_OK;
}
static ret_t debugger_fscript_after_exec_func(debugger_t* debugger, int32_t line) {
debugger_fscript_t* d = DEBUGGER_FSCRIPT(debugger);
if (debugger_fscript_lock(debugger) == RET_OK) {
if (d->last_executed_line != line) {
d->executed_lines++;
}
d->last_executed_line = line;
debugger_fscript_unlock(debugger);
}
return RET_OK;
}
ret_t debugger_fscript_exec_func(fscript_t* fscript, const char* name, fscript_func_call_t* iter,
value_t* result) {
ret_t ret = RET_FAIL;
debugger_t* debugger = NULL;
return_value_if_fail(fscript != NULL, RET_BAD_PARAMS);
if (fscript != NULL && fscript->code_id != NULL) {
debugger = debugger_server_find_debugger(fscript->code_id);
}
if (debugger == NULL) {
return fscript_exec_func_default(fscript, iter, result);
} else {
int32_t line = iter->row;
debugger_fscript_before_exec_func(debugger, line);
ret = fscript_exec_func_default(fscript, iter, result);
debugger_fscript_after_exec_func(debugger, line);
}
return ret;
}
ret_t debugger_fscript_set_var(fscript_t* fscript, const char* name, const value_t* v) {
ret_t ret = RET_FAIL;
debugger_t* debugger = NULL;
return_value_if_fail(fscript != NULL, RET_BAD_PARAMS);
if (fscript != NULL && fscript->code_id != NULL) {
debugger = debugger_server_find_debugger(fscript->code_id);
}
if (debugger == NULL) {
return fscript_set_var_default(fscript, name, v);
} else {
int32_t line = fscript->curr->row;
debugger_fscript_before_exec_func(debugger, line);
ret = fscript_set_var_default(fscript, name, v);
debugger_fscript_after_exec_func(debugger, line);
}
return ret;
}

View File

@ -0,0 +1,97 @@
/**
* File: fscript_debugger_fscript.h
* Author: AWTK Develop Team
* Brief: debugger_fscript for fscript
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-12 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_DEBUGGER_FSCRIPT_H
#define TK_DEBUGGER_FSCRIPT_H
#include "tkc/fscript.h"
#include "tkc/cond_var.h"
#include "tkc/mutex_nest.h"
#include "debugger/debugger.h"
BEGIN_C_DECLS
/**
* @class debugger_fscript_t
* fscript调试器
*
*/
typedef struct _debugger_fscript_t {
debugger_t debugger;
/*private*/
char* code_id;
fscript_t* fscript;
uint32_t last_executed_line;
int32_t next_stop_line;
int32_t prev_breaked_line;
uint32_t executed_lines;
uint32_t next_stop_executed_line;
str_t code;
bool_t paused;
str_t callstack;
tk_mutex_nest_t* mutex;
tk_cond_var_t* cond_var;
darray_t break_points;
} debugger_fscript_t;
/**
* @method debugger_fscript_create
*
*
* @return {debugger_t*} debugger对象
*/
debugger_t* debugger_fscript_create(void);
/**
* @method debugger_fscript_set_fscript
* fscript对象
* @param {debugger_t*} debugger debugger对象
* @param {fscript_t*} fscript
*
* @return {debugger_t*} debugger对象
*/
ret_t debugger_fscript_set_fscript(debugger_t* debugger, fscript_t* fscript);
/**
* @method debugger_fscript_cast
*
* @param {debugger_t*} debugger debugger对象
*
* @return {debugger_fscript_t*} debugger对象
*/
debugger_fscript_t* debugger_fscript_cast(debugger_t* debugger);
#define DEBUGGER_FSCRIPT(debugger) debugger_fscript_cast((debugger_t*)debugger);
#define DEBUGGER_LANG_FSCRIPT "fscript"
/*fscript hooks*/
ret_t debugger_fscript_set_var(fscript_t* fscript, const char* name, const value_t* v);
ret_t debugger_fscript_exec_func(fscript_t* fscript, const char* name, fscript_func_call_t* iter,
value_t* result);
END_C_DECLS
#endif /*TK_DEBUGGER_FSCRIPT_H*/

View File

@ -0,0 +1,95 @@
/**
* File: debugger_global.c
* Author: AWTK Develop Team
* Brief: debugger global
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-12 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "debugger/debugger_fscript.h"
#include "debugger/debugger_factory.h"
#include "debugger/debugger_global.h"
#include "debugger/debugger_server.h"
static ret_t debugger_fscript_on_connect(fscript_t* fscript) {
debugger_t* debugger = NULL;
return_value_if_fail(fscript != NULL, RET_BAD_PARAMS);
if (fscript->code_id == NULL) {
return RET_OK;
}
debugger = debugger_server_find_debugger(fscript->code_id);
if (debugger != NULL) {
debugger_fscript_set_fscript(debugger, fscript);
}
return RET_FAIL;
}
static ret_t debugger_fscript_on_disconnect(fscript_t* fscript) {
debugger_t* debugger = NULL;
return_value_if_fail(fscript != NULL, RET_BAD_PARAMS);
if (fscript->code_id == NULL) {
return RET_OK;
}
debugger = debugger_server_find_debugger(fscript->code_id);
if (debugger != NULL) {
debugger_fscript_set_fscript(debugger, NULL);
}
return RET_FAIL;
}
static ret_t debugger_fscript_on_fscript_init(fscript_t* fscript, const char* code) {
return debugger_fscript_on_connect(fscript);
}
static ret_t debugger_fscript_on_fscript_before_exec(fscript_t* fscript) {
return debugger_fscript_on_connect(fscript);
}
static ret_t debugger_fscript_on_fscript_after_exec(fscript_t* fscript) {
return RET_OK;
}
static ret_t debugger_fscript_on_fscript_deinit(fscript_t* fscript) {
return debugger_fscript_on_disconnect(fscript);
}
static const fscript_hooks_t s_fscript_hooks = {
.on_init = debugger_fscript_on_fscript_init,
.on_deinit = debugger_fscript_on_fscript_deinit,
.set_var = debugger_fscript_set_var,
.exec_func = debugger_fscript_exec_func,
.before_exec = debugger_fscript_on_fscript_before_exec,
.after_exec = debugger_fscript_on_fscript_after_exec,
};
ret_t debugger_global_init(void) {
debugger_factory_init();
debugger_factory_reg(DEBUGGER_LANG_FSCRIPT, debugger_fscript_create);
fscript_set_hooks(&s_fscript_hooks);
return RET_OK;
}
ret_t debugger_global_deinit(void) {
fscript_set_hooks(NULL);
debugger_factory_deinit();
return RET_OK;
}

View File

@ -0,0 +1,53 @@
/**
* File: debugger_global.h
* Author: AWTK Develop Team
* Brief: debugger global
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-12 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_DEBUGGER_GLOBAL_H
#define TK_DEBUGGER_GLOBAL_H
#include "debugger/debugger_fscript.h"
BEGIN_C_DECLS
/**
* @class debugger_global_t
* @annotaion ["fake"]
*
*/
/**
* @method debugger_global_init
*
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_global_init(void);
/**
* @method debugger_global_deinit
*
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_global_deinit(void);
END_C_DECLS
#endif /*TK_DEBUGGER_GLOBAL_H*/

View File

@ -0,0 +1,79 @@
/**
* File: debugger_message.c
* Author: AWTK Develop Team
* Brief: debugger message
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-15 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "debugger/debugger_message.h"
event_t* debugger_log_event_init(debugger_log_event_t* event, uint32_t line, const char* message) {
return_value_if_fail(event != NULL, NULL);
memset(event, 0x00, sizeof(*event));
event->e = event_init(DEBUGGER_RESP_MSG_LOG, NULL);
event->e.size = sizeof(*event);
event->line = line;
event->message = message;
return (event_t*)event;
}
debugger_log_event_t* debugger_log_event_cast(event_t* event) {
return_value_if_fail(event != NULL && event->type == DEBUGGER_RESP_MSG_LOG, NULL);
return_value_if_fail(event->size == sizeof(debugger_log_event_t), NULL);
return (debugger_log_event_t*)event;
}
event_t* debugger_error_event_init(debugger_error_event_t* event, uint32_t line,
const char* message) {
return_value_if_fail(event != NULL, NULL);
memset(event, 0x00, sizeof(*event));
event->e = event_init(DEBUGGER_RESP_MSG_ERROR, NULL);
event->e.size = sizeof(*event);
event->line = line;
event->message = message;
return (event_t*)event;
}
debugger_error_event_t* debugger_error_event_cast(event_t* event) {
return_value_if_fail(event != NULL && event->type == DEBUGGER_RESP_MSG_ERROR, NULL);
return_value_if_fail(event->size == sizeof(debugger_error_event_t), NULL);
return (debugger_error_event_t*)event;
}
event_t* debugger_breaked_event_init(debugger_breaked_event_t* event, uint32_t line) {
return_value_if_fail(event != NULL, NULL);
memset(event, 0x00, sizeof(*event));
event->e = event_init(DEBUGGER_RESP_MSG_BREAKED, NULL);
event->e.size = sizeof(*event);
event->line = line;
return (event_t*)event;
}
debugger_breaked_event_t* debugger_breaked_event_cast(event_t* event) {
return_value_if_fail(event != NULL && event->type == DEBUGGER_RESP_MSG_BREAKED, NULL);
return_value_if_fail(event->size == sizeof(debugger_breaked_event_t), NULL);
return (debugger_breaked_event_t*)event;
}

View File

@ -0,0 +1,447 @@
/**
* File: debugger_message.h
* Author: AWTK Develop Team
* Brief: debugger message
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-12 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_DEBUGGER_MESSAGE_H
#define TK_DEBUGGER_MESSAGE_H
#include "debugger/debugger_fscript.h"
BEGIN_C_DECLS
/**
* @enum debugger_req_type_t
* @prefix DEBUGGER_REQ
*
*/
typedef enum _debugger_req_type_t {
DEBUGGER_REQ_NONE = 0,
/**
* @const DEBUGGER_REQ_INIT
*
*/
DEBUGGER_REQ_INIT,
/**
* @const DEBUGGER_REQ_STOP
*
*/
DEBUGGER_REQ_STOP,
/**
* @const DEBUGGER_REQ_PAUSE
*
*/
DEBUGGER_REQ_PAUSE,
/**
* @const DEBUGGER_REQ_IS_PAUSED
*
*/
DEBUGGER_REQ_IS_PAUSED,
/**
* @const DEBUGGER_REQ_NEXT
*
*/
DEBUGGER_REQ_NEXT,
/**
* @const DEBUGGER_REQ_STEP_IN
*
*/
DEBUGGER_REQ_STEP_IN,
/**
* @const DEBUGGER_REQ_STEP_OUT
* 退
*/
DEBUGGER_REQ_STEP_OUT,
/**
* @const DEBUGGER_REQ_NEXT
*
*/
DEBUGGER_REQ_STEP_OVER,
/**
* @const DEBUGGER_REQ_CONTINUE
*
*/
DEBUGGER_REQ_CONTINUE,
/**
* @const DEBUGGER_REQ_SET_BREAK_POINT
*
*/
DEBUGGER_REQ_SET_BREAK_POINT,
/**
* @const DEBUGGER_REQ_REMOVE_BREAK_POINT
*
*/
DEBUGGER_REQ_REMOVE_BREAK_POINT,
/**
* @const DEBUGGER_REQ_CLEAR_BREAK_POINTS
*
*/
DEBUGGER_REQ_CLEAR_BREAK_POINTS,
/**
* @const DEBUGGER_REQ_GET_SELF
* self对象请求码
*/
DEBUGGER_REQ_GET_SELF,
/**
* @const DEBUGGER_REQ_GET_LOCAL
*
*/
DEBUGGER_REQ_GET_LOCAL,
/**
* @const DEBUGGER_REQ_GET_GLOBAL
* global对象请求码
*/
DEBUGGER_REQ_GET_GLOBAL,
/**
* @const DEBUGGER_REQ_GET_CODE
*
*/
DEBUGGER_REQ_GET_CODE,
/**
* @const DEBUGGER_REQ_GET_CALLSTACK
* callstack请求码
*/
DEBUGGER_REQ_GET_CALLSTACK,
/**
* @const DEBUGGER_REQ_UPDATE_CODE
*
*/
DEBUGGER_REQ_UPDATE_CODE,
/**
* @const DEBUGGER_REQ_DEINIT
*
*/
DEBUGGER_REQ_DEINIT,
} debugger_req_type_t;
/**
* @class debugger_resp_type_t
* @prefix DEBUGGER_RESP
* /
*/
typedef enum _debugger_resp_type_t {
DEBUGGER_RESP_NONE = 0,
/**
* @const DEBUGGER_RESP_INIT
*
*/
DEBUGGER_RESP_INIT = DEBUGGER_REQ_INIT,
/**
* @const DEBUGGER_RESP_STOP
*
*/
DEBUGGER_RESP_STOP = DEBUGGER_REQ_STOP,
/**
* @const DEBUGGER_RESP_IS_PAUSED
*
*/
DEBUGGER_RESP_IS_PAUSED = DEBUGGER_REQ_IS_PAUSED,
/**
* @const DEBUGGER_RESP_PAUSE
*
*/
DEBUGGER_RESP_PAUSE = DEBUGGER_REQ_PAUSE,
/**
* @const DEBUGGER_RESP_NEXT
*
*/
DEBUGGER_RESP_NEXT = DEBUGGER_REQ_NEXT,
/**
* @const DEBUGGER_RESP_STEP_IN
*
*/
DEBUGGER_RESP_STEP_IN = DEBUGGER_REQ_STEP_IN,
/**
* @const DEBUGGER_RESP_STEP_OUT
* 退
*/
DEBUGGER_RESP_STEP_OUT = DEBUGGER_REQ_STEP_OUT,
/**
* @const DEBUGGER_RESP_NEXT
*
*/
DEBUGGER_RESP_STEP_OVER = DEBUGGER_REQ_STEP_OVER,
/**
* @const DEBUGGER_RESP_CONTINUE
*
*/
DEBUGGER_RESP_CONTINUE = DEBUGGER_REQ_CONTINUE,
/**
* @const DEBUGGER_REQ_SET_BREAK_POINT
*
*/
DEBUGGER_RESP_SET_BREAK_POINT = DEBUGGER_REQ_SET_BREAK_POINT,
/**
* @const DEBUGGER_RESP_REMOVE_BREAK_POINT
*
*/
DEBUGGER_RESP_REMOVE_BREAK_POINT = DEBUGGER_REQ_REMOVE_BREAK_POINT,
/**
* @const DEBUGGER_RESP_CLEAR_BREAK_POINTS
*
*/
DEBUGGER_RESP_CLEAR_BREAK_POINTS = DEBUGGER_REQ_CLEAR_BREAK_POINTS,
/**
* @const DEBUGGER_RESP_GET_SELF
* self对象响应码
*/
DEBUGGER_RESP_GET_SELF = DEBUGGER_REQ_GET_SELF,
/**
* @const DEBUGGER_RESP_GET_LOCAL
*
*/
DEBUGGER_RESP_GET_LOCAL = DEBUGGER_REQ_GET_LOCAL,
/**
* @const DEBUGGER_RESP_GET_GLOBAL
* global对象响应码
*/
DEBUGGER_RESP_GET_GLOBAL = DEBUGGER_REQ_GET_GLOBAL,
/**
* @const DEBUGGER_RESP_GET_CODE
*
*/
DEBUGGER_RESP_GET_CODE = DEBUGGER_REQ_GET_CODE,
/**
* @const DEBUGGER_RESP_GET_CALLSTACK
* callstack响应码
*/
DEBUGGER_RESP_GET_CALLSTACK = DEBUGGER_REQ_GET_CALLSTACK,
/**
* @const DEBUGGER_RESP_UPDATE_CODE
*
*/
DEBUGGER_RESP_UPDATE_CODE = DEBUGGER_REQ_UPDATE_CODE,
/**
* @const DEBUGGER_RESP_DEINIT
*
*/
DEBUGGER_RESP_DEINIT = DEBUGGER_REQ_DEINIT,
/**
* @const DEBUGGER_RESP_MSG_LOG
* /
*/
DEBUGGER_RESP_MSG_LOG = 0x1000,
/**
* @const DEBUGGER_RESP_MSG_ERROR
* /
*/
DEBUGGER_RESP_MSG_ERROR,
/**
* @const DEBUGGER_RESP_MSG_BREAKED
* /
*/
DEBUGGER_RESP_MSG_BREAKED,
/**
* @const DEBUGGER_RESP_MSG_COMPLETED
* /
*/
DEBUGGER_RESP_MSG_COMPLETED,
} debugger_resp_type_t;
/**
* @class debugger_req_t
*
*/
typedef struct _debugger_req_t {
/**
* @property {uint32_t} code
* @annotation ["readable"]
*
*/
uint32_t code;
/**
* @property {uint32_t} size
* @annotation ["readable"]
* ()
*/
uint32_t size;
/**
* @property {uint32_t} version
* @annotation ["readable"]
*
*/
uint32_t version;
/**
* @property {uint32_t} data
* @annotation ["readable"]
*
*/
uint32_t data;
} debugger_req_t;
/**
* @class debugger_resp_t
*
*/
typedef struct _debugger_resp_t {
/**
* @property {uint32_t} code
* @annotation ["readable"]
*
*/
uint32_t code;
/**
* @property {uint32_t} error
* @annotation ["readable"]
* (ret_t)
*/
uint32_t error;
/**
* @property {uint32_t} version
* @annotation ["readable"]
*
*/
uint32_t version;
/**
* @property {uint32_t} size
* @annotation ["readable"]
* ()
*/
uint32_t size;
} debugger_resp_t;
/**
* @class debugger_log_event_t
* @parent event_t
*
*/
typedef struct _debugger_log_event_t {
event_t e;
/**
* @property {uint32_t} line
* @annotation ["readable"]
*
*/
uint32_t line;
/**
* @property {const char*} message
* @annotation ["readable"]
*
*/
const char* message;
} debugger_log_event_t;
/**
* @method debugger_log_event_init
*
*
* @param {debugger_log_event_t*} event event对象
* @param {uint32_t} line
* @param {const char*} message
*
* @return {event_t*} event对象
*/
event_t* debugger_log_event_init(debugger_log_event_t* event, uint32_t line, const char* message);
/**
* @method debugger_log_event_cast
* @annotation ["cast"]
*
* event对象转debugger_log_event_t对象
* @param {event_t*} event event对象
*
* @return {debugger_log_event_t*} event对象
*/
debugger_log_event_t* debugger_log_event_cast(event_t* event);
/**
* @class debugger_error_event_t
* @parent event_t
*
*/
typedef struct _debugger_error_event_t {
event_t e;
/**
* @property {uint32_t} line
* @annotation ["readable"]
*
*/
uint32_t line;
/**
* @property {const char*} message
* @annotation ["readable"]
*
*/
const char* message;
} debugger_error_event_t;
/**
* @method debugger_error_event_init
*
*
* @param {debugger_error_event_t*} event event对象
* @param {uint32_t} line
* @param {const char*} message
*
* @return {event_t*} event对象
*/
event_t* debugger_error_event_init(debugger_error_event_t* event, uint32_t line,
const char* message);
/**
* @method debugger_error_event_cast
* @annotation ["cast"]
*
* event对象转debugger_error_event_t对象
* @param {event_t*} event event对象
*
* @return {debugger_error_event_t*} event对象
*/
debugger_error_event_t* debugger_error_event_cast(event_t* event);
/**
* @class debugger_breaked_event_t
* @parent event_t
*
*/
typedef struct _debugger_breaked_event_t {
event_t e;
/**
* @property {uint32_t} line
* @annotation ["readable"]
*
*/
uint32_t line;
} debugger_breaked_event_t;
/**
* @method debugger_breaked_event_init
*
*
* @param {debugger_breaked_event_t*} event event对象
* @param {uint32_t} line
*
* @return {event_t*} event对象
*/
event_t* debugger_breaked_event_init(debugger_breaked_event_t* event, uint32_t line);
/**
* @method debugger_breaked_event_cast
* @annotation ["cast"]
*
* event对象转debugger_breaked_event_t对象
* @param {event_t*} event event对象
*
* @return {debugger_breaked_event_t*} event对象
*/
debugger_breaked_event_t* debugger_breaked_event_cast(event_t* event);
END_C_DECLS
#endif /*TK_DEBUGGER_MESSAGE_H*/

View File

@ -0,0 +1,532 @@
/**
* File: debugger_server.h
* Author: AWTK Develop Team
* Brief: debugger server
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-12 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "tkc/thread.h"
#include "tkc/buffer.h"
#include "tkc/object_default.h"
#include "ubjson/ubjson_writer.h"
#include "debugger/debugger_factory.h"
#include "debugger/debugger_server.h"
#include "debugger/debugger_message.h"
typedef struct _debugger_server_t {
darray_t debuggers;
debugger_t* debugger;
tk_thread_t* thread;
/*等待退出*/
bool_t quiting;
/*退出完成*/
bool_t quited;
/*启动完成*/
bool_t started;
tk_istream_t* in;
tk_ostream_t* out;
tk_iostream_t* io;
tk_mutex_nest_t* mutex;
/*读取数据的缓冲区*/
void* buff;
uint32_t capacity;
} debugger_server_t;
static void* debugger_server_run(void* ctx);
static ret_t debugger_server_send_object(debugger_server_t* server, debugger_resp_t* resp,
tk_object_t* obj);
static debugger_server_t* debugger_server_create(tk_iostream_t* io) {
debugger_server_t* server = TKMEM_ZALLOC(debugger_server_t);
return_value_if_fail(server != NULL, NULL);
assert(io != NULL);
server->io = io;
server->in = tk_iostream_get_istream(io);
server->out = tk_iostream_get_ostream(io);
darray_init(&(server->debuggers), 5, (tk_destroy_t)tk_object_unref, NULL);
server->mutex = tk_mutex_nest_create();
goto_error_if_fail(server->mutex != NULL);
server->thread = tk_thread_create(debugger_server_run, server);
goto_error_if_fail(server->thread != NULL);
tk_thread_start(server->thread);
while (!(server->started)) {
sleep_ms(100);
}
log_debug("debugger_server_thread started\n");
return server;
error:
TK_OBJECT_UNREF(io);
darray_deinit(&(server->debuggers));
TKMEM_FREE(server);
return NULL;
}
static ret_t debugger_server_extend(debugger_server_t* server, uint32_t size) {
ret_t ret = RET_OK;
return_value_if_fail(server != NULL, RET_BAD_PARAMS);
if (server->capacity < size) {
void* buff = TKMEM_REALLOC(server->buff, size);
if (buff != NULL) {
server->buff = buff;
server->capacity = size;
} else {
ret = RET_FAIL;
}
}
return ret;
}
static ret_t debugger_server_write_data(tk_ostream_t* out, const void* data, uint32_t size) {
return tk_ostream_write_len(out, data, size, DEBUGGER_IO_WRITE_TIMEOUT) == size ? RET_OK : RET_IO;
}
static ret_t debugger_server_read_data(tk_istream_t* in, void* data, uint32_t size) {
return tk_istream_read_len(in, data, size, DEBUGGER_IO_READ_TIMEOUT) == size ? RET_OK : RET_IO;
}
static ret_t debugger_server_send_data_impl(tk_ostream_t* out, debugger_resp_t* resp,
binary_data_t* data) {
ret_t ret = RET_FAIL;
resp->version = DEBUGGER_VERSION;
resp->size = data != NULL ? data->size : 0;
ret = debugger_server_write_data(out, resp, sizeof(*resp));
return_value_if_fail(ret == RET_OK, RET_IO);
if (resp->size > 0) {
ret = debugger_server_write_data(out, data->data, data->size);
}
return ret;
}
static ret_t debugger_server_send_data(debugger_server_t* server, debugger_resp_t* resp,
binary_data_t* data) {
ret_t ret = RET_FAIL;
if (tk_mutex_nest_lock(server->mutex) == RET_OK) {
ret = debugger_server_send_data_impl(server->out, resp, data);
tk_mutex_nest_unlock(server->mutex);
}
return ret;
}
static ret_t debugger_server_send_object(debugger_server_t* server, debugger_resp_t* resp,
tk_object_t* obj) {
wbuffer_t wb;
ret_t ret = RET_FAIL;
ubjson_writer_t writer;
binary_data_t data = {0, NULL};
if (obj != NULL) {
return_value_if_fail(wbuffer_init_extendable(&wb) != NULL, RET_OOM);
ubjson_writer_init(&writer, (ubjson_write_callback_t)wbuffer_write_binary, &wb);
ret = ubjson_writer_write_object(&writer, obj);
goto_error_if_fail(ret == RET_OK);
data.data = wb.data;
data.size = wb.cursor;
}
ret = debugger_server_send_data(server, resp, &data);
error:
wbuffer_deinit(&wb);
return ret;
}
static ret_t debugger_server_read_request_impl(debugger_server_t* server, debugger_req_t* req) {
tk_istream_t* in = server->in;
ret_t ret = debugger_server_read_data(in, req, sizeof(*req));
return_value_if_fail(ret == RET_OK, RET_IO);
assert(req->version == DEBUGGER_VERSION);
return_value_if_fail(debugger_server_extend(server, req->size) == RET_OK, RET_OOM);
if (req->size > 0) {
ret = debugger_server_read_data(in, server->buff, req->size);
} else {
ret = RET_OK;
}
return ret;
}
static ret_t debugger_server_read_request(debugger_server_t* server, debugger_req_t* req) {
ret_t ret = tk_istream_wait_for_data(server->in, 500);
if (ret != RET_OK) {
return ret;
}
if (tk_mutex_nest_lock(server->mutex) == RET_OK) {
ret = debugger_server_read_request_impl(server, req);
tk_mutex_nest_unlock(server->mutex);
}
return ret;
}
static debugger_t* debugger_server_find(debugger_server_t* server, const char* code_id) {
uint32_t i = 0;
debugger_t* debugger = NULL;
return_value_if_fail(code_id != NULL, NULL);
return_value_if_fail(server != NULL, NULL);
if (tk_mutex_nest_lock(server->mutex) == RET_OK) {
for (i = 0; i < server->debuggers.size; i++) {
debugger_t* iter = (debugger_t*)darray_get(&(server->debuggers), i);
if (debugger_match(iter, code_id)) {
debugger = iter;
break;
}
}
tk_mutex_nest_unlock(server->mutex);
}
return debugger;
}
static ret_t debugger_server_on_events(void* ctx, event_t* e) {
ret_t ret = RET_OK;
debugger_resp_t msg;
tk_object_t* obj = NULL;
tk_ostream_t* out = NULL;
debugger_t* debugger = DEBUGGER(e->target);
debugger_server_t* server = (debugger_server_t*)ctx;
return_value_if_fail(debugger != NULL && server != NULL, RET_BAD_PARAMS);
out = server->out;
return_value_if_fail(out != NULL, RET_BAD_PARAMS);
obj = object_default_create();
return_value_if_fail(obj != NULL, RET_BAD_PARAMS);
memset(&msg, 0x00, sizeof(msg));
msg.code = e->type;
msg.error = RET_OK;
switch (e->type) {
case DEBUGGER_RESP_MSG_LOG: {
debugger_log_event_t* event = debugger_log_event_cast(e);
tk_object_set_prop_int(obj, STR_DEBUGGER_EVENT_PROP_LINE, event->line);
tk_object_set_prop_str(obj, STR_DEBUGGER_EVENT_PROP_MESSAGE, event->message);
ret = debugger_server_send_object(server, &msg, obj);
break;
}
case DEBUGGER_RESP_MSG_ERROR: {
debugger_error_event_t* event = debugger_error_event_cast(e);
tk_object_set_prop_int(obj, STR_DEBUGGER_EVENT_PROP_LINE, event->line);
tk_object_set_prop_str(obj, STR_DEBUGGER_EVENT_PROP_MESSAGE, event->message);
ret = debugger_server_send_object(server, &msg, obj);
break;
}
case DEBUGGER_RESP_MSG_BREAKED: {
debugger_breaked_event_t* event = debugger_breaked_event_cast(e);
tk_object_set_prop_int(obj, STR_DEBUGGER_EVENT_PROP_LINE, event->line);
ret = debugger_server_send_object(server, &msg, obj);
break;
}
case DEBUGGER_RESP_MSG_COMPLETED: {
debugger_server_send_data(server, &msg, NULL);
break;
}
default: {
log_debug("not supported event:%d\n", (int)(e->type));
break;
}
}
TK_OBJECT_UNREF(obj);
return RET_OK;
}
static ret_t debugger_server_init_debugger(debugger_server_t* server, const char* arg) {
ret_t ret = RET_FAIL;
char lang[TK_NAME_LEN + 1];
const char* code_id = NULL;
return_value_if_fail(server != NULL, RET_BAD_PARAMS);
code_id = strchr(arg, ':');
return_value_if_fail(code_id != NULL, RET_BAD_PARAMS);
tk_strncpy_s(lang, TK_NAME_LEN, arg, code_id - arg);
code_id++;
if (tk_mutex_nest_lock(server->mutex) == RET_OK) {
debugger_t* debugger = debugger_server_find(server, code_id);
if (debugger == NULL) {
debugger = debugger_factory_create_debugger(lang, code_id);
if (debugger != NULL) {
ret = darray_push(&(server->debuggers), debugger);
if (ret != RET_OK) {
OBJECT_UNREF(debugger);
} else {
emitter_on(EMITTER(debugger), DEBUGGER_RESP_MSG_LOG, debugger_server_on_events, server);
emitter_on(EMITTER(debugger), DEBUGGER_RESP_MSG_ERROR, debugger_server_on_events, server);
emitter_on(EMITTER(debugger), DEBUGGER_RESP_MSG_BREAKED, debugger_server_on_events,
server);
emitter_on(EMITTER(debugger), DEBUGGER_RESP_MSG_COMPLETED, debugger_server_on_events,
server);
}
} else {
log_debug("create debugger:%s %s failed\n", lang, code_id);
}
}
if (ret == RET_OK) {
server->debugger = debugger;
}
tk_mutex_nest_unlock(server->mutex);
}
return ret;
}
static ret_t debugger_server_destroy(debugger_server_t* server) {
return_value_if_fail(server != NULL, RET_BAD_PARAMS);
server->quiting = TRUE;
while (!server->quited) {
sleep_ms(100);
}
tk_mutex_nest_destroy(server->mutex);
server->mutex = NULL;
darray_deinit(&(server->debuggers));
tk_thread_destroy(server->thread);
TK_OBJECT_UNREF(server->io);
TKMEM_FREE(server->buff);
TKMEM_FREE(server);
return RET_OK;
}
static ret_t debugger_server_dispatch(debugger_server_t* server) {
ret_t ret = RET_OK;
debugger_req_t req;
debugger_resp_t resp;
debugger_t* debugger = NULL;
server->started = TRUE;
while (!(server->quiting)) {
ret = debugger_server_read_request(server, &req);
if (ret == RET_TIMEOUT) {
continue;
} else if (ret != RET_OK) {
break;
}
resp.size = 0;
resp.code = req.code;
resp.error = RET_OK;
if (req.code == DEBUGGER_REQ_INIT) {
resp.error = debugger_server_init_debugger(server, (const char*)(server->buff));
break_if_fail(debugger_server_send_data(server, &resp, NULL) == RET_OK);
continue;
}
if (server->debugger == NULL) {
resp.error = RET_NOT_FOUND;
break_if_fail(debugger_server_send_data(server, &resp, NULL) == RET_OK);
continue;
}
debugger = server->debugger;
switch (req.code) {
case DEBUGGER_REQ_STOP: {
resp.error = debugger_stop(debugger);
break;
}
case DEBUGGER_REQ_PAUSE: {
resp.error = debugger_pause(debugger);
break;
}
case DEBUGGER_REQ_IS_PAUSED: {
resp.error = debugger_is_paused(debugger) ? RET_OK : RET_FAIL;
break;
}
case DEBUGGER_REQ_NEXT: {
resp.error = debugger_next(debugger);
break;
}
case DEBUGGER_REQ_STEP_IN: {
resp.error = debugger_step_in(debugger);
break;
}
case DEBUGGER_REQ_STEP_OUT: {
resp.error = debugger_step_out(debugger);
break;
}
case DEBUGGER_REQ_STEP_OVER: {
resp.error = debugger_step_over(debugger);
break;
}
case DEBUGGER_REQ_CONTINUE: {
resp.error = debugger_continue(debugger);
break;
}
case DEBUGGER_REQ_SET_BREAK_POINT: {
resp.error = debugger_set_break_point(debugger, req.data);
break;
}
case DEBUGGER_REQ_REMOVE_BREAK_POINT: {
resp.error = debugger_remove_break_point(debugger, req.data);
break;
}
case DEBUGGER_REQ_CLEAR_BREAK_POINTS: {
resp.error = debugger_clear_break_points(debugger);
break;
}
case DEBUGGER_REQ_GET_SELF: {
if (debugger_lock(debugger) == RET_OK) {
tk_object_t* obj = debugger_get_self(debugger);
ret = debugger_server_send_object(server, &resp, obj);
TK_OBJECT_UNREF(obj);
debugger_unlock(debugger);
goto_error_if_fail(ret == RET_OK);
continue;
}
break;
}
case DEBUGGER_REQ_GET_LOCAL: {
if (debugger_lock(debugger) == RET_OK) {
tk_object_t* obj = debugger_get_local(debugger, req.data);
ret = debugger_server_send_object(server, &resp, obj);
TK_OBJECT_UNREF(obj);
debugger_unlock(debugger);
goto_error_if_fail(ret == RET_OK);
continue;
}
break;
}
case DEBUGGER_REQ_GET_GLOBAL: {
if (debugger_lock(debugger) == RET_OK) {
tk_object_t* obj = debugger_get_global(debugger);
ret = debugger_server_send_object(server, &resp, obj);
TK_OBJECT_UNREF(obj);
debugger_unlock(debugger);
goto_error_if_fail(ret == RET_OK);
continue;
}
break;
}
case DEBUGGER_REQ_GET_CODE: {
binary_data_t data = {0, NULL};
if (debugger_lock(debugger) == RET_OK) {
resp.error = debugger_get_code(debugger, &data);
ret = debugger_server_send_data(server, &resp, &data);
debugger_unlock(debugger);
goto_error_if_fail(ret == RET_OK);
}
continue;
}
case DEBUGGER_REQ_GET_CALLSTACK: {
binary_data_t data = {0, NULL};
if (debugger_lock(debugger) == RET_OK) {
resp.error = debugger_get_callstack(debugger, &data);
ret = debugger_server_send_data(server, &resp, &data);
debugger_unlock(debugger);
goto_error_if_fail(ret == RET_OK);
}
continue;
}
case DEBUGGER_REQ_UPDATE_CODE: {
binary_data_t code = {req.size, server->buff};
resp.error = debugger_update_code(debugger, &code);
break;
}
case DEBUGGER_REQ_DEINIT: {
resp.error = debugger_deinit(debugger);
break;
}
default: {
log_debug("not supported code:%u\n", req.code);
resp.error = RET_NOT_IMPL;
break;
}
}
break_if_fail(debugger_server_send_data(server, &resp, NULL) == RET_OK);
if (req.code == DEBUGGER_REQ_DEINIT) {
log_debug("quit because deinit\n");
break;
}
}
error:
server->quited = TRUE;
return RET_OK;
}
static void* debugger_server_run(void* ctx) {
debugger_server_dispatch((debugger_server_t*)ctx);
return NULL;
}
static debugger_server_t* s_debugger_server = NULL;
ret_t debugger_server_start(tk_iostream_t* io) {
debugger_server_t* server = NULL;
return_value_if_fail(io != NULL && s_debugger_server == NULL, RET_BAD_PARAMS);
server = debugger_server_create(io);
return_value_if_fail(server != NULL, RET_BAD_PARAMS);
s_debugger_server = server;
return RET_OK;
}
ret_t debugger_server_stop(void) {
return_value_if_fail(s_debugger_server != NULL, RET_BAD_PARAMS);
debugger_server_destroy(s_debugger_server);
s_debugger_server = NULL;
return RET_OK;
}
debugger_t* debugger_server_find_debugger(const char* code_id) {
debugger_server_t* server = s_debugger_server;
return_value_if_fail(code_id != NULL, NULL);
return debugger_server_find(server, code_id);
}
bool_t debugger_server_is_running(void) {
return s_debugger_server != NULL;
}

View File

@ -0,0 +1,72 @@
/**
* File: debugger_server.h
* Author: AWTK Develop Team
* Brief: debugger server
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-12 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_DEBUGGER_SERVER_H
#define TK_DEBUGGER_SERVER_H
#include "tkc/iostream.h"
#include "debugger/debugger.h"
BEGIN_C_DECLS
/**
* @class debugger_server_t
* @annotaion ["fake"]
*
*/
/**
* @method debugger_server_start
*
* @param {tk_iostream_t*} io IO对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_server_start(tk_iostream_t* io);
/**
* @method debugger_server_stop
*
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_server_stop(void);
/**
* @method debugger_server_is_running
*
*
* @return {bool_t} TRUE表示在运行
*/
bool_t debugger_server_is_running(void);
/**
* @method debugger_server_find_debugger
*
* @param {const char*} code_id ID
*
* @return {debugger_t*} debugger对象或者NULL
*/
debugger_t* debugger_server_find_debugger(const char* code_id);
END_C_DECLS
#endif /*TK_DEBUGGER_SERVER_H*/

View File

@ -0,0 +1,67 @@
/**
* File: debugger_server.h
* Author: AWTK Develop Team
* Brief: debugger server
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-14 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "tkc/socket_helper.h"
#include "streams/inet/iostream_tcp.h"
#include "debugger/debugger_server_tcp.h"
static int s_server_sock = -1;
ret_t debugger_server_tcp_init(uint32_t port) {
int sock = -1;
return_value_if_fail(!debugger_server_is_running(), RET_BAD_PARAMS);
sock = tk_tcp_listen(port);
return_value_if_fail(sock >= 0, RET_BAD_PARAMS);
s_server_sock = sock;
return RET_OK;
}
ret_t debugger_server_tcp_start(void) {
int sock = -1;
return_value_if_fail(s_server_sock >= 0, RET_BAD_PARAMS);
return_value_if_fail(!debugger_server_is_running(), RET_BAD_PARAMS);
sock = tk_tcp_accept(s_server_sock);
if (sock >= 0) {
tk_iostream_t* io = tk_iostream_tcp_create(sock);
if (io != NULL) {
debugger_server_start(io);
} else {
log_warn("tk_iostream_tcp_create failed\n");
}
} else {
log_warn("tk_tcp_accept failed\n");
}
return RET_OK;
}
ret_t debugger_server_tcp_deinit(void) {
return_value_if_fail(s_server_sock >= 0, RET_BAD_PARAMS);
socket_close(s_server_sock);
s_server_sock = -1;
debugger_server_stop();
return RET_OK;
}

View File

@ -0,0 +1,64 @@
/**
* File: debugger_server_tcp.h
* Author: AWTK Develop Team
* Brief: debugger server_tcp
*
* Copyright (c) 2022 - 2022 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2022-01-14 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_DEBUGGER_SERVER_TCP_H
#define TK_DEBUGGER_SERVER_TCP_H
#include "tkc/iostream.h"
#include "debugger/debugger.h"
#include "debugger/debugger_server.h"
BEGIN_C_DECLS
/**
* @class debugger_server_tcp_t
* TCP服务端
*
*/
/**
* @method debugger_server_tcp_init
*
* @param {uint32_t} port
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_server_tcp_init(uint32_t port);
/**
* @method debugger_server_tcp_start
*
* >
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_server_tcp_start(void);
/**
* @method debugger_server_tcp_deinit
*
*
* @return {ret_t} RET_OK表示成功
*/
ret_t debugger_server_tcp_deinit(void);
END_C_DECLS
#endif /*TK_DEBUGGER_SERVER_TCP_H*/

View File

@ -325,13 +325,13 @@ static ret_t func_flow_get(fscript_t* fscript, fscript_args_t* args, value_t* re
const char* subname = NULL;
FSCRIPT_FUNC_CHECK(args->size >= 2, RET_BAD_PARAMS);
type = value_str(args->args);
subname = value_str(args->args+1);
subname = value_str(args->args + 1);
FSCRIPT_FUNC_CHECK(name != NULL && subname != NULL, RET_BAD_PARAMS);
tk_snprintf(name, sizeof(name)-1, "%s.%s", type, subname);
tk_snprintf(name, sizeof(name) - 1, "%s.%s", type, subname);
if (tk_object_get_prop(fscript->obj, name, result) != RET_OK) {
if(args->size > 2) {
value_copy(result, args->args+2);
if (args->size > 2) {
value_copy(result, args->args + 2);
} else {
result->type = VALUE_TYPE_INVALID;
}
@ -346,10 +346,10 @@ static ret_t func_flow_set(fscript_t* fscript, fscript_args_t* args, value_t* re
const char* subname = NULL;
FSCRIPT_FUNC_CHECK(args->size == 3, RET_BAD_PARAMS);
type = value_str(args->args);
subname = value_str(args->args+1);
subname = value_str(args->args + 1);
FSCRIPT_FUNC_CHECK(name != NULL && subname != NULL, RET_BAD_PARAMS);
tk_snprintf(name, sizeof(name)-1, "%s.%s", type, subname);
tk_snprintf(name, sizeof(name) - 1, "%s.%s", type, subname);
value_set_bool(result, tk_object_set_prop(fscript->obj, name, args->args + 2) == RET_OK);
return RET_OK;

View File

@ -242,7 +242,7 @@ static ret_t func_is_positive(fscript_t* fscript, fscript_args_t* args, value_t*
}
static ret_t func_random0to1(fscript_t* fscript, fscript_args_t* args, value_t* result) {
double v = (double)(random()%100000)/100000.0f;
double v = (double)(random() % 100000) / 100000.0f;
value_set_double(result, v);

View File

@ -27,6 +27,13 @@
#define STR_GLOBAL_PREFIX "global."
#define GLOBAL_PREFIX_LEN 7
static const fscript_hooks_t* s_hooks;
ret_t fscript_set_hooks(const fscript_hooks_t* hooks) {
s_hooks = hooks;
return RET_OK;
}
static ret_t func_function_def(fscript_t* fscript, fscript_args_t* args, value_t* result) {
return RET_OK;
}
@ -64,9 +71,17 @@ static ret_t func_return(fscript_t* fscript, fscript_args_t* args, value_t* resu
static ret_t func_get(fscript_t* fscript, fscript_args_t* args, value_t* result);
static ret_t func_set(fscript_t* fscript, fscript_args_t* args, value_t* result);
static ret_t func_unset(fscript_t* fscript, fscript_args_t* args, value_t* result);
static ret_t fscript_exec_func(fscript_t* fscript, fscript_func_call_t* iter, value_t* result);
static ret_t func_set_local(fscript_t* fscript, fscript_args_t* args, value_t* result);
static ret_t fscript_exec_func(fscript_t* fscript, const char* name, fscript_func_call_t* iter,
value_t* result) {
if (s_hooks != NULL && s_hooks->exec_func != NULL) {
return s_hooks->exec_func(fscript, name, iter, result);
} else {
return fscript_exec_func_default(fscript, iter, result);
}
}
ret_t fscript_set_error(fscript_t* fscript, ret_t code, const char* func, const char* message) {
fscript->error_code = code;
fscript->error_func = fscript->curr;
@ -93,6 +108,14 @@ ret_t fscript_set_on_error(fscript_t* fscript, fscript_on_error_t on_error, void
return RET_OK;
}
ret_t fscript_set_print_func(fscript_t* fscript, fscript_func_t print) {
return_value_if_fail(fscript != NULL, RET_BAD_PARAMS);
fscript->print = print;
return RET_OK;
}
static value_t* value_set_func(value_t* v, fscript_func_call_t* func) {
value_set_pointer(v, func);
v->type = VALUE_TYPE_FSCRIPT_FUNC;
@ -193,14 +216,17 @@ static ret_t fscript_func_call_destroy(fscript_func_call_t* call) {
}
typedef struct _fscript_function_def_t {
char* name;
darray_t params;
fscript_func_call_t* body;
} fscript_function_def_t;
static fscript_function_def_t* fscript_function_def_create(fscript_func_call_t* body) {
static fscript_function_def_t* fscript_function_def_create(const char* name,
fscript_func_call_t* body) {
fscript_function_def_t* func = TKMEM_ZALLOC(fscript_function_def_t);
return_value_if_fail(func != NULL, NULL);
func->body = body;
func->name = tk_strdup(name);
darray_init(&(func->params), 3, default_destroy, NULL);
return func;
}
@ -209,6 +235,7 @@ static ret_t fscript_function_def_destroy(fscript_function_def_t* func) {
return_value_if_fail(func != NULL, RET_BAD_PARAMS);
darray_deinit(&(func->params));
fscript_func_call_destroy(func->body);
TKMEM_FREE(func->name);
memset(func, 0x00, sizeof(fscript_function_def_t));
TKMEM_FREE(func);
@ -288,7 +315,7 @@ static ret_t fscript_get_var(fscript_t* fscript, const char* name, value_t* valu
return tk_object_get_prop(fscript->obj, name, value);
}
static ret_t fscript_set_var(fscript_t* fscript, const char* name, const value_t* value) {
ret_t fscript_set_var_default(fscript_t* fscript, const char* name, const value_t* value) {
value_t v;
ret_t ret = RET_FAIL;
@ -305,6 +332,14 @@ static ret_t fscript_set_var(fscript_t* fscript, const char* name, const value_t
return ret;
}
ret_t fscript_set_var(fscript_t* fscript, const char* name, const value_t* value) {
if (s_hooks != NULL && s_hooks->set_var != NULL) {
return s_hooks->set_var(fscript, name, value);
} else {
return fscript_set_var_default(fscript, name, value);
}
}
static ret_t fscript_eval_arg(fscript_t* fscript, fscript_func_call_t* iter, uint32_t i,
value_t* d) {
value_t v;
@ -352,7 +387,7 @@ static ret_t fscript_eval_arg(fscript_t* fscript, fscript_func_call_t* iter, uin
}
}
} else if (s->type == VALUE_TYPE_FSCRIPT_FUNC) {
fscript_exec_func(fscript, value_func(s), d);
fscript_exec_func(fscript, NULL, value_func(s), d);
} else {
value_copy(d, s);
}
@ -603,7 +638,7 @@ static ret_t fscript_exec_ext_func(fscript_t* fscript, fscript_func_call_t* iter
return ret;
}
static ret_t fscript_exec_func(fscript_t* fscript, fscript_func_call_t* iter, value_t* result) {
ret_t fscript_exec_func_default(fscript_t* fscript, fscript_func_call_t* iter, value_t* result) {
fscript->curr = iter;
result->type = VALUE_TYPE_INVALID;
if (fscript_exec_core_func(fscript, iter, result) == RET_NOT_FOUND) {
@ -617,12 +652,16 @@ ret_t fscript_exec(fscript_t* fscript, value_t* result) {
fscript_func_call_t* iter = NULL;
return_value_if_fail(fscript != NULL, RET_FAIL);
if (s_hooks != NULL && s_hooks->before_exec != NULL) {
s_hooks->before_exec(fscript);
}
value_set_str(result, NULL);
iter = fscript->first;
while (iter != NULL) {
return_value_if_fail(iter->func != NULL, RET_FAIL);
value_reset(result);
return_value_if_fail(fscript_exec_func(fscript, iter, result) == RET_OK, RET_FAIL);
return_value_if_fail(fscript_exec_func(fscript, NULL, iter, result) == RET_OK, RET_FAIL);
if (fscript->returned) {
fscript->returned = FALSE;
break;
@ -630,6 +669,10 @@ ret_t fscript_exec(fscript_t* fscript, value_t* result) {
iter = iter->next;
}
if (s_hooks != NULL && s_hooks->after_exec != NULL) {
s_hooks->after_exec(fscript);
}
return RET_OK;
}
@ -643,6 +686,10 @@ static ret_t on_free_func_def(void* ctx, const void* data) {
ret_t fscript_destroy(fscript_t* fscript) {
return_value_if_fail(fscript != NULL, RET_FAIL);
if (s_hooks != NULL && s_hooks->on_deinit != NULL) {
s_hooks->on_deinit(fscript);
}
str_reset(&(fscript->str));
TK_OBJECT_UNREF(fscript->locals);
if (fscript->funcs_def != NULL) {
@ -1559,6 +1606,11 @@ fscript_t* fscript_create_impl(fscript_parser_t* parser) {
fscript->first = parser->first;
fscript->funcs_def = parser->funcs_def;
fscript->code_id = parser->code_id;
fscript->lines = parser->row + 1;
if (s_hooks != NULL && s_hooks->on_init != NULL) {
s_hooks->on_init(fscript, parser->str);
}
parser->obj = NULL;
parser->first = NULL;
@ -1588,7 +1640,7 @@ static ret_t func_function(fscript_t* fscript, fscript_args_t* args, value_t* re
}
}
ret = fscript_exec_func(fscript, func, result);
ret = fscript_exec_func(fscript, func_def->name, func, result);
TK_OBJECT_UNREF(fscript->locals);
fscript->locals = saved_locals;
@ -1617,7 +1669,7 @@ static ret_t fscript_parse_function_def(fscript_parser_t* parser, fscript_func_c
statements = fscript_func_call_create(parser, "func", 4);
return_value_if_fail(statements != NULL, RET_OOM);
func_def = fscript_function_def_create(statements);
func_def = fscript_function_def_create(func_name, statements);
return_value_if_fail(func_def != NULL, RET_OOM);
tk_object_set_prop_pointer(parser->funcs_def, func_name, func_def);
@ -2029,22 +2081,20 @@ static ret_t func_expr(fscript_t* fscript, fscript_args_t* args, value_t* result
}
static ret_t func_print(fscript_t* fscript, fscript_args_t* args, value_t* result) {
fscript_func_t func = NULL;
func =
(fscript_func_t)tk_object_get_prop_pointer(fscript->obj, STR_FSCRIPT_FUNCTION_PREFIX "print");
uint32_t i = 0;
char buff[64];
if (func != NULL) {
return func(fscript, args, result);
} else {
uint32_t i = 0;
char buff[64];
value_set_bool(result, TRUE);
for (i = 0; i < args->size; i++) {
log_info("%s ", value_str_ex(args->args + i, buff, sizeof(buff) - 1));
}
log_info("\n");
return RET_OK;
value_set_bool(result, TRUE);
for (i = 0; i < args->size; i++) {
log_info("%s ", value_str_ex(args->args + i, buff, sizeof(buff) - 1));
}
log_info("\n");
if (fscript->print != NULL) {
return fscript->print(fscript, args, result);
}
return RET_OK;
}
static ret_t func_iformat(fscript_t* fscript, fscript_args_t* args, value_t* result) {

View File

@ -135,7 +135,6 @@ struct _fscript_t {
*
*/
tk_object_t* obj;
/**
* @property {ret_t} error_code
* @annotation ["readable"]
@ -160,6 +159,12 @@ struct _fscript_t {
*
*/
int32_t error_col;
/**
* @property {uint16_t} lines
* @annotation ["readable"]
*
*/
uint16_t lines;
/*private*/
char* code_id;
@ -178,6 +183,7 @@ struct _fscript_t {
void* on_error_ctx;
fscript_on_error_t on_error;
fscript_func_t print;
};
/**
@ -253,6 +259,16 @@ ret_t fscript_set_error(fscript_t* fscript, ret_t code, const char* func, const
*/
ret_t fscript_set_on_error(fscript_t* fscript, fscript_on_error_t on_error, void* ctx);
/**
* @method fscript_set_print_func
*
* @param {fscript_t*} fscript
* @param {fscript_func_t} print_func
*
* @return {ret_t} RET_OK表示成功
*/
ret_t fscript_set_print_func(fscript_t* fscript, fscript_func_t print);
/**
* @method fscript_destroy
*
@ -386,6 +402,28 @@ static inline const char* value_id(const value_t* v) {
return (const char*)(v->value.str);
}
typedef ret_t (*fscript_on_init_t)(fscript_t* fscript, const char* code);
typedef ret_t (*fscript_on_deinit_t)(fscript_t* fscript);
typedef ret_t (*fscript_before_exec_t)(fscript_t* fscript);
typedef ret_t (*fscript_after_exec_t)(fscript_t* fscript);
typedef ret_t (*fscript_set_var_t)(fscript_t* fscript, const char* name, const value_t* v);
typedef ret_t (*fscript_exec_func_t)(fscript_t* fscript, const char* name,
fscript_func_call_t* iter, value_t* result);
ret_t fscript_set_var_default(fscript_t* fscript, const char* name, const value_t* value);
ret_t fscript_exec_func_default(fscript_t* fscript, fscript_func_call_t* iter, value_t* result);
typedef struct _fscript_hooks_t {
fscript_on_init_t on_init;
fscript_on_deinit_t on_deinit;
fscript_set_var_t set_var;
fscript_exec_func_t exec_func;
fscript_before_exec_t before_exec;
fscript_after_exec_t after_exec;
} fscript_hooks_t;
ret_t fscript_set_hooks(const fscript_hooks_t* hooks);
END_C_DECLS
#endif /*TK_FSCRIPTS_H*/

View File

@ -195,11 +195,11 @@ void awtk_ios_log(const char* message, ...);
#define log_debug(format, args...) \
if (log_get_log_level() <= LOG_LEVEL_DEBUG) printf(format, ##args); \
fflush(stdout)
#define log_info(format, args...) \
if (log_get_log_level() <= LOG_LEVEL_INFO) printf(format, ##args); \
#define log_info(format, args...) \
if (log_get_log_level() <= LOG_LEVEL_INFO) printf(format, ##args); \
fflush(stdout)
#define log_warn(format, args...) \
if (log_get_log_level() <= LOG_LEVEL_WARN) printf(format, ##args); \
#define log_warn(format, args...) \
if (log_get_log_level() <= LOG_LEVEL_WARN) printf(format, ##args); \
fflush(stdout)
#define log_error(format, args...) \
if (log_get_log_level() <= LOG_LEVEL_ERROR) printf(format, ##args); \

View File

@ -5,7 +5,7 @@ cp -fv ../tkc/tools/idl_gen/* tools/idl_gen/.
rm -f tools/dll_def_gen/package-lock.json
cp -rvf ../tkc/awtk_config_common.py .
for f in tkc.h compressors fscript_ext platforms conf_io hal streams ubjson charset csv misc tkc xml
for f in tkc.h compressors fscript_ext platforms conf_io hal streams ubjson charset csv misc tkc xml debugger
do
cp -rvf ../tkc/src/$f src
done

View File

@ -191,24 +191,41 @@ TEST(DateTime, fscript_object) {
value_t v1;
tk_object_t* obj = object_default_create();
fscript_eval(obj, "a=date_time_create();date_time_set_prop(a,\"year\",2050);b=date_time_get_prop(a,\"year\");b", &v1);
fscript_eval(
obj,
"a=date_time_create();date_time_set_prop(a,\"year\",2050);b=date_time_get_prop(a,\"year\");b",
&v1);
ASSERT_EQ(value_int(&v1), 2050);
fscript_eval(obj, "a=date_time_create();date_time_set_prop(a,\"month\",10);b=date_time_get_prop(a,\"month\");b", &v1);
fscript_eval(
obj,
"a=date_time_create();date_time_set_prop(a,\"month\",10);b=date_time_get_prop(a,\"month\");b",
&v1);
ASSERT_EQ(value_int(&v1), 10);
fscript_eval(obj, "a=date_time_create();date_time_set_prop(a,\"day\",11);b=date_time_get_prop(a,\"day\");b", &v1);
fscript_eval(
obj,
"a=date_time_create();date_time_set_prop(a,\"day\",11);b=date_time_get_prop(a,\"day\");b",
&v1);
ASSERT_EQ(value_int(&v1), 11);
fscript_eval(obj, "a=date_time_create();date_time_set_prop(a,\"hour\",8);b=date_time_get_prop(a,\"hour\");b", &v1);
ASSERT_EQ(value_int(&v1), 8);
fscript_eval(obj, "a=date_time_create();date_time_set_prop(a,\"minute\",9);b=date_time_get_prop(a,\"minute\");b", &v1);
ASSERT_EQ(value_int(&v1), 9);
fscript_eval(obj, "a=date_time_create();date_time_set_prop(a,\"second\",5);b=date_time_get_prop(a,\"second\");b", &v1);
ASSERT_EQ(value_int(&v1), 5);
fscript_eval(
obj,
"a=date_time_create();date_time_set_prop(a,\"hour\",8);b=date_time_get_prop(a,\"hour\");b",
&v1);
ASSERT_EQ(value_int(&v1), 8);
fscript_eval(obj,
"a=date_time_create();date_time_set_prop(a,\"minute\",9);b=date_time_get_prop(a,"
"\"minute\");b",
&v1);
ASSERT_EQ(value_int(&v1), 9);
fscript_eval(obj,
"a=date_time_create();date_time_set_prop(a,\"second\",5);b=date_time_get_prop(a,"
"\"second\");b",
&v1);
ASSERT_EQ(value_int(&v1), 5);
TK_OBJECT_UNREF(obj);
}

432
tests/debugger_test.cc Normal file
View File

@ -0,0 +1,432 @@
#include "debugger/debugger_fscript.h"
#include "debugger/debugger_global.h"
#include "debugger/debugger_server.h"
#include "debugger/debugger_message.h"
#include "debugger/debugger_server_tcp.h"
#include "debugger/debugger_client_tcp.h"
#include "tkc/fscript.h"
#include "tkc/thread.h"
#include "tkc/object_default.h"
#include "gtest/gtest.h"
#define DEBUGGER_TCP_PORT 8080
static void* fscript_thread_entry(void* args) {
value_t v;
fscript_t* fscript = (fscript_t*)args;
fscript_exec(fscript, &v);
fscript_destroy(fscript);
return NULL;
}
static ret_t on_debugger_client_event(void* ctx, event_t* e) {
str_t* str = (str_t*)ctx;
switch (e->type) {
case DEBUGGER_RESP_MSG_BREAKED: {
debugger_breaked_event_t* event = debugger_breaked_event_cast(e);
str_append(str, "breaked");
str_append(str, "(");
str_append_int(str, event->line);
str_append(str, ")");
break;
}
case DEBUGGER_RESP_MSG_LOG: {
debugger_log_event_t* event = debugger_log_event_cast(e);
str_append(str, "log");
str_append(str, "(");
str_append_int(str, event->line);
str_append(str, ",\"");
str_append(str, event->message);
str_append(str, "\")");
break;
}
case DEBUGGER_RESP_MSG_ERROR: {
debugger_error_event_t* event = debugger_error_event_cast(e);
str_append(str, "error");
str_append(str, "(");
str_append_int(str, event->line);
str_append(str, ",\"");
str_append(str, event->message);
str_append(str, "\")");
break;
}
case DEBUGGER_RESP_MSG_COMPLETED: {
str_append(str, "completed()");
}
default:
break;
}
return RET_OK;
}
TEST(Debugger, event1) {
const char* code =
"print(1)\nprint(2)\nprint(3)\n//"
"code_id(\"85e86311e2d595c65b745d8143b6085efe819c354584742f72aeacd3336a0a5e\")";
str_t str;
str_init(&str, 100);
debugger_global_init();
tk_object_t* obj = object_default_create();
fscript_t* fscript = fscript_create(obj, code);
tk_thread_t* thread = tk_thread_create(fscript_thread_entry, fscript);
debugger_server_tcp_init(DEBUGGER_TCP_PORT);
debugger_t* client = debugger_client_tcp_create("localhost", DEBUGGER_TCP_PORT);
ASSERT_EQ(client != NULL, TRUE);
emitter_on(EMITTER(client), DEBUGGER_RESP_MSG_BREAKED, on_debugger_client_event, &str);
emitter_on(EMITTER(client), DEBUGGER_RESP_MSG_LOG, on_debugger_client_event, &str);
emitter_on(EMITTER(client), DEBUGGER_RESP_MSG_ERROR, on_debugger_client_event, &str);
emitter_on(EMITTER(client), DEBUGGER_RESP_MSG_COMPLETED, on_debugger_client_event, &str);
debugger_server_tcp_start();
ASSERT_EQ(debugger_init(client, DEBUGGER_LANG_FSCRIPT, fscript->code_id), RET_OK);
ASSERT_EQ(debugger_set_break_point(client, 0), RET_OK);
tk_thread_start(thread);
sleep_ms(500);
debugger_t* debugger = debugger_server_find_debugger(fscript->code_id);
ASSERT_EQ(debugger_is_paused(debugger), TRUE);
ASSERT_EQ(debugger_is_paused(client), TRUE);
ASSERT_EQ(debugger_continue(client), RET_OK);
ASSERT_EQ(debugger_clear_break_points(client), RET_OK);
debugger_client_wait_for_completed(client);
tk_thread_join(thread);
tk_thread_destroy(thread);
TK_OBJECT_UNREF(obj);
TK_OBJECT_UNREF(client);
debugger_server_tcp_deinit();
debugger_global_deinit();
ASSERT_STREQ(str.str, "breaked(0)log(0,\"1\")log(1,\"2\")log(2,\"3\")completed()");
str_reset(&str);
}
#if 1
TEST(Debugger, event2) {
const char* code =
"print(1)\nprint(2)\nprint(3)\n//"
"code_id(\"85e86311e2d595c65b745d8143b6085efe819c354584742f72aeacd3336a0a5e\")";
str_t str;
str_init(&str, 100);
debugger_global_init();
tk_object_t* obj = object_default_create();
fscript_t* fscript = fscript_create(obj, code);
tk_thread_t* thread = tk_thread_create(fscript_thread_entry, fscript);
debugger_server_tcp_init(DEBUGGER_TCP_PORT);
debugger_t* client = debugger_client_tcp_create("localhost", DEBUGGER_TCP_PORT);
ASSERT_EQ(client != NULL, TRUE);
emitter_on(EMITTER(client), DEBUGGER_RESP_MSG_BREAKED, on_debugger_client_event, &str);
emitter_on(EMITTER(client), DEBUGGER_RESP_MSG_LOG, on_debugger_client_event, &str);
emitter_on(EMITTER(client), DEBUGGER_RESP_MSG_ERROR, on_debugger_client_event, &str);
emitter_on(EMITTER(client), DEBUGGER_RESP_MSG_COMPLETED, on_debugger_client_event, &str);
debugger_server_tcp_start();
ASSERT_EQ(debugger_init(client, DEBUGGER_LANG_FSCRIPT, fscript->code_id), RET_OK);
ASSERT_EQ(debugger_set_break_point(client, 2), RET_OK);
tk_thread_start(thread);
sleep_ms(500);
debugger_t* debugger = debugger_server_find_debugger(fscript->code_id);
ASSERT_EQ(debugger_is_paused(debugger), TRUE);
ASSERT_EQ(debugger_continue(client), RET_OK);
ASSERT_EQ(debugger_clear_break_points(client), RET_OK);
debugger_client_wait_for_completed(client);
tk_thread_join(thread);
tk_thread_destroy(thread);
TK_OBJECT_UNREF(obj);
TK_OBJECT_UNREF(client);
debugger_server_tcp_deinit();
debugger_global_deinit();
ASSERT_STREQ(str.str, "log(0,\"1\")log(1,\"2\")breaked(2)log(2,\"3\")completed()");
str_reset(&str);
}
TEST(Debugger, basic) {
const char* code =
"print(1)\nprint(2)\nprint(3)\n//"
"code_id(\"85e86311e2d595c65b745d8143b6085efe819c354584742f72aeacd3336a0a5e\")";
debugger_global_init();
tk_object_t* obj = object_default_create();
fscript_t* fscript = fscript_create(obj, code);
tk_thread_t* thread = tk_thread_create(fscript_thread_entry, fscript);
debugger_server_tcp_init(DEBUGGER_TCP_PORT);
debugger_t* client = debugger_client_tcp_create("localhost", DEBUGGER_TCP_PORT);
ASSERT_EQ(client != NULL, TRUE);
debugger_server_tcp_start();
ASSERT_EQ(debugger_init(client, DEBUGGER_LANG_FSCRIPT, fscript->code_id), RET_OK);
ASSERT_EQ(debugger_set_break_point(client, 0), RET_OK);
tk_thread_start(thread);
sleep_ms(500);
debugger_t* debugger = debugger_server_find_debugger(fscript->code_id);
ASSERT_EQ(debugger_is_paused(debugger), TRUE);
ASSERT_EQ(debugger_continue(client), RET_OK);
ASSERT_EQ(debugger_clear_break_points(client), RET_OK);
tk_thread_join(thread);
tk_thread_destroy(thread);
TK_OBJECT_UNREF(obj);
TK_OBJECT_UNREF(client);
debugger_server_tcp_deinit();
debugger_global_deinit();
}
TEST(Debugger, basic1) {
const char* code =
"print(1)\nprint(2)\nprint(3)\n//"
"code_id(\"85e86311e2d595c65b745d8143b6085efe819c354584742f72aeacd3336a0a5e\")";
debugger_global_init();
tk_object_t* obj = object_default_create();
fscript_t* fscript = fscript_create(obj, code);
tk_thread_t* thread = tk_thread_create(fscript_thread_entry, fscript);
debugger_server_tcp_init(DEBUGGER_TCP_PORT);
debugger_t* client = debugger_client_tcp_create("localhost", DEBUGGER_TCP_PORT);
ASSERT_EQ(client != NULL, TRUE);
debugger_server_tcp_start();
ASSERT_EQ(debugger_init(client, DEBUGGER_LANG_FSCRIPT, fscript->code_id), RET_OK);
ASSERT_EQ(debugger_set_break_point(client, 0), RET_OK);
ASSERT_EQ(debugger_set_break_point(client, 1), RET_OK);
ASSERT_EQ(debugger_set_break_point(client, 2), RET_OK);
tk_thread_start(thread);
sleep_ms(500);
ASSERT_EQ(debugger_next(client), RET_OK);
ASSERT_EQ(debugger_next(client), RET_OK);
ASSERT_EQ(debugger_remove_break_point(client, 2), RET_OK);
ASSERT_EQ(debugger_clear_break_points(client), RET_OK);
tk_thread_join(thread);
tk_thread_destroy(thread);
TK_OBJECT_UNREF(obj);
TK_OBJECT_UNREF(client);
debugger_server_tcp_deinit();
debugger_global_deinit();
}
TEST(Debugger, local) {
const char* code =
"var aaa=111\nvar bbb =222;\nvar "
"ccc=\"abc\"\nprint(a);\n//"
"code_id(\"85e86311e2d595c65b745d8143b6085efe819c354584742f72aeacd3336a0a5e\")";
debugger_global_init();
tk_object_t* obj = object_default_create();
fscript_t* fscript = fscript_create(obj, code);
tk_thread_t* thread = tk_thread_create(fscript_thread_entry, fscript);
debugger_server_tcp_init(DEBUGGER_TCP_PORT);
debugger_t* client = debugger_client_tcp_create("localhost", DEBUGGER_TCP_PORT);
ASSERT_EQ(client != NULL, TRUE);
debugger_server_tcp_start();
ASSERT_EQ(debugger_init(client, DEBUGGER_LANG_FSCRIPT, fscript->code_id), RET_OK);
ASSERT_EQ(debugger_set_break_point(client, 3), RET_OK);
tk_thread_start(thread);
sleep_ms(500);
tk_object_t* local = debugger_get_local(client, 0);
ASSERT_EQ(tk_object_get_prop_int(local, "aaa", 0), 111);
ASSERT_EQ(tk_object_get_prop_int(local, "bbb", 0), 222);
ASSERT_STREQ(tk_object_get_prop_str(local, "ccc"), "abc");
TK_OBJECT_UNREF(local);
ASSERT_EQ(debugger_clear_break_points(client), RET_OK);
tk_thread_join(thread);
tk_thread_destroy(thread);
TK_OBJECT_UNREF(obj);
TK_OBJECT_UNREF(client);
debugger_server_tcp_deinit();
debugger_global_deinit();
}
TEST(Debugger, self) {
const char* code =
"aaa=111\nbbb "
"=222;\nccc=\"abc\"\nprint(a);\n//"
"code_id(\"85e86311e2d595c65b745d8143b6085efe819c354584742f72aeacd3336a0a5e\")";
debugger_global_init();
tk_object_t* obj = object_default_create();
fscript_t* fscript = fscript_create(obj, code);
tk_thread_t* thread = tk_thread_create(fscript_thread_entry, fscript);
debugger_server_tcp_init(DEBUGGER_TCP_PORT);
debugger_t* client = debugger_client_tcp_create("localhost", DEBUGGER_TCP_PORT);
ASSERT_EQ(client != NULL, TRUE);
debugger_server_tcp_start();
ASSERT_EQ(debugger_init(client, DEBUGGER_LANG_FSCRIPT, fscript->code_id), RET_OK);
ASSERT_EQ(debugger_set_break_point(client, 3), RET_OK);
tk_thread_start(thread);
sleep_ms(500);
tk_object_t* self = debugger_get_self(client);
ASSERT_EQ(tk_object_get_prop_int(self, "aaa", 0), 111);
ASSERT_EQ(tk_object_get_prop_int(self, "bbb", 0), 222);
ASSERT_STREQ(tk_object_get_prop_str(self, "ccc"), "abc");
TK_OBJECT_UNREF(self);
ASSERT_EQ(debugger_clear_break_points(client), RET_OK);
tk_thread_join(thread);
tk_thread_destroy(thread);
TK_OBJECT_UNREF(obj);
TK_OBJECT_UNREF(client);
debugger_server_tcp_deinit();
debugger_global_deinit();
}
TEST(Debugger, global) {
const char* code =
"global.aaa=111\nglobal.bbb "
"=222;\nglobal.ccc=\"abc\"\nprint(a);\n//"
"code_id(\"85e86311e2d595c65b745d8143b6085efe819c354584742f72aeacd3336a0a5e\")";
debugger_global_init();
tk_object_t* obj = object_default_create();
fscript_t* fscript = fscript_create(obj, code);
tk_thread_t* thread = tk_thread_create(fscript_thread_entry, fscript);
debugger_server_tcp_init(DEBUGGER_TCP_PORT);
debugger_t* client = debugger_client_tcp_create("localhost", DEBUGGER_TCP_PORT);
ASSERT_EQ(client != NULL, TRUE);
debugger_server_tcp_start();
ASSERT_EQ(debugger_init(client, DEBUGGER_LANG_FSCRIPT, fscript->code_id), RET_OK);
ASSERT_EQ(debugger_set_break_point(client, 3), RET_OK);
tk_thread_start(thread);
sleep_ms(500);
tk_object_t* global = debugger_get_global(client);
ASSERT_EQ(tk_object_get_prop_int(global, "aaa", 0), 111);
ASSERT_EQ(tk_object_get_prop_int(global, "bbb", 0), 222);
ASSERT_STREQ(tk_object_get_prop_str(global, "ccc"), "abc");
TK_OBJECT_UNREF(global);
ASSERT_EQ(debugger_clear_break_points(client), RET_OK);
tk_thread_join(thread);
tk_thread_destroy(thread);
TK_OBJECT_UNREF(obj);
TK_OBJECT_UNREF(client);
debugger_server_tcp_deinit();
debugger_global_deinit();
}
TEST(Debugger, callstack) {
const char* code =
"global.aaa=111\nglobal.bbb "
"=222;\nglobal.ccc=\"abc\"\nprint(a);\n//"
"code_id(\"85e86311e2d595c65b745d8143b6085efe819c354584742f72aeacd3336a0a5e\")";
debugger_global_init();
tk_object_t* obj = object_default_create();
fscript_t* fscript = fscript_create(obj, code);
tk_thread_t* thread = tk_thread_create(fscript_thread_entry, fscript);
debugger_server_tcp_init(DEBUGGER_TCP_PORT);
debugger_t* client = debugger_client_tcp_create("localhost", DEBUGGER_TCP_PORT);
ASSERT_EQ(client != NULL, TRUE);
debugger_server_tcp_start();
ASSERT_EQ(debugger_init(client, DEBUGGER_LANG_FSCRIPT, fscript->code_id), RET_OK);
ASSERT_EQ(debugger_set_break_point(client, 3), RET_OK);
tk_thread_start(thread);
sleep_ms(500);
binary_data_t data = {0, NULL};
ASSERT_EQ(debugger_get_callstack(client, &data), RET_OK);
ASSERT_STREQ((char*)(data.data), "<root>\n");
ASSERT_EQ(debugger_clear_break_points(client), RET_OK);
tk_thread_join(thread);
tk_thread_destroy(thread);
TK_OBJECT_UNREF(obj);
TK_OBJECT_UNREF(client);
debugger_server_tcp_deinit();
debugger_global_deinit();
}
TEST(Debugger, code) {
const char* code =
"global.aaa=111\nglobal.bbb "
"=222;\nglobal.ccc=\"abc\"\nprint(a);\n//"
"code_id(\"85e86311e2d595c65b745d8143b6085efe819c354584742f72aeacd3336a0a5e\")";
debugger_global_init();
tk_object_t* obj = object_default_create();
fscript_t* fscript = fscript_create(obj, code);
tk_thread_t* thread = tk_thread_create(fscript_thread_entry, fscript);
debugger_server_tcp_init(DEBUGGER_TCP_PORT);
debugger_t* client = debugger_client_tcp_create("localhost", DEBUGGER_TCP_PORT);
ASSERT_EQ(client != NULL, TRUE);
debugger_server_tcp_start();
ASSERT_EQ(debugger_init(client, DEBUGGER_LANG_FSCRIPT, fscript->code_id), RET_OK);
ASSERT_EQ(debugger_set_break_point(client, 3), RET_OK);
tk_thread_start(thread);
sleep_ms(500);
binary_data_t data;
data.data = (void*)"print(1)";
data.size = strlen((char*)data.data);
ASSERT_EQ(debugger_update_code(client, &data), RET_OK);
data.data = NULL;
ASSERT_EQ(debugger_get_code(client, &data), RET_OK);
ASSERT_STREQ((char*)data.data, "print(1)");
ASSERT_EQ(debugger_clear_break_points(client), RET_OK);
tk_thread_join(thread);
tk_thread_destroy(thread);
TK_OBJECT_UNREF(obj);
TK_OBJECT_UNREF(client);
debugger_server_tcp_deinit();
debugger_global_deinit();
}
#endif

View File

@ -9,15 +9,14 @@ TEST(FScriptArray, size) {
fscript_eval(obj, "a=array_create();array_push(a, 1);array_push(a, 2);array_size(a)", &v);
ASSERT_EQ(value_uint32(&v), 2);
value_reset(&v);
fscript_eval(obj, "a=array_create();array_is_empty(a)", &v);
ASSERT_EQ(value_bool(&v), TRUE);
value_reset(&v);
fscript_eval(obj, "a=array_create();array_push(a, 1);array_push(a, 2);array_is_empty(a)", &v);
ASSERT_EQ(value_bool(&v), FALSE);
value_reset(&v);
TK_OBJECT_UNREF(obj);
}

View File

@ -15,6 +15,7 @@ TEST(FScript, args) {
fscript_eval(obj, "sum(1,2,3,4,5,6,7,8,9,10,11)", &v);
ASSERT_EQ(66, value_int(&v));
value_reset(&v);
TK_OBJECT_UNREF(obj);
}
TEST(FScript, basic0) {
@ -1728,6 +1729,7 @@ TEST(FScript, convert1) {
ASSERT_EQ(v.type == VALUE_TYPE_DOUBLE, true);
ASSERT_EQ(123, value_double(&v));
TK_OBJECT_UNREF(obj);
value_reset(&v);
}
@ -1752,10 +1754,12 @@ TEST(FScript, print) {
str_init(&str, 10);
tk_object_set_prop_pointer(obj, "str", &str);
tk_object_set_prop_pointer(obj, STR_FSCRIPT_FUNCTION_PREFIX "print", (void*)my_print);
fscript_eval(obj, "print(\"hello\")", &v);
fscript_t* fscript = fscript_create(obj, "print(\"hello\")");
fscript_set_print_func(fscript, my_print);
fscript_exec(fscript, &v);
ASSERT_STREQ(str.str, "hello");
str_reset(&str);
fscript_destroy(fscript);
value_reset(&v);
TK_OBJECT_UNREF(obj);
@ -1783,6 +1787,7 @@ TEST(FScript, on_error) {
value_reset(&v);
TK_OBJECT_UNREF(obj);
fscript_destroy(fscript);
}
TEST(FScript, while_return) {
@ -1940,6 +1945,8 @@ TEST(FExr, str_append) {
fscript_eval(obj, "aa=\"hello \";bb=str_append(aa, \"world\");bb", &v1);
ASSERT_STREQ(value_str(&v1), "hello world");
value_reset(&v1);
TK_OBJECT_UNREF(obj);
}
@ -1975,21 +1982,31 @@ TEST(FExr, char_at) {
fscript_eval(obj, "char_at(\"hello\", 0)", &v1);
ASSERT_STREQ(value_str(&v1), "h");
value_reset(&v1);
fscript_eval(obj, "char_at(\"hello\", 1)", &v1);
ASSERT_STREQ(value_str(&v1), "e");
value_reset(&v1);
fscript_eval(obj, "char_at(\"hello\", -1)", &v1);
ASSERT_STREQ(value_str(&v1), "o");
value_reset(&v1);
fscript_eval(obj, "char_at(\"hello\", -2)", &v1);
ASSERT_STREQ(value_str(&v1), "l");
value_reset(&v1);
fscript_eval(obj, "char_at_first(\"hello\")", &v1);
ASSERT_STREQ(value_str(&v1), "h");
value_reset(&v1);
fscript_eval(obj, "char_at_last(\"hello\")", &v1);
ASSERT_STREQ(value_str(&v1), "o");
value_reset(&v1);
fscript_eval(obj, "char_at_random(\"hhh\")", &v1);
ASSERT_STREQ(value_str(&v1), "h");
value_reset(&v1);
TK_OBJECT_UNREF(obj);
}

View File

@ -730,6 +730,7 @@ TEST(ObjectArray, reverse) {
ASSERT_EQ(object_array_join(obj, ",", &s), RET_OK);
ASSERT_STREQ(s.str, "1,0");
str_clear(&s);
TK_OBJECT_UNREF(obj);
obj = object_array_create_with_str("0,1,2", ",", VALUE_TYPE_INT32);
ASSERT_EQ(object_array_reverse(obj), RET_OK);