Пример #1
0
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;
}
Пример #2
0
/**
 * 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;

}
Пример #3
0
/**
 * 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;
}
Пример #4
0
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;
}
Пример #5
0
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;
}