Ranjit Jhala Rupak Majumdar Bit-level Types for High-level Reasoning
The Problem Bit-level operators in low-level systems code Why ? –Interact with hardware –Reduce memory footprint mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte = (p & 0xFFFFF000)>> 12; b = tab[pte] & 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte = (p & 0xFFFFF000)>> 12; b = tab[pte] & 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; }
The Problem Bit-level operators in low-level systems code Inscrutable to humans, optimizers, verifiers mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte = (p & 0xFFFFF000)>> 12; b = tab[pte] & 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte = (p & 0xFFFFF000)>> 12; b = tab[pte] & 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; }
Whats going on ? mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } 32 p 31 1
Whats going on ? mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } 31 1 ppte
Whats going on ? mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } ppte tab[pte]
Whats going on ? mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } ppte b o 12 2
Whats going on ? mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } ppte 1220 b o 20 2
Q: How to infer complex information flow to understand, optimize, verify code ? mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (u32 p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } ppte 1220 b o 20 2
Plan Motivation Approach
Our approach: (1) Bit-level Types p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,12}{idx,20} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} Bit-level Types Sequences of {name,size} pairs
Our approach: (2) Translation p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,20}{idx,10} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } Expressions ! Records Bit-ops ! Field accesses if (p.rd == 0){
Our approach: (2) Translation p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,20}{idx,10} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } if (p.rd == 0){ Expressions ! Records Bit-ops ! Field accesses
mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } if (p.rd == 0){ Our approach: (2) Translation p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,20}{idx,10} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} pte.idx = p.idx; Expressions ! Records Bit-ops ! Field accesses
Our approach: (2) Translation p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,20}{idx,10} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } if (p.rd == 0){ pte.idx = p.idx; Expressions ! Records Bit-ops ! Field accesses
mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } if (p.rd == 0){ pte.idx = p.idx; Our approach: (2) Translation p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,20}{idx,10} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} b.addr = tab[pte.idx].addr; Expressions ! Records Bit-ops ! Field accesses
Our approach: (2) Translation p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,20}{idx,10} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } b.addr = tab[pte.idx].addr; if (p.rd == 0){ pte.idx = p.idx; Expressions ! Records Bit-ops ! Field accesses
mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } b.addr = tab[pte.idx].addr; if (p.rd == 0){ pte.idx = p.idx; Our approach: (2) Translation p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,20}{idx,10} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} o.addr = p.addr; Expressions ! Records Bit-ops ! Field accesses
Our approach: (2) Translation p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,20}{idx,10} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } o.addr = p.addr; b.addr = tab[pte.idx].addr; if (p.rd == 0){ pte.idx = p.idx; Expressions ! Records Bit-ops ! Field accesses
mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } o.addr = p.addr; b.addr = tab[pte.idx].addr; if (p.rd == 0){ pte.idx = p.idx; Our approach: (2) Translation p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,20}{idx,10} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} return m[b.addr + o.addr]; Expressions ! Records Bit-ops ! Field accesses
Our approach: (2) Translation p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,20}{idx,10} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } o.addr = p.addr; return m[b.addr + o.addr]; b.addr = tab[pte.idx].addr; if (p.rd == 0){ pte.idx = p.idx; Expressions ! Records Bit-ops ! Field accesses
Our approach mget(p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget(p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } Low-level operations eliminated bit-level types + translation o.addr = p.addr; return m[b.addr + o.addr]; b.addr = tab[pte.idx].addr; if (p.rd == 0){ pte.idx = p.idx; Program can be understood, optimized, verified
Plan Motivation Approach –Bit-level types + Translation Key: Bit-level type Inference Experiences Related work
Constraint-based Type Inference Algorithm: 0. Variables for unknowns 1. Generate constraints on vars 2. Solve constraints 2a = b – 10 b = Alice’s age: a Bob’s age: b = 22 = 54 Remember these: If Alice doubles her age, she would still be 10 years younger than Bob, who was born in How old are Alice and Bob ?
Constraint-based Type Inference Algorithm: 0. Variables for unknown bit-level types of all program expressions 1.Generate constraints on vars 2.Solve constraints
Plan Motivation Approach –Bit-level types + Translation Key: Bit-level type Inference –Constraint Generation –Constraint Solving Experiences Related work
Constraint Generation Type variables for each expression: p p p&0x1 p&0x1 pte pte mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; }
Generating Zero Constraints Mask: p&0xFFC [31:12] = ; p&0xFFC [1:0] = ; mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; }
Generating Zero Constraints 0 12 mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } Shift: e>>12 [31:20]= ; e is p&0xFFFFF
Why are zeros special ? Consider assignment (value flows e to x ) Should x and e have same bit-level type? x = e K K + Common idiom: k-bit values special case of k+ -bit values Equality results in unnecessary breaks Zeros enable precise subtyping subtypes( · ) · x e Inequality constraint x ¸ e
Generating Inequality Constraints Mask: p&0xFFC [11:2] ¸ p [11:2] mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; }
Shift: e>>12 [19:0] ¸ e [31:12] 0 12 Generating Inequality Constraints mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } e e>>12
Generating Inequality Constraints Assignment: o ¸ p&0xFFC that is… o [31:0] ¸ p&0xFFC [31:0] mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; }
Plan Motivation Approach –Bit-level types + Translation Key: Bit-level type Inference –Constraint Generation –Constraint Solving Experiences Related work
Constraint Solutions Solution is an assignment A: type variables ! bit-level types A( )[i:j] = subsequence of A( ) from bit i through j p ) = {idx,20}{addr,10}{wr,1}{rd,1} A( p )[12:1] = {addr,10} {wr,1} A( p )[31:2] = {idx,20} {addr,10} A( p )[31:5] = undefined
Constraint Solving Overview Solution is an assignment A: type variables ! bit-level types A( [i:j]) = subsequence from bit i through j A satisfies: zero Constraint : [i:j] = ; –If A( )[i:j] = ; i-j+1 inequality Constraint: [i:j] · ’[i’:j’] –If A( )[i:j] · A( ’)[i’:j’] In both cases, A( )[i:j] must be defined
Constraint Solving Algorithm Input:Zero constraints {z_1,…,z_m} Inequality constraints{c 1,…,c n } Output:Assignment satisfying all constraints A = A 0 for i in [1…n]: A = refine(A,c i ) return A A 0 = Initial asgn satisfying zero constraints (details in paper) refine(A,c i ) adjusts A such that: c i becomes satisfied earlier constraints stay satisfied built using Split, Unify
Refine: Split(A, ,k) f,12 A( ) p,32 12 A’( ) A’ = Split(A, , 12 ) Throughout A, substitute: p,12 + 12 f,12 e, where e, f are fresh e,20 p,12- f,12- and substitute:
Refine: Split(A, ,k) Used to ensure A( )[i:j] is defined 2 f,12 g,10 A( ) p, A’( ) A’’( ) e,20 h,2 e,20 A’ = Split(A, , 12 ) Ensure A( [ 11:2 ] is defined A’’ = Split(A’, , 2 ) 11 2 A’’( [ 11:2 ] defined
Refine: Unify(A,p,q) p, q, Throughout A, substitute:
Refine(A, [31:12] · ’[19:0]) r :12 A( ’) p : 32 A( ) ; :10q :10 A( ’)[19:0] undefined A’ = Split(A, ’,19+1) A’’ = Unify(A’,q,t) r : 12 A’( ’) t : 20 A’( ) ; :10q :10 s : r : 12 A’’( ’) t : 32 A’’( ) ; :10t :10 A’’ satisfies constraint t : A’( ’)[19:0] A’( )[31:12] ·
Constraint Solving Input:Constraints Output:Assignment satisfying all constraints A = A 0 for i in [1…n]: A = refine(A,c i ) return A Substitution (in Split, Unify) ensures earlier constraints stay satisfied most general solution found Efficiently implemented using graphs
Plan Motivation Approach –Bit-level types + Translation Key: Bit-level type Inference –Constraint Generation –Constraint Solving Experiences Related work
Experiences Implemented bit-level type inference for C pmap: a kernel virtual memory system Implements the code for our running example mondrian: a memory protection system scull: a linux device driver (1-3 Kloc) Inference/Translation takes less than 1s
Mondrian [Witchel et. al.] Bit packing for memory and permission bits –2600 lines of code, generated 775 constraints –Translated to program without bit-operations –18 different bit-packed structures 10 assertions provided by programmer –After translation, assertions verified using BLAST –6 safe: all require bit-level reasoning Previously, verification was not possible –4 false positives: imprecise modeling of arrays
Cop outs (i.e. Future Work) 1.Truly binary bit-vector operations –x << y, x && y –Currently: Value-flow analysis to infer constants flowing to y Break into a switch statement 2.Flow-sensitivity Currently: SSA renaming 3.Arithmetic overflow does a k-bit value “spill over” Currently: Assume no overflow 4.Path-sensitivity (value dependent types) Type of suffix depends on value of first field e.g. Instruction decoder for architecture simulator Number/type of operands depends on opcode
Plan Motivation Approach –Bit-level types + Translation Key: Bit-level type Inference –Constraint Generation –Constraint Solving Experiences Related work
Related Work O Callahan – Jackson [ICSE 97] –Type Inference Gupta et. al. [POPL 03, CC02] –Dataflow analyses for packing bit-sections Ramalingam et. al. [POPL 99] –Aggregate structure inference for COBOL
Conclusions (Automatic) reasoning about Bit-operations hard Structure: bit-operations pack data into one word Structure Inferred via Bit-level Type Inference Structure Exploited via Translation to fields Precise, efficient reasoning about Bit-operations
Thank you
Previous approaches model bitwise ops by: 1.Uninterpreted functions Imprecise 2.Logical axioms Inefficient 3.Bit-blasting terms into 32/64-bits Lose high-level relationships Q: How to infer complex information flow to understand, optimize, verify code ?
Refine Two basic operations: split, unify Split(A, ,[i:j]): ensures A( )[i:j] is defined 2 f : 12 g : 10 A( ) p : A’( ) A’’( ) e : 20h:2 Split(A, , [11:2] ) A’ = in A, substitute: p : +(11+1) 11+1 f : 11+1 e : where e, f are fresh e : 20 A’’ = in A’, substitute: f : +2 h : 2 g : where g,h are fresh 2
Generating Zero Constraints Mask: All but 1 st bit are zero p&0x1 [31:1] = ; mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } 0 31
Our approach: (2) Translation p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,20}{idx,10} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } Expressions ! Records Bit-ops ! Field accesses if (p.rd == 0){ pte.idx = p.idx; b.addr = tab[pte.idx].addr; o.addr = p.addr; return m[o.addr + p.addr];
Our approach: (2) Translation p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,20}{idx,10} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } Expressions ! Records Bit-ops ! Field accesses if (p.rd == 0){
Our approach: (2) Translation p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,20}{idx,10} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } Expressions ! Records Bit-ops ! Field accesses if (p.rd == 0){ pte.idx = p.idx; b.addr = tab[pte.idx].addr; o.addr = p.addr; return m[o.addr + p.addr];
Our approach: (2) Translation p pte 1220 b o 20 2 p : {idx,20}{addr,10}{wr,1}{rd,1} pte : { ;,20}{idx,10} b : {addr,30}{ ;,2} o : { ;,20}{addr,10}{ ;,2} mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } mget (p) { if (p & 0x1 == 0){ error(“permission”); } pte =(p & 0xFFFFF000)>>12; b = tab[pte]& 0xFFFFFFFC; o = p & 0xFFC; return m[(b+o)>>2]; } Expressions ! Records Bit-ops ! Field accesses if (p.rd == 0){ pte.idx = p.idx; b.addr = tab[pte.idx].addr; o.addr = p.addr; return m[o.addr + p.addr];
Constraint Solutions Solution is an assignment A: variables ! bit-level types A( )[i:j] = subsequence of A( ) from bit i through j p ) = {idx,20}{addr,10}{wr,1}{rd,1} A( p )[12:1] = {addr,10} {wr,1} A( p )[31:2] = {idx,20} {addr,10} A( p )[31:5] = undefined
Ranjit Jhala Rupak Majumdar Bit-level Types for High-level Reasoning via