DPROBES.LANG

NAME
DESCRIPTION
PROBE PROGRAM FILE FORMAT
PREPROCESSOR DIRECTIVES
SUBSTITUTION
RPN EXCEPTION HANDLING AND STACK TRACING
SAMPLE RPN FILES
COMPLETE EXAMPLES OF RPN
APPENDIX A
APPENDIX B
APPENDIX C
APPENDIX D
APPENDIX E
AUTHOR
VERSION
LICENSE

NAME

Dynamic Probes Program File Format and Language Reference

DESCRIPTION

The Dynamic Probes (dprobes) facility can be used to insert software probes dynamically into executing code modules. When a probe is fired, a user written probe-handler is executed. The probe-handler is a program written in an assembly-like language, based on the Reverse Polish Notation (RPN).

Dynamic Probes also allows probes to be fired on specific type of memory accesses(execute|write|read or write|io). This is made possible by using the debug registers available on Intel x86 processors. These probes are called watchpoint probes. Watchpoint probes are not currently available for S/390.

A probe program file specifies one or more probes for an executable program. It consists of a file header followed by a set of probe definitions. A probe definition contains the probe’s identity and a series of instructions that make up the probe handler.

The assembly-like language in which the probe handlers are written provides:

- arithmetic/logical/bitwise operations
- control flow instructions (conditional branching/calls)
- preprocessing directives (same as those in C language)

Special instructions are provided for a probe handler to: - access CPU registers - access user/kernel memory contents - access key system variables - access IO ports - log data into a buffer - exit to other debug facilities

RPN instructions work on a circular stack of 1024 elements. The top of the stack is the only element accessible at any time. Typical instruction to place a data item on to the top of the stack is by a push instruction. Similarly, a pop instructions a retrieves the data item on the top of the stack.

The stack elements are of fixed size (machine word length — typically sizeof(long)), and instructions always operate on an integral number of elements. The stack pointer will always be aligned on a machine-word-length boundary. Thus, even if a byte is pushed on to the stack, it will be padded to size of machine word length and placed on the stack.

In addition to RPN program stack, RPN program interpreter also provides a call stack. Call stack is primarily present to hold the return address of the call rpn instruction.

RPN language supports Exception Handling and Stack Tracing. Several kinds of faults can occur when rpn instructions are executed. RPN program interpreter generates different exceptions based on the type of fault. Programmer has the option of catching the exceptions and try to recover from faults by coding exception handlers. Programmer has the option of masking/unmasking different exceptions. Some exceptions are non-maskable. Maskable exceptions are not generated if they are masked. Non-maskable exceptions terminate the probe program interpretation if they are masked.

When an exception is generated, programmer has the option to store probe program execution state (RPN stack entries, probe point details, call chain etc) in Stack trace buffer. This is called stack tracing. Stack trace buffer data is logged along with the normal dprobes log(see man page dprobes(8) ) when the probe program terminates. Programmer can also store the execution state at arbitrary time during probe program execution by using an rpn instruction (explained later).

Exception handling and stack tracing are primarily intended to be used by the High-Level Language (HLL) DProbes Compiler, dpcc. The HLL compiler allows probe programs to be written in a C-like language, which will then be compiled into the RPN language.

Refer to the section RPN Exception Handling and Stack Tracing for a complete explanation.

The dprobes interpreter provides some internal registers which the probe program can make use of. There are rpn instructions provided to access/modify these.

Top of the Stack Pointer register(TSP) This register always contains the pointer to top of the RPN stack. This register gets modified on every push and pop rpn instruction.

Stack Base Pointer register(SBP) This register is intended to be a pointer to arbitrary locations on RPN stack. SBP is stored/restored on every call/return. Programmer can use SBP as pointer to the base of RPN stack during the call.

Log Pointer register(LP) Holds the value of the current dprobes log buffer pointer. It is initialized to the beginning of the user log area in the log buffer. Note that a few bytes in the beginning of the log buffer are used to store the log header elements.

Previous Log Pointer register(PLP) PLP will be maintained as a lagging value of LP. This will normally be the same value as LP when a logging instruction starts execution. PLP is updated to LP only if logging instruction succeeds. Using PLP, programmer has the option of backing out the partial log in the log buffer if logging fails.

PROBE PROGRAM FILE FORMAT

Probe Program file consists of the following sections:

* File Header

* Probe Point Definitions (one or more)

- Probe Point Header

- RPN Instructions

