Pátek IX 12, 2008

DTrace: Insufficient registers to generate code

Recently during a development of a DTrace script I hit a strange dtrace error. The intent was to trace TCP packets flow at different levels in IP stack, dumping sequence and acknowledge numbers. It started as a small script and I continued adding more and more lines until next attempt to run the script failed with a strange error message I have never seen before. The error message was:

dtrace: failed to compile script ./tcp.d: Insufficient registers to generate code

I didn't want to spend much time as I suspected I did some common mistake, which was already hit by many people before. Unfortunately not. According to google search engine, it's not a common mistake and it wasn't hit by many people before. It motivated me to post a blog to make life easier for the next one. First I thought that my script exceeded number of allowed self variables, but commenting out assignments to new self variables had no effect. I've started to go backwards by removing last changes from the script, until I got back to the point where the script compiled fine. It showed that the line, which caused the compilation problem contained quite complex expression, which used several memory dereferences. The aim of faulty macro was to read memory, not necessarily aligned, in network byte order. Reading 16 bits was fine, while reading 32 bits by reassembling the value from 4 bytes broke the compilation. The workaround was to split memory operation to several statements (macro READ_DWORD), rather than having all memory dereferences in one expression (macro DWORD). The examples follows. They do no real work, only demonstrate.

Broken example:

#define WORD(_x_) (((uint8_t \*)(_x_))[0] \* 256 + ((uint8_t \*)(_x_))[1])
#define DWORD(_x_) WORD(_x_) \* 65536 + WORD((uint8_t \*)(_x_) + 2)

BEGIN {
         x = &`utsname;
         result = DWORD(x);
         trace(result);
}

# dtrace -C -s /tmp/broken.d 
dtrace: failed to compile script /tmp/broken.d: Insufficient registers to generate code

Version which compiles:

#define WORD(_x_) (((uint8_t \*)(_x_))[0] \* 256 + ((uint8_t \*)(_x_))[1])
#define READ_DWORD(_x_, _dest_) _dest_ = WORD(_x_) << 16; \\
     _dest_ += WORD((uint8_t \*)(_x_) + 2);

BEGIN {
         x = &`utsname;
         READ_DWORD(x, result);
         trace(result);
}

# dtrace -C -s /tmp/good.d   
dtrace: script '/tmp/good.d' matched 1 probe
CPU     ID                    FUNCTION:NAME
  0      1                           :BEGIN  1400204879

About

vita78

Search

Categories
Archives
« duben 2014
PoÚtStČtSoNe
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Today