/* constructor */ PyObject *p_btp_frame_new(PyTypeObject *object, PyObject *args, PyObject *kwds) { FrameObject *fo = (FrameObject *)PyObject_New(FrameObject, &FrameTypeObject); if (!fo) return PyErr_NoMemory(); const char *str = NULL; if (!PyArg_ParseTuple(args, "|s", &str)) return NULL; if (str) { struct btp_location location; btp_location_init(&location); fo->frame = btp_frame_parse(&str, &location); if (!fo->frame) { PyErr_SetString(PyExc_ValueError, location.message); return NULL; } } else fo->frame = btp_frame_new(); return (PyObject *)fo; }
struct btp_thread * btp_thread_parse(char **input, struct btp_location *location) { char *local_input = *input; /* Read the Thread keyword, which is mandatory. */ int chars = btp_skip_string(&local_input, "Thread"); location->column += chars; if (0 == chars) { location->message = "\"Thread\" header expected"; return NULL; } /* Skip spaces, at least one space is mandatory. */ int spaces = btp_skip_char_sequence(&local_input, ' '); location->column += spaces; if (0 == spaces) { location->message = "Space expected after the \"Thread\" keyword."; return NULL; } /* Read thread number. */ struct btp_thread *imthread = btp_thread_new(); int digits = btp_parse_unsigned_integer(&local_input, &imthread->number); location->column += digits; if (0 == digits) { location->message = "Thread number expected."; btp_thread_free(imthread); return NULL; } /* Skip spaces after the thread number and before parentheses. */ spaces = btp_skip_char_sequence(&local_input, ' '); location->column += spaces; if (0 == spaces) { location->message = "Space expected after the thread number."; btp_thread_free(imthread); return NULL; } /* Read the LWP section in parentheses, optional. */ location->column += btp_thread_skip_lwp(&local_input); /* Read the Thread keyword in parentheses, optional. */ chars = btp_skip_string(&local_input, "(Thread "); location->column += chars; if (0 != chars) { /* Read the thread identification number. It can be either in * decimal or hexadecimal form. * Examples: * "Thread 10 (Thread 2476):" * "Thread 8 (Thread 0xb07fdb70 (LWP 6357)):" */ digits = btp_skip_hexadecimal_number(&local_input); if (0 == digits) digits = btp_skip_unsigned_integer(&local_input); location->column += digits; if (0 == digits) { location->message = "The thread identification number expected."; btp_thread_free(imthread); return NULL; } /* Handle the optional " (LWP [0-9]+)" section. */ location->column += btp_skip_char_sequence(&local_input, ' '); location->column += btp_thread_skip_lwp(&local_input); /* Read the end of the parenthesis. */ if (!btp_skip_char(&local_input, ')')) { location->message = "Closing parenthesis for Thread expected."; btp_thread_free(imthread); return NULL; } } /* Read the end of the header line. */ chars = btp_skip_string(&local_input, ":\n"); if (0 == chars) { location->message = "Expected a colon followed by a newline ':\\n'."; btp_thread_free(imthread); return NULL; } /* Add the newline from the last btp_skip_string. */ btp_location_add(location, 2, 0); /* Read the frames. */ struct btp_frame *frame, *prevframe = NULL; struct btp_location frame_location; btp_location_init(&frame_location); while ((frame = btp_frame_parse(&local_input, &frame_location))) { if (prevframe) { btp_frame_add_sibling(prevframe, frame); prevframe = frame; } else imthread->frames = prevframe = frame; btp_location_add(location, frame_location.line, frame_location.column); } if (!imthread->frames) { location->message = frame_location.message; btp_thread_free(imthread); return NULL; } *input = local_input; return imthread; }
bool btp_backtrace_parse_header(const char **input, struct btp_frame **frame, struct btp_location *location) { int first_thread_line, first_thread_column; const char *first_thread = btp_strstr_location(*input, "\nThread ", &first_thread_line, &first_thread_column); /* Skip the newline. */ if (first_thread) { ++first_thread; first_thread_line += 1; first_thread_column = 0; } int first_frame_line, first_frame_column; const char *first_frame = btp_strstr_location(*input, "\n#", &first_frame_line, &first_frame_column); /* Skip the newline. */ if (first_frame) { ++first_frame; first_frame_line += 1; first_frame_column = 0; } if (first_thread) { if (first_frame && first_frame < first_thread) { /* Common case. The crash frame is present in the input * before the list of threads begins. */ *input = first_frame; btp_location_add(location, first_frame_line, first_frame_column); } else { /* Uncommon case (caused by some kernel bug) where the * frame is missing from the header. The backtrace * contains just threads. We silently skip the header and * return true. */ *input = first_thread; btp_location_add(location, first_thread_line, first_thread_column); *frame = NULL; return true; } } else if (first_frame) { /* Degenerate case when the backtrace contains no thread, but * the frame is there. */ *input = first_frame; btp_location_add(location, first_frame_line, first_frame_column); } else { /* Degenerate case where the input is empty or completely * meaningless. Report a failure. */ location->message = "No frame and no thread found."; return false; } /* Parse the frame header. */ *frame = btp_frame_parse(input, location); return *frame; }