Comments can be specified anywhere in the probe program file. Comments start with two backslashes(//) and extend up to the end of the line. Blank lines are allowed anywhere in the probe program file.

File header and each probe point header consist of a number of statements of the key = value format.

Numeric values may be specified in decimal or hexadecimal. Hexadecimal values have to be prefixed with 0x , as in the C language.

Except the value of name= statement in the file header, everything else is case-insensitive. The value of name= has to be case-sensitive as the executable file names in Linux are case-sensitive.

All the sections are defined below in detail.

PROBE PROGRAM FILE HEADER
File header may comprises of one or more statements of the key = value format. Any combination of the below explained statements may be specified with the name = statement being mandatory.

name = <modulename>
<modulename> is the name of the module on which probe is to be applied. It needs to be specified within quotes if it contains any characters other than a-zA-Z0-9. For ex.:

name = testapp (valid)
name = /home/user/testapp (invalid)
name = "/home/user/testapp" (valid)
name = "a+b/testapp" (valid).

modtype = <typename>
Type of the module. <typename> can take the any of the following values: kernel - the name specified above is the kernel kmod - the name specified above is a kernel module user - the name specified above is user space module. It could be an executable file or a shared library

vars = <n>
Probe handlers can use a specified number (<n>) of local variables. Variables are of fixed size (machine word length — typically sizeof(long)). Many instructions can take a variable as an operand, usually referred to as "lv,index", where index is the variable index from 0 to <n>-1. They are all initialized to zero. Variables retain their values across probe hits. These variables are available to all the probe handlers in this probe program. Default value of <n> is 0 which implies that this probe program does not make use of variables.

gvars = <n>
<n> specifies the number of global variables that the probe handler can use. The use and accessing mechanisms of global variables are similar to local variables except that they are accessible across probe points. i.e., they are global in nature. Default value of <n> is 0 which implies that this probe program does not make use of global variables.

groupdef = <group_name>[ <group_name>[ <group_name> ...]]
This field is used to define all the valid group definitions which can be used by the individual probe points. The <group_name> used in the group field of any probe-point header should have a definition present in this field.

typedef = <type_name>[ <type_name>[ <type_name> ...]]
This field is used to define all the valid type definitions which can be used by the individual probe points. The <type_name> used in the type field of any probe-point header should have definition present in this field.

major = <n>
<n> is the number to be assigned as the probe point major code, The major code can be used for easy identification of the log generated by the probe handlers specified in this program. Default value is 0.

id = <n>
<n> is a number which can be used as probe program identifier. This is not validated for uniqueness. Default value is 0.

logmax = <n>
<n> is the maximum number of bytes that can be logged in the log buffer during one run of a probe handler. Default is 1024 bytes.

jmpmax = <n>
<n> is the maximum number of jumps and loop iterations allowed for one run of a probe handler. This is needed to ensure that probe handlers will not loop infinitely causing the system to hang. Default is 256.

logonfault = <yes|no>
This specifies if the probe on faulting instruction should produce log or not. The default action is not to produce log. But if yes is specified, even if the probed instruction faults, the log is generated. This keyword in probe program file header applies uniformly to all the probes specified in this probe program file.

PROBE-POINT DEFINITION

Probe-Point Header:

Probe point header consists of statements of the key = value format. The valid statements are explained below. These can be specified in any order, with the exception that offset = <n> must appear first. opcode = <n> and offset = <n> statements are mandatory, remaining statements are optional.

In case of kernel mode probe program files, instead of offset = <n> one can specify address = statement (explained below) to specify the probe location by its absolute linear address.

offset = <n>
<n> is the offset within the module where probe-point will be applied. It can also be specified symbolically using function symbol names and symbol expressions. e.g offset = main + 0x10 By default, the symbols will be looked up in the module specified on the name= line in the file header. The file to be used for looking up the symbols can also be specified on the --insert command line using --sym option.
Kernel symbols can only be looked up in the
System.map
file. The pathname of System.map should be specified using the --sym option on the command line.
See man page dprobes(8) for more details.

address = <n1>[:<n2>]
This statement may be present only in kernel mode probe program files. n1 specifies the absolute virtual address of the probe location. For watchpoint probes, n1 and n2 together specify the range of memory address for which the watchpoint is active. n1 is the lower address and n2 is the higher address of the range. Note that if this range is not consistent with the range specified by the processor, probes won’t be inserted. On Intel x86 processors, the allowed memory ranges are 1, 2 and 4 bytes. Note that n2 is an optional argument here and it has no meaning in case of breakpoint probes.

This statement is mutually exclusive with the offset = <n> statement. Only one of them should be present. Instead of specifying the probe point by offset, this statement can be used to specify it directly by its absolute linear address. However, this statement can also take symbolic expressions.

watchpoint = <x|w|rw|io> This classifies the probe as watchpoint type and also specifies the type of watchpoint probe. This statement can be present only in the kernel mode probe program files. When this statement is not present, probes are meant to be of breakpoint type. (Currently not implemented on S/390)

x: Watchpoint probes will be hit on instruction fetch from the address specified in ’address =’ statement. Here the valid address range is 1 byte.

w: Watchpoint probes will be hit if any write is made to the address range specified in ’address =’ statement. Valid address ranges are 1, 2 and 4 bytes.

rw: Watchpoint probes will be hit if any read or write occurs in the address range specified. Valid address ranges are 1, 2 and 4 bytes.

io: Watchpoint probes will be hit if any io read or write happens in the address range specified. Valid address ranges are 1, 2 and 4 bytes.

Probes won’t be applied if the address range specified is not consistent with the address range specified by the processor.

Note: If watchpoint probes are to be put on user address , the user address should be specified in a kernel mode probe program file. Also note that user mode watchpoints are global. i.e., the are active across all process contexts.

See Example 7 in COMPLETE EXAMPLES OF RPN for typical use of watchpoint probes.

opcode = <n>
For most architectures, <n> is the first byte of the opcode of the instruction present at the probe location. For S390, <n> is the first two bytes of the instruction, which may be the opcode, the opcode and part of the operands, or part of the opcode. At the time of inserting probes, the opcode present there is compared with the one specified here and the probe is applied only if they match. This is to ensure that the probe is actually being inserted in the intended location.

Opcode specification is mandatory only for breakpoint probes. For watchpoint probes, it may not be specified.

Note that only the first byte of the instruction on which a probe is desired is specified in this statement. If the instruction has a prefix, the prefix byte has to be specified here.

There are a few instructions on which probes cannot be placed. They are:

int3, int, into, wait (IA32, X86-64)

svc, lpsw (S/390)

and floating point instructions when FPU is emulated.

WARNING: The onus is on the user to correctly specify the offset and the opcode statements. Incorrect use may cause probes to be inserted in the middle of an instruction which could lead to a system crash and data corruption.

While Dprobes interoperates well with other debuggers, if a breakpoint is placed using another debugger at the same location where a probe already exists, the breakpoint will be ineffective.

Although probes on floating point instructions are not allowed, when the FPU is emulated, we are not explicitly disallowing probes on FXSAVE and FXSTOR instructions. Putting probes on these instructions when FPU is emulated might result in unexpected behavior.

group = <group_name>
This field classifies the probe-point under some specified group. The <group_name> specified here should be present in the <group_name> list present in the groupdef field of the probe program file header. The group field is used by the --apply-ppdf option on the command line to selectively apply the probes.

type = <type_name>
This field classifies the probe-point under some specified type. The <type_name> specified here should be present in the <type_name> list present in the typedef field of the probe program file header. The type field is used by the --apply-ppdf option on the command line to selectively apply the probes.

Note: See Example 6. in COMPLETE EXAMPLES OF RPN for usage of the keywords group, type, groupdef and typedef.

minor = <n>
<n> is the number to be assigned as the probe point minor code, The minor code can be used for easy identification of the log generated by this probe handler. Default value is 0.

ignore = <n>
If this entry is present, this probe handler will not be executed the first <n> times it is hit. Default value is 0. This instruction was called pass_count in dprobes versions before 3.4.0.

maxhits = <n>
This probe point will be disabled automatically after it is hit <n> times. Default value is 0x7fffffff. This instruction was called max_hits in dprobes versions before 3.4.0.

logonfault = <yes|no>
This keyword has the same meaning as the logonfault keyword present in the probe program file header, but here it specifies the ’log on fault’ behavior for this probe. Any settings by the use of logonfault keyword in probe program file header gets over-ridden here.

INSTRUCTION SET
Probe handler consists of any meaningful combination of valid RPN instructions. The general format of an instruction is:
[label:] operator [op1 [,op2 [, ..... ]]] [// comment]
[// comment]

label: optional string used to specify "jmp" targets. It has to start with a non-numeric character and delimited by a ’:’ and can consist of any alpha-numeric characters. An RPN instruction has to follow a label.

operator: any of the instructions listed below.

opN: any operands required for the instruction.

Note that TOS in the following description refers to the contents of the top of the stack on which RPN instructions operate.

The Instructions in this language are classified under various categories as follows:

RPN Execution Group:

jmp <label>
program control is transferred to <label>

jlt <label>
program control is transferred to <label> if TOS < 0.

jle <label>
program control is transferred to <label> if TOS <= 0.

jgt <label>
program control is transferred to <label> if TOS > 0.

jge <label>
program control is transferred to <label> if TOS >= 0.

jz <label>
program control is transferred to <label> if TOS == 0.

jnz <label>
program control is transferred to <label> if TOS != 0.

Loop <label>
Decrement TOS and jump to <label> if TOS != 0.

Note: If the total number of branches (jumps+loops) taken during one run of the probe handler exceeds the jmpmax value specified in the program file header, probe handler will generate a JMP_MAX exception or will terminate if this exception is masked.

call <procname>
Call the procedure <procname>. When a procedure is called, the return addresses are stored on the call stack, If the number of nested calls exceeds 32 at any point of time, a CALL_MAX exception is generated. If the exception is masked, the probe handling is terminated.

ret
Return from the procedure. The address to return to is the top of the call stack. If ret doesn’t have an associated call (can happen if ret is done with an empty call stack) a CALL_MAX exception is generated. If the exception is masked, the probe handling is terminated.

Format of Procedure:
A procedure can be written in the probe program file using the proc and endproc instructions. These procedures are accessible to all the probe handlers in this probe program file. Procedures defined in one probe program cannot be called from a different probe program. Note that, using the preprocessor directive #include <filename> one can write libraries of probe programs and include them in multiple probe program files.
The format of a procedure definition is:

proc <procname>
:
instructions
:
ret
endproc

callk
This instruction can be used to allow one or more kernel modules to be called from the RPN command interpreter. Modules registering for this will use the GKHI mechanism and will exist as hook_exits to DProbes. A sample kernel module that registers exits to be called when callk instruction is interpreted, callk.c, can be found in the command directory.

abort
Terminate the execution of the probe handler without saving the data logged so far.

exit
Terminate the execution of the probe handler, saving the data logged so far.

exit <n>
This facility is used to interface with other debug facilities. The debug facilities are invoked when this instruction is encountered in the probe handler. This instruction terminates the probe handler. The exit n instruction can be used when it is more appropriate to invoke the exit facilities when certain conditions are detected in the probe handler. The value of <n> can be any one of the following:

1 = SGI kdb
exit 1 invokes kdb only for kernel mode probes. For user mode probes it is equivalent to nop as user applications are not expected to use kernel debugger. When kdb is terminated, probe handler terminates. This instruction will be effective only if the kernel is configured with the kdb support.

2 = SGI crash dump
exit 3 takes the crash dump for only kernel mode probes. This instruction will be effective only if the kernel is configured with the crash dump support. Note that dump taken might not show the correct back trace.

3 = Core Dump
exit 3 dumps the core of the process which has probe in it. After core dump, the probe handler terminates. Also dumping the core of the process doesn’t cause the process to stop. This instruction is meaningful only in case of user probes.

Any other value of <n> will result in an INVALID_OPERAND exception being generated.

remove
Remove the current probe. This can be used to remove a probe from within the probe handler when certain conditions are detected that may render this probe unnecessary.

nop
No operation.

Logging Group

setmin <minor>
Override the minor code with <minor> when data for this probe point is logged to the log buffer.

setmin
Override the minor code with TOS when data for this probe point is logged to the log buffer.

setmaj <major>
Override the major code with <major> when data for this probe point is logged to the log buffer.

setmaj
Override the major code with TOS when data for this probe point is logged to the log buffer.

Note that the instructions to temporarily override major and minor codes are provided to enable users to easily identify of certain log records in the log buffer.

log str
It pops two elements from the RPN stack ( addr and n in that order). It logs the n number of bytes starting at the addr. Logging is discontinued if a NULL byte is encountered. The NULL byte is not logged. If the log buffer becomes full, the program interpreter will either generate a LOG_MAX exception, if this exception is unmasked, or will exit. In either case, the partial string is not logged.

If the log is successful, the logged string is prefixed by a token byte of 1 and a word indicating the length of the string logged. This data is intended to be used by any applications that may try to format the data collected in the log buffer.

If the logging fails due to an invalid memory reference, the fault record is logged. Then an INVALID_ADDR exception is generated if this exception is unmasked, or the probe handler is terminated if it is masked. The fault record consists of a token byte of -1(0xff), an unsigned short containing the length (4 or 8) of the faulting address, and the faulting address itself.

This instruction is intended to be used to log null-terminated strings at a known address to the log buffer. The length is only used to specify the upper limit on the string length. An example scenario would be (say we know that address of the string is in ECX)

push 256
push r, ecx
log str

log arf
This instruction has been renamed to log str in dprobes v3.4.0.

log ars
This instruction providing segmented addressing mode has been removed from dprobes v3.4.0.

log mrf
It pops two elements from the RPN stack ( addr and n in that order). It logs the n number of bytes starting at the addr. If the log is successful, the logged data is prefixed by a token byte of 0 and a word indicating the length of the data logged. This data is intended to be used by any applications that may try to format the data collected in the log buffer.

If the logging fails due to invalid memory reference, a fault record is logged and an INVALID_ADDR exception is generated. If this exception is masked, the probe handler is terminated. The fault record consists of a token byte of -1(0xff), an unsigned short containing the length (4 or 8) of the faulting address, and the faulting address itself.

This instruction is intended to be used to log any data structures at a known address to the log buffer. An example scenario to log, say, the first 40 bytes of the current task structure would be:

push 40
push task
log mrf

log mrs
This instruction providing segmented addressing mode has been removed from dprobes v3.4.0.

log <count>
Pops <count> number of elements from the RPN stack and stores them in the log buffer.

log b, <count>
log w, <count>
log d, <count>

These instructions have been replaced with the simpler log <count> instruction in dprobes v3.4.0.

Note that the above logging instructions will generate a LOG_OVERFLOW exception if the size of the log exceeds the size specified on the logmax= statement in the probe program file header. The exception is generated only if it is unmasked. The partial log is retained.

log
Pops count and logs count number of elements from RPN stack(by popping) to log buffer.

Note: With this instruction, the actual log is preceded by a 3-byte prefix having a token byte of 7 and a word indicating number of RPN elements logged. If logging fails due to log buffer overflow, a LOG_OVERFLOW exception is generated (only if this exception is unmasked). The partial log is retained.

Local Variable Group

The following instructions are provided to manipulate variables. Note that the local here means that the variables defined in a probe program are not accessible from other probe programs. However, variables defined in a probe program are accessible to all the probe handlers in that program, as mentioned before.

Variables are identified by their index. An index must be in the range 0 to n where n is the number specified on the vars= statement in the probe program file header. The instructions that manipulate local variables obtain the index of the variable to operate on either as an immediate operand in the instruction or from the RPN stack (in which case the value on the top of the stack is considered as the index). When index specified as an immediate operand, if its value is not the allowed range, then a compilation error will be returned when the probe program is being applied.

push lv, <index>
Push the content of the specified variable on to the RPN stack.

push lv
Pops an element ( index ) from the stack and pushes the content of the variable on to the RPN stack.

pop lv, <index>
Pop one element from the RPN stack and set it as the value of the specified variable.

pop lv
Pops two elements ( value , and index ) from the stack and sets the specified variable to value

move lv, <index>
Set the specified variable to TOS. Note that here the contents of the RPN stack remain unchanged.

move lv
Pops one element ( index ) from the stack and sets the specified variable to the current TOS.

inc lv, <index>
Increments the specified variable.

inc lv
Pops one element ( index ) from the stack and increments the specified variable.

dec lv, <index>
Decrements the specified variable.

dec lv
Pops one element ( index ) from the stack and decrements the specified variable.

log lv
Pops two elements (range and starting index in that order) and logs local variables starting from index=starting index till index=starting index+range to log buffer. The actual log is preceded by a 3-byte prefix having a token byte of 5 and a word indicating number of local variables logged. If the log buffer becomes full, a LOG_OVERFLOW exception is generated (only if this exception is unmasked) after logging as many variables as possible.

Note: For all the above instructions accessing local variables, an INVALID_OPERAND exception is generated if the index is exceeds the range specified by vars = statement in the file header. If this exception is masked, the probe handling is terminated.

Global Variable Group.

Global variables can be accessed across all the probe programs that are active. Probe programs are expected to use global variables in a cooperative manner. Variables are identified by their index. An index must be in the range 0 to n where n is the number specified on the gvars= statement in the probe program file header. The instructions that manipulate global variables obtain the index of the variable to operate on either as an immediate operand in the instruction or from the RPN stack (in which case the value on the top of the stack is considered as the index). When index specified as an immediate operand, if its value is not the allowed range, then a compilation error will be returned when the probe program is being applied.

push gv, <index>
Push the content of the specified variable on to the RPN stack.

push gv
Pops an element ( index ) from the stack and pushes the content of the variable on to the RPN stack.

pop gv, <index>
Pop one element from the RPN stack and set it as the value of the specified variable.

pop gv
Pops two elements ( value , and index ) from the stack and sets the specified variable to value

move gv, <index>
Set the specified variable to TOS. Note that here the contents of the RPN stack remain unchanged.

move gv
Pops one element ( index ) from the stack and sets the specified variable to the current TOS.

inc gv, <index>
Increments the specified variable.

inc gv
Pops one element ( index ) from the stack and increments the specified variable.

dec gv, <index>
Decrements the specified variable.

dec gv
Pops one element ( index ) from the stack and decrements the specified variable.

log gv
Pops two elements (range and starting index in that order) and logs global variables starting from index=starting index till index=starting index+range to log buffer. The actual log is preceded by a 3-byte prefix having a token byte of 6 and a word indicating number of global variables logged. If the log buffer becomes full, a LOG_OVERFLOW exception is generated (only if this exception is unmasked) after logging as many variables as possible.

Note: For all the above instructions accessing global variables, an INVALID_OPERAND exception is generated if the index is exceeds the range specified by gvars = statement in the file header. If this exception is masked, the probe handling is terminated.

Arithmetic & Logic Group

add
Pops two elements ( val1 and val2 ) from the stack and pushes the result of ( val1+val2 ) on to the stack.

sub
Pops two elements ( val1 and val2 ) from the stack and pushes the result of ( val1-val2 ) on to the stack.

mul
Pops two elements ( val1 and val2 ) from the stack and pushes the result of ( val1*val2 ) on to the stack.

div
Pops two elements ( divisor and dividend ) from the stack and performs an unsigned division (dividend/divisor). Pushes the remainder first and quotient next on to the stack.

idiv
Pops two elements ( divisor and dividend ) from the stack and performs a signed division (dividend/divisor). Pushes the remainder first and quotient next on to the stack.

Note: The division instructions generate DIVIDE_BY_ZERO exception if divisor is zero. If this exception is masked, the probe handling is terminated.

neg
Pops one element ( val ) from the stack and pushes its 1’s complement ( ~val ) on to the stack.

and
Pops two elements ( val1 and val2 ) from the stack and pushes the result of ( val1 & val2 ) on to the stack.

or
Pops two elements ( val1 and val2 ) from the stack and pushes the result of ( val1 | val2 ) on to the stack.

xor
Pops two elements ( val1 and val2 ) from the stack and pushes the result of ( val1 ^ val2 ) on to the stack(.

rol <count>
Rotates left TOS by (byte operand) number of bits.

rol
Pops two elements ( val and count ) from the stack, rotates left val by count number of bits and pushes the result on to the stack.

ror <count>
Rotates right TOS by (byte operand) number of bits.

ror
Pops two elements ( val and count ) from the stack, rotates right val by count number of bits and pushes the result on to the stack.

shl <count>
Shifts left TOS by (byte operand) number of bits.

shl
Pops two elements ( val and count ) from the stack, shifts left val by count number of bits and pushes the result on to the stack.

shr <count>
Shifts right TOS by (byte operand) number of bits.

shr
Pops two elements ( val and count ) from the stack, shifts right val by count number of bits and pushes the result on to the stack.

pbl
Pops two elements ( bit index n and operand ) from the stack, sets all the bits to the left of bit n-1 of the operand to the value of the bit n-1. Operand is pushed back to rpn stack.

pbl <n>
Pops one element ( operand ) from the stack, sets all the bits to the left of bit n-1 of the operand to the value of the bit n-1. Operand is pushed back to rpn stack.

pbr
Pops two elements ( bit index n and operand ) from the stack, sets all the bits to the right of bit n-1 of the operand to the value of the bit n-1. Operand is pushed back to rpn stack.

pbr <n>
Pops one element ( operand ) from the stack, sets all the bits to the right of bit n-1 of the operand to the value of the bit n-1. Operand is pushed back to rpn stack.

Note:
For all these propagate instructions, the valid value of bit index n ranges between 1 and rpn stack width. If the bit index n is 0 or greater than RPN stack width, an INVALID_OPERAND exception is generated. If this exception is masked, the probe handling is terminated.

xchg
Exchange the top two elements of the RPN stack.

dup <count>
The TOS will be pushed on to the stack <count> times.

dup
Pops two elements ( val and count ) from the stack and pushes the val on to the stack count+1 times.

ros <count>
Rotate the RPN stack down count number of times. This is equivalent to popping count elements from the stack.

Register Group

Inside the probe handler, access is provided to two different kinds of register contexts, the user context registers and current context registers. The current context registers refer to the state of the registers at the time of the probe hit. User context registers refer to the state of the registers in the current process context just before it switched to kernel mode. For probes in user space code, user and current context registers are same. In the following instructions, r indicates registers in the current context and u indicates registers in the user context. Please refer to Appendix A for names of the registers and which registers are valid in these contexts.

push r, <name>
Pushes the contents of the name register in the current context onto the stack.

push u, <name>
Pushes the contents of the name register in the user context onto the stack.

pop r, <name>
Pops an element ( value ) from the stack sets the contents of the name register in the current context to it.

pop u, <name>
Pops an element ( value ) from the stack sets the contents of the name register in the user context to it.

Writing to user and current context registers (code and stack segment, instruction pointer, stack pointer), or to control and debug registers, is not permitted. Also writing to gdtr, ldtr, tr, idtr is not permitted. Registers fs and gs are context independent. Processor registers are directly used when fs and gs are referenced.

WARNING Changing the contents of registers in the probe handlers is dangerous and can cause system crashes and data corruption. Use these features with caution and only when you know exactly what you are doing.

Data Group

push <value>
Pushes value onto the stack.

push b, <val>
push w, <val>
push d, <val>

These instructions have been replaced with the simpler push <value> instruction in dprobes v3.4.0.

push <symbol>
Allowed only for Kernel Symbols. Pushes the address of the symbol onto the stack.

push mem, u8
Pops one element ( addr ) from the stack and pushes a byte at addr onto the stack.

push mem, u16
Pops one element ( addr ) from the stack and pushes a 16-bit value at addr onto the stack.

push mem, u32
Pops one element ( addr ) from the stack and pushes a 32-bit value at addr onto the stack.

push mem, u64
Pops one element ( addr ) from the stack and pushes a 64 bit value at addr onto the stack.

pop mem, u8
Pops two elements ( val and addr ) from the stack and stores the least significant byte of val at addr

pop mem, u16
Pops two elements ( val and addr ) from the stack and stores the least significant 16bits of val at addr

pop mem, u32
Pops two elements ( val and addr ) from the stack and stores val at addr

pop mem, u64
Pops val and addr from the stack, and stores val at addr On 32-bit architectures, val comprises two stack elements.

push bif
push wif
push dif
push qif
pop bif
pop wif
pop dif
pop qif

All these instructions have been renamed in dprobes v3.4.0. So, now the equivalent of push bif is push mem, u8 pop wif is pop mem, u16

All these instructions providing segmented addressing mode have been removed in dprobes v3.4.0.

push bis
push wis
push dis
push qis
pop bis
pop wis
pop dis
pop qis

All these instructions providing segmented addressing mode have been removed in dprobes v3.4.0.

Note: The instructions which access memory will generate an INVALID_ADDR exception if the memory accessed is invalid or is currently paged out. If these exceptions are masked, the probe handling is terminated.

System Variable Group
The following instructions can be used to access details of the current process (like the pid) and relevant system data structures.

push pid
Pushes the pid of the current process onto the stack.

push procid
Pushes the id of the processor, on which the current process is executing, on to the stack.

push task Pushes the address of the current task (system variable current) onto the stack.

IO Group (IA32, X86-64)

The following instructions can be used to read and write to IO ports from the probe handlers.

push io, u8
Pops an element ( ioport ) from the stack, reads a byte from ioport and pushes it onto the stack.

push io, u16
Pops an element ( ioport ) from the stack, reads a 16-bit value from ioport and pushes it onto the stack.

push io, u32
Pops an element ( ioport ) from the stack, reads a 32-bit value from ioport and pushes it onto the stack.

pop io, u8
Pops val and ioport from the stack, writes the least significant byte of val to ioport

pop io, u16
Pops val and ioport from the stack, writes the least significant 16-bit value of val to ioport

pop io, u32
Pops val and ioport from the stack, writes the 32-bit value val to ioport

Address Verification

The following instructions can be used to verify the validity of an address before actually accessing it. If the given address is valid, a zero will be pushed onto the RPN stack. Otherwise, 1 will be pushed to indicate invalid address. Note that the execution of a probe handler can be terminated if it attempts to access any invalid address.

vfyr
Pops an element ( addr ) from the stack and verifies read access to a byte at addr

vfa
This instruction has been renamed to in dprobes v3.4.0.

vfyrw
Pops an element ( addr ) from the stack and verifies read-write access to a byte at addr

vsa
This instruction providing segmented addressing mode has been removed from dprobes v3.4.0.

Miscellaneous

seg2lin
Pops two elements ( offset and selector ) from the stack and converts the segmented address selector:offset into its equivalent flat address and pushes it onto the stack. This instruction generates a SEG_FAULT exception if the selector is invalid (IA32 only)

cnvrt sxf
This instruction has been renamed to seg2lin in dprobes v3.4.0.

cnvrt sxd
This instruction has been removed from dprobes v3.4.0.

PREPROCESSOR DIRECTIVES

The RPN Compiler works in two passes. In the first pass it does all the pre-processing for the conditional and unconditional directives and in the second pass it actually compiles the RPN files. All the conditional directives & macros can be specified in an RPN file in the same way as in C language.
The following types of directives are supported in an RPN file:

#define <variable> <value>

#include <RPN filename>

#ifdef <some-condn>

#elseif <other-condn>

#endif

SUBSTITUTION

The RPN compiler allows for substitution of variables from the command line as provided by the GNU C Compiler(gcc). With the -D option in the command line, the keys to be substituted by values can be specified as follows:

dprobes -i <rpn-file> -D key = value
where -

key is the string present in the RPN file and value is the value (string/numeral) to be substituted for key.

RPN EXCEPTION HANDLING AND STACK TRACING

Several RPN instructions generate faults during execution. RPN program interpreter throws exceptions when it encounters RPN instruction faults. Interpreter provides infrastructure/instructions for catching the exceptions, handling them, rethrowing the exceptions and propagating them up the call chain.

When the interpreter throws an exception, it puts the exception information on the RPN stack. The top of the RPN stack will look like this when an exception occurs:

Exception code identifies the type of exception. This depends on the type of RPN instruction fault. The width of the exception code is equal to the RPN stack width. For IA32, X86-64, and S/390, the exception code is of the form:

The u-field is for user use and does not affect the meaning of the exception to the interpreter when the exception is re-thrown. For a non-user exception, the u-field is initialized to zero. The x-field actually defines the exception.

The values indicated by parameter 1 and parameter 2 depends on the type of exception.

The following table gives a list of exceptions, associated parameter meanings and the type of fault causing the exception.

Masking/Unmasking Exceptions

Exceptions can be selectively masked/unmasked by using the probe header control statement excpt_mask. Masked exceptions are not generated. Presently only LOG_OVERFLOW and USER_EX are maskable exceptions. All others are non-maskable. By default excpt_mask is set to 0x0FFF so that these exceptions are masked. If a masked non-maskable exception occurs, probe handling will be terminated. Bits in excpt_mask corresponds to the bits in x-field of the exception code. An exception type can be masked by resetting it’s corresponding bit in excpt_mask.

Exception related instructions

sx <handler> / ux
This instruction pair sets an exception handler for any exceptions generated by the instructions that follow sx until the instruction ux. So if any exception is generated by an instruction lying between sx and ux, the control is transferred to the label handler Note that handler must be a label local to the current subroutine. If sx is not matched by a ux, the scope of the exception handler ends at the subroutine boundary.

push x
Pushes the last exception information (ex code, parm1, parm2) onto the exception stack. Note that the interpreter remembers the last exception that was generated. push x either pushes the last generated exception information, if there was any, or pushes NULL information(0, 0, 0).

rx
Raises an exception. Expects to find the exception information on the RPN stack. This instruction along with push x can be used to re-raise/ throw an exception.

Exception handling - some rules

1. Exceptions handlers cannot nest. That is if there are nested sx/ux pairs within a subroutine scope, only the innermost one will be effective.

2. A raised (generated) exception remains handled once a handler is called.

3. On raising an exception, the handler is implicitly reset. That is, a handler to catch an exception in a group of instructions will be effective only for the 1st exception generated by the group. The same handler will not be called for subsequent exceptions generated by the group.

4. Exceptions propagate up the call chain until a handler is found. That is, if an exception occurs in a sub-routine which has not set any exception handlers, the exception will automatically propagate up to the calling routine. During this, an implicit return is made to the calling routine.

If the exception is not handled anywhere till the outermost routine, the probe handling is terminated.

5. The program interpreter remembers the last generated exception.

STACK TRACING

Interpreter provides a stack trace buffer to store stack trace information. Stack trace buffer data is logged along with the dprobes log data using dprobes (major, minor) = (0,0) This data can be used to debug the rpn program.

The size of the stack trace buffer is governed by a file header control statement excpt_log. Default size of excpt_log is 1024 bytes.

Stack trace information can be filled up in two ways: implicitly when an exception is generated, or explicitly using the log st instruction.

log st
This instruction writes current stack trace information into the stack trace buffer.

purge st
This instruction clears (flushes) the stack trace buffer.

autostacktrace = [yes|no] This is a file header control statement. If set to yes stack trace information is collected whenever an exception is generated.

Stack trace information has the following format
header
stack trace records (with 3-byte prefix having
a token byte 2 and word
indicating the number
number of records)

The header consists of
name of the module (with 3-byte prefix having
a token byte 1 and word
indicating the length of
the string)
offset of the probe point
id of the probe point
major code
minor code

Stack trace records

Stack trace record contains information about the execution state of the probe point. It has the following format:
last exception code or 0
last exception handler address or -1
last exception parameter 1 or 0
last exception parameter 2 or 0
call stack frame records (with a 3-byte prefix
having a token byte of 3 and word
indicating the number of records)

The number of call stack frame records depends on the number of calls (nested) made at the time log st is executed (implicitly or explicitly)

Format of call stack frame record
called address
return address
RPN stack entries prefixed with 3-byte prefix
lv entries prefixed with 3-byte prefix
gv entries prefixed with 3-byte prefix

The 3-byte prefixes associated with RPN stack entries, lv entries and gv entries indicate the number of RPN stack entries, local variables and global variables logged and have token bytes of 4, 5 and 6 respectively.

Prior to the collection of stack trace information, interpreter needs to be told about the range of RPN stack, lv, and gv entries to be logged as part of stack trace. This is achieved by the following instructions.

trace pv
Pops two elements ( range and index ). If this call stack frame is logged as part of stack trace, the interpreter logs the RPN stack entries starting from the stack pointer index up to index + range. to the stack trace buffer.

trace lv
Pops two elements ( range and index ). If this call stack frame is logged as part of stack trace, the interpreter logs the local variables starting from index up to index + range to the stack trace buffer.

trace gv
Pops two elements ( range and index ). If this call stack frame is logged as part of stack trace, the interpreter logs the global variables starting from index up to index + range to the stack trace buffer.

If the interpreter is not told about the range and index (i.e., if the above instructions are not present in a call scope), it logs 0 number of RPN stack, lv and gv entries, while building the call stack frame record for this call scope. So if any subroutine wants the RPN stack, lv and gv entries to be logged as part of its call stack, it should code the above three instructions.

Interpreter provides Stack Trace Pointer register which will always point to the stack trace buffer from where the next log starts.

Instructions using interpreter internal registers.

push stp
Push(save) the value in stack trace pointer register to RPN stack.

pop stp
Pop (from the RPN stack) a value to stack trace pointer register.

push lp
Push(save) the value in log pointer register to RPN stack.

pop lp
Pop(from the RPN stack) a value to log pointer register.

push plp
Push the value in previous log pointer register to RPN stack.

save sbp
Push (save) the value of stack base pointer register to RPN stack.

restore sbp
Pop (from RPN stack) a value to stack base pointer register.

save tsp
Push (save) the value of top of the stack pointer register to RPN stack.

restore tsp
Pop (from RPN stack) a value to top of the stack pointer register.

push sbp
Pops an element ( n ) from RPN stack and pushes the stack element at sbp + n to the top of RPN stack. n can be negative also.

pop sbp
Pops two elements ( value and n ) from RPN stack and sets the contents of stack element at sbp + n to value. Note that n can be negative also.

copy sbp
Pops an element ( n ) and copies (without popping) the element at RPN TOS to the location pointed by sbp + n in the RPN stack. n can be negative.

push sbp, n
Pushes the RPN stack element at sbp + n to RPN TOS. n can be negative.

pop sbp, n
Pops an element from RPN stack and stores it in the RPN stack at the location pointed by sbp + n. Here n can be negative.

copy sbp, n
Copies (without popping) the element at RPN TOS to the location pointed by sbp + n in the RPN stack. n can be negative.

push tsp
Pops an element ( n ) from RPN stack and pushes the element at tsp + n to TOS. Here tsp refers to the value after n is popped. Here n can be negative.

pop tsp
Pops two elements ( value and n ) from RPN stack and stores the value at the location pointed by tsp + n in the RPN stack. Here tsp refers to the value after value and n are popped. Here n can be negative.

copy tsp
Pops and element ( n ) from RPN stack and copies the element at TOS (after popping n ) to the location pointed by tsp + n in the RPN stack. Here tsp refers to value after n is popped. Here n can be negative.

push tsp, n
Pushes the RPN stack element at tsp + n to RPN TOS. Here tsp refers to the stack location before the instruction executes. n can be negative.

pop tsp, n
Pops a RPN stack element and stores it at location pointed by tsp + n in the RPN stack. tsp refers to the stack location before the instruction executes. n can be negative.

copy tsp, n
Copies (without popping) the RPN stack element at TOS to the location pointed by tsp + n in the RPN stack. Here tsp refers to the stack location before the instruction is executed. n can be negative.

SAMPLE RPN FILES

The comments in RPN Language are specified by //.
The following examples illustrate common usage of the RPN commands:

1) Log EAX and EBX registers:

push r, eax

push u, ebx

log 2 // logs two elements from the top of stack

2) Log the values after exchanging the two elements on the stack:

push 0x02

push 0xff

xchg

log 2 // logs two elements after exchanging

3) Operations on a local variable (the var = keyword should be present in the RPN file header):

push 0xffffffff
pop lv, 0x0000
// pops the value on top of stack // into local variable
inc lv, 0x0000
// increments the local variable // at index 0x0000
dec lv, 0x0000
// decrements the local variable // at index 0x0000
push lv, 0x0000
// pushes the local variable on // the stack
log 1
// logs an element from the stack

4) Arithmetic operations:

