kme - Kernel Memory Editor
- kme
- [-ahirstx] [-b base]
[-c corefile]
[-d defsnames]
[-D defspaths]
[-e emuldev]
[-f fepdev]
[-L extension]
[-m hostlist]
[-M offset:len]
[-n namelist]
[-p row] [-P pid]
[-S addressmask]
[-u uptime] [params
...]
Kme is a general purpose screen-oriented tool for viewing and modifying
UNIX kernel memory. Upon invokation, the program continuously displays and
updates one or more sections of /dev/kmem in a spreadsheet-like format.
The memory range and display format may be defined on the command line or
entered on the screen. Thereafter the corresponding memory contents are
continuously displayed and updated on the screen, and may be modified by field
entry. Available builtin display formats are character, hex and decimal in
various byte, word and longword combinations. The file kme_defs in the
current directory may contain user-defined display formats for composite
memory structures.
Command line options include:
- -a
- Do not display address expressions.
- -A addrscale
- Scale input addresses by multiplying them by addrscale before
accessing the corefile. Scale displayed addresses by dividing them
by addrscale before displaying them.
The default value for addrscale is 1 (no scaling).
This feature is useful for displaying memory on devices that
are not byte addressable, such as DSP memory. For example, when
displaying memory on an Analog Devices 2187 DSP, a scale factor of 2 can
be used for data memory and a scale factor of 4 can be used for program
memory (4 is used instead of 3 because the underlying DSP interface is
32 bits wide, not 24 bits wide).
NOTE: this feature is not very well tested.
- -b base
- Add the hex number base to all addresses before accessing kernel
memory.
- -c corefile
- Use the file corefile for memory accesses. If the environment
variable KME_CORE is defined, it contains the default file name.
Otherwise the default is /dev/kmem.
- -d defsnames
- Read user-defined display definitions from the colon-separated list of
file names given in defsnames. If the environment variable
KME_DEFS is defined, it contains the list of default file names.
Otherwise the default is kme_defs in the current directory. The
search path can be modified using the -D option. If a file can't be
opened, a warning will be printed except that no warning will be printed
if the file kme_defs can't be found.
- -D defspaths
- When searching for display definition files which aren't absolute file
names (see -d), use defspaths as a colon separated list of
directories to search. If the environment variable KME_PATH is
defined, it contains the list of default directory names. Otherwise the
default is the current directory.
- -e emuldev
- Access kernel memory using the HP64000 emulator connected to tty device
emuldev. The program assumes a 38400 connection to port B of the
emulator.
- -f fepdev
- Access kernel memory using DIGI_KME ioctl() calls directed to tty device
fepdev.
- -h
- Suppress the one-line help memu normally displayed at screen bottom.
- -i
- Allow curses to use insert/delete line sequences when updating the
screen.
- -L extension.so
- Dynamically load a shared object as an extension to the display format
capabilities of "kme". Not supported on all operating
systems.
- -m hostlist
- Specifies a colon-separated list of TCP/IP hostnames where memory should
be displayed. Each host must provide a kme/udp memory read/write server,
as specified in the services file.
- -M offset:len
- Access memory by using the mmap() system call to map the corefile
directly into kme's address space. Memory is mapped beginning at
offset bytes from the beginning of corefile for a length of
len bytes. Note that corefile is typically set to
/dev/pmem when this option is used. Offset and len
are specified using the conventions of strtol(), e.g.
0x500000:0x1000.
- -n namelist
- Read symbol definitions from the colon separated list of file names given
in namelist. If the environment variable KME_SYMS is
defined, it contains the default file list. Otherwise the default is
kme_syms in the current directory. Each file may be either a binary
file (defined by the ld library) or an ASCII file where each line contains
a hexidecimal symbol value followed by a alphanumeric symbol name.
- -p
- Position the initial display so row is at the top of the
screen.
- -P process_id
- If process_id is zero, it uses the process id of KME itself. (Useful
mostly for debugging KME itself.). Monitoring other processes is generally
more fun.) Otherwise, attaches to process and examine global symbols in
that process. Most useful when combined with NLIST support.
- -r
- Open /dev/kmem read-only, and prohibit all attempts to modify
memory.
- -s
- Swap 2-byte and 4-byte quantities displayed from and written to the core
file.
- -S addressmask
- All addresses read from the symbols file (ascii, coff, or nlisted) will be
binary masked with addressmask.
- -t
- Normally, indexed arrays are displayed in the form of
"foo+0xb4". This flag changes it to display the index into the
array instead of the offset. The example may then display as
"foo[4]". Same as ^T within the program.
- -u uptime
- Wait uptime tenths of a second after refreshing the screen before
beginning a new refresh cycle. Default is 2, limiting screen refresh time
to 5/second.
- -V
- Print version and other information determined by the configuration
process when kme was built.
-x Print debugging information to stderr.
Additional parameters specify initial screen display requests, or
user format defines. The form:
line_number = memory_address /
display_format
says to display data at screen line_number from at
memory_address according to display_format. If
line_number is 0 this data will display on the line following the
first blank line after the previous display_format has completed.
This method of determining format positioning may affect subsequent
absolutely anchored references.
The form:
user_display_char =
display_format
defines the upper-case single user_display_char to be an
abbreviation for the display_format string which follows.
As a special case when using the -f option, the memory
address field may be prefined by one or two hexidecimal digits and a
(:) to designate the address space of a particular DigiBoard device.
The first digit specifies the PC-bus board, while the second digit (if
present) further specifies a concentrator attached to that host adapter. For
example the prefix 03:1000 specifies address 0x1000 in the 3rd
concentrator attached to the 1st host adapter board.
The CRT screen display is tabular, with a line number leftmost, the hex memory
address next, and memory data fields every 8 columns thereafter across the
screen. On a 24 by 80 CRT screen, the display is 23 address lines tall by 8
data columns wide, with a help menu on the bottom line.
Regardless of the screen size, kme supports 200 virtual
display lines. At any given time, only a subset of these lines may be viewed
through the screen window. The screen window follows the cursor, so the user
may scroll through the range in the manner of an editor or spreadsheet.
Through command line parameters, or by screen entry, the user
selects the data to be displayed on each address line. From the screen there
are two methods to accomplish this. The user may type an m and enter
a memory display string or user format character definition just as it would
appear on a command line. He may also position the cursor to the desired
address field, type the letter c for change, or e for edit,
and then enter a string of the form:
address_expression /
display_format
In either case, the memory address_expression value
immediately appears on the specified display line, followed by zero or more
data fields according to the display_format given. If more data
fields are specified than fit across the screen, the data is extended to
multiple lines, and the memory address of the first data field on each line
is displayed in the corresponding address field.
The address_expression may include decimal (0t prefix) and
hexidecimal numbers, symbols defined in the namelist file, and the operators
listed below. Precedence is modeled after the C-language.
- .
- Structure element designator. Performs a simple binary add, but with much
higher precedence.
- {}
- 2-byte Subscript. The form a{b} returns the
16-bit quantity at address a+b in the corefile.
- []
- 4-byte Subscript. The form a[b] returns the
32-bit quantity at address a+b in the corefile.
- ∗
- Unary 32-bit indirection.
- @
- Unary 16-bit indirection.
- #
- Unary 8-bit indirection.
- $
- Fetch temporary value. The size of the current display item is available
in temporary 0, although it will always be zero the first time the item is
displayed. Other temporaries are stored with the $ display
operator.
- +
- Unary plus.
- −
- Unary minus.
- ~
- Unary NOT.
- ^
- Swap 2 byte operand.
- %
- Swap 4 byte operand.
- ∗
- Multiply.
- /
- Divide. This operator is recognized only in parenthesized expressions, so
it is not confused with the / separator character.
- %
- Modulus.
- +
- Binary add.
- −
- Binary subtract.
- <<
- Shift left.
- >>
- Shift right.
- <
- Less than.
- >
- Greater than.
- <=
- Less equal.
- >=
- Greater equal.
- ==
- Equal.
- !=
- Not equal.
- &
- Bitwise AND.
- ^
- Bitwise Exclusive OR.
- |
- Bitwise Inclusive OR.
- ?:
- C-language style if-else conditional value operator.
- <be16>
- Conditional swap 2 byte operand. On a big-endian CPU, this operator is a
NOP. On a little-endian CPU, this operator is the same as the ^
operator.
- <be32>
- Conditional swap 4 byte operand. On a big-endian CPU, this operator is a
NOP. On a little-endian CPU, this operator is the same as the %
operator.
- <le16>
- Conditional swap 2 byte operand. On a little-endian CPU, this operator is
a NOP. On a big-endian CPU, this operator is the same as the ^
operator.
- <le32>
- Conditional swap 4 byte operand. On a little-endian CPU, this operator is
a NOP. On a big-endian CPU, this operator is the same as the %
operator.
Builtin format characters are lower-case letters, punctuation
marks, and text strings delimited by single and double quotes. As a special
case, text strings containing ´\h´ are used to toggle
highlighting in the displayed string. You may want to use this for section
headers or elsewhere for emphasis. User-defined format characters are upper
case alpha letters. Format characters, and format strings enclosed in parens
may be preceeded by a decimal repetition count, and concatenated to
form a display string of arbitrary complexity. User-defined format
characters may include other user-defined characters to a recursive limit of
10.
The builtin format characters are given below. Except as otherwise
described, a preceeding decimal repetition behaves exactly as though the
following character were repeated that number of times.
- +
- Increment the working memory address.
- −
- Decrement the working memory address.
- ´text´
- Display text. If text is more than 8 characters, use
multiple fields as required. Ignore any repetition count.
- "text"
- Same as above.
- .
- Display a blank data field.
- :
- Display nothing, but fetch subsequent blocks of display data from the
memory device in blocks of count bytes. The effect continues until
the end of the format string. This is often useful when reading device
registers.
- $
- Display nothing, but store the current display address in the temporary
value given by count.
- %
- Display nothing, but toggle the endianness swap flag. If enclosed in
parenthesis, the effect ends at the next right paren. Otherwise the effect
continues until the end of the format string.
- =
- Display nothing, but set an internal variable called width to the
value of count.
- *
- Display nothing, but set the new count to the temporary value
stored in temporary register number count.
- &
- Display nothing, but store the value at the current display address in
temporary register number count. The width of the value fetched is
determined by the current setting of width (see = format).
- ^
- Display nothing, but roundup the value in temporary register number
count. The value is rounded up to the next multiple of the current
value of width.
- #
- Display nothing. If enclosed in parenthesis, set the working memory
address to the working memory address at the last left paren plus
count. Otherwise set the working memory address to
address_expression plus count.
- a
- Mask the next memory byte with 0x7f and display the result in ASCII.
Characters below 0x20 are shown with a caret as control characters.
- b
- Display the next memory byte in hexadecimal.
- c
- Display the next byte in an unambiguous character format. Characters below
0x20 are shown with a caret as control characters. Characters
greater-equal 0x7f are shown in hexadecimal.
- d
- Display the next 2 bytes as signed decimal.
- e
- Display the next 4 bytes as an unsigned decimal. To keep the field size
down to 8 characters, if the number exceeds 9,999,999, display a plus sign
(+) followed by the lower 7 digits of the decimal value.
- i
- Display the next byte as a character (masked to 7 bits), and the following
byte in hexadecimal.
- l
- Display the next 4 bytes as an 8-digit hexadecimal number.
- n
- Advance to the next display line.
- s
- Display string data with zeroes shown as spaces, and other unprintable
characters shown as periods. When used with a repeat count, up to 8
characters are shown per field, using as many fields as necessary to show
the complete string.
- t
- Display the next byte of memory as unsigned decimal. u Display the
next 2 bytes as an unsigned decimal.
- x
- Display the next 2 bytes of memory in hexadecimal.
- z
- Display the next 4 bytes of memory in decimal.
Screen commands are all single keystrokes, possibly preceeded by a repeat count.
Available commands are:
- ^F
- Page forward.
- ^U
- Page back.
- ^D
- Scroll down. The line scroll count is remembered and becomes the default
scroll count next time.
- ^T
- Normally, indexed arrays are displayed in the form of
"foo+0xb4". This flag changes it to display the index into the
array instead of the offset. The example may then display as
"foo[4]". Same as -t on the command line.
- ^U
- Scroll up. The line scroll count is remembered and becomes the default
scroll count next time.
- ^J
- Move down to the beginning of the next line.
- ^
- Move to the address field.
- +
- Advance the memory address of the current display line by the size of the
data displayed.
- −
- Decrement the memory address of the current display line by the size of
the data displayed.
- !
- Prompt for and execute a shell command.
- ?
- Toggle the appearance of the help menu on the bottom line of the
screen.
- a
- Toggle address display mode.
- b
- Prompt for and accept a new memory base address.
- c
- Change the field under the cursor.
- d
- Delete the current line, and remember it in the save buffer. If a repeat
count is given, delete and keep all those lines in a single
operation.
- e
- Edit the contents of the field under the cursor using vi style
editing commands.
- f
- When using an HP64000 emulator, switch command input to control port A.
Memory updates will not succeed until switched back by other means.
- g
- If no repeat count is given, move the cursor to the last virtual display
line. If a count is given, move to the line number given in that
count.
- h
- Move left.
- i
- Insert count lines before the current one.
- j
- Move down.
- k
- Move up.
- l
- Move right.
- m
- Prompt for and accept either a display line request or a user format macro
using the command line syntax.
- n
- Discard all existing symbol definitions and re-read the namelist
files to get a fresh copy.
- o
- Output (print) the contents of the current screen to a file. If the first
character of the file name is the pipe character (|), then the
output is piped to a program. If the first two characters of the file name
are >> then the output is appended to the file.
- p
- Put deleted lines back into the display.
- q
- Quit the program.
- r
- Discard all existing macro definitions and re-read the defspath
files to get a fresh copy.
- s
- Save the configuration of the current display to a command file.
Subsequently executing that command file should automatically recreate the
current display.
- u
- Allow the user to enter a new update interval.
- y
- Yank (copy) the specified number of screen lines into the save
buffer.
- z
- Zero the memory location under the cursor.
During all field entry, the user may invoke vi-style commands to
edit the entry in the style of ksh. This facility supports the basic
line editing command characters $.0abcdDfhiIlrstuwx, and the history
command characters +-/jkn. The character q quits the field
entry w/o change.
On startup, user-defined display formats are read from the colon-separated list
of files defined in defspath. In this file, a line beginning with an
upper-case letter defines the corresponding user format character. Subsequent
indented lines are continuations. Single and double quoted strings are passed
verbatim, otherwise white space is discarded, and everything on a line after
an unquoted (#) is a comment.
An example file might contain:
A "thead""ttail""tstart""tmax""rhead""rtail""rstart""rmax"
8xN
"cport""seg""rlow""rhigh"n
4xnN
"tlow""dcdtime""flow""mstat""lstat""status"n
2x4bnN
"imask""baud""dtype""hndshk""xoff""xon""hflush""btime"
4b2c2bN
"bcount""portnum""dmask""irq""tmask""tval""bstart"n
6bxnN
"rr0""rr1""rr3""rr10""wr0""wr1""wr2""wr3"
8bN
"wr4""wr5""wr9""wr11""wr12""wr13""wr14""wr15"
8bN
"ov/un""dcdlo""dcdhi""portbit"n
4xnN
"mcount""m10ms""mand""mor""mval"n
xxbbbn 49+
L l.
N n
This file defines format A to display a 128 byte structure.
The name of each field is displayed immediately above it. The 49+ at
the end of the A definition pads out the size of the structure to be
128 bytes so that the + and - commands will work as desired.
Normally, double spacing is used between lines, but the user may make it
single spaced by redefining N to be Null.
When l format fields are displayed side-by-side, they run
together. The L user format overcomes this by placing a blank field
after the 8-character hexadecimal number.
The syntax for user defined formats has been enhanced, while
remaining compatible with the mode described above. In a complex system, a
limit of 26 uppercase user defined formats was restricive and difficult to
make mnemonic. You can now also define the above format like this:
!channel "thead""ttail""tstart""tmax""rhead""rtail""rstart""rmax"
8xN
...
You must display this symbolically named format with a leading
! character, so the program knows the difference between a symbol
named "channel" and a format string consisting of c,
h, and so on. All alphanumeric (plus underbar) characters following
the ! are interpreted to be part of the format name.
A new feature in kme is the ability to extend display formats using shared
objects. You can write your own C program to add an arbitrary display format
to kme. The method to do this is operating system specific. With the GNU
toolchain, you would do something like the following:
$ cc -c dxbmsg.c -o dxbmsg.o
$ ld -shared dxbmsg.o -o dxbmsg.so
$ kme -L dxbmsg.so 1=0/!dxbmsg
The shared object must have an _init() routine which
calls:
typedef char * (*DLFUNC)(ulong *addrp);
add_format(char *name, char *format, DLFUNC dlfunc);
for each new format name that it wants to define. If
format is not NULL, then the new format is just a simple string. This
is not interesting as you can already do this with kme_defs files. However,
if dlfunc is not NULL, then (*dlfunc)(&addr) is called whenever
the format needs to be displayed. &addr is a pointer to the
variable which holds the current display address.
(*dlfunc)(ulong *addrp) can do one of two things. It can
generate a format string on the fly and return a pointer to it. In this
case, kme will display the format as returned. Or it can handle doing
display updates itself. In this case, it returns NULL and must update the
current display address (*addrp) itself.
An example format that displays a real C-string by returning a
customized display format string is:
extern unsigned char *mem;
typedef unsigned long ulong;
char *
format(ulong * addrp)
{
ulong faddr = *addrp;
ulong zaddr;
static char fmt[32];
for (;;)
{
if (!getmem(1))
return "
if (*mem == 0)
break;
(*addrp)++;
}
zaddr = *addrp;
*addrp = faddr;
sprintf(fmt, "%d a 1+0, zaddr - faddr);
return (fmt);
}
void
_init(void)
{
add_format("asciiz", NULL, &format);
}
The above example, although simple to implement, also shows why
there is a second method for the way that extensions can choose to operate.
The above example is inefficient, as memory will be traversed twice (once in
the extension, and once in kme itself). However, the second method currently
requires some knowledge of how kme is implemented internally. Translation:
we are currently too busy to clean up and expose a set of functions for your
convenient use.
- /usr/lib/kme_defs
- User defined formatting commands.
- /dev/kmem
- Access to kernel memory.
- /etc/services
- Internet Services file.
There needs to be a stack of last memory addresses, so that you can use '-' to
step backwards thru memory when a variable length format from an extension is
being used.