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
12711e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh/* Return pointer to first word "pc", "eip", or "ip" in string "frame"
12811e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh * param:
12911e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh *  frame - a line from dump
13011e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh * Return:
13111e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh *  The first occurrence of "pc", "eip", or "ip"
13211e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh */
13311e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsiehstatic const char* find_pc(const char *frame);
13411e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh
1355e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineNdkCrashParser*
1365e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineCreateNdkCrashParser(FILE* out_handle, const char* sym_root)
1375e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
138c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  NdkCrashParser* parser;
139c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner
140c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  parser = (NdkCrashParser*)calloc(sizeof(*parser), 1);
141c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  if (parser == NULL)
142c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      return NULL;
143c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner
144c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  parser->out_handle = out_handle;
145c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  parser->state      = EXPECTS_CRASH_DUMP;
146c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner
147c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  parser->sym_root = strdup(sym_root);
148c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  if (!parser->sym_root)
149c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      goto BAD_INIT;
150c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner
151c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  if (regcomp(&parser->re_pid_header, _pid_header, REG_EXTENDED | REG_NEWLINE) ||
152c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      regcomp(&parser->re_sig_header, _sig_header, REG_EXTENDED | REG_NEWLINE) ||
153c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      regcomp(&parser->re_frame_header, _frame_header, REG_EXTENDED | REG_NEWLINE))
154c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      goto BAD_INIT;
1555e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1565e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  return parser;
157c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner
158c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' TurnerBAD_INIT:
159c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  DestroyNdkCrashParser(parser);
160c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  return NULL;
1615e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
1625e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1635e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinevoid
1645e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineDestroyNdkCrashParser(NdkCrashParser* parser)
1655e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
1665e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  if (parser != NULL) {
167c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    /* Release compiled regular expressions */
168c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    regfree(&parser->re_frame_header);
169c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    regfree(&parser->re_sig_header);
170c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    regfree(&parser->re_pid_header);
171c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    /* Release symbol path */
172c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    free(parser->sym_root);
173c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    /* Release parser itself */
1745e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    free(parser);
1755e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
1765e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
1775e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1785e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkineint
1795e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineParseLine(NdkCrashParser* parser, const char* line)
1805e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
1815e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  regmatch_t match;
1825647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  int found = 0;
1835e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1845e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  if (line == NULL || *line == '\0') {
1855e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    // Nothing to parse.
1865e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    return 1;
1875e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
1885e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1895e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // Lets see if this is the beginning of a crash dump.
1905e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  if (strstr(line, _crash_dump_header) != NULL) {
1915e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    if (parser->state != EXPECTS_CRASH_DUMP) {
1925e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      // Printing another crash dump was in progress. Mark the end of it.
1935e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      fprintf(parser->out_handle, "Crash dump is completed\n\n");
1945e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    }
1955e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
1965e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    // New crash dump begins.
1975e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    fprintf(parser->out_handle, "********** Crash dump: **********\n");
1985e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    parser->state = EXPECTS_BUILD_FINGREPRINT_OR_PID;
1995e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2005e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    return 0;
2015e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
2025e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2035e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  switch (parser->state) {
2045e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    case EXPECTS_BUILD_FINGREPRINT_OR_PID:
2055e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      if (strstr(line, _build_fingerprint_header) != NULL) {
2065e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        fprintf(parser->out_handle, "%s\n",
2075e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine                strstr(line, _build_fingerprint_header));
2085e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        parser->state = EXPECTS_PID;
2095647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh        found = 1;
2105e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      }
2115e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      // Let it fall through to the EXPECTS_PID, in case the dump doesn't
2125e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      // contain build fingerprint.
2135e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    case EXPECTS_PID:
214c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      if (MatchRegex(line, &parser->re_pid_header, &match)) {
2155e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        fprintf(parser->out_handle, "%s\n", line + match.rm_so);
2165e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        parser->state = EXPECTS_SIGNAL_OR_FRAME;
2175e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        return 0;
2185e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      } else {
2195647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh        return !found;
2205e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      }
2215e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2225e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    case EXPECTS_SIGNAL_OR_FRAME:
223c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      if (MatchRegex(line, &parser->re_sig_header, &match)) {
2245e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        fprintf(parser->out_handle, "%s\n", line + match.rm_so);
2255e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine        parser->state = EXPECTS_FRAME;
2265647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh        found = 1;
2275e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      }
2285e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      // Let it fall through to the EXPECTS_FRAME, in case the dump doesn't
2295e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      // contain signal fingerprint.
2305e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    case EXPECTS_FRAME:
23111e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      if (!MatchRegex(line, &parser->re_frame_header, &match))
2325647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh        return !found;
23311e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      // Regex generated by x86_64-w64-mingw32 compiler erroneously match
23411e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      // frame line with #[0-9]+ in "stack:" section even when the line has
23511e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      //  no word "pc", "eip", or "ip" in it.
23611e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      //
23711e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      //   stack:
23811e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      //      I/DEBUG   ( 1151):     #00  5f09db68  401f01c4  /system/lib/libc.so
23911e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      //
24011e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      // To workaround, let's double check if pc is found!
24111e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      //
24211e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      if (!(find_pc(line)))
24311e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh        return !found;
24411e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh
24511e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      parser->state = EXPECTS_FRAME;
24611e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      return ParseFrame(parser, line + match.rm_so);
2475e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2485e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    default:
2495e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine      return 1;
2505e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
2515e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
2525e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2535e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic int
254c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' TurnerMatchRegex(const char* line, const regex_t* regex, regmatch_t* match)
2555e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
256c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  int err = regexec(regex, line, 1, match, 0x00400/*REG_TRACE*/);
2575e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#if 0
25827db2fc052a03217689a4be833ad79458742d7faLogan Chien  char rerr[4096];
25927db2fc052a03217689a4be833ad79458742d7faLogan Chien  if (err) {
26027db2fc052a03217689a4be833ad79458742d7faLogan Chien    regerror(err, regex, rerr, sizeof(rerr));
26127db2fc052a03217689a4be833ad79458742d7faLogan Chien    fprintf(stderr, "regexec(%s, %s) has failed: %s\n", line, regex, rerr);
26227db2fc052a03217689a4be833ad79458742d7faLogan Chien  }
2635e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine#endif
2647ecfaaa424d561d670f643993bb9b373db85d832Vladimir Chtchetkine
265c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  return err == 0;
2665e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
2675e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2685e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char*
2695e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinenext_separator(const char* str)
2705e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
2715e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  return str + strcspn(str, " \t");
2725e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
2735e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2745e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char*
2755e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinenext_token(const char* str)
2765e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
2775e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  str = next_separator(str);
2785e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  return str + strspn(str, " \t");
2795e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
2805e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
2815e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkinestatic const char*
2825e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkineget_next_token(const char* str, char* token, size_t size)
2835e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
2845e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  const char* start = next_token(str);
2855e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  const char* end = next_separator(start);
2865e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  if (start != end) {
287273fd4fcae7d1ee68ff3096108f623c6db6007a8Logan Chien    const size_t to_copy = min((size_t)(end - start), (size - 1));
2885e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    memcpy(token, start, to_copy);
2895e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    token[to_copy] = '\0';
2905e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    return start;
2915e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  } else {
2925e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    return NULL;
2935e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
2945e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
2955e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
29611e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsiehstatic const char *
29711e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsiehfind_pc(const char *frame)
29811e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh{
29911e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh  const char *pcstrs[] = { "pc", "eip", "ip" };
30011e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh  int i;
30111e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh  for (i=0; i<sizeof(pcstrs)/sizeof(pcstrs[0]); i++) {
30211e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh    const char *p = strstr(frame, pcstrs[i]);
30311e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh    // check it's a word, not part of filename or something
30411e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh    if (p && p!=frame) {
30511e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      char l = p[-1];
30611e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      char r = p[strlen(pcstrs[i])];
30711e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh      if ((l==' ' || l=='\t') && (r==' ' || r=='\t'))
30811e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh        return p;
30911e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh    }
31011e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh  }
31111e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh  return NULL;
31211e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh}
31311e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh
3145e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkineint
3155e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir ChtchetkineParseFrame(NdkCrashParser* parser, const char* frame)
3165e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine{
3175e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  uint64_t address;
3185e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  const char* wrk;
3195e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  char* eptr;
3205e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  char pc_address[17];
3215e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  char module_path[2048];
322c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  char* module_name;
3235e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  char sym_file[2048];
3245647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh#if !defined(WITH_LIBBFD)
3255e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  ELFF_HANDLE elff_handle;
3265e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  Elf_AddressInfo pc_info;
3275647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh#else
3285647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  const int ac = 5;
3295647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  char *av[ac];
3305647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  FILE *f;
3315647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh#endif
3325e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
333c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  fprintf(parser->out_handle, "Stack frame %s", frame);
3345e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
3355e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // Advance to the instruction pointer token.
33611e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh  if ((wrk=find_pc(frame)) == NULL) {
33711e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh    fprintf(parser->out_handle,
33811e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh            "Parser is unable to locate instruction pointer token.\n");
33911e5edf52e996b8d10520c67669a9d920f5eaf6fAndrew Hsieh    return -1;
3405e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
3415e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
3425e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // Next token after the instruction pointer token is its address.
3435e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  wrk = get_next_token(wrk, pc_address, sizeof(pc_address));
3445e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // PC address is a hex value. Get it.
3455e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  eptr = pc_address + strlen(pc_address);
3465e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  address = strtoul(pc_address, &eptr, 16);
3475e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
3485e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // Next token is module path.
3495e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  get_next_token(wrk, module_path, sizeof(module_path));
3505e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
351c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  // Extract basename of module, we should not care about its path
352c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  // on the device.
353c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  module_name = strrchr(module_path,'/');
354c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  if (module_name == NULL)
355c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      module_name = module_path;
356c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  else {
357c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      module_name += 1;
358c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      if (*module_name == '\0') {
359c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner          /* Trailing slash in the module path, this should not happen */
360c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner          /* Back-off with the full module-path */
361c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner          module_name = module_path;
362c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      }
363c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner  }
364c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner
3655e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // Build path to the symbol file.
3665079ebbb32c44bb3a4bc3602d696521eba6abfffLogan Chien  snprintf(sym_file, sizeof(sym_file), "%s/%s", parser->sym_root, module_name);
3675e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine
3685647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh#if defined(WITH_LIBBFD)
3695647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  if ((f=fopen(sym_file, "r")) == NULL) {
3705647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh    if (errno == ENOENT) {
3715647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh        printf("\n");
3725647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh    } else {
3735647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh        printf(": Unable to open symbol file %s. Error (%d): %s\n",
3745647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh                sym_file, errno, strerror(errno));
3755647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh    }
3765647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh    return -1;
3775647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  }
3785647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh
3795647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  // call addr2line if sym_file exist
3805647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  extern int addr2line_main (int argc, char **argv);
3815647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh
3825647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  av[0] = "ndk-stack";
3835647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  av[1] = "-fpC";  // f:function, p:pretty-print, C:demangle
3845647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  av[2] = "-e";    // e:exe-filename
3855647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  av[3] = sym_file;
3865647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  av[4] = pc_address;
3875647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  (void)address;
3885647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh
3895647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  printf(": Routine ");
3905647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh  return addr2line_main(ac, av);
3915647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh#else
3925e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // Init ELFF wrapper for the symbol file.
3935e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  elff_handle = elff_init(sym_file);
3945e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  if (elff_handle == NULL) {
395c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    if (errno == ENOENT) {
396c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner        fprintf(parser->out_handle, "\n");
397c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    } else {
398c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner        fprintf(parser->out_handle,
399c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner                ": Unable to open symbol file %s. Error (%d): %s\n",
400c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner                sym_file, errno, strerror(errno));
401c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner    }
4025e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    return -1;
4035e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
4045e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  // Extract address info from the symbol file.
4055e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  if (!elff_get_pc_address_info(elff_handle, address, &pc_info)) {
4065e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    if (pc_info.dir_name != NULL) {
407c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      fprintf(parser->out_handle, ": Routine %s in %s/%s:%d\n",
4085e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine              pc_info.routine_name, pc_info.dir_name, pc_info.file_name,
4095e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine              pc_info.line_number);
4105e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    } else {
411c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner      fprintf(parser->out_handle, ": Routine %s in %s:%d\n",
4125e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine              pc_info.routine_name, pc_info.file_name, pc_info.line_number);
4135e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    }
4145e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    elff_free_pc_address_info(elff_handle, &pc_info);
4155e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    elff_close(elff_handle);
4165e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    return 0;
4175e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  } else {
4185e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    fprintf(parser->out_handle,
419c0bf90ae0f4f84875d0af5d7166b57deb77e57a3David 'Digit' Turner            ": Unable to locate routine information for address %x in module %s\n",
4205e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine            (uint32_t)address, sym_file);
4215e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    elff_close(elff_handle);
4225e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine    return -1;
4235e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine  }
4245647b5efe1584bfcb3ed10ca617f7b1d73f63d9bAndrew Hsieh#endif // WITH_LIBBFD
4255e0720014efeafbf6228ae4cd93b3968c1de53fcVladimir Chtchetkine}
426