push 0x02
push 0x04
add
log 1
// logs the result of addition // from top of stack

5) Logs the cpuid data after pushing it on to the stack :

push 0x0
push r, cpuid
log 4
// logs 4 elements containing the // cpuid

6) Example depicting the use of jumps and calls:

push 0xff
jnz down
exit
down: call proc1
exit
proc proc1
push 0x01
log 1
ret
endproc

COMPLETE EXAMPLES OF RPN

In the following examples offset and opcodes must be verified accordingly before running any of these on a Linux system.

1) This rpn program puts a probe on an user application.

name = appln //appln is the module on which //probe is put.
modtype = user
//appln is a user application.
major = 1
//major number.

offset = main //probe is on function main.
opcode = 0x55
//0x55 is the opcode present at offset.
minor = 2
//minor number.

push u, cs //push user context code segment register.
push u, ds
//push user context data segment register.
log 2
//log the two registers.
exit
//exit this probe handler.

Whenever the application appln is executed the probe is hit and the log shows the values of cs and ds.

2) This rpn file puts probe on kernel
name = vmlinux
//kernel probe
modtype = kernel
major = 2
//major point

offset = do_fork //probe on do_fork
opcode = 0x55
//opcode is 0x55
minor = 1
//minor point

push pid //push pid
push task
//push the address of the current //task_struct
log 2
//log the pid and task_struct
exit

