pykdump.API Main Package


This module provides everything necessary to write PyKdump programs. It imports other modules as needed.

Conversion of Integers

Python integers are always signed and have arbitrary precision. As a result, they do not behave in the same way as in C, e.g. they do not overflow. So to emulate C behavior, we need to use special functions.

pykdump.API.cpu_to_le32(uint)

Similar to le32_to_cpu() but invokes C macro __cpu_to_le32

pykdump.API.le32_to_cpu(ulong)

Interface to __le32_to_cpu C macro

Parameters:

ulong -- unsigned integer

Returns:

converts Python integer to C ulong val, applies __le32_to_cpu(val) and returns a Python integer

pykdump.API.le16_to_cpu(uint)

Similar to le32_to_cpu() but invokes C macro __le16_to_cpu

pykdump.API.sLong(i)

In C, the same bit 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 C unsigned long and return this value as signed long

An example:

l = 0xffffffffffffffff
print(l, sLong(l))

# Prints 18446744073709551615 -1
pykdump.API.unsigned16(i)
Parameters:

i -- a Python integer

Returns:

i & 0xffff

pykdump.API.unsigned32(i)
Parameters:

i -- a Python integer

Returns:

i & 0xffffffff

pykdump.API.unsigned64(i)
Parameters:

i -- a Python integer

Returns:

i & 0xffffffffffffffff

Reading Memory

There are different types of memory. See Reading Memory for details about possible memory types. If you need to use these types, you should import them from the crash module explicitly.

Several low-level subroutines are automatically imported from the crash module (implemented in C); you do not need to import them yourself. They are documented in the description of the crash module.

pykdump.API.mem2long(bytestr, signed, array)

see crash.mem2long()

pykdump.API.readmem(addr, size[, mtype])

see crash.readmem()

Reading Integers

pykdump.API.readInt(addr, size[, signedvar[, mtype]])

Given an address, read an integer of given size

See crash.readInt()

pykdump.API.readPtr(addr[, mtype])

Assuming that addr contains a pointer, read the pointer value.

See crash.readPtr()

pykdump.API.readS32(addr)
Parameters:

addr -- address to read from

Returns:

read 4 bytes, intepret it as signed

pykdump.API.readS64(addr)
Parameters:

addr -- address to read from

Returns:

read 8 bytes, intepret it as signed

pykdump.API.readU8(addr)
Parameters:

addr -- address to read from

Returns:

read 1 byte, intepret it as unsigned

pykdump.API.readU16(addr)
Parameters:

addr -- address to read from

Returns:

read 2 byte, intepret it as unsigned

pykdump.API.readU32(addr)
Parameters:

addr -- address to read from

Returns:

read 4 bytes, intepret it as unsigned

pykdump.API.readU64(addr)
Parameters:

addr -- address to read from

Returns:

read 8 bytes, intepret it as unsigned

Working with Lists

There are several standard ways in the Linux kernel to define lists:

  • using 'struct list_head' and embedding it into another structure

  • using next and/or prev pointers embedded directly in a structure, without any list_head

pykdump.API.LH_isempty(lh)
Parameters:

lh -- list head address or StructResult object for list_head

Returns:

in boolean context, evaluates to True (when list head is empty) or False

pykdump.API.list_for_each_entry(start, offset=0, maxel=None, warn=True)

Another name for readListByHead()

class pykdump.API.ListHead(lh, sname=None, maxel=None, warn=True)

To read a list of structures with list_head embedded, we can create an instance of this class and then use it for iterations:

lh is the address of a list_head.

If sname is specified, this is a string with structure name embedding our list_head.

maxel is the maximum number of elements to traverse.

warn specifies whether we would like to see warnings if we reach the maxel limit while iterating.

An object created can be used in two ways:

  • if sname was not specified, we should use as an iterator the object itself, and iterations return a list of list_head results.

  • if sname is specified, we should use as an iterator not the object itself, but rather obj.fieldname where fieldname is the name of the structure field containing list_head. In this case, we return a list of structures of sname type.

For example, in C we have

static LIST_HEAD(cache_list);

struct cache_detail {
        struct module *         owner;
        int                     hash_size;
        struct cache_head **    hash_table;
        ...
        struct list_head        others;

Traversing this list in Python:

cache_list = ListHead(sym2addr("cache_list"), "struct cache_detail")

for c in cache_list.others:
    if (c.name == cname):
        details = c
        break
pykdump.API.readBadList(start, offset=0, maxel=_MAXEL, inchead=True)

Similar to readList() but in case we are interested in partial lists even when there are low-level errors.

Returns:

a tuple (partiallist, error/None)

pykdump.API.readList((start, offset=0, maxel = None, inchead = True, warn = True)
Parameters:
  • start -- address of first structure

  • offset -- offset of the pointer to the next structure in the list

  • maxel -- maximum number of elements to follow (to limit the number of found elements). If not defined, uses the default value (which can be changed).

  • inchead -- whether to include the list head itself in the output or not

  • warn -- if True, print a warning when the maximum number of elements is reached

pykdump.API.readListByHead(start, offset=0, maxel=None, warn=True)
Parameters:
  • start -- address of first structure

  • offset -- offset of the pointer to the next structure in the list

  • maxel -- maximum number of elements to follow (to limit the number of found elements). If not defined, continues indefinitely.

  • warn -- if True, print a warning when the maximum number of elements is reached

Working with Hash-Lists

pykdump.API.hlist_for_each_entry(emtype, head, member)

Traverse hlist_node hash-lists, e.g. hlist_for_each_entry("struct xfrm_policy", table, "bydst") for

struct xfrm_policy {
      possible_net_t          xp_net;
      struct hlist_node       bydst;
      struct hlist_node       byidx;
      ...
Parameters:
  • emtype -- a string with struct name

  • head -- a StructResult object for struct hlist_node

  • member -- a string with the field name embedded in our main struct

pykdump.API.getFullBuckets(start, bsize, items, chain_off=0)

See crash.getFullBuckets()

Struct Lists and Arrays

pykdump.API.readSUArray(suname, startaddr, dim=0)

Read an array of structs/unions given the structname, start, and dimension.

Normally a list with dim elements is returned, but if the dimension specified is zero, return a generator instead.

Parameters:
  • suname -- a string with struct/union name

  • startaddr -- address of the first element

  • dim -- an integer, either the number of elements to read or zero

pykdump.API.readSUListFromHead(headaddr, listfieldname, mystruct, maxel=None, inchead=False, warn=True)
pykdump.API.readStructNext(shead, nextname, maxel=None, inchead=True)

Suppressing Internal Crash/GDB Messages

When you execute crash/GDB commands, they might display errors, e.g. if you try to execute an invalid command, or a page is missing in the vmcore. Sometimes you may want to suppress such error messages. This can be done using the following context manager:

class pykdump.API.SuppressCrashErrors(outfile='/dev/null')

A context manager to redirect or suppress internal crash/GDB error messages

An example:

with SuppressCrashErrors():
   try:
       print("test", exec_crash_command("set scope st_create"))
   except:
       print("Exception caught")