15e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Copyright (C) 2007-2011 The Android Open Source Project
25e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine**
35e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine** This software is licensed under the terms of the GNU General Public
45e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine** License version 2, as published by the Free Software Foundation, and
55e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine** may be copied, distributed, and modified under those terms.
65e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine**
75e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine** This program is distributed in the hope that it will be useful,
85e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine** but WITHOUT ANY WARRANTY; without even the implied warranty of
95e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
105e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine** GNU General Public License for more details.
115e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine*/
125e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
135e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/*
145e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * Contains implementation of a class DumpFile of routines that implements
155e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * access to a log file.
165e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine */
175e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
185e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#include <stdio.h>
195e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#include <stdlib.h>
205e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#include <string.h>
215e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#include <errno.h>
22f9e88edc21c894886747e899dc29c02a28728d65Vladimir Chtchetkine#include "regex/regex.h"
237ecfaaa424d561d670f643993bb9b373db85d832Vladimir Chtchetkine#include "elff/elff_api.h"
245e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
255e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#include "ndk-stack-parser.h"
265e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
275e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Enumerates states of the crash parser.
285e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine */
295e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinetypedef enum NDK_CRASH_PARSER_STATE {
305e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  /* Parser expects the beginning of the crash dump. */
315e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  EXPECTS_CRASH_DUMP,
325e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  /* Parser expects the build fingerprint, or process and thread information. */
335e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  EXPECTS_BUILD_FINGREPRINT_OR_PID,
345e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  /* Parser expects the process and thread information. */
355e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  EXPECTS_PID,
365e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  /* Parser expects the signal information, or the first crash frame. */
375e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  EXPECTS_SIGNAL_OR_FRAME,
385e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  /* Parser expects a crash frame. */
395e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  EXPECTS_FRAME,
405e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine} NDK_CRASH_PARSER_STATE;
415e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
425e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Crash parser descriptor.
435e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine */
445e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestruct NdkCrashParser {
455e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  /* Handle to the stream where to print the output. */
465e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  FILE*                 out_handle;
475e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
485e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  /* Path to the root folder where symbols are stored. */
495e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  char*                 sym_root;
505e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
515e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  /* Current state of the parser. */
525e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  NDK_CRASH_PARSER_STATE state;
53c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner
54c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  /* Compiled regular expressions */
55c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  regex_t     re_pid_header;
56c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  regex_t     re_sig_header;
57c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  regex_t     re_frame_header;
585e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine};
595e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
605e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Crash dumps begin with a string containing this substring. */
615e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char _crash_dump_header[] =
625e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***";
635e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
645e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Build fingerprint contains this substring. */
655e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char _build_fingerprint_header[] = "Build fingerprint:";
665e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
675e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Regular expression for the process ID information line. */
687ecfaaa424d561d670f643993bb9b373db85d832Vladimir Chtchetkinestatic const char _pid_header[] = "pid: [0-9]+, tid: [0-9]+.*";
695e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
705e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Regular expression for the signal information line. */
717ecfaaa424d561d670f643993bb9b373db85d832Vladimir Chtchetkinestatic const char _sig_header[] = "signal*[ \t][0-9]+";
725e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
735e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Regular expression for the frame information line. */
74b3682c489e0c54b1ab05f78e8f91d0642bf975e1Vladimir Chtchetkinestatic const char _frame_header[] = "\\#[0-9]+[ |\t]+[pc|eip]+:*[ |\t]+([0-9a-f]{8})*";
755e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
765e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#ifndef min
775e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#define min(a,b) (((a) < (b)) ? a : b)
785e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#endif
795e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
805e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Parses a line representing a crash frame.
815e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * This routine will try to obtain source file / line information for the
825e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * frame's address, and print that information to the specified output handle.
835e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * Param:
845e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *  parser - NdkCrashParser descriptor, created and initialized with a call to
855e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *    NdkCrashParser routine.
865e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *  frame - Line containing crash frame.
875e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * Return:
885e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *  0 If source file information has been found and printed, or -1 if that
895e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *  information was not available.
905e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine */
915e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic int ParseFrame(NdkCrashParser* parser, const char* frame);
925e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
935e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Matches a string against a regular expression.
945e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * Param:
955e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *  line - String to matches against the regular expression.
965e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *  regex - Regular expression to match the string against.
975e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *  match - Upon successful match contains information about the part of the
985e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *    string that matches the regular expression.
995e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * Return:
1005e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *  Boolean: 1 if a match has been found, or 0 if match has not been found in
1015e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *  the string.
1025e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine */
103c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turnerstatic int MatchRegex(const char* line, const regex_t* regex, regmatch_t* match);
1045e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1055e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Returns pointer to the next separator (a space, or a tab) in the string. */
1065e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char* next_separator(const char* str);
1075e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1085e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Returns pointer to the next token (a character other than space, or a tab)
1095e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * in the string.
1105e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine */
1115e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char* next_token(const char* str);
1125e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1135e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Gets next token from the string.
1145e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * param:
1155e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *  str - String where to get the next token from. Note that if string begins
1165e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *    with a separator, this routine will return first token after that
1175e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *    separator. If string begins with a token, this routine will return next
1185e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *    token after that.
1195e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *  token - Upon success contains a copy of the next token in the string.
1205e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *  size - Size of the 'token' buffer.
1215e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * Return:
1225e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine *  Beginning of the returned token in the string.
1235e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine */
1245e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char* get_next_token(const char* str, char* token, size_t size);
1255e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1265e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineNdkCrashParser*
1275e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineCreateNdkCrashParser(FILE* out_handle, const char* sym_root)
1285e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
129c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  NdkCrashParser* parser;
130c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner
131c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  parser = (NdkCrashParser*)calloc(sizeof(*parser), 1);
132c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  if (parser == NULL)
133c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      return NULL;
134c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner
135c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  parser->out_handle = out_handle;
136c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  parser->state      = EXPECTS_CRASH_DUMP;
137c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner
138c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  parser->sym_root = strdup(sym_root);
139c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  if (!parser->sym_root)
140c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      goto BAD_INIT;
141c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner
142c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  if (regcomp(&parser->re_pid_header, _pid_header, REG_EXTENDED | REG_NEWLINE) ||
143c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      regcomp(&parser->re_sig_header, _sig_header, REG_EXTENDED | REG_NEWLINE) ||
144c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      regcomp(&parser->re_frame_header, _frame_header, REG_EXTENDED | REG_NEWLINE))
145c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      goto BAD_INIT;
1465e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1475e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  return parser;
148c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner
149c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' TurnerBAD_INIT:
150c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  DestroyNdkCrashParser(parser);
151c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  return NULL;
1525e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
1535e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1545e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinevoid
1555e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineDestroyNdkCrashParser(NdkCrashParser* parser)
1565e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
1575e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  if (parser != NULL) {
158c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    /* Release compiled regular expressions */
159c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    regfree(&parser->re_frame_header);
160c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    regfree(&parser->re_sig_header);
161c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    regfree(&parser->re_pid_header);
162c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    /* Release symbol path */
163c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    free(parser->sym_root);
164c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    /* Release parser itself */
1655e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    free(parser);
1665e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
1675e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
1685e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1695e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkineint
1705e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineParseLine(NdkCrashParser* parser, const char* line)
1715e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
1725e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  regmatch_t match;
1735e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1745e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  if (line == NULL || *line == '\0') {
1755e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    // Nothing to parse.
1765e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    return 1;
1775e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
1785e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1795e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // Lets see if this is the beginning of a crash dump.
1805e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  if (strstr(line, _crash_dump_header) != NULL) {
1815e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    if (parser->state != EXPECTS_CRASH_DUMP) {
1825e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      // Printing another crash dump was in progress. Mark the end of it.
1835e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      fprintf(parser->out_handle, "Crash dump is completed\n\n");
1845e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    }
1855e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1865e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    // New crash dump begins.
1875e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    fprintf(parser->out_handle, "********** Crash dump: **********\n");
1885e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    parser->state = EXPECTS_BUILD_FINGREPRINT_OR_PID;
1895e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1905e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    return 0;
1915e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
1925e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1935e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  switch (parser->state) {
1945e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    case EXPECTS_BUILD_FINGREPRINT_OR_PID:
1955e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      if (strstr(line, _build_fingerprint_header) != NULL) {
1965e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        fprintf(parser->out_handle, "%s\n",
1975e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine                strstr(line, _build_fingerprint_header));
1985e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        parser->state = EXPECTS_PID;
1995e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      }
2005e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      // Let it fall through to the EXPECTS_PID, in case the dump doesn't
2015e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      // contain build fingerprint.
2025e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    case EXPECTS_PID:
203c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      if (MatchRegex(line, &parser->re_pid_header, &match)) {
2045e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        fprintf(parser->out_handle, "%s\n", line + match.rm_so);
2055e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        parser->state = EXPECTS_SIGNAL_OR_FRAME;
2065e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        return 0;
2075e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      } else {
2085e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        return 1;
2095e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      }
2105e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2115e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    case EXPECTS_SIGNAL_OR_FRAME:
212c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      if (MatchRegex(line, &parser->re_sig_header, &match)) {
2135e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        fprintf(parser->out_handle, "%s\n", line + match.rm_so);
2145e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        parser->state = EXPECTS_FRAME;
2155e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      }
2165e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      // Let it fall through to the EXPECTS_FRAME, in case the dump doesn't
2175e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      // contain signal fingerprint.
2185e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    case EXPECTS_FRAME:
219c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      if (MatchRegex(line, &parser->re_frame_header, &match)) {
2205e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        parser->state = EXPECTS_FRAME;
2215e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        return ParseFrame(parser, line + match.rm_so);
2225e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      } else {
2235e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        return 1;
2245e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      }
2255e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2265e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    default:
2275e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      return 1;
2285e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
2295e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
2305e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2315e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic int
232c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' TurnerMatchRegex(const char* line, const regex_t* regex, regmatch_t* match)
2335e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
234c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  int err = regexec(regex, line, 1, match, 0x00400/*REG_TRACE*/);
2355e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#if 0
23627db2fc052a03217689a4be833ad79458742d7faLogan Chien  char rerr[4096];
23727db2fc052a03217689a4be833ad79458742d7faLogan Chien  if (err) {
23827db2fc052a03217689a4be833ad79458742d7faLogan Chien    regerror(err, regex, rerr, sizeof(rerr));
23927db2fc052a03217689a4be833ad79458742d7faLogan Chien    fprintf(stderr, "regexec(%s, %s) has failed: %s\n", line, regex, rerr);
24027db2fc052a03217689a4be833ad79458742d7faLogan Chien  }
2415e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#endif
2427ecfaaa424d561d670f643993bb9b373db85d832Vladimir Chtchetkine
243c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  return err == 0;
2445e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
2455e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2465e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char*
2475e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinenext_separator(const char* str)
2485e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
2495e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  return str + strcspn(str, " \t");
2505e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
2515e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2525e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char*
2535e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinenext_token(const char* str)
2545e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
2555e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  str = next_separator(str);
2565e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  return str + strspn(str, " \t");
2575e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
2585e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2595e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char*
2605e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkineget_next_token(const char* str, char* token, size_t size)
2615e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
2625e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  const char* start = next_token(str);
2635e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  const char* end = next_separator(start);
2645e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  if (start != end) {
265273fd4fcae7d1ee68ff3096108f623c6db6007a8Logan Chien    const size_t to_copy = min((size_t)(end - start), (size - 1));
2665e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    memcpy(token, start, to_copy);
2675e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    token[to_copy] = '\0';
2685e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    return start;
2695e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  } else {
2705e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    return NULL;
2715e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
2725e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
2735e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2745e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkineint
2755e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineParseFrame(NdkCrashParser* parser, const char* frame)
2765e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
2775e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  uint64_t address;
2785e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  const char* wrk;
2795e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  char* eptr;
2805e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  char pc_address[17];
2815e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  char module_path[2048];
282c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  char* module_name;
2835e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  char sym_file[2048];
2845e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  ELFF_HANDLE elff_handle;
2855e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  Elf_AddressInfo pc_info;
2865e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
287c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  fprintf(parser->out_handle, "Stack frame %s", frame);
2885e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2895e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // Advance to the instruction pointer token.
2905e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  wrk = strstr(frame, "pc");
2915e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  if (wrk == NULL) {
2925e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    wrk = strstr(frame, "eip");
2935e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    if (wrk == NULL) {
2945e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      wrk = strstr(frame, "ip");
2955e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      if (wrk == NULL) {
2965e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        fprintf(parser->out_handle,
2975e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine                "Parser is unable to locate instruction pointer token.\n");
2985e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        return -1;
2995e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      }
3005e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    }
3015e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
3025e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
3035e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // Next token after the instruction pointer token is its address.
3045e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  wrk = get_next_token(wrk, pc_address, sizeof(pc_address));
3055e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // PC address is a hex value. Get it.
3065e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  eptr = pc_address + strlen(pc_address);
3075e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  address = strtoul(pc_address, &eptr, 16);
3085e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
3095e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // Next token is module path.
3105e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  get_next_token(wrk, module_path, sizeof(module_path));
3115e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
312c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  // Extract basename of module, we should not care about its path
313c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  // on the device.
314c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  module_name = strrchr(module_path,'/');
315c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  if (module_name == NULL)
316c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      module_name = module_path;
317c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  else {
318c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      module_name += 1;
319c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      if (*module_name == '\0') {
320c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner          /* Trailing slash in the module path, this should not happen */
321c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner          /* Back-off with the full module-path */
322c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner          module_name = module_path;
323c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      }
324c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  }
325c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner
3265e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // Build path to the symbol file.
3275079ebbb32c44bb3a4bc3602d696521eba6abfffLogan Chien  snprintf(sym_file, sizeof(sym_file), "%s/%s", parser->sym_root, module_name);
3285e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
3295e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // Init ELFF wrapper for the symbol file.
3305e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  elff_handle = elff_init(sym_file);
3315e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  if (elff_handle == NULL) {
332c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    if (errno == ENOENT) {
333c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner        fprintf(parser->out_handle, "\n");
334c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    } else {
335c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner        fprintf(parser->out_handle,
336c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner                ": Unable to open symbol file %s. Error (%d): %s\n",
337c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner                sym_file, errno, strerror(errno));
338c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    }
3395e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    return -1;
3405e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
3415e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // Extract address info from the symbol file.
3425e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  if (!elff_get_pc_address_info(elff_handle, address, &pc_info)) {
3435e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    if (pc_info.dir_name != NULL) {
344c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      fprintf(parser->out_handle, ": Routine %s in %s/%s:%d\n",
3455e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine              pc_info.routine_name, pc_info.dir_name, pc_info.file_name,
3465e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine              pc_info.line_number);
3475e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    } else {
348c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      fprintf(parser->out_handle, ": Routine %s in %s:%d\n",
3495e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine              pc_info.routine_name, pc_info.file_name, pc_info.line_number);
3505e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    }
3515e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    elff_free_pc_address_info(elff_handle, &pc_info);
3525e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    elff_close(elff_handle);
3535e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    return 0;
3545e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  } else {
3555e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    fprintf(parser->out_handle,
356c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner            ": Unable to locate routine information for address %x in module %s\n",
3575e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine            (uint32_t)address, sym_file);
3585e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    elff_close(elff_handle);
3595e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    return -1;
3605e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
3615e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
362