Whenever fork occurs, this probe logs the pid and the address of the current task_struct.

2) Putting a probe on the network device driver and logging memory and register values.Traces the entry points to the various driver functions and logs the data.

// The module 3c59x (Ethernet module) is loaded at boot // time and for testing the probe, network services are // restarted.

#define func1 vortex_open

name = "/lib/modules/2.2.12-20/net/3c59x.o"
modtype = kmod
major = 0

offset = func1 // After preprocessing "func1" is // replaced by "vortex_open"
opcode = 0x55
minor = 0

push r, eip // push the address of the instruction // pointer
push mem, u16
// push the word found at the above address
log 1
// log the word
push r, eax
// also log the contents of the eax and ebx // registers
push r, ebx
log 2

offset = vortex_start_xmit
opcode = 0x55
minor = 1

push 0x10
push r, eip
log mrf
// logs 0x10 bytes from the address pushed.
exit

offset = vortex_close
opcode = 0x55
minor = 2
push 0x10
push r, eip
// logs 0x10 bytes from the address pushed
log mrf
#include "test.rpn"
// After preprocessing the "test.rpn" // file is copied in this RPN file.
exit

3) Monitor the number of calls to do_fork

name = vmlinux
modtype = kernel
major = 0
jmpmax = 15
vars = 3
// Shows that number of variables used in the // probe program is 3 (i.e. index is // from 0 to 2)

offset = do_fork
opcode = 0x55
minor = 0

inc lv, 0x01 // increments the local variable // at index 1
abort

4) Dump the system registers whenever swap_out function is called.

name = vmlinux
modtype = kernel
major = 0
ignore = 5
maxhits = 50

offset = swap_out
opcode = 0x55
minor = 1

push r, eax // dump the current registers
log 1
push r, ebx
log 1
push r, eip
log mrf
// log memory at the flat address pushed // previously
push u, eax
// dump the user context registers
log 1
push u, ebx
log 1

5) Putting probe on an interrupt handler "do_general_protection" by keeping some maxhits and logging some information.

name = vmlinux
modtype = kernel
major = 0
vars = 1
// index of the variable is 0

offset = do_general_protection
opcode = 0x55
minor = 0
maxhits = 10
// after getting hit for 10 times // the probe will be disabled
push r, cr0
// pushes cr0 on to the stack
push r, cr2
// push cr2
push r, cr3
// push cr3
push r, cr4
// push cr4
log 4
// log all control registers.
exit

6) Putting probes on the entry and exit points of some of the most frequently used functions in the kernel like do_fork, kmalloc and do_page_fault. This example makes use of the group and type keywords in the probe program file header and groupdef and typedef keywords in the RPN file header. This probe program can be used to selectively apply probes of same group and same type.

