crash C-module¶
This module implements Python bindings to crash and GDB
internal commands and structures. Some of these subroutines are
intended for framework itself. Those of general interest are available
after import pydkump.API, there is no need to import crash to
use them.
That is - in most cases, you do not need to import this module in your own programs.
Basic Info about struct/union/enum¶
-
crash.struct_size(structname)¶ - Parameters
structname – a string with struct name, e.g. struct task_struct. While
crashlets you specify simplified names without struct, this subroutine needs proper C-syntax- Returns
size as an integer, or -1 if there is no symbolic info for this struct
-
crash.union_size(unionname)¶ Similar to
struct_size()but for unions instead of structs
-
crash.member_offset(sname, smember)¶ - Parameters
sname – a string with struct name
smember – a string with member name
- Returns
offset as an integer, or -1 if there is no such member
-
crash.member_size(sname, smember)¶ - Parameters
sname – a string with struct name
smember – a string with member name
- Returns
size as an integer, or -1 if there is no such member
-
crash.enumerator_value(ename)¶ Interface to
crashinternal subroutineint enumerator_value(char *e, long *value)- Parameters
ename – a string with enum name
- Returns
an int with numeric value
Example:
WORK_CPU_NONE = enumerator_value("WORK_CPU_NONE")
Symbol/Address Subroutines¶
-
crash.symbol_exits(symname)¶ Tests whether symbol symname exists in this kernel (as listed by
crashbuiltinsymcommand)Returns value that evaluates to True if it does and False if it does not
-
crash.sym2addr(symbolname)¶ - Parameters
symbolname – a string with symbol name
- Returns
address as an integer. 0 means that there is no such symbol. If there are multiple variables with this name (e.g. in different DLKMs), address of the first one is returned
-
crash.sym2alladdr(symbolname)¶ Similar to
sym2addr()but returns a list of addresses. If there are no matches at all, returns an empty list. If there is one match only, returns a list of one element
-
crash.addr2sym(addr, loose_match=False)¶ Tries to find a symbol matching the given address.
By default, it tries to find an exact match and if found, returns a string. If no exact match is found, returns None
If we call this subroutine with
loose_match= True, we are trying to find an approximate match and return a tuple(name, offset)Example: there is a symbol tcp_shudown with address 0xffffffff8147e580:
print(crash.addr2sym(0xffffffff8147e581, True)) ('tcp_shutdown', 1)
In case when there is no match for loose matching we return a tuple of
(None, None)
-
crash.addr2mod(addr)¶ - Parameters
addr – address as an integer
- Returns
a string with module name where this address belongs, or None
Reading Memory¶
There are different types of memory, e.g. KVADDR. Some of the
following subroutines let you specify the memory type as an extra
argument and some rely on default
-
crash.mem2long(bytestr, signed, array)¶ This is a swiss-army knife subroutine to convert a byte string into integers or a list of integers. In C, we have integers of different sizes, signed/unsigned and arrays of integers (this subroutine can handle 1-dimensional arrays only). After we read a chunk of memory, it is represented by a byte string. Thus subroutine converts it according as specified by arguments. We assume that byte string consists of int for this architecture. So you cannot use this subroutine for dealing e.g. with
short in a[10], only for C-objects likeint a[10]orsigned int[10].- Parameters
bytestr – a byte-string with data
signed – True/False to specify whether integers are signed or not, unsigned by default
array – if specified, we will return a list of array integers instead of one value
-
crash.readmem(addr, size[, mtype])¶ Interface to
crashbuiltinreadmem().- Parameters
addr – address to read from
size – how many bytes to read
mtype – memory type to read, by default
KVADDR
- Returns
a bytestring with data
-
crash.readPtr(addr[, mtype])¶ Assuming that addr contains a pointer, read pointer value.
- Parameters
addr – address
mtype – memory type, by default
KVADDR
-
crash.readInt(addr, size[, signedvar[, mtype]])¶ Given an address, read an integer of given size
- Parameters
addr – address to read from
size – integer size, according to C char/short/int/long/longlong specification for this architecture
signedvar – False for
unsigned, True forsigned. If not specified, we assumeunsignedmtype – memory type, by default
KVADDR
-
crash.set_readmem_task(taskaddr)¶ - Parameters
taskaddr – task address or zero
if taskaddr=0, reset readmem operations to use KVADDR
if taskaddr is a valid task address, set readmem operations to UVADDR and set the current context to this task
- Returns
nothing
Conversion between Memory Types¶
-
crash.uvtop(taskaddr, vaddr)¶ Interface to
crashbuiltinuvtop(tskaddr, vaddr)- converts a virtual address to physical address in the context of specified task- Parameters
taskaddr – address of
struct task_structvaddr – virtual address
- Returns
physical address as an integer
-
crash.phys_to_page(physaddr)¶ Interface to
crashbulitinphys_to_page(physaddr_t phys- Parameters
physaddr – physical address
- Returns
page as an integer
-
crash.PAGEOFFSET(vaddr)¶ Interface to
crashbulitinPAGEOFFSET(vaddr)
Miscellaneous¶
-
crash.getListSize(addr, offset[, maxel = 1000])¶ Assuming that addr points to a list head, find a total number of elements. The same can be done in Python easily - but C is faster for big lists
- Parameters
addr – address of a structure representing a list head
offset – offset or
nextpointer in this structuremaxel – maximum number of elements to search for, that is we stop iteration of we reach this limit
- Returns
number of list elements found (not counting the list head itself)
-
crash.getFullBuckets(start, bsize, items, chain_off)¶ Find full buckets in hash-tables. If we have hash-tables consisting of many buckets (>100,000) but just a few of them are non-empty, this subroutine is significantly faster than trying to do the same in pure Python. Useful for networking tables
- Parameters
start – address of the hash-table
bsize – hash-bucket size
items – how many buckets (hash-size)
chain_off – chain offset
- Returns
a list of addresses of full buckets
-
crash.getFullBucketsH(start, bsize, items, chain_off)¶ Similar to
getFullBuckets()but for different hash-table (needs to be further explained ASID)
-
crash.FD_ISSET(i, fileparray)¶ Interface to C-macro
FD_ISSET- Parameters
i – an index in
fileparrayfileparray – address of
struct fdtable *fdtinstruct files_struct
-
crash.get_NR_syscalls(void)¶ - Returns
number of system calls registered in sys_call_table
-
crash.get_pathname(dentry, vfsmnt)¶ - Parameters
dentry – dentry address
vfsmnt – vfsmnt address
- Returns
a string with pathname of this object
-
crash.setprocname(name)¶ Changes the name of the currently running process - needed if we want to implement daemons or background processes
- Parameters
name – a string with a new name
-
crash.is_task_active(taskaddr)¶ Interface to internal
crashsubroutineis_task_active- Parameters
taskaddr – address of a task
- Returns
True for active tasks, False for inactive ones
-
crash.pid_to_task(pid)¶ Interface to internal
crashsubroutinepid_to_task- Returns
address of the task
-
crash.task_to_pid(taskaddr)¶ Interface to internal
crashsubroutinetask_to_pid- Returns
PID of this task
-
crash.get_uptime()¶ Interface to
crashbuiltin subroutineget_uptime(NULL, &jiffies)- Returns
an integer - seconds since boot
-
crash.get_task_mem_usage()¶
Conversion of Integers¶
Python integers are always signed and have arbitrary precision. As a result, they do not behave in the same way - e.g. they do not overflow. So to emulate C behavior we need to use special functions
-
crash.sLong(i)¶ In C, the same bits sequence can represent either signed or unsigned integer. In Python, there is no native unsigned integer. This subroutine lets you convert a Python integer to signed assuming that integer size is that for long type of this architecture.
- Parameters
i – Python integer of any size/value
- Returns
process
sizeof(long)lower bits of provided integer as Cunsigned longand return this value assigned long
An example:
l = 0xffffffffffffffff print(l, sLong(l)) # Prints 18446744073709551615 -1
-
crash.le32_to_cpu(ulong)¶ Interface to
__le32_to_cpuC macro- Parameters
ulong – unsigned integer
- Returns
converts Python integer to C
ulongval, applies__le32_to_cpu(val)and returns a Python integer
-
crash.le16_to_cpu(uint)¶ Similar to
le32_to_cpu()but invoked C macro__le16_to_cpu
-
crash.cpu_to_le32(uint)¶ Similar to
le32_to_cpu()but invoked C macro__cpu_to_le32
Executing Commands¶
-
crash.exec_crash_command(cmd, no_stdout=0)¶ Execute a built-in
crashcommand and return output as a string. There is no timeout mechanism for this subroutine- Parameters
cmd – a string with command name and arguments
-
crash.exec_crash_command_bg2(cmd, no_stdout=0)¶ This command opens and writes to FIFO so we expect someone to read it. Execution is done in the background - we fork() a child process that does executing with output redirected to a pipe.
This function is used in high-level subroutine
exec_crash_command_bg(cmd, timeout = None)- Parameters
cmd – a string with command name and arguments
- Returns
a tuple of (fileno, pid) where fileno is OS filedescriptor and pid is PID of the child process
-
crash.exec_epython_command(cmd)¶ - Parameters
cmd – a string with command name and arguments
- Returns
nothing - at this moment we just execute the command and output goes to stdout
-
crash.set_default_timeout(timeout)¶ Set default timeout for execution of
crashbuilt-in commands as done viaexec_crash_command_bg2()- Parameters
timeout – default timeout in seconds
Registering Commands¶
Normally you execute your own programs doing epython progname. But
if you develop a program to be included in PyKdump for general
consumption, it makes sense to register it so that you can execute it
in crash without specifying epython every time, so that you
would be able to execute it just as progname. For example,
xportshow is implemented in Python but is registered.
-
crash.register_epython_prog(progname, description, shorthelp, longhelp)¶ - Parameters
progname – a string with program name
description – a string with description
shorthelp – a string with short help
longhelp – a string with detailed help
An example:
help = '''
Print information about tasks in more details as the built-in 'ps'
command
'''
register_epython_prog("taskinfo", "Detailed info about tasks",
"-h - list available options",
help)
-
crash.get_epython_cmds()¶ Get a list of registered
epythoncommands. Used internally in higher-level PyKdump API- Returns
a list of strings
GDB Interface¶
This section describes GDB-specific subroutines, intended primarily to be used by framework developers, not end-users.
When we use whatis or struct command in crash, we really
execute internal gdb commands whatis and ptype and they print
information in C-syntax. Programmatically in GDB we rely on
struct symbol obtained by calling different internal GDB
functions.
Python bindings to GDB internals return type info as a dictionary
with the following keys:
basetype - type name, e.g. ‘int’ or ‘struct net_protocol’
codetype - GDB type, e.g.
TYPE_CODE_INTfname - field or variable name
typelength - an integer, sizeof() for this type
dims - for array, a list of integers with dimensions
stars - for pointers, how many starts in C-syntax
ptrbasetype - for pointers, base type of object
uint - 0 for signed, 1 for unsigned
bitsize - for bitfields, the size in bits. For normal fields, this key is not present in dictionary
bitoffset - for bitfields, offset from the word boundary, in bits
edef - for enumeration types, a list of pairs (name, value)
For struct, we have an extra key - body - which is a list of dictionaries for all fields. These entries have bitoffset keys with values showing what is the offset (in bits) from the beginning of this struct. This is true even for normal fields (when there is no bitsize key).
To make this clearer, here are some examples.
In crash:
crash64> whatis int
SIZE: 4
crash64> whatis struct task_struct
struct task_struct {
volatile long state;
void *stack;
...
crash64> whatis inet_protos
const struct net_protocol *inet_protos[256];
crash64> struct list_head
struct list_head {
struct list_head *next;
struct list_head *prev;
}
SIZE: 16
Now the same in PyKdump program:
pp.pprint(crash.gdb_whatis("int"))
pp.pprint(crash.gdb_whatis("struct task_struct"))
pp.pprint(crash.gdb_whatis("inet_protos"))
pp.pprint(crash.gdb_typeinfo("struct list_head"))
This results in output:
{'basetype': 'int', 'codetype': 8, 'fname': 'int', 'typelength': 4, 'uint': 0}
{ 'basetype': 'struct task_struct',
'codetype': 3,
'fname': 'struct task_struct',
'typelength': 2648}
{ 'basetype': 'struct net_protocol',
'codetype': 1,
'dims': [256],
'fname': 'inet_protos',
'ptrbasetype': 3,
'stars': 1,
'typelength': 8}
{ 'basetype': 'struct list_head',
'body': [ { 'basetype': 'struct list_head',
'bitoffset': 0,
'codetype': 1,
'fname': 'next',
'ptrbasetype': 3,
'stars': 1,
'typelength': 8},
{ 'basetype': 'struct list_head',
'bitoffset': 64,
'codetype': 1,
'fname': 'prev',
'ptrbasetype': 3,
'stars': 1,
'typelength': 8}],
'codetype': 3,
'typelength': 16}
-
crash.get_GDB_output(cmd)¶ Execute
GDBcommand and return its output as a string
-
crash.gdb_whatis(varname)¶ Interface to
gdb_whatisGDB internal subroutine- Parameters
varname – a string that will be passed to
gdb_whatis- Returns
a dictionary describing this object
-
crash.gdb_typeinfo(typename)¶ - Parameters
typename – a string with data type, e.g.
struct task_struct- Returns
a dictionary describing this type
gdb/gdbtypes.h from GDB sources defines
enum type_code
{
TYPE_CODE_BITSTRING = -1, /* Deprecated */
TYPE_CODE_UNDEF = 0, /* Not used; catches errors */
TYPE_CODE_PTR, /* Pointer type */
...
Some of these values are accessible as module constants, namely:
-
crash.TYPE_CODE_PTR¶
-
crash.TYPE_CODE_ARRAY¶
-
crash.TYPE_CODE_STRUCT¶
-
crash.TYPE_CODE_UNION¶
-
crash.TYPE_CODE_ENUM¶
-
crash.TYPE_CODE_FUNC¶
-
crash.TYPE_CODE_INT¶
-
crash.TYPE_CODE_FLT¶
-
crash.TYPE_CODE_VOID¶
-
crash.TYPE_CODE_BOOL¶
Other Module-level Constants¶
-
crash.error¶ Exception raised when we have a problem when executing
crashinternal subroutine, e.g. bad address
-
crash.version¶ A string with
crashmodule version, e.g. “3.2.0”
The following constants are copied from crash sources, namely from
defs.h
-
crash.HZ¶ An integer with the value of HZ for this vmcore
-
crash.WARNING¶ A string to be used while printing warnings, at this moment set to “++WARNING+++”
When we build PyKdump, we use headers from a specific crash
sources. We do not necessarily need to load the extension using
exactly the same version of crash`, typically extensions are
compatible with any crash binary as long as its major version is
the same. So it is OK to build extensions using e.g. crash-7.2.3 and
use them with the binary of crash-7.2.8. But when major version of
crash changes, extensions built with previous major version might
not work.
-
crash.Crash_run¶ Version of
crashutility that we are using at this moment
-
crash.Crash_build¶ version of
crashused for building the extension