diff --git a/src/ssb.c b/src/ssb.c index ca340261..5b9d4afc 100644 --- a/src/ssb.c +++ b/src/ssb.c @@ -25,6 +25,15 @@ #include #include +#include + +#ifndef _WIN32 +#ifndef __ANDROID__ +#include +#endif +#include +#endif + #if !defined(_countof) #define _countof(a) ((int)(sizeof((a)) / sizeof(*(a)))) #endif @@ -622,30 +631,68 @@ void tf_ssb_connection_rpc_send_json(tf_ssb_connection_t* connection, uint8_t fl JS_FreeValue(context, json); } +static int _tf_ssb_backtrace_callback(void* data, uintptr_t pc, const char* filename, int line_number, const char* function) +{ + char** stack = data; + char line[256]; + int length = snprintf(line, sizeof(line), "%p %s:%d %s\n", (void*)pc, filename, line_number, function); + int current = *stack ? strlen(*stack) : 0; + *stack = tf_resize_vec(*stack, current + length + 1); + memcpy(*stack + current, line, length + 1); + return 0; +} + +static void _tf_ssb_backtrace_error(void* data, const char* message, int error) +{ + char** stack = data; + int length = strlen(message); + if (message) + { + int current = *stack ? strlen(*stack) : 0; + *stack = tf_resize_vec(*stack, current + length + 1); + memcpy(*stack + current, message, length + 1); + } +} + +static char* _tf_ssb_backtrace_string() +{ + extern struct backtrace_state* g_backtrace_state; + int count = 0; + void* buffer[32]; + char* string = NULL; +#ifdef _WIN32 + count = CaptureStackBackTrace(0, sizeof(buffer) / sizeof(*buffer), buffer, NULL); +#elif !defined(__ANDROID__) + count = backtrace(buffer, sizeof(buffer) / sizeof(*buffer)); +#endif + for (int i = 0; i < count; i++) + { + backtrace_pcinfo( + g_backtrace_state, + (uintptr_t)buffer[i], + _tf_ssb_backtrace_callback, + _tf_ssb_backtrace_error, + &string); + } + return string; +} + void tf_ssb_connection_rpc_send_error(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, const char* error) { JSContext* context = connection->ssb->context; JSValue message = JS_NewObject(context); + char* stack = _tf_ssb_backtrace_string(); JS_SetPropertyStr(context, message, "name", JS_NewString(context, "Error")); - JS_SetPropertyStr(context, message, "stack", JS_NewString(context, "none")); + JS_SetPropertyStr(context, message, "stack", JS_NewString(context, stack)); JS_SetPropertyStr(context, message, "message", JS_NewString(context, error)); - tf_ssb_connection_rpc_send_json(connection, flags | k_ssb_rpc_flag_end_error, request_number, message, NULL, NULL, NULL); + tf_ssb_connection_rpc_send_json(connection, ((flags & k_ssb_rpc_flag_stream) ? (k_ssb_rpc_flag_stream | k_ssb_rpc_flag_end_error) : 0), request_number, message, NULL, NULL, NULL); JS_FreeValue(context, message); + tf_free(stack); } void tf_ssb_connection_rpc_send_error_method_not_allowed(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number) { - const char* k_unsupported = "{\"message\": \"method: is not in list of allowed methods\", \"name\": \"Error\", \"stack\": \"none\"}"; - tf_ssb_connection_rpc_send( - connection, - k_ssb_rpc_flag_json | - ((flags & k_ssb_rpc_flag_stream) ? (k_ssb_rpc_flag_stream | k_ssb_rpc_flag_end_error) : 0), - request_number, - (const uint8_t*)k_unsupported, - strlen(k_unsupported), - NULL, - NULL, - NULL); + tf_ssb_connection_rpc_send_error(connection, flags, request_number, "method is not in list of allowed methods"); } static int _utf8_len(uint8_t ch) @@ -1378,8 +1425,7 @@ static void _tf_ssb_connection_rpc_recv(tf_ssb_connection_t* connection, uint8_t } } - if (request_number < 0 && - (flags & k_ssb_rpc_flag_end_error)) + if (flags & k_ssb_rpc_flag_end_error) { _tf_ssb_connection_remove_request(connection, -request_number); }