name = vmlinux
modtype = kernel
major = 1
groupdef = filesys memory process faults
// Valid groups
type = enter leave
// Valid types

offset = do_fork
opcode = 0x83
// Entry point of do_fork
minor = 0
group = process
// probe point group
type = enter
// probe point type
push r, esp
push r, ss
log 2
exit

offset = do_fork + 1987
opcode = 0xc3
// Exit point of the do_fork function
minor = 1
group = process
// probe point group
type = leave
// probe point type
push r, esp
push r, ss
log 2
exit

offset = kmalloc
opcode = 0x55
// First instruction in kmalloc().
minor = 2
group = memory
// probe point group
type = enter
// probe point type
maxhits = 100
push r, esp
push r, ss
log 2
exit

offset = kmalloc + 344
opcode = 0xc3
// Exit point of kmalloc().
minor = 4
group = memory
// probe point group
type = leave
maxhits = 100
push r, esp
push r, ss
log 2
exit

offset = ext2_file_write
opcode = 0x83
// Entry point of ext2_file_write
minor = 5
group = filesys
// probe point group
type = enter
// probe point type
maxhits = 100
push r, esp
push r, ss
log 2
exit

offset = ext2_file_write + 1583
opcode = 0xc3
// Entry point of ext2_file_write
minor = 6
group = filesys
// probe point group
type = leave
// probe point type
maxhits = 100
push r, esp
push r, ss
log 2
exit

