Skip to content
Snippets Groups Projects
Commit 2307bae2 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "linux-ramdump-parser-v2: parse trace data using qtf"

parents 76fc1362 036723ac
No related branches found
No related tags found
No related merge requests found
......@@ -40,6 +40,10 @@ linux-parser-output.txt is used
--stdout : Write to stdout instead of the out-file. This overrides any
--out-file given.
--qtf : Use QTF tool to parse and save QDSS trace data
--qtf-path <path> : QTF tool executable
The list of features parsed is constantly growing. Please use --help option
to see the full list of features that can be parsed.
......@@ -86,6 +90,7 @@ gdb_path - absolute path to the gdb tool for the ramdumps
nm_path - absolute path to the gdb tool for the ramdumps
gdb64_path - absolute path to the 64-bit gdb tool for the ramdumps
nm64_path - absolute path to the 64-bit nm tool for the ramdumps
qtf_path - absolute path to qtf tool executable
Note that local_settings.py is just a python file so the file may take advantage
of python features.
......@@ -10,6 +10,12 @@
# GNU General Public License for more details.
import struct
import linux_list as llist
import re
import shutil
import os
import platform
import subprocess
from print_out import print_out_str
from qdss import QDSSDump
......@@ -85,6 +91,130 @@ class DebugImage_v2():
else:
setattr(self.qdss, qdss_tag_to_field_name[client_name], start)
def ftrace_field_func(self, common_list, ram_dump):
name_offset = ram_dump.field_offset('struct ftrace_event_field', 'name')
type_offset = ram_dump.field_offset('struct ftrace_event_field', 'type')
filter_type_offset = ram_dump.field_offset('struct ftrace_event_field', 'filter_type')
field_offset = ram_dump.field_offset('struct ftrace_event_field', 'offset')
size_offset = ram_dump.field_offset('struct ftrace_event_field', 'size')
signed_offset = ram_dump.field_offset('struct ftrace_event_field', 'is_signed')
name = ram_dump.read_word(common_list + name_offset)
field_name = ram_dump.read_cstring(name, 256)
type_name = ram_dump.read_word(common_list + type_offset)
type_str = ram_dump.read_cstring(type_name, 256)
offset = ram_dump.read_u32(common_list + field_offset)
size = ram_dump.read_u32(common_list + size_offset)
signed = ram_dump.read_u32(common_list + signed_offset)
if re.match('(.*)\[(.*)', type_str) and not(re.match('__data_loc', type_str)):
s = re.split('\[', type_str)
s[1] = '[' + s[1]
self.formats_out.write("\tfield:{0} {1}{2};\toffset:{3};\tsize:{4};\tsigned:{5};\n".format(s[0], field_name, s[1], offset, size, signed))
else:
self.formats_out.write("\tfield:{0} {1};\toffset:{2};\tsize:{3};\tsigned:{4};\n".format(type_str, field_name, offset, size, signed))
def ftrace_events_func(self, ftrace_list, ram_dump):
name_offset = ram_dump.field_offset('struct ftrace_event_call', 'name')
event_offset = ram_dump.field_offset('struct ftrace_event_call', 'event')
fmt_offset = ram_dump.field_offset('struct ftrace_event_call', 'print_fmt')
class_offset = ram_dump.field_offset('struct ftrace_event_call', 'class')
type_offset = ram_dump.field_offset('struct trace_event', 'type')
fields_offset = ram_dump.field_offset('struct ftrace_event_class', 'fields')
common_field_list = ram_dump.addr_lookup('ftrace_common_fields')
field_next_offset = ram_dump.field_offset('struct ftrace_event_field', 'link')
name = ram_dump.read_word(ftrace_list + name_offset)
name_str = ram_dump.read_cstring(name, 512)
event_id = ram_dump.read_word(ftrace_list + event_offset + type_offset)
fmt = ram_dump.read_word(ftrace_list + fmt_offset)
fmt_str = ram_dump.read_cstring(fmt, 2048)
self.formats_out.write("name: {0}\n".format(name_str))
self.formats_out.write("ID: {0}\n".format(event_id))
self.formats_out.write("format:\n")
list_walker = llist.ListWalker(ram_dump, common_field_list, field_next_offset)
list_walker.walk_prev(common_field_list, self.ftrace_field_func, ram_dump)
self.formats_out.write("\n")
event_class = ram_dump.read_word(ftrace_list + class_offset)
field_list = event_class + fields_offset
list_walker = llist.ListWalker(ram_dump, field_list, field_next_offset)
list_walker.walk_prev(field_list, self.ftrace_field_func, ram_dump)
self.formats_out.write("\n")
self.formats_out.write("print fmt: {0}\n".format(fmt_str))
def collect_ftrace_format(self, ram_dump):
formats = os.path.join(self.qtf_dir, 'map_files\\formats.txt')
formats_out = ram_dump.open_file(formats)
self.formats_out = formats_out
ftrace_events_list = ram_dump.addr_lookup('ftrace_events')
next_offset = ram_dump.field_offset('struct ftrace_event_call', 'list')
list_walker = llist.ListWalker(ram_dump, ftrace_events_list, next_offset)
list_walker.walk_prev(ftrace_events_list, self.ftrace_events_func, ram_dump)
self.formats_out.close
def parse_qtf(self, ram_dump):
if platform.system() != 'Windows':
return
qtf_path = ram_dump.qtf_path
if qtf_path is None:
try:
import local_settings
try:
qtf_path = local_settings.qtf_path
except AttributeError as e:
print_out_str("attribute qtf_path in local_settings.py looks bogus. Please see README.txt")
print_out_str("Full message: %s" % e.message)
return
except ImportError:
print_out_str("missing qtf_path local_settings.")
print_out_str("Please see the README for instructions on setting up local_settings.py")
return
if qtf_path is None:
print_out_str("!!! Incorrect path for qtf specified.")
print_out_str("!!! Please see the README for instructions on setting up local_settings.py")
return
if not os.path.exists(qtf_path):
print_out_str("!!! qtf_path {0} does not exist! Check your settings!".format(qtf_path))
return
if not os.access(qtf_path, os.X_OK):
print_out_str("!!! No execute permissions on qtf path {0}".format(qtf_path))
return
if os.path.getsize('tmc-etf.bin') > 0:
trace_file = 'tmc-etf.bin'
elif os.path.getsize('tmc-etr.bin') > 0:
trace_file = 'tmc-etr.bin'
else:
return
port = 12345
qtf_dir = 'qtf'
workspace = os.path.join(qtf_dir, 'qtf.workspace')
qtf_out = 'qtf.txt'
chipset = 'msm' + str(ram_dump.hw_id)
hlos = 'LA'
p = subprocess.Popen([qtf_path, '-s', '{0}'.format(port)])
subprocess.call('{0} -c {1} new workspace {2} {3} {4}'.format(qtf_path, port, qtf_dir, chipset, hlos))
self.qtf_dir = qtf_dir
self.collect_ftrace_format(ram_dump)
subprocess.call('{0} -c {1} open workspace {2}'.format(qtf_path, port, workspace))
subprocess.call('{0} -c {1} open bin {2}'.format(qtf_path, port, trace_file))
subprocess.call('{0} -c {1} stream trace table {2}'.format(qtf_path, port, qtf_out))
subprocess.call('{0} -c {1} exit'.format(qtf_path, port))
p.communicate('quit')
def parse_dump_v2(self, ram_dump):
self.dump_type_lookup_table = ram_dump.gdbmi.get_enum_lookup_table(
'msm_dump_type', 2)
......@@ -241,3 +371,5 @@ class DebugImage_v2():
client_id, ram_dump)
self.qdss.dump_all(ram_dump)
if ram_dump.qtf:
self.parse_qtf(ram_dump)
......@@ -58,3 +58,30 @@ class ListWalker(object):
break
node_addr = next_node
self.seen_nodes.append(node_addr)
def walk_prev(self, node_addr, func, *args):
"""Walk the linked list starting at `node_addr' previous node and traverse the list in
reverse order, calling `func' on each node. `func' will be passed the current node and *args,
if given.
"""
node_addr = self.ram_dump.read_word(node_addr + self.ram_dump.field_offset('struct list_head', 'prev'))
while True:
if node_addr == 0:
break
funcargs = [node_addr - self.list_elem_offset] + list(args)
func(*funcargs)
prev_node_addr = node_addr + self.ram_dump.field_offset('struct list_head', 'prev')
prev_node = self.ram_dump.read_word(prev_node_addr)
if prev_node == self.last_node:
break
if prev_node in self.seen_nodes:
print_out_str(
'[!] WARNING: Cycle found in attach list. List is corrupted!')
break
node_addr = prev_node
self.seen_nodes.append(node_addr)
......@@ -436,7 +436,7 @@ class RamDump():
if urc < 0:
break
def __init__(self, vmlinux_path, nm_path, gdb_path, objdump_path, ebi, file_path, phys_offset, outdir, hw_id=None, hw_version=None, arm64=False, page_offset=None):
def __init__(self, vmlinux_path, nm_path, gdb_path, objdump_path, ebi, file_path, phys_offset, outdir, qtf_path, hw_id=None, hw_version=None, arm64=False, page_offset=None, qtf=False):
self.ebi_files = []
self.phys_offset = None
self.tz_start = 0
......@@ -456,6 +456,8 @@ class RamDump():
self.arm64 = arm64
self.page_offset = 0xc0000000
self.thread_size = 8192
self.qtf_path = qtf_path
self.qtf = qtf
if ebi is not None:
# TODO sanity check to make sure the memory regions don't overlap
for file_path, start, end in ebi:
......
......@@ -122,6 +122,10 @@ if __name__ == '__main__':
help='Run an interactive python interpreter with the ramdump loaded')
parser.add_option('', '--classic-shell', action='store_true',
help='Like --shell, but forces the use of the classic python shell, even if ipython is installed')
parser.add_option('', '--qtf', action='store_true', dest='qtf',
help='Use QTF tool to parse and save QDSS trace data')
parser.add_option('', '--qtf-path', dest='qtf_path',
help='QTF tool executable')
for p in parser_util.get_parsers():
parser.add_option(p.shortopt or '',
......@@ -263,11 +267,14 @@ if __name__ == '__main__':
print_out_str("!!! If this tool is being run from a shared location, contact the maintainer")
sys.exit(1)
if options.everything:
options.qtf = True
dump = RamDump(options.vmlinux, nm_path, gdb_path, objdump_path, options.ram_addr,
options.autodump, options.phys_offset, options.outdir,
options.autodump, options.phys_offset, options.outdir, options.qtf_path,
options.force_hardware, options.force_hardware_version,
arm64=options.arm64,
page_offset=options.page_offset)
page_offset=options.page_offset, qtf=options.qtf)
if options.shell or options.classic_shell:
print("Entering interactive shell mode.")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment