enum gdbwire_result gdbmi_parser_push_data(struct gdbmi_parser *parser, const char *data, size_t size) { struct gdbwire_string *line = 0; enum gdbwire_result result = GDBWIRE_OK; GDBWIRE_ASSERT(parser && data); GDBWIRE_ASSERT(gdbwire_string_append_data(parser->buffer, data, size) == 0); // Loop until no more lines available for (;;) { result = gdbmi_parser_get_next_line(parser->buffer, &line); GDBWIRE_ASSERT_GOTO(result == GDBWIRE_OK, result, cleanup); if (line) { result = gdbmi_parser_parse_line(parser, gdbwire_string_data(line)); gdbwire_string_destroy(line); line = 0; GDBWIRE_ASSERT_GOTO(result == GDBWIRE_OK, result, cleanup); } else { break; } } cleanup: return result; }
/** * Get the next line available in the buffer. * * @param buffer * The entire buffer the user has pushed onto the gdbmi parser * through gdbmi_parser_push. If a line is found, the returned line * will be removed from this buffer. * * @param line * Will return as an allocated line if a line is available or NULL * otherwise. If this function does not return GDBWIRE_OK then ignore * the output of this parameter. It is the callers responsibility to * free the memory. * * @return * GDBWIRE_OK on success or appropriate error result on failure. */ static enum gdbwire_result gdbmi_parser_get_next_line(struct gdbwire_string *buffer, struct gdbwire_string **line) { enum gdbwire_result result = GDBWIRE_OK; GDBWIRE_ASSERT(buffer && line); char *data = gdbwire_string_data(buffer); size_t size = gdbwire_string_size(buffer); size_t pos = gdbwire_string_find_first_of(buffer, "\r\n"); // Search to see if a newline has been reached in gdb/mi. // If a line of data has been recieved, process it. if (pos != size) { int status; /** * We have the position of the newline character from * gdbwire_string_find_first_of. However, the length must be * calculated to make a copy of the line. * * This is either pos + 1 (for \r or \n) or pos + 1 + 1 for (\r\n). * Check for\r\n for the special case. */ size_t line_length = (data[pos] == '\r' && (pos + 1 < size) && data[pos + 1] == '\n') ? pos + 2 : pos + 1; /** * - allocate the buffer * - append the new line * - append a null terminating character * - if successful, delete the new line found from buffer * - any failures cleanup and return an error */ *line = gdbwire_string_create(); GDBWIRE_ASSERT(*line); status = gdbwire_string_append_data(*line, data, line_length); GDBWIRE_ASSERT_GOTO(status == 0, result, cleanup); status = gdbwire_string_append_data(*line, "\0", 1); GDBWIRE_ASSERT_GOTO(status == 0, result, cleanup); status = gdbwire_string_erase(buffer, 0, line_length); GDBWIRE_ASSERT_GOTO(status == 0, result, cleanup); } return result; cleanup: gdbwire_string_destroy(*line); *line = 0; return result; }
/** * Parse a single line of output in GDB/MI format. * * The normal usage of this function is to call it over and over again with * more data lines and wait for it to return an mi output command. * * @param parser * The parser context to operate on. * * @param line * A line of output in GDB/MI format to be parsed. * * \return * GDBWIRE_OK on success or appropriate error result on failure. */ static enum gdbwire_result gdbmi_parser_parse_line(struct gdbmi_parser *parser, const char *line) { struct gdbmi_parser_callbacks callbacks = gdbmi_parser_get_callbacks(parser); struct gdbmi_output *output = 0; YY_BUFFER_STATE state = 0; int pattern, mi_status; GDBWIRE_ASSERT(parser && line); /* Create a new input buffer for flex. */ state = gdbmi__scan_string(line, parser->mils); GDBWIRE_ASSERT(state); gdbmi_set_column(1, parser->mils); /* Iterate over all the tokens found in the scanner buffer */ do { pattern = gdbmi_lex(parser->mils); if (pattern == 0) break; mi_status = gdbmi_push_parse(parser->mips, pattern, NULL, parser->mils, &output); } while (mi_status == YYPUSH_MORE); /* Free the scanners buffer */ gdbmi__delete_buffer(state, parser->mils); /** * The push parser will return, * - 0 if parsing was successful (return is due to end-of-input). * - 1 if parsing failed because of invalid input, i.e., input * that contains a syntax error or that causes YYABORT to be invoked. * - 2 if parsing failed due to memory exhaustion. * - YYPUSH_MORE if more input is required to finish parsing the grammar. * Anything besides this would be unexpected. * * The grammar is designed to accept an infinate list of GDB/MI * output commands. For this reason, YYPUSH_MORE is the expected * return value of all the calls to gdbmi_push_parse. However, * in reality, gdbwire only translates a line at a time from GDB. * When the line is finished, gdbmi_lex returns 0, and the parsing * is done. */ // Check mi_status, will be 1 on parse error, and YYPUSH_MORE on success GDBWIRE_ASSERT(mi_status == 1 || mi_status == YYPUSH_MORE); /* Each GDB/MI line should produce an output command */ GDBWIRE_ASSERT(output); output->line = strdup(line); callbacks.gdbmi_output_callback(callbacks.context, output); return GDBWIRE_OK; }
enum gdbwire_result gdbwire_interpreter_exec( const char *interpreter_exec_output, enum gdbwire_mi_command_kind kind, struct gdbwire_mi_command **out_mi_command) { struct gdbwire_interpreter_exec_context context = { GDBWIRE_OK, kind, 0 }; size_t len; enum gdbwire_result result = GDBWIRE_OK; struct gdbwire_callbacks callbacks = { &context, gdbwire_interpreter_exec_stream_record, gdbwire_interpreter_exec_async_record, gdbwire_interpreter_exec_result_record, gdbwire_interpreter_exec_prompt, gdbwire_interpreter_exec_parse_error }; struct gdbwire *wire; GDBWIRE_ASSERT(interpreter_exec_output); GDBWIRE_ASSERT(out_mi_command); len = strlen(interpreter_exec_output); wire = gdbwire_create(callbacks); GDBWIRE_ASSERT(wire); result = gdbwire_push_data(wire, interpreter_exec_output, len); if (result == GDBWIRE_OK) { /* Honor function documentation, * When it returns GDBWIRE_OK - the command will exist. * Otherwise it will not. */ if (context.result == GDBWIRE_OK && !context.mi_command) { result = GDBWIRE_LOGIC; } else if (context.result != GDBWIRE_OK && context.mi_command) { result = context.result; gdbwire_mi_command_free(context.mi_command); } else { result = context.result; *out_mi_command = context.mi_command; } } gdbwire_destroy(wire); return result; }
enum gdbwire_result gdbwire_push_data(struct gdbwire *wire, const char *data, size_t size) { enum gdbwire_result result; GDBWIRE_ASSERT(wire); result = gdbwire_mi_parser_push_data(wire->parser, data, size); return result; }