3 # Copyright (c) 2017-2018 Cray Inc. All Rights Reserved.
5 from collections import namedtuple
8 from crash import addr2sym, PAGESIZE
9 from pykdump.API import (Addr, exec_crash_command, getSizeOf, member_offset,
10 readmem, readU8, readULong, sys_info)
12 from crashlib.cl import (cl_err, cl_warn, cl_info, cl_trace)
15 BYTES_1M = BYTES_1K * 1024
16 BYTES_1G = BYTES_1M * 1024
17 BYTES_1T = BYTES_1G * 1024
19 def bytes2size(bytes):
20 '''Return a string representation of bytes, including order,
21 ie '15.0M' or '2.1G'.'''
26 elif bytes >= BYTES_1G:
29 elif bytes >= BYTES_1M:
32 elif bytes >= BYTES_1K:
38 rem = ((bytes % size) * 10) / size
39 return "%d.%d%s" % (full, rem, suffix)
41 def pages2size(npages):
42 '''Return a string representation of the number of bytes contained
44 return bytes2size(npages * PAGESIZE)
46 def page_to_virt(page):
47 # run kmem -p to get the pys addr for the page
48 cmd = "kmem -p %#x" % page
49 kmemp = exec_crash_command(cmd)
50 paddr = kmemp.splitlines()[1].split()[1]
51 cl_trace("*>>> page_to_virt #### phys_addr = %s" % paddr)
52 # find vaddr from crash ptov command
53 res = exec_crash_command("ptov " + paddr)
54 vaddr = res.splitlines()[1].split()[0]
55 cl_trace("*>>> page_to_virt #### vaddr = %s" % vaddr)
56 return long(vaddr, 16)
59 cl_trace(">>> get_config: searching system config for %s" % name)
60 res = exec_crash_command("sys config")
61 for line in res.splitlines():
64 (key, value) = line.split("=", 1)
66 cl_trace(">>> get_config: %s has a value of '%s'" % (name, value))
68 raise ValueError("Name %s not found in system config" % name)
71 # See if the user specified the format.
75 # Nope, be generous and try again as hex.
79 # No luck. Return an error.
80 print("Invalid number: %s" % arg)
84 def is_kernel_address(addr):
85 # The top 17 bits should all be ones.
87 if (addr >> 47) != val:
91 def is_kernel_text_address(addr):
92 # The top 33 bits should all be ones.
94 if (addr >> 31) != val:
98 def is_valid_address(addr):
105 def readString(addr):
106 res = readmem(addr, 64)
107 return res.split('\0')[0]
109 def symbol_name(addr):
110 if not is_kernel_text_address(addr):
112 (name, offset) = addr2sym(addr, True)
116 name += "+" + hex(offset)
120 '''pykdump can't read bools on its own.'''
121 return bool(readU8(addr))
123 def read_bool_member(struct, member_name):
124 '''struct must be a pykdump object, member name is the string name
125 of the bool member in the struct.'''
126 struct_type = struct.PYT_symbol
127 return read_bool(Addr(struct) + member_offset(struct_type, member_name))
129 def read_bitmap(addr, num_bits):
130 '''Return an integer representation of the 'num_bits' sized bitmap
131 at 'addr'. Note Python has arbitrary precision ints so the return
132 value may be very large.'''
133 bits_per_long = 8 * getSizeOf('long')
134 num_longs = int(ceil(float(num_bits) / bits_per_long))
136 for i in range(num_longs):
137 total |= (readULong(addr + i * getSizeOf('long'))
138 << ((num_longs - i - 1) * bits_per_long))
139 # Mask off unused bits when num_bits not a multiple of bits/long.
140 mask = 2 ** num_bits - 1
143 def read_cpumask(cpumask_addr):
144 '''Return an integer representation of the cpumask bitmap.'''
145 return read_bitmap(cpumask_addr, sys_info.CPUS)
147 def read_cpumask_var_t(container_struct, member_name):
148 '''Return an integer representation of the cpumask_var_t bitmap.
149 'container_struct' is the struct object which has a cpumask_var_t
150 as a member. 'member_name' is the name of the cpumask_var_t field
151 within the container struct.
153 Pykdump crashes when trying to read a cpumask_var_t. This function
154 provides a workaround which does not read a cpumask_var_t directly.'''
155 container_type = container_struct.PYT_symbol
156 offset = member_offset(container_type, member_name)
157 cpumask_addr = Addr(container_struct) + offset
158 return read_cpumask(cpumask_addr)
161 # Bit offsets and masks for read_qspinlock
162 # Copied from linux/include/asm-generic/qspinlock_types.h.
164 # Bitfields in the atomic value:
171 # 18-31: tail cpu (+1)
173 # When NR_CPUS >= 16K
177 # 11-31: tail cpu (+1)'''
179 if sys_info.CPUS < 2 ** 14:
183 _q_tail_index_offset = 9
184 _q_tail_index_bits = 2
185 _q_tail_index_mask = (2 ** _q_tail_index_bits - 1) << _q_tail_index_offset
186 _q_tail_cpu_offset = _q_tail_index_offset + _q_tail_index_bits
187 _q_tail_cpu_bits = 32 - _q_tail_cpu_offset
188 _q_tail_cpu_mask = (2 ** _q_tail_cpu_bits - 1) << _q_tail_cpu_offset
190 qspinlock_tuple = namedtuple('qspinlock',
191 ['locked', 'pending', 'tail_index', 'tail_cpu'])
193 def read_qspinlock(qspinlock):
194 '''Given a struct qspinlock, which consists of a single 32 bit atomic
195 value, return a namedtuple of ints (locked, pending, tail_index, tail_cpu),
196 representing the bit fields of the qspinlock.'''
198 val = qspinlock.val.counter
199 locked_byte = val & 0xff
200 pending = (val & 0x100) >> 8
202 tail_index = (val & _q_tail_index_mask) >> _q_tail_index_offset
204 _q_tail_cpu_offset = _q_tail_index_offset + _q_tail_index_bits
205 _q_tail_cpu_bits = 32 - _q_tail_cpu_offset
206 _q_tail_cpu_mask = (2 ** _q_tail_cpu_bits - 1) << _q_tail_cpu_offset
207 tail_cpu = ((val & _q_tail_cpu_mask) >> _q_tail_cpu_offset) - 1
209 return qspinlock_tuple(locked=locked_byte, pending=pending,
210 tail_index=tail_index, tail_cpu=tail_cpu)