Skip to content

Commit b7f55c3

Browse files
committed
Add debug-intrinsics option to control translating llvm.dbg statements
Unfortunately, Clang can sometimes generate ill-scoped `llvm.dbg` statements (see #778), so this patch adds a `debug-intrinsics` option that controls whether `llvm.dbg` statements should be translated at all. The default value for `crux-llvm` is `no`, as `crux-llvm` does not yet make use of `llvm.dbg` information. We may wish to revisit this choice in the future should the upstream LLVM bug (https://bugs.llvm.org/show_bug.cgi?id=51155) be fixed. Fixes #778.
1 parent 36cbd02 commit b7f55c3

File tree

11 files changed

+69
-24
lines changed

11 files changed

+69
-24
lines changed

Diff for: crucible-llvm/src/Lang/Crucible/LLVM/Translation.hs

+6-5
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ buildRegTypeMap m0 bb = foldM stmt m0 (L.bbStmts bb)
187187

188188

189189
-- | Generate crucible code for each LLVM statement in turn.
190-
generateStmts :: (?laxArith :: Bool)
190+
generateStmts :: (?laxArith :: Bool, ?debugIntrinsics :: Bool)
191191
=> TypeRepr ret
192192
-> L.BlockLabel
193193
-> [L.Stmt]
@@ -308,7 +308,7 @@ findFile _ = Nothing
308308
-- | Lookup the block info for the given LLVM block and then define a new crucible block
309309
-- by translating the given LLVM statements.
310310
defineLLVMBlock
311-
:: (?laxArith :: Bool)
311+
:: (?laxArith :: Bool, ?debugIntrinsics :: Bool)
312312
=> TypeRepr ret
313313
-> Map L.BlockLabel (LLVMBlockInfo s)
314314
-> L.BasicBlock
@@ -326,7 +326,7 @@ defineLLVMBlock _ _ _ = fail "LLVM basic block has no label!"
326326
--
327327
-- This step introduces a new dummy entry point that simply jumps to the LLVM entry
328328
-- point. It is inconvenient to avoid doing this when using the Generator interface.
329-
genDefn :: (?laxArith :: Bool)
329+
genDefn :: (?laxArith :: Bool, ?debugIntrinsics :: Bool)
330330
=> L.Define
331331
-> TypeRepr ret
332332
-> LLVMGenerator s arch ret (Expr ext s ret)
@@ -357,7 +357,8 @@ genDefn defn retType =
357357
--
358358
-- | Translate a single LLVM function definition into a crucible CFG.
359359
transDefine :: forall arch wptr.
360-
(HasPtrWidth wptr, wptr ~ ArchWidth arch, ?laxArith :: Bool, ?optLoopMerge :: Bool)
360+
( HasPtrWidth wptr, wptr ~ ArchWidth arch
361+
, ?laxArith :: Bool, ?optLoopMerge :: Bool, ?debugIntrinsics :: Bool )
361362
=> HandleAllocator
362363
-> LLVMContext arch
363364
-> L.Define
@@ -386,7 +387,7 @@ transDefine halloc ctx d = do
386387
-- | Translate a module into Crucible control-flow graphs.
387388
-- Note: We may want to add a map from symbols to existing function handles
388389
-- if we want to support dynamic loading.
389-
translateModule :: (?laxArith :: Bool, ?optLoopMerge :: Bool)
390+
translateModule :: (?laxArith :: Bool, ?optLoopMerge :: Bool, ?debugIntrinsics :: Bool)
390391
=> HandleAllocator -- ^ Generator for nonces.
391392
-> GlobalVar Mem -- ^ Memory model to associate with this context
392393
-> L.Module -- ^ Module to translate

Diff for: crucible-llvm/src/Lang/Crucible/LLVM/Translation/Instruction.hs

+29-19
Original file line numberDiff line numberDiff line change
@@ -1362,7 +1362,7 @@ translateSelect instr _ _ _ _ _ _ =
13621362

13631363
-- | Do the heavy lifting of translating LLVM instructions to crucible code.
13641364
generateInstr :: forall s arch ret a.
1365-
(?laxArith :: Bool) =>
1365+
(?laxArith :: Bool, ?debugIntrinsics :: Bool) =>
13661366
TypeRepr ret {- ^ Type of the function return value -} ->
13671367
L.BlockLabel {- ^ The label of the current LLVM basic block -} ->
13681368
L.Instr {- ^ The instruction to translate -} ->
@@ -1811,7 +1811,8 @@ callFunction instr _tailCall fnTy _fn _args _assign_f =
18111811
-- | Generate a call to an LLVM function, with a continuation to fetch more
18121812
-- instructions.
18131813
callFunctionWithCont :: forall s arch ret a.
1814-
L.Instr {- ^ Source instruction o the call -} ->
1814+
(?debugIntrinsics :: Bool) =>
1815+
L.Instr {- ^ Source instruction o the call -} ->
18151816
Bool {- ^ Is the function a tail call? -} ->
18161817
L.Type {- ^ type of the function to call -} ->
18171818
L.Value {- ^ function value to call -} ->
@@ -1845,7 +1846,7 @@ callFunctionWithCont instr tailCall_ fnTy fn args assign_f k
18451846
extensionStmt (LLVM_Debug (LLVM_Dbg_Value repr val lv di)) >> k
18461847
_ -> k
18471848

1848-
-- Skip calls to debugging intrinsics. We might want to support these in some way
1849+
-- Skip calls to other debugging intrinsics. We might want to support these in some way
18491850
-- in the future. However, they take metadata values as arguments, which
18501851
-- would require some work to support.
18511852
| L.ValSymbol nm <- fn
@@ -1871,24 +1872,33 @@ callFunctionWithCont instr tailCall_ fnTy fn args assign_f k
18711872
| otherwise = callFunction (Just instr) tailCall_ fnTy fn args assign_f >> k
18721873

18731874
-- | Match the arguments used by @dbg.addr@, @dbg.declare@, and @dbg.value@.
1874-
dbgArgs ::
1875+
dbgArgs ::
1876+
(?debugIntrinsics :: Bool) =>
18751877
[L.Typed L.Value] {- ^ debug call arguments -} ->
18761878
LLVMGenerator s arch ret (Either String (LLVMExpr s arch, L.DILocalVariable, L.DIExpression))
1877-
dbgArgs args =
1878-
case args of
1879-
[valArg, lvArg, diArg] ->
1880-
case valArg of
1881-
L.Typed _ (L.ValMd (L.ValMdValue val)) ->
1882-
case lvArg of
1883-
L.Typed _ (L.ValMd (L.ValMdDebugInfo (L.DebugInfoLocalVariable lv))) ->
1884-
case diArg of
1885-
L.Typed _ (L.ValMd (L.ValMdDebugInfo (L.DebugInfoExpression di))) ->
1886-
do v <- transTypedValue val
1887-
pure (Right (v, lv, di))
1888-
_ -> pure (Left ("dbg: argument 3 expected DIExpression, got: " ++ show diArg))
1889-
_ -> pure (Left ("dbg: argument 2 expected local variable metadata, got: " ++ show lvArg))
1890-
_ -> pure (Left ("dbg: argument 1 expected value metadata, got: " ++ show valArg))
1891-
_ -> pure (Left ("dbg: expected 3 arguments, got: " ++ show (length args)))
1879+
dbgArgs args
1880+
| -- Why guard translating llvm.dbg statements behind its own option? It's
1881+
-- because Clang can sometimes generate llvm.dbg statements with improperly
1882+
-- scoped arguments—see https://bugs.llvm.org/show_bug.cgi?id=51155. This
1883+
-- wreaks all sorts of havoc on Crucible's later analyses, so one can work
1884+
-- around the issue by not translating the llvm.dbg statements at all.
1885+
?debugIntrinsics
1886+
= case args of
1887+
[valArg, lvArg, diArg] ->
1888+
case valArg of
1889+
L.Typed _ (L.ValMd (L.ValMdValue val)) ->
1890+
case lvArg of
1891+
L.Typed _ (L.ValMd (L.ValMdDebugInfo (L.DebugInfoLocalVariable lv))) ->
1892+
case diArg of
1893+
L.Typed _ (L.ValMd (L.ValMdDebugInfo (L.DebugInfoExpression di))) ->
1894+
do v <- transTypedValue val
1895+
pure (Right (v, lv, di))
1896+
_ -> pure (Left ("dbg: argument 3 expected DIExpression, got: " ++ show diArg))
1897+
_ -> pure (Left ("dbg: argument 2 expected local variable metadata, got: " ++ show lvArg))
1898+
_ -> pure (Left ("dbg: argument 1 expected value metadata, got: " ++ show valArg))
1899+
_ -> pure (Left ("dbg: expected 3 arguments, got: " ++ show (length args)))
1900+
| otherwise
1901+
= pure (Left ("Not translating llvm.dbg statement due to debugIntrinsics not being enabled"))
18921902

18931903
typedValueAsCrucibleValue ::
18941904
L.Typed L.Value ->

Diff for: crucible-llvm/test/MemSetup.hs

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ withLLVMCtx mod' action =
6262
sym <- CBS.newSimpleBackend CBS.FloatRealRepr nonceGen
6363
let ?laxArith = False
6464
let ?optLoopMerge = False
65+
let ?debugIntrinsics = False
6566
memVar <- LLVMM.mkMemVar "test_llvm_memory" halloc
6667
Some (LLVMTr.ModuleTranslation _ ctx _ _) <- LLVMTr.translateModule halloc memVar mod'
6768
case LLVMTr.llvmArch ctx of { LLVME.X86Repr width ->

Diff for: crucible-llvm/test/Tests.hs

+1
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ testBuildTranslation srcPath llvmTransTests =
222222
trans = do halloc <- newHandleAllocator
223223
let ?laxArith = False
224224
let ?optLoopMerge = False
225+
let ?debugIntrinsics = False
225226
memVar <- mkMemVar "buildTranslation_test_llvm_memory" halloc
226227
translateModule halloc memVar =<<
227228
(fromRight (error "parsing was already verified") <$> parseLLVM bcPath)

Diff for: crux-llvm/src/Crux/LLVM/Config.hs

+4
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ data LLVMOptions = LLVMOptions
7171
, noCompile :: Bool
7272
, optLevel :: Int
7373
, loopMerge :: Bool
74+
, debugIntrinsics :: Bool
7475
}
7576

7677
-- | The @c-src@ directory, which contains @crux-llvm@–specific files such as
@@ -161,6 +162,9 @@ llvmCruxConfig = do
161162
loopMerge <- Crux.section "opt-loop-merge" Crux.yesOrNoSpec False
162163
"Insert merge blocks in loops with early exits (i.e. breaks or returns). This may improve simulation performance."
163164

165+
debugIntrinsics <- Crux.section "debug-intrinsics" Crux.yesOrNoSpec False
166+
"Translate statements using certain llvm.dbg intrinsic functions."
167+
164168
return LLVMOptions { .. }
165169

166170
, Crux.cfgEnv =

Diff for: crux-llvm/src/Crux/LLVM/Simulate.hs

+1
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ prepLLVMModule llvmOpts halloc sym bcFile memVar = do
192192
llvmMod <- parseLLVM bcFile
193193
Some trans <- let ?laxArith = laxArithmetic llvmOpts
194194
?optLoopMerge = loopMerge llvmOpts
195+
?debugIntrinsics = debugIntrinsics llvmOpts
195196
in translateModule halloc memVar llvmMod
196197
mem <- let llvmCtxt = trans ^. transContext in
197198
let ?lc = llvmCtxt ^. llvmTypeCtx

Diff for: crux-llvm/test-data/golden/T778.c

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
unsigned int addflt(unsigned int a , unsigned int b )
2+
{
3+
unsigned int ma = a;
4+
unsigned int mb = b;
5+
int ea = (int)(a >> 24U) - 128;
6+
int eb = (int)(b >> 24U) - 128;
7+
unsigned int delta = ea - eb;
8+
9+
mb = mb >> delta;
10+
ma = ma + mb;
11+
12+
// This if statement seems critical
13+
if (ma) {
14+
ea = ea + 1;
15+
}
16+
17+
return ((unsigned int) ea);
18+
}
19+
20+
int main() {
21+
return 0;
22+
}

Diff for: crux-llvm/test-data/golden/T778.config

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-- We may wish to reconsider this choice if
2+
-- https://bugs.llvm.org/show_bug.cgi?id=51155 is fixed in the future.
3+
debug-intrinsics: no

Diff for: crux-llvm/test-data/golden/T778.good

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[Crux] Overall status: Valid.

Diff for: crux-llvm/test-data/golden/T778.result

Whitespace-only changes.

Diff for: uc-crux-llvm/src/UCCrux/LLVM/Main.hs

+1
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ translateLLVMModule ucOpts halloc memVar moduleFilePath llvmMod =
177177
Some trans <-
178178
let ?laxArith = laxArithmetic llvmOpts
179179
?optLoopMerge = loopMerge llvmOpts
180+
?debugIntrinsics = debugIntrinsics llvmOpts
180181
in translateModule halloc memVar llvmMod
181182
llvmPtrWidth
182183
(trans ^. transContext)

0 commit comments

Comments
 (0)