[T]utorial [A]bout

Understanding the source code

Every time you see something not clearly understandable, it means Panoramix failed to do it's job properly.

It has issues with loops and dynamic-length objects. Also, a bit, around displaying storage properly. Some of the code it produces may be outright wrong, and no amount of head-scratching will help you get it.


Mask(size, offset, value)
Means "take 'size' number of bits, 'offset' from the right".

Mask(8, 16, 0x123456) == 0x4.
Mask(255, 0, _param) == _param with a last bit set to 0
Mask(251, 5, _param) == _param modulo 32


CallData (cd[xxx])
Mask(32,0,cd[0]) == 4 bytes function identifier
cd[32+4], cd[64+4], cd[92+4]... == first, second and third... parameter

Dynamic length paremeters (strings, byte arrays) have a pointer as their parameter, so:
cd[cd[36]+4], or cd[_param1+4] mean "data at the place pointed by cd[36]/_param1"

Usually:
cd[_param+4] == _param.length
cd[_param+4+32+32*x] == _param[x]

cd[cd[_param+4+32+32*x]+4+32+32*y] == _param[x][y]

Obviously, a good decompiler would parse this correctly.


Storage
storX == obvious
storX[pos] == obvious

storX[pos].off == Mask(*, off, storageX[pos])
(* is described in storage definitions on top of the output)

You will see this when dealing with structs usually, e,.g.:
stor6[_id].0
stor6[_id].64
stor6[_id].192
stor6[_id].224
all refer to the same storage location (stor6[_id]), just different bit position.

Sometimes the code accesses the same location, but using different masks.
E.g.
stor6.0.uint256 = 0x123456
stor6.0.uint8 = 0xaa

After the two above calls: 0x1234aa == stor6.0.256

Yes, I know it's confusing, and not always perfect.

Another exercise here:
stor2.0.160 = addr(caller)
stor2.160.8 = bool(call.value>0)
After these two operations in stor2 there will be:
- the address of the caller (first 160 bits)
- either 0 or 1 depending on call.value (next 8 bits)
- the last 88 bits untouched


Memory
Whenever you see memory operations, it means Panoramix was uncertain as to what was going on in the code. Hopefully, the outputted function will make still some sense to you, but often it may not, and it may be completly incorrect.

Having said all that:
mem[var1 + (Mask(251, 0, stor8[addr(_owner)].0.251) << 5) + 256] = mem[var1 + 192]

means - "write to a memory" at position "var1" plus Mask(251, 0, stor8[_owner])*32 + 256 stuff from mem[var1 + 192].

Around 50% of the time spent working on Panoramix, I spent trying to make these memcalls disappear.