Skip to content
Snippets Groups Projects
Commit 5a24c118 authored by Adrian Salido-Moreno's avatar Adrian Salido-Moreno
Browse files

lrdp-v2: add Support for parsing MDP registers

Add module to get information from MDP dumps, which can occur under
situations where MDP cannot recover.

Change-Id: I8ecdced37206947c434c7ddf4d7d61979c9cf92f
parent d01bed4a
No related branches found
No related tags found
No related merge requests found
# Copyright (c) 2016, The Linux Foundation. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 and
# only version 2 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
from parser_util import register_parser, RamParser
from print_out import print_out_str
from linux_list import ListWalker
from ramdump import Struct
class MdssDbgBase(Struct):
_struct_name = "struct mdss_debug_base"
_fields = {
'name': Struct.get_cstring,
'base': Struct.get_pointer,
'max_offset': Struct.get_u32,
'dump_list': Struct.get_address,
'reg_dump': Struct.get_pointer,
}
class MdssDbgXlog(Struct):
def get_dbgbase_arr(self, key):
arr = self.get_array_ptrs(key)
return [MdssDbgBase(self.ramdump, b) for b in arr]
_struct_name = "struct mdss_dbg_xlog"
_fields = {
'blk_arr': get_dbgbase_arr,
}
class RangeDumpNode(Struct):
def get_offset(self, key):
return Struct(self.ramdump, self.get_address(key),
struct_name="struct dump_offset",
fields={
'start': Struct.get_u32,
'end': Struct.get_u32,
})
_struct_name = "struct range_dump_node"
_fields = {
'offset': get_offset,
'range_name': Struct.get_cstring,
'reg_dump': Struct.get_pointer,
}
@register_parser('--print-mdpinfo', 'print mdp info')
class MDPinfo(RamParser):
def __init__(self, *args):
super(MDPinfo, self).__init__(*args)
self.outfile = None
def mdss_dump_reg(self, addr, length, reg_dump):
if reg_dump == 0:
return
# Making length multiple of 16
length = int((length + 15) / 16)
# Print out registers
for i in range(0, length):
self.outfile.write('{0:x} : '.format(addr))
for j in range(0, 4):
read = reg_dump + (16 * i) + (4 * j)
self.outfile.write('{0:#0{1}x} '
.format(self.ramdump.read_u32(read), 10))
self.outfile.write('\n')
addr += 16
def print_range(self, blk, node):
rng = RangeDumpNode(self.ramdump, node)
if (rng.offset.start > rng.offset.end) or (rng.offset.end == 0):
print_out_str("Invalid offsets (%d, %d) for range: %s" %
(rng.offset.start, rng.offset.end, rng.range_name))
return
addr = blk.base + rng.offset.start
self.outfile.write('{0}: base=0x{1:x} start=0x{2:x} end=0x{3:x}\n'
.format(rng.range_name, addr,
rng.offset.start, rng.offset.end))
self.outfile.write('start_addr:{0:x} end_addr:{1:x} reg_addr={2:x}\n'
.format(rng.offset.start, rng.offset.end, addr))
# Calculating length
length = min(blk.max_offset, rng.offset.end) - rng.offset.start
self.mdss_dump_reg(addr, length, rng.reg_dump)
def parse(self):
mdss_dbg = MdssDbgXlog(self.ramdump, 'mdss_dbg_xlog')
if mdss_dbg.is_empty():
return
for blk in mdss_dbg.blk_arr:
if blk.is_empty():
continue
# Delays file creation until we have found a non-null array element
if not self.outfile:
self.outfile = self.ramdump.open_file('mdpinfo_out.txt')
self.outfile.write('mdss_dump_reg_by_ranges:'
'=========%s DUMP=========\n' % blk.name)
head_offset = self.ramdump.field_offset('struct range_dump_node',
'head')
dump_list = ListWalker(self.ramdump, blk.dump_list, head_offset)
if dump_list.is_empty():
self.outfile.write('Ranges not found, '
'will dump full registers\n')
self.outfile.write('base:0x%x length:%d\n' %
(blk.base, blk.max_offset))
self.mdss_dump_reg(blk.base, blk.max_offset, blk.reg_dump)
else:
for node in dump_list:
self.print_range(blk, node)
# Close the file only if it was created
if self.outfile:
self.outfile.close()
self.outfile = None
......@@ -1347,3 +1347,165 @@ class RamDump():
return self.thread_saved_field_common_64(task, self.field_offset('struct cpu_context', 'fp'))
else:
return self.thread_saved_field_common_32(task, self.field_offset('struct cpu_context_save', 'fp'))
class Struct(object):
"""
Helper class to abstract C structs retrieval by providing a map of fields
to functions on how to retrieve these
Given C struct::
struct my_struct {
char label[MAX_STR_SIZE];
u32 number;
void *address;
}
You can abstract as:
>>> var = Struct(ramdump, var_name, struct_name="struct my_struct",
fields={'label': Struct.get_cstring,
'number': Struct.get_u32,
'address': Struct.get_pointer})
>>> var.label
'label string'
>>> var.number
1234
"""
_struct_name = None
_fields = None
def __init__(self, ramdump, base, struct_name=None, fields=None):
"""
:param ram_dump: Reference to the ram dump
:param base: The virtual address or variable name of struct
:param struct_name: Name of the structure, should start with 'struct'.
Ex: 'struct my_struct'
:param fields: Dictionary with key being the element name and value
being a function pointer to method used to retrieve it.
"""
self.ramdump = ramdump
self._base = self.ramdump.resolve_virt(base)
self._data = {}
if struct_name:
self._struct_name = struct_name
if fields:
self._fields = fields
def is_empty(self):
"""
:return: true if struct is empty
"""
return self._base == 0 or self._base is None or self._fields is None
def get_address(self, key):
"""
:param key: struct field name
:return: returns address of the named field within the struct
"""
return self._base + self.ramdump.field_offset(self._struct_name, key)
def get_pointer(self, key):
"""
:param key: struct field name
:return: returns the addressed pointed by field within the struct
example struct::
struct {
void *key;
};
"""
address = self.get_address(key)
return self.ramdump.read_pointer(address)
def get_struct_sizeof(self, key):
"""
:param key: struct field name
:return: returns the size of a field within struct
Given C struct::
struct my_struct {
char key1[10];
u32 key2;
};
You could do:
>>> struct = Struct(ramdump, 0, struct="struct my_struct",
fields={"key1": Struct.get_cstring,
"key2": Struct.get_u32})
>>> struct.get_struct_sizeof(key1)
10
>>> struct.get_struct_sizeof(key2)
4
"""
return self.ramdump.sizeof('((%s *) 0)->%s' % (self._struct_name, key))
def get_cstring(self, key):
"""
:param key: struct field name
:return: returns a string that is contained within struct memory
Example C struct::
struct {
char key[10];
};
"""
address = self.get_address(key)
length = self.get_struct_sizeof(key)
return self.ramdump.read_cstring(address, length)
def get_u32(self, key):
"""
:param key: struct field name
:return: returns a u32 integer within the struct
Example C struct::
struct {
u32 key;
};
"""
address = self.get_address(key)
return self.ramdump.read_u32(address)
def get_array_ptrs(self, key):
"""
:param key: struct field name
:return: returns an array of pointers
Example C struct::
struct {
void *key[4];
};
"""
ptr_size = self.ramdump.sizeof('void *')
length = self.get_struct_sizeof(key) / ptr_size
address = self.get_address(key)
arr = []
for i in range(0, length - 1):
ptr = self.ramdump.read_pointer(address + (ptr_size * i))
arr.append(ptr)
return arr
def __setattr__(self, key, value):
if self._fields and key in self._fields:
raise ValueError(key + "is read-only")
else:
super(Struct, self).__setattr__(key, value)
def __getattr__(self, key):
if not self.is_empty():
if key in self._data:
return self._data[key]
elif key in self._fields:
fn = self._fields[key]
value = fn(self, key)
self._data[key] = value
return value
return None
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