ndk-stack-parser.c revision 5647b5efe1584bfcb3ed10ca617f7b1d73f63d9b
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 185647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh#include <inttypes.h> 195e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#include <stdio.h> 205e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#include <stdlib.h> 215e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#include <string.h> 225e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#include <errno.h> 23f9e88edc21c894886747e899dc29c02a28728d65Vladimir Chtchetkine#include "regex/regex.h" 247ecfaaa424d561d670f643993bb9b373db85d832Vladimir Chtchetkine#include "elff/elff_api.h" 255e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 265e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#include "ndk-stack-parser.h" 275e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 285e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Enumerates states of the crash parser. 295e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine */ 305e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinetypedef enum NDK_CRASH_PARSER_STATE { 315e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine /* Parser expects the beginning of the crash dump. */ 325e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine EXPECTS_CRASH_DUMP, 335e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine /* Parser expects the build fingerprint, or process and thread information. */ 345e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine EXPECTS_BUILD_FINGREPRINT_OR_PID, 355e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine /* Parser expects the process and thread information. */ 365e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine EXPECTS_PID, 375e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine /* Parser expects the signal information, or the first crash frame. */ 385e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine EXPECTS_SIGNAL_OR_FRAME, 395e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine /* Parser expects a crash frame. */ 405e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine EXPECTS_FRAME, 415e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine} NDK_CRASH_PARSER_STATE; 425e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 435e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Crash parser descriptor. 445e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine */ 455e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestruct NdkCrashParser { 465e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine /* Handle to the stream where to print the output. */ 475e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine FILE* out_handle; 485e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 495e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine /* Path to the root folder where symbols are stored. */ 505e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine char* sym_root; 515e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 525e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine /* Current state of the parser. */ 535e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine NDK_CRASH_PARSER_STATE state; 54c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner 55c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner /* Compiled regular expressions */ 56c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner regex_t re_pid_header; 57c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner regex_t re_sig_header; 58c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner regex_t re_frame_header; 595e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}; 605e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 615e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Crash dumps begin with a string containing this substring. */ 625e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char _crash_dump_header[] = 635e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***"; 645e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 655e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Build fingerprint contains this substring. */ 665e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char _build_fingerprint_header[] = "Build fingerprint:"; 675e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 685e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Regular expression for the process ID information line. */ 697ecfaaa424d561d670f643993bb9b373db85d832Vladimir Chtchetkinestatic const char _pid_header[] = "pid: [0-9]+, tid: [0-9]+.*"; 705e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 715e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Regular expression for the signal information line. */ 727ecfaaa424d561d670f643993bb9b373db85d832Vladimir Chtchetkinestatic const char _sig_header[] = "signal*[ \t][0-9]+"; 735e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 745e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Regular expression for the frame information line. */ 75b3682c489e0c54b1ab05f78e8f91d0642bf975e1Vladimir Chtchetkinestatic const char _frame_header[] = "\\#[0-9]+[ |\t]+[pc|eip]+:*[ |\t]+([0-9a-f]{8})*"; 765e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 775e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#ifndef min 785e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#define min(a,b) (((a) < (b)) ? a : b) 795e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#endif 805e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 815e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Parses a line representing a crash frame. 825e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * This routine will try to obtain source file / line information for the 835e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * frame's address, and print that information to the specified output handle. 845e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * Param: 855e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * parser - NdkCrashParser descriptor, created and initialized with a call to 865e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * NdkCrashParser routine. 875e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * frame - Line containing crash frame. 885e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * Return: 895e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * 0 If source file information has been found and printed, or -1 if that 905e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * information was not available. 915e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine */ 925e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic int ParseFrame(NdkCrashParser* parser, const char* frame); 935e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 945e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Matches a string against a regular expression. 955e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * Param: 965e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * line - String to matches against the regular expression. 975e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * regex - Regular expression to match the string against. 985e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * match - Upon successful match contains information about the part of the 995e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * string that matches the regular expression. 1005e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * Return: 1015e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * Boolean: 1 if a match has been found, or 0 if match has not been found in 1025e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * the string. 1035e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine */ 104c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turnerstatic int MatchRegex(const char* line, const regex_t* regex, regmatch_t* match); 1055e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 1065e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Returns pointer to the next separator (a space, or a tab) in the string. */ 1075e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char* next_separator(const char* str); 1085e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 1095e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Returns pointer to the next token (a character other than space, or a tab) 1105e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * in the string. 1115e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine */ 1125e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char* next_token(const char* str); 1135e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 1145e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine/* Gets next token from the string. 1155e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * param: 1165e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * str - String where to get the next token from. Note that if string begins 1175e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * with a separator, this routine will return first token after that 1185e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * separator. If string begins with a token, this routine will return next 1195e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * token after that. 1205e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * token - Upon success contains a copy of the next token in the string. 1215e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * size - Size of the 'token' buffer. 1225e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * Return: 1235e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine * Beginning of the returned token in the string. 1245e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine */ 1255e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char* get_next_token(const char* str, char* token, size_t size); 1265e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 1275e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineNdkCrashParser* 1285e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineCreateNdkCrashParser(FILE* out_handle, const char* sym_root) 1295e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{ 130c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner NdkCrashParser* parser; 131c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner 132c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner parser = (NdkCrashParser*)calloc(sizeof(*parser), 1); 133c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner if (parser == NULL) 134c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner return NULL; 135c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner 136c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner parser->out_handle = out_handle; 137c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner parser->state = EXPECTS_CRASH_DUMP; 138c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner 139c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner parser->sym_root = strdup(sym_root); 140c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner if (!parser->sym_root) 141c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner goto BAD_INIT; 142c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner 143c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner if (regcomp(&parser->re_pid_header, _pid_header, REG_EXTENDED | REG_NEWLINE) || 144c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner regcomp(&parser->re_sig_header, _sig_header, REG_EXTENDED | REG_NEWLINE) || 145c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner regcomp(&parser->re_frame_header, _frame_header, REG_EXTENDED | REG_NEWLINE)) 146c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner goto BAD_INIT; 1475e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 1485e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine return parser; 149c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner 150c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' TurnerBAD_INIT: 151c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner DestroyNdkCrashParser(parser); 152c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner return NULL; 1535e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine} 1545e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 1555e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinevoid 1565e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineDestroyNdkCrashParser(NdkCrashParser* parser) 1575e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{ 1585e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine if (parser != NULL) { 159c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner /* Release compiled regular expressions */ 160c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner regfree(&parser->re_frame_header); 161c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner regfree(&parser->re_sig_header); 162c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner regfree(&parser->re_pid_header); 163c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner /* Release symbol path */ 164c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner free(parser->sym_root); 165c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner /* Release parser itself */ 1665e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine free(parser); 1675e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 1685e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine} 1695e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 1705e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkineint 1715e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineParseLine(NdkCrashParser* parser, const char* line) 1725e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{ 1735e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine regmatch_t match; 1745647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh int found = 0; 1755e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 1765e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine if (line == NULL || *line == '\0') { 1775e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // Nothing to parse. 1785e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine return 1; 1795e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 1805e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 1815e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // Lets see if this is the beginning of a crash dump. 1825e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine if (strstr(line, _crash_dump_header) != NULL) { 1835e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine if (parser->state != EXPECTS_CRASH_DUMP) { 1845e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // Printing another crash dump was in progress. Mark the end of it. 1855e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine fprintf(parser->out_handle, "Crash dump is completed\n\n"); 1865e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 1875e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 1885e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // New crash dump begins. 1895e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine fprintf(parser->out_handle, "********** Crash dump: **********\n"); 1905e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine parser->state = EXPECTS_BUILD_FINGREPRINT_OR_PID; 1915e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 1925e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine return 0; 1935e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 1945e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 1955e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine switch (parser->state) { 1965e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine case EXPECTS_BUILD_FINGREPRINT_OR_PID: 1975e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine if (strstr(line, _build_fingerprint_header) != NULL) { 1985e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine fprintf(parser->out_handle, "%s\n", 1995e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine strstr(line, _build_fingerprint_header)); 2005e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine parser->state = EXPECTS_PID; 2015647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh found = 1; 2025e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 2035e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // Let it fall through to the EXPECTS_PID, in case the dump doesn't 2045e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // contain build fingerprint. 2055e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine case EXPECTS_PID: 206c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner if (MatchRegex(line, &parser->re_pid_header, &match)) { 2075e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine fprintf(parser->out_handle, "%s\n", line + match.rm_so); 2085e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine parser->state = EXPECTS_SIGNAL_OR_FRAME; 2095e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine return 0; 2105e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } else { 2115647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh return !found; 2125e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 2135e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 2145e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine case EXPECTS_SIGNAL_OR_FRAME: 215c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner if (MatchRegex(line, &parser->re_sig_header, &match)) { 2165e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine fprintf(parser->out_handle, "%s\n", line + match.rm_so); 2175e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine parser->state = EXPECTS_FRAME; 2185647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh found = 1; 2195e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 2205e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // Let it fall through to the EXPECTS_FRAME, in case the dump doesn't 2215e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // contain signal fingerprint. 2225e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine case EXPECTS_FRAME: 223c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner if (MatchRegex(line, &parser->re_frame_header, &match)) { 2245e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine parser->state = EXPECTS_FRAME; 2255e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine return ParseFrame(parser, line + match.rm_so); 2265e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } else { 2275647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh return !found; 2285e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 2295e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 2305e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine default: 2315e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine return 1; 2325e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 2335e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine} 2345e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 2355e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic int 236c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' TurnerMatchRegex(const char* line, const regex_t* regex, regmatch_t* match) 2375e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{ 238c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner int err = regexec(regex, line, 1, match, 0x00400/*REG_TRACE*/); 2395e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#if 0 24027db2fc052a03217689a4be833ad79458742d7faLogan Chien char rerr[4096]; 24127db2fc052a03217689a4be833ad79458742d7faLogan Chien if (err) { 24227db2fc052a03217689a4be833ad79458742d7faLogan Chien regerror(err, regex, rerr, sizeof(rerr)); 24327db2fc052a03217689a4be833ad79458742d7faLogan Chien fprintf(stderr, "regexec(%s, %s) has failed: %s\n", line, regex, rerr); 24427db2fc052a03217689a4be833ad79458742d7faLogan Chien } 2455e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#endif 2467ecfaaa424d561d670f643993bb9b373db85d832Vladimir Chtchetkine 247c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner return err == 0; 2485e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine} 2495e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 2505e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char* 2515e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinenext_separator(const char* str) 2525e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{ 2535e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine return str + strcspn(str, " \t"); 2545e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine} 2555e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 2565e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char* 2575e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinenext_token(const char* str) 2585e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{ 2595e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine str = next_separator(str); 2605e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine return str + strspn(str, " \t"); 2615e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine} 2625e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 2635e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char* 2645e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkineget_next_token(const char* str, char* token, size_t size) 2655e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{ 2665e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine const char* start = next_token(str); 2675e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine const char* end = next_separator(start); 2685e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine if (start != end) { 269273fd4fcae7d1ee68ff3096108f623c6db6007a8Logan Chien const size_t to_copy = min((size_t)(end - start), (size - 1)); 2705e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine memcpy(token, start, to_copy); 2715e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine token[to_copy] = '\0'; 2725e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine return start; 2735e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } else { 2745e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine return NULL; 2755e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 2765e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine} 2775e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 2785e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkineint 2795e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineParseFrame(NdkCrashParser* parser, const char* frame) 2805e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{ 2815e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine uint64_t address; 2825e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine const char* wrk; 2835e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine char* eptr; 2845e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine char pc_address[17]; 2855e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine char module_path[2048]; 286c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner char* module_name; 2875e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine char sym_file[2048]; 2885647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh#if !defined(WITH_LIBBFD) 2895e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine ELFF_HANDLE elff_handle; 2905e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine Elf_AddressInfo pc_info; 2915647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh#else 2925647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh const int ac = 5; 2935647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh char *av[ac]; 2945647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh FILE *f; 2955647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh#endif 2965e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 297c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner fprintf(parser->out_handle, "Stack frame %s", frame); 2985e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 2995e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // Advance to the instruction pointer token. 3005e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine wrk = strstr(frame, "pc"); 3015e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine if (wrk == NULL) { 3025e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine wrk = strstr(frame, "eip"); 3035e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine if (wrk == NULL) { 3045e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine wrk = strstr(frame, "ip"); 3055e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine if (wrk == NULL) { 3065e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine fprintf(parser->out_handle, 3075e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine "Parser is unable to locate instruction pointer token.\n"); 3085e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine return -1; 3095e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 3105e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 3115e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 3125e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 3135e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // Next token after the instruction pointer token is its address. 3145e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine wrk = get_next_token(wrk, pc_address, sizeof(pc_address)); 3155e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // PC address is a hex value. Get it. 3165e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine eptr = pc_address + strlen(pc_address); 3175e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine address = strtoul(pc_address, &eptr, 16); 3185e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 3195e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // Next token is module path. 3205e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine get_next_token(wrk, module_path, sizeof(module_path)); 3215e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 322c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner // Extract basename of module, we should not care about its path 323c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner // on the device. 324c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner module_name = strrchr(module_path,'/'); 325c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner if (module_name == NULL) 326c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner module_name = module_path; 327c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner else { 328c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner module_name += 1; 329c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner if (*module_name == '\0') { 330c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner /* Trailing slash in the module path, this should not happen */ 331c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner /* Back-off with the full module-path */ 332c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner module_name = module_path; 333c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner } 334c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner } 335c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner 3365e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // Build path to the symbol file. 3375079ebbb32c44bb3a4bc3602d696521eba6abfffLogan Chien snprintf(sym_file, sizeof(sym_file), "%s/%s", parser->sym_root, module_name); 3385e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine 3395647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh#if defined(WITH_LIBBFD) 3405647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh if ((f=fopen(sym_file, "r")) == NULL) { 3415647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh if (errno == ENOENT) { 3425647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh printf("\n"); 3435647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh } else { 3445647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh printf(": Unable to open symbol file %s. Error (%d): %s\n", 3455647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh sym_file, errno, strerror(errno)); 3465647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh } 3475647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh return -1; 3485647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh } 3495647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh 3505647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh // call addr2line if sym_file exist 3515647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh extern int addr2line_main (int argc, char **argv); 3525647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh 3535647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh av[0] = "ndk-stack"; 3545647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh av[1] = "-fpC"; // f:function, p:pretty-print, C:demangle 3555647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh av[2] = "-e"; // e:exe-filename 3565647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh av[3] = sym_file; 3575647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh av[4] = pc_address; 3585647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh (void)address; 3595647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh 3605647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh printf(": Routine "); 3615647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh return addr2line_main(ac, av); 3625647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh#else 3635e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // Init ELFF wrapper for the symbol file. 3645e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine elff_handle = elff_init(sym_file); 3655e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine if (elff_handle == NULL) { 366c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner if (errno == ENOENT) { 367c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner fprintf(parser->out_handle, "\n"); 368c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner } else { 369c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner fprintf(parser->out_handle, 370c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner ": Unable to open symbol file %s. Error (%d): %s\n", 371c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner sym_file, errno, strerror(errno)); 372c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner } 3735e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine return -1; 3745e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 3755e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine // Extract address info from the symbol file. 3765e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine if (!elff_get_pc_address_info(elff_handle, address, &pc_info)) { 3775e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine if (pc_info.dir_name != NULL) { 378c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner fprintf(parser->out_handle, ": Routine %s in %s/%s:%d\n", 3795e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine pc_info.routine_name, pc_info.dir_name, pc_info.file_name, 3805e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine pc_info.line_number); 3815e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } else { 382c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner fprintf(parser->out_handle, ": Routine %s in %s:%d\n", 3835e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine pc_info.routine_name, pc_info.file_name, pc_info.line_number); 3845e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 3855e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine elff_free_pc_address_info(elff_handle, &pc_info); 3865e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine elff_close(elff_handle); 3875e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine return 0; 3885e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } else { 3895e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine fprintf(parser->out_handle, 390c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner ": Unable to locate routine information for address %x in module %s\n", 3915e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine (uint32_t)address, sym_file); 3925e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine elff_close(elff_handle); 3935e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine return -1; 3945e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine } 3955647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh#endif // WITH_LIBBFD 3965e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine} 397