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