- added patch to Improving progress/error output for telnet & GDB monitor
(thanks to Øyvind for the patch) git-svn-id: svn://svn.berlios.de/openocd/trunk@293 b42882b7-edfa-0310-969c-e2dbd0fdcd60
This commit is contained in:
parent
edc0db163a
commit
2a0317e6f4
|
@ -268,7 +268,7 @@ void command_print(command_context_t *context, char *format, ...)
|
|||
/* process format string */
|
||||
/* TODO: possible bug. va_list is undefined after the first call to vsnprintf */
|
||||
while (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)
|
||||
{
|
||||
{
|
||||
/* increase buffer until it fits the whole string */
|
||||
if (!(p = realloc(buffer, size += 4096)))
|
||||
{
|
||||
|
@ -359,7 +359,7 @@ int find_and_run_command(command_context_t *context, command_t *commands, char *
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int command_run_line(command_context_t *context, char *line)
|
||||
static int command_run_line_inner(command_context_t *context, char *line)
|
||||
{
|
||||
int nwords;
|
||||
char *words[128] = {0};
|
||||
|
@ -399,6 +399,17 @@ int command_run_line(command_context_t *context, char *line)
|
|||
return retval;
|
||||
}
|
||||
|
||||
int command_run_line(command_context_t *context, char *line)
|
||||
{
|
||||
int retval=command_run_line_inner(context, line);
|
||||
// we don't want any dangling callbacks!
|
||||
//
|
||||
// Capturing output from logging is *very* loosly modeled on C/C++ exceptions.
|
||||
// the capture must be set up at function entry and
|
||||
// stops when the function call returns
|
||||
log_setCallback(NULL, NULL);
|
||||
return retval;
|
||||
}
|
||||
int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
|
@ -441,7 +452,7 @@ int command_run_file(command_context_t *context, FILE *file, enum command_mode m
|
|||
break;
|
||||
|
||||
/* run line */
|
||||
if ((retval = command_run_line(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)
|
||||
if ((retval = command_run_line_inner(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,16 @@ int debug_level = -1;
|
|||
|
||||
static FILE* log_output;
|
||||
|
||||
|
||||
static void *privData;
|
||||
static logCallback callback;
|
||||
|
||||
void log_setCallback(logCallback c, void *p)
|
||||
{
|
||||
callback=c;
|
||||
privData=p;
|
||||
}
|
||||
|
||||
static char *log_strings[4] =
|
||||
{
|
||||
"Error: ",
|
||||
|
@ -56,25 +66,18 @@ void log_printf(enum log_levels level, const char *file, int line, const char *f
|
|||
fflush(log_output);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void short_log_printf(enum log_levels level, const char *format, ...)
|
||||
if (callback)
|
||||
{
|
||||
va_list args;
|
||||
char buffer[512];
|
||||
|
||||
if (level > debug_level)
|
||||
return;
|
||||
|
||||
va_start(args, format);
|
||||
vsnprintf(buffer, 512, format, args);
|
||||
|
||||
fprintf(log_output, "%s %s\n", log_strings[level], buffer);
|
||||
fflush(log_output);
|
||||
callback(privData, file, line, function, format, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* change the current debug level on the fly
|
||||
* 0: only ERRORS
|
||||
* 1: + WARNINGS
|
||||
|
@ -136,3 +139,42 @@ int log_init(struct command_context_s *cmd_ctx)
|
|||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int set_log_output(struct command_context_s *cmd_ctx, FILE *output)
|
||||
{
|
||||
log_output=output;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* return allocated string w/printf() result */
|
||||
char *allocPrintf(const char *fmt, va_list ap)
|
||||
{
|
||||
char *string=NULL;
|
||||
int size=0; // start by 0 to exercise all the code paths. Need minimum 2 bytes to fit 1 char and 0 terminator.
|
||||
int first=1;
|
||||
for (;;)
|
||||
{
|
||||
if ((string==NULL)||(!first))
|
||||
{
|
||||
size=size*2+2;
|
||||
char *t=string;
|
||||
string=realloc(string, size);
|
||||
if (string==NULL)
|
||||
{
|
||||
if (t!=NULL)
|
||||
free(t);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ret;
|
||||
ret = vsnprintf(string, size, fmt, ap);
|
||||
// NB! The result of the vsnprintf() might be an *EMPTY* string!
|
||||
if ((ret>=0)&&((ret+1)<size))
|
||||
{
|
||||
return string;
|
||||
}
|
||||
// there was just enough or not enough space, allocate more.
|
||||
first=0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,12 @@ extern void log_printf(enum log_levels level, const char *file, int line,
|
|||
__attribute__ ((format (printf, 5, 6)));
|
||||
extern int log_register_commands(struct command_context_s *cmd_ctx);
|
||||
extern int log_init(struct command_context_s *cmd_ctx);
|
||||
extern int set_log_output(struct command_context_s *cmd_ctx, FILE *output);
|
||||
|
||||
typedef void (*logCallback)(void *privData, const char *file, int line,
|
||||
const char *function, const char *format, va_list args);
|
||||
|
||||
void log_setCallback(logCallback callback, void *privData);
|
||||
|
||||
extern int debug_level;
|
||||
|
||||
|
@ -67,25 +73,6 @@ extern int debug_level;
|
|||
log_printf (LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, expr); \
|
||||
} while(0)
|
||||
|
||||
#define SDEBUG(expr ...) \
|
||||
do { \
|
||||
short_log_printf (LOG_DEBUG, expr); \
|
||||
} while(0)
|
||||
|
||||
#define SINFO(expr ...) \
|
||||
do { \
|
||||
short_log_printf (LOG_INFO, expr); \
|
||||
} while(0)
|
||||
|
||||
#define SWARNING(expr ...) \
|
||||
do { \
|
||||
short_log_printf (LOG_WARNING, expr); \
|
||||
} while(0)
|
||||
|
||||
#define SERROR(expr ...) \
|
||||
do { \
|
||||
short_log_printf (LOG_ERROR, expr); \
|
||||
} while(0)
|
||||
|
||||
/* general failures
|
||||
* error codes < 100
|
||||
|
@ -95,4 +82,7 @@ extern int debug_level;
|
|||
#define ERROR_NO_CONFIG_FILE (-2)
|
||||
#define ERROR_BUF_TOO_SMALL (-3)
|
||||
|
||||
#endif /* ERROR_H */
|
||||
char *allocPrintf(const char *fmt, va_list ap);
|
||||
|
||||
|
||||
#endif /* LOG_H */
|
||||
|
|
|
@ -44,6 +44,10 @@
|
|||
|
||||
static unsigned short gdb_port;
|
||||
|
||||
static void gdb_log_callback(void *privData, const char *file, int line,
|
||||
const char *function, const char *format, va_list args);
|
||||
|
||||
|
||||
enum gdb_detach_mode
|
||||
{
|
||||
GDB_DETACH_RESUME,
|
||||
|
@ -180,7 +184,7 @@ int gdb_putback_char(connection_t *connection, int last_char)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int gdb_put_packet(connection_t *connection, char *buffer, int len)
|
||||
int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
|
||||
{
|
||||
int i;
|
||||
unsigned char my_checksum = 0;
|
||||
|
@ -245,10 +249,19 @@ int gdb_put_packet(connection_t *connection, char *buffer, int len)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int gdb_get_packet(connection_t *connection, char *buffer, int *len)
|
||||
int gdb_put_packet(connection_t *connection, char *buffer, int len)
|
||||
{
|
||||
gdb_connection_t *gdb_connection = connection->priv;
|
||||
gdb_connection->output_disable=1;
|
||||
int retval=gdb_put_packet_inner(connection, buffer, len);
|
||||
gdb_connection->output_disable=0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
|
||||
{
|
||||
int character;
|
||||
int count;
|
||||
int count = 0;
|
||||
int retval;
|
||||
char checksum[3];
|
||||
unsigned char my_checksum = 0;
|
||||
|
@ -286,8 +299,9 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len)
|
|||
} while (character != '$');
|
||||
|
||||
my_checksum = 0;
|
||||
count = 0;
|
||||
|
||||
count=0;
|
||||
gdb_connection_t *gdb_con = connection->priv;
|
||||
for (;;)
|
||||
{
|
||||
/* The common case is that we have an entire packet with no escape chars.
|
||||
|
@ -391,11 +405,18 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int gdb_output(struct command_context_s *context, char* line)
|
||||
int gdb_get_packet(connection_t *connection, char *buffer, int *len)
|
||||
{
|
||||
connection_t *connection = context->output_handler_priv;
|
||||
gdb_connection_t *gdb_connection = connection->priv;
|
||||
gdb_connection->output_disable=1;
|
||||
int retval=gdb_get_packet_inner(connection, buffer, len);
|
||||
gdb_connection->output_disable=0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int gdb_output_con(connection_t *connection, char* line)
|
||||
{
|
||||
gdb_connection_t *gdb_connection = connection->priv;
|
||||
char *hex_buffer;
|
||||
int i, bin_size;
|
||||
|
||||
|
@ -422,6 +443,12 @@ int gdb_output(struct command_context_s *context, char* line)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int gdb_output(struct command_context_s *context, char* line)
|
||||
{
|
||||
connection_t *connection = context->output_handler_priv;
|
||||
return gdb_output_con(connection, line);
|
||||
}
|
||||
|
||||
int gdb_program_handler(struct target_s *target, enum target_event event, void *priv)
|
||||
{
|
||||
FILE *script;
|
||||
|
@ -458,6 +485,9 @@ int gdb_target_callback_event_handler(struct target_s *target, enum target_event
|
|||
case TARGET_EVENT_HALTED:
|
||||
if (gdb_connection->frontend_state == TARGET_RUNNING)
|
||||
{
|
||||
// stop forwarding log packets!
|
||||
log_setCallback(NULL, NULL);
|
||||
|
||||
if (gdb_connection->ctrl_c)
|
||||
{
|
||||
signal = 0x2;
|
||||
|
@ -895,7 +925,6 @@ int gdb_memory_packet_error(connection_t *connection, int retval)
|
|||
case ERROR_TARGET_NOT_HALTED:
|
||||
ERROR("gdb tried to read memory but we're not halted, dropping connection");
|
||||
return ERROR_SERVER_REMOTE_CLOSED;
|
||||
break;
|
||||
case ERROR_TARGET_DATA_ABORT:
|
||||
gdb_send_error(connection, EIO);
|
||||
break;
|
||||
|
@ -1398,6 +1427,9 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
|
|||
cmd[i] = tmp;
|
||||
}
|
||||
cmd[(packet_size - 6)/2] = 0x0;
|
||||
|
||||
/* We want to print all debug output to GDB connection */
|
||||
log_setCallback(gdb_log_callback, connection);
|
||||
target_call_timer_callbacks();
|
||||
command_run_line(cmd_ctx, cmd);
|
||||
free(cmd);
|
||||
|
@ -1759,6 +1791,22 @@ int gdb_detach(connection_t *connection, target_t *target)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void gdb_log_callback(void *privData, const char *file, int line,
|
||||
const char *function, const char *format, va_list args)
|
||||
{
|
||||
connection_t *connection=(connection_t *)privData;
|
||||
|
||||
char *t=allocPrintf(format, args);
|
||||
if (t==NULL)
|
||||
return;
|
||||
|
||||
gdb_output_con(connection, t);
|
||||
|
||||
free(t);
|
||||
}
|
||||
|
||||
int gdb_input(connection_t *connection)
|
||||
{
|
||||
gdb_service_t *gdb_service = connection->service->priv;
|
||||
|
@ -1833,6 +1881,9 @@ int gdb_input(connection_t *connection)
|
|||
break;
|
||||
case 'c':
|
||||
case 's':
|
||||
/* We're running/stepping, in which case we can
|
||||
* forward log output until the target is halted */
|
||||
log_setCallback(gdb_log_callback, connection);
|
||||
gdb_step_continue_packet(connection, target, packet, packet_size);
|
||||
break;
|
||||
case 'v':
|
||||
|
|
|
@ -57,6 +57,12 @@ void telnet_prompt(connection_t *connection)
|
|||
write_socket(connection->fd, t_con->prompt, strlen(t_con->prompt));
|
||||
}
|
||||
|
||||
int telnet_outputline(connection_t *connection, char* line)
|
||||
{
|
||||
write_socket(connection->fd, line, strlen(line));
|
||||
return write_socket(connection->fd, "\r\n\0", 3);
|
||||
}
|
||||
|
||||
int telnet_output(struct command_context_s *cmd_ctx, char* line)
|
||||
{
|
||||
connection_t *connection = cmd_ctx->output_handler_priv;
|
||||
|
@ -67,6 +73,19 @@ int telnet_output(struct command_context_s *cmd_ctx, char* line)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
void telnet_log_callback(void *privData, const char *file, int line,
|
||||
const char *function, const char *format, va_list args)
|
||||
{
|
||||
connection_t *connection=(connection_t *)privData;
|
||||
char *t=allocPrintf(format, args);
|
||||
if (t==NULL)
|
||||
return;
|
||||
|
||||
telnet_outputline(connection, t);
|
||||
|
||||
free(t);
|
||||
}
|
||||
|
||||
int telnet_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)
|
||||
{
|
||||
struct command_context_s *cmd_ctx = priv;
|
||||
|
@ -244,6 +263,10 @@ int telnet_input(connection_t *connection)
|
|||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
log_setCallback(telnet_log_callback, connection);
|
||||
|
||||
if ((retval = command_run_line(command_context, t_con->line)) != ERROR_OK)
|
||||
{
|
||||
if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
|
||||
|
|
Loading…
Reference in New Issue