offset = do_page_fault
opcode = 0x83
// Entry point of do_page_fault
minor = 7
group = faults
// probe point group
type = enter
// probe point type
maxhits = 100
push r, esp
push r, ss
log 2
exit

offset = do_page_fault + 813 // Exit point of do_page_fault
opcode = 0xc3
minor = 8
group = faults
// probe point group
type = leave
// probe point type
maxhits = 100
push r, esp
push r, ss
log 2
exit

The above RPN file can be built and applied in the following ways:
Let us call the RPN file example.rpn

dprobes --build-ppdf example.rpn -o example.ppdf

Generates ppdf file example.ppdf.

dprobes --apply-ppdf example.ppdf

Applies all the probes present in example.ppdf.

dprobes --apply-ppdf example.ppdf --group process --type enter

Applies probes belonging to the group process and type enter.

dprobes --apply-ppdf example.ppdf --group = filesys

Applies all probes belonging to the group filesys.

dprobes --apply-ppdf example.ppdf --type = leave

Applies all probes belonging to type leave.

dprobes --apply-ppdf example.ppdf --group process memory --type leave

Applies all probes belonging to group process, type leave and group memory, type leave.

7) Illustration of watchpoint probes

a) This examples puts probe on a kernel data symbol and watches it whenever a 4 byte write occurs to it.

