1#!/usr/bin/python
2#
3# Copyright (c) 2012 The Native Client Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6#
7
8from __future__ import print_function
9
10import sys
11import textwrap
12from subprocess import Popen, PIPE
13
14_OBJDUMP = 'arm-linux-gnueabi-objdump'
15
16def _objdump(binary, vaddr, ctx_before, ctx_after):
17  args = [
18      _OBJDUMP, '-d', '-G', binary,
19      '--start-address=0x%08X' % (vaddr - (4 * ctx_before)),
20      '--stop-address=0x%08X' % (vaddr + 4 + (4 * ctx_after))
21  ]
22  highlight = ctx_before
23  lines = 0
24  for line in Popen(args, stdout=PIPE).stdout.read().split('\n'):
25    if line.startswith(' '):
26      if highlight == 0:
27        print('--> ', line)
28      else:
29        print('    ', line)
30      highlight -= 1
31      lines += 1
32  if not lines:
33    print('    (not found)')
34
35
36def _problem_info(code):
37  return {
38      'kProblemUnsafe': ['Instruction is unsafe', 0, 0],
39      'kProblemBranchSplitsPattern': [
40          'The destination of this branch is '
41          'part of an instruction sequence that must be executed in full, '
42          'or is inline data', 0, 0
43      ],
44      'kProblemPatternCrossesBundle': [
45          'This instruction is part of a '
46          'sequence that must execute in full, but it spans a bundle edge '
47          '-- so an indirect branch may target it', 1, 1
48      ],
49      'kProblemBranchInvalidDest': [
50          'This branch targets a location that is '
51          'outside of the application\'s executable code, and is not a valid '
52          'trampoline entry point', 0, 0
53      ],
54      'kProblemUnsafeLoadStore': [
55          'This store instruction is not preceded by '
56          'a valid address mask instruction', 1, 0
57      ],
58      'kProblemUnsafeBranch': [
59          'This indirect branch instruction is not '
60          'preceded by a valid address mask instruction', 1, 0
61      ],
62      'kProblemUnsafeDataWrite': [
63          'This instruction affects a register that '
64          'must contain a valid data-region address, but is not followed by '
65          'a valid address mask instruction', 0, 1
66      ],
67      'kProblemReadOnlyRegister': [
68          'This instruction changes the contents of '
69          'a read-only register', 0, 0
70      ],
71      'kProblemMisalignedCall': [
72          'This linking branch instruction is not in '
73          'the last slot of its bundle, so when its LR result is masked, the '
74          'caller will not return to the next instruction', 0, 0
75      ],
76  }[code]
77
78
79def _safety_msg(val):
80  return {
81      0: 'UNKNOWN',  # Should not appear
82      1: 'is undefined',
83      2: 'has unpredictable effects',
84      3: 'is deprecated',
85      4: 'is forbidden',
86      5: 'uses forbidden operands',
87  }[val]
88
89
90def _explain_problem(binary, vaddr, safety, code, ref_vaddr):
91  msg, ctx_before, ctx_after = _problem_info(code)
92  if safety == 6:
93    msg = "At %08X: %s:" % (vaddr, msg)
94  else:
95    msg = ("At %08X: %s (%s):" % (vaddr, msg, _safety_msg(safety)))
96  print('\n'.join(textwrap.wrap(msg, 70, subsequent_indent='  ')))
97  _objdump(binary, vaddr, ctx_before, ctx_after)
98  if ref_vaddr:
99    print("Destination address %08X:" % ref_vaddr)
100    _objdump(binary, ref_vaddr, 1, 1)
101
102
103def _parse_report(line):
104  vaddr_hex, safety, code, ref_vaddr_hex = line.split()
105  return (int(vaddr_hex, 16), int(safety), code, int(ref_vaddr_hex, 16))
106
107
108for line in sys.stdin:
109  if line.startswith('ncval: '):
110    line = line[7:].strip()
111    _explain_problem(sys.argv[1], *_parse_report(line))
112