blob: bf54b2d59a5a76744d9fe6daffd885ecb83aa3c0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2009 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
/*
* This module defines agent error codes in addition to system codes defined in errno.h
*/
#include <config.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <framework/errors.h>
#include <framework/events.h>
#include <framework/streams.h>
#include <framework/myalloc.h>
#include <framework/json.h>
#include <framework/trace.h>
#define ERR_MESSAGE_MIN (STD_ERR_BASE + 100)
#define ERR_MESSAGE_MAX (STD_ERR_BASE + 199)
#define MESSAGE_CNT (ERR_MESSAGE_MAX - ERR_MESSAGE_MIN + 1)
#define SRC_SYSTEM 1
#define SRC_GAI 2
#define SRC_MESSAGE 3
#define SRC_REPORT 4
typedef struct ReportBuffer {
ErrorReport pub; /* public part of error report */
int refs;
int gets;
} ReportBuffer;
typedef struct ErrorMessage {
int source;
int error;
char * text;
ReportBuffer * report;
} ErrorMessage;
static ErrorMessage msgs[MESSAGE_CNT];
static int msgs_pos = 0;
static void release_report(ReportBuffer * report) {
if (report == NULL) return;
assert(report->refs > report->gets);
report->refs--;
if (report->refs == 0) {
while (report->pub.props != NULL) {
ErrorReportItem * i = report->pub.props;
report->pub.props = i->next;
loc_free(i->name);
loc_free(i->value);
loc_free(i);
}
loc_free(report->pub.format);
loc_free(report);
}
}
static ErrorMessage * alloc_msg(int source) {
ErrorMessage * m = msgs + msgs_pos;
assert(is_dispatch_thread());
errno = ERR_MESSAGE_MIN + msgs_pos++;
if (msgs_pos >= MESSAGE_CNT) msgs_pos = 0;
release_report(m->report);
loc_free(m->text);
m->source = source;
m->error = 0;
m->report = NULL;
m->text = NULL;
return m;
}
#ifdef WIN32
static char * system_strerror(DWORD errno_win32) {
static char msg[512];
WCHAR * buf = NULL;
assert(is_dispatch_thread());
if (!FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL,
errno_win32,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
(LPWSTR)&buf, 0, NULL) ||
!WideCharToMultiByte(CP_UTF8, 0, buf, -1, msg, sizeof(msg), NULL, NULL))
{
snprintf(msg, sizeof(msg), "System Error Code %lu", (unsigned long)errno_win32);
}
if (buf != NULL) LocalFree(buf);
return msg;
}
typedef struct EventArgs {
HANDLE done;
int win32_code;
int error_code;
} EventArgs;
static void set_win32_errno_event(void * args) {
ErrorMessage * m = NULL;
EventArgs * e = (EventArgs *)args;
m = alloc_msg(SRC_SYSTEM);
m->error = e->win32_code;
e->error_code = errno;
SetEvent(e->done);
}
int set_win32_errno(DWORD win32_error_code) {
if (win32_error_code) {
if (is_dispatch_thread()) {
ErrorMessage * m = alloc_msg(SRC_SYSTEM);
m->error = win32_error_code;
}
else {
/* Called on background thread */
int error = 0;
EventArgs * e = (EventArgs *)loc_alloc_zero(sizeof(EventArgs));
e->done = CreateEvent(NULL, TRUE, FALSE, NULL);
e->win32_code = win32_error_code;
post_event(set_win32_errno_event, e);
WaitForSingleObject(e->done, INFINITE);
CloseHandle(e->done);
error = e->error_code;
loc_free(e);
errno = error;
}
}
else {
errno = 0;
}
return errno;
}
#elif defined(__SYMBIAN32__)
#include <e32err.h>
static char * system_strerror(int err) {
static char static_error[32];
switch (err) {
case KErrNotFound:
return "item not found";
case KErrNotSupported:
return "functionality is not supported";
case KErrBadHandle:
return "an invalid handle";
case KErrAccessDenied:
return "access to a file is denied";
case KErrAlreadyExists:
return "an object already exists";
case KErrWrite:
return "error in write operation";
case KErrPermissionDenied:
return "permission denied";
case KErrBadDescriptor:
return "bad descriptor";
default:
snprintf(static_error, sizeof(static_error), "Error code %d", err);
return static_error;
}
}
#endif
const char * errno_to_str(int err) {
switch (err) {
case ERR_ALREADY_STOPPED: return "Already stopped";
case ERR_ALREADY_EXITED: return "Already exited";
case ERR_ALREADY_RUNNING: return "Already running";
case ERR_JSON_SYNTAX: return "JSON syntax error";
case ERR_PROTOCOL: return "Protocol format error";
case ERR_INV_CONTEXT: return "Invalid context ID";
case ERR_INV_ADDRESS: return "Invalid address";
case ERR_EOF: return "End of file";
case ERR_BASE64: return "Invalid BASE64 string";
case ERR_INV_EXPRESSION: return "Invalid expression";
case ERR_SYM_NOT_FOUND: return "Symbol not found";
case ERR_ALREADY_ATTACHED: return "Already attached";
case ERR_BUFFER_OVERFLOW: return "Buffer overflow";
case ERR_INV_FORMAT: return "Format is not supported";
case ERR_INV_NUMBER: return "Invalid number";
case ERR_IS_RUNNING: return "Execution context is running";
case ERR_INV_DWARF: return "Error reading DWARF data";
case ERR_UNSUPPORTED: return "Unsupported command";
case ERR_CHANNEL_CLOSED: return "Channel closed";
case ERR_COMMAND_CANCELLED: return "Command cancelled";
case ERR_UNKNOWN_PEER: return "Unknown peer ID";
case ERR_INV_DATA_SIZE: return "Invalid data size";
case ERR_INV_DATA_TYPE: return "Invalid data type";
case ERR_INV_COMMAND: return "Command is not recognized";
case ERR_INV_TRANSPORT: return "Invalid transport name";
case ERR_CACHE_MISS: return "Invalid data cache state";
default:
if (err >= ERR_MESSAGE_MIN && err <= ERR_MESSAGE_MAX) {
ErrorMessage * m = msgs + (err - ERR_MESSAGE_MIN);
if (m->report != NULL && m->report->pub.format != NULL) {
/* TODO: error report args */
return m->report->pub.format;
}
switch (m->source) {
#ifdef WIN32
case SRC_SYSTEM:
return system_strerror(m->error);
#endif
case SRC_GAI:
return loc_gai_strerror(m->error);
case SRC_MESSAGE:
return m->text;
case SRC_REPORT:
return errno_to_str(m->error);
}
}
#ifdef __SYMBIAN32__
if (err < 0) {
return system_strerror(err);
}
#endif
return strerror(err);
}
}
int set_errno(int no, const char * msg) {
errno = no;
if (no != 0 && msg != NULL) {
const char * text0 = errno_to_str(no);
int len = strlen(msg) + strlen(text0) + 4;
char * text1 = (char *)loc_alloc(len);
ErrorMessage * m = NULL;
snprintf(text1, len, "%s. %s", msg, text0);
m = alloc_msg(SRC_MESSAGE);
m->error = get_error_code(no);
m->text = text1;
}
return errno;
}
int set_gai_errno(int no) {
errno = no;
if (no != 0) {
ErrorMessage * m = alloc_msg(SRC_GAI);
m->error = no;
}
return errno;
}
int set_error_report_errno(ErrorReport * r) {
errno = 0;
if (r != NULL) {
ReportBuffer * report = (ReportBuffer *)((char *)r - offsetof(ReportBuffer, pub));
ErrorMessage * m = alloc_msg(SRC_REPORT);
m->error = report->pub.code + STD_ERR_BASE;
m->report = report;
report->refs++;
}
return errno;
}
int get_error_code(int no) {
while (no >= ERR_MESSAGE_MIN && no <= ERR_MESSAGE_MAX) {
ErrorMessage * m = msgs + (no - ERR_MESSAGE_MIN);
switch (m->source) {
case SRC_REPORT:
case SRC_MESSAGE:
no = m->error;
continue;
}
return ERR_OTHER;
}
return no;
}
static void add_report_prop(ReportBuffer * report, const char * name, ByteArrayOutputStream * buf) {
ErrorReportItem * i = (ErrorReportItem *)loc_alloc(sizeof(ErrorReportItem));
i->name = loc_strdup(name);
get_byte_array_output_stream_data(buf, &i->value, NULL);
i->next = report->pub.props;
report->pub.props = i;
}
static void add_report_prop_int(ReportBuffer * report, const char * name, unsigned long n) {
ByteArrayOutputStream buf;
OutputStream * out = create_byte_array_output_stream(&buf);
json_write_ulong(out, n);
write_stream(out, 0);
add_report_prop(report, name, &buf);
}
static void add_report_prop_str(ReportBuffer * report, const char * name, const char * str) {
ByteArrayOutputStream buf;
OutputStream * out = create_byte_array_output_stream(&buf);
json_write_string(out, str);
write_stream(out, 0);
add_report_prop(report, name, &buf);
}
ErrorReport * get_error_report(int err) {
ErrorMessage * m = NULL;
if (err >= ERR_MESSAGE_MIN && err <= ERR_MESSAGE_MAX) {
m = msgs + (err - ERR_MESSAGE_MIN);
if (m->report != NULL) {
m->report->refs++;
m->report->gets++;
return &m->report->pub;
}
}
if (err != 0) {
ReportBuffer * report = (ReportBuffer *)loc_alloc_zero(sizeof(ReportBuffer));
struct timespec timenow;
if (clock_gettime(CLOCK_REALTIME, &timenow) == 0) {
report->pub.time_stamp = (uint64_t)timenow.tv_sec * 1000 + timenow.tv_nsec / 1000000;
}
report->pub.format = loc_strdup(errno_to_str(err));
if (m != NULL) {
if (m->source == SRC_MESSAGE) {
err = m->error;
}
#ifdef WIN32
else if (m->source == SRC_SYSTEM) {
add_report_prop_int(report, "AltCode", m->error);
add_report_prop_str(report, "AltOrg", "WIN32");
err = ERR_OTHER;
}
#endif
else {
err = ERR_OTHER;
}
}
if (err < STD_ERR_BASE || err > ERR_MESSAGE_MAX) {
add_report_prop_int(report, "AltCode", err);
#if defined(_MSC_VER)
add_report_prop_str(report, "AltOrg", "MSC");
#elif defined(_WRS_KERNEL)
add_report_prop_str(report, "AltOrg", "VxWorks");
#elif defined(__CYGWIN__)
add_report_prop_str(report, "AltOrg", "CygWin");
#elif defined(__linux__)
add_report_prop_str(report, "AltOrg", "Linux");
#elif defined(__SYMBIAN32__)
add_report_prop_str(report, "AltOrg", "Symbian");
#else
add_report_prop_str(report, "AltOrg", "POSIX");
#endif
err = ERR_OTHER;
}
assert(err >= STD_ERR_BASE);
assert(err < ERR_MESSAGE_MIN);
report->pub.code = err - STD_ERR_BASE;
report->refs = 1;
report->gets = 1;
if (m != NULL) {
assert(m->report == NULL);
m->report = report;
report->refs++;
}
return &report->pub;
}
return NULL;
}
ErrorReport * create_error_report(void) {
ReportBuffer * report = (ReportBuffer *)loc_alloc_zero(sizeof(ReportBuffer));
report->refs = 1;
report->gets = 1;
return &report->pub;
}
void release_error_report(ErrorReport * r) {
if (r != NULL) {
ReportBuffer * report = (ReportBuffer *)((char *)r - offsetof(ReportBuffer, pub));
assert(is_dispatch_thread());
assert(report->gets > 0);
report->gets--;
release_report(report);
}
}
#ifdef NDEBUG
void check_error(int error) {
if (error == 0) return;
#if ENABLE_Trace
trace(LOG_ALWAYS, "Fatal error %d: %s", error, errno_to_str(error));
trace(LOG_ALWAYS, " Exiting agent...");
if (log_file == stderr) exit(1);
#endif
fprintf(stderr, "Fatal error %d: %s", error, errno_to_str(error));
fprintf(stderr, " Exiting agent...");
exit(1);
}
#else /* NDEBUG */
void check_error_debug(const char * file, int line, int error) {
if (error == 0) return;
#if ENABLE_Trace
trace(LOG_ALWAYS, "Fatal error %d: %s", error, errno_to_str(error));
trace(LOG_ALWAYS, " At %s:%d", file, line);
trace(LOG_ALWAYS, " Exiting agent...");
if (log_file == stderr) exit(1);
#endif
fprintf(stderr, "Fatal error %d: %s", error, errno_to_str(error));
fprintf(stderr, " At %s:%d", file, line);
fprintf(stderr, " Exiting agent...");
exit(1);
}
#endif /* NDEBUG */