name = vmlinux
modtype = kernel

address = nr_free_pages:nr_free_pages+3
watchpoint = w
maxhits = 100

push nr_free_pages
push dif
log 1
exit

b) This example shows how to watch a user space address.

name = vmlinux
modtype = kernel
// note that modtype is kernel.

address = 0x0804040c:0x0804040f // User data address
watchpoint = rw
// readwrite type of watchpoint
push u, eip
log 1
exit

APPENDIX A

List of user and current registers for X86-64 allowed/not allowed for push and pop operations.

y -- allowed, n -- not allowed.

Floating Point Registers

fr0 - fr7 Floating point data registers (Each register is 80bit wide, hence occupies > 1 rpn stack elements)

fcw Control register

fsw Status register

ftw Tag word register

fop Operand (data) pointer register

fip Instruction pointer register

fdp Data segment register

Streaming SIMD Extension (SSE) Registers

xmm0 - xmm15 SSE Floating Point Registers each 128 bits wide, occupying 2 rpn stack elements

mxcsr SSE Floating Point Control/Status Register 64 bits wide

APPENDIX B

List of user and current registers for INTEL allowed/not allowed for push and pop operations.

y -- allowed, n -- not allowed.

Floating Point Registers

fr0 - fr7 Floating point data registers (Each register is 80bit wide, hence occupies 2.5 rpn stack elements)

fcw Control register

fsw Status register

ftw Tag word register

fip Instruction pointer register

fcs Code segment register

fdp Data (operand) pointer register

fds Data segment register

Inserting probes on floating point instructions when the FPU is emulated is not allowed. If FPU is emulated, accessing FPU registers will give a default value of zero.

Streaming SIMD Extension (SSE) Registers

xmm0 - xmm7 SSE Floating Point Registers each 128 bits wide, occupying 4 rpn stack elements

mxcsr SSE Floating Point Control/Status Register 32 bits wide

APPENDIX C

List of user and current registers for S/390(32bit) and zSeries(64bit) Lallowed/not allowed for push and pop operations.

y -- allowed, n -- not allowed.

Inserting probes on floating point instructions when the FPU is emulated is not allowed. If FPU is emulated, accessing FPU registers will give a default value of zero.

FPR0-15 Floating Point Registers each 64 bits wide, occupying 2 rpn stack elements

FPC Floating Point Control Register 32 bits wide

APPENDIX D

List of user and current registers for ppc and ppc64 allowed/not allowed for push and pop operations.

y -- allowed, n -- not allowed.

APPENDIX E

Some methods to get the opcode present at any offset.

For any user executable, objdump with -D option can be used to obtain the complete disassembly of the executable. Disassembled code can then be used to obtain the opcode.

For example, the disassembled section of the function main of a user application looks like this:

080483d0 <main>: 80483d0: 55 pushl %ebp 80483d1: 89 e5 movl %esp,%ebp 80483d3: 83 ec 0c subl $0xc,%esp . . .

If probe has to be put on main then opcode is 0x55.

For S/390 code the method is the same, but the object code looks a bit different:

004007ac <main>: 4007ac: 90 af f0 28 stm %r10,%r15,40(%r15) 4007b0: a7 d5 00 0a bras %r13,4007c4 <main+0x18> . . .

If probe has to be put on main then the opcode for the probe definition is 0x90af (S/390 has to use two byte opcodes in the probe point definition).

The above method can also be used for kernel probes by disassembling and obtaining the opcode from vmlinux. Application debuggers or Kernel debuggers can also be used for the purpose.

AUTHOR

IBM Corporation

VERSION

DProbes version: 3.6.5
man page last modified on: 24 June 2004

LICENSE

Dynamic Probes is licensed under GNU General Public License version 2 or later.

Copyright (c) International Business Machines Corp., 2000