[llvm] r317050 - Parse DWARF information to reduce false positives.

Mitch Phillips via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 31 16:20:05 PDT 2017


Author: hctim
Date: Tue Oct 31 16:20:05 2017
New Revision: 317050

URL: http://llvm.org/viewvc/llvm-project?rev=317050&view=rev
Log:
Parse DWARF information to reduce false positives.

Summary: Help differentiate code and data by parsing DWARF information. This will reduce false positive rates where data is placed in executable sections and is mistakenly parsed as code, resulting in an inflation in the number of indirect CF instructions (and hence an inflation of the number of unprotected).

Also prints the DWARF line data around the region of each indirect CF instruction.

Reviewers: pcc

Subscribers: probinson, llvm-commits, vlad.tsyrklevich, mgorny, aprantl, kcc

Differential Revision: https://reviews.llvm.org/D38654

Added:
    llvm/trunk/test/tools/llvm-cfi-verify/
    llvm/trunk/test/tools/llvm-cfi-verify/X86/
    llvm/trunk/test/tools/llvm-cfi-verify/X86/indirect-cf-elimination.s
    llvm/trunk/test/tools/llvm-cfi-verify/X86/lit.local.cfg
    llvm/trunk/test/tools/llvm-cfi-verify/X86/protected-lineinfo.s
    llvm/trunk/test/tools/llvm-cfi-verify/X86/unprotected-lineinfo.s
    llvm/trunk/test/tools/llvm-cfi-verify/X86/unprotected-nolineinfo.s
Modified:
    llvm/trunk/tools/llvm-cfi-verify/CMakeLists.txt
    llvm/trunk/tools/llvm-cfi-verify/LLVMBuild.txt
    llvm/trunk/tools/llvm-cfi-verify/lib/CMakeLists.txt
    llvm/trunk/tools/llvm-cfi-verify/lib/FileAnalysis.cpp
    llvm/trunk/tools/llvm-cfi-verify/lib/FileAnalysis.h
    llvm/trunk/tools/llvm-cfi-verify/lib/GraphBuilder.cpp
    llvm/trunk/tools/llvm-cfi-verify/lib/LLVMBuild.txt
    llvm/trunk/tools/llvm-cfi-verify/llvm-cfi-verify.cpp

Added: llvm/trunk/test/tools/llvm-cfi-verify/X86/indirect-cf-elimination.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cfi-verify/X86/indirect-cf-elimination.s?rev=317050&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cfi-verify/X86/indirect-cf-elimination.s (added)
+++ llvm/trunk/test/tools/llvm-cfi-verify/X86/indirect-cf-elimination.s Tue Oct 31 16:20:05 2017
@@ -0,0 +1,206 @@
+# RUN: llvm-mc %s -filetype obj -triple x86_64-linux-elf -o %t.o
+# RUN: llvm-cfi-verify %t.o 2>&1 | FileCheck %s
+
+# This is the same file as protected-lineinfo.s, however contains a hand-
+# assembled function (fake_function) that has no line table information
+# associated with it. Because there is no LT info, the indirect call made in the
+# function should not be reported at all by llvm-cfi-verify.
+
+# We can test that this indirect call is ignored from the final statistics
+# reporting of the cfi-verify program. It should only find a single indirect CF
+# instruction at `tiny.cc:11` (see protected-lineinfo.s for the source).
+
+# CHECK: Unprotected: 0 (0.00%), Protected: 1 (100.00%)
+
+  .text
+  .file "ld-temp.o"
+  .p2align  4, 0x90
+  .type fake_function, at function
+fake_function:
+  nop
+  nop
+  nop
+  nop
+  callq *%rax
+  nop
+  nop
+  nop
+  nop
+  .type _Z1av.cfi, at function
+_Z1av.cfi:
+.Lfunc_begin0:
+  .file 1 "tiny.cc"
+  .loc  1 3 0
+  .cfi_startproc
+  pushq %rbp
+  .cfi_def_cfa_offset 16
+  .cfi_offset %rbp, -16
+  movq  %rsp, %rbp
+  .cfi_def_cfa_register %rbp
+.Ltmp0:
+  .loc  1 3 11 prologue_end
+  popq  %rbp
+  retq
+.Ltmp1:
+.Lfunc_end0:
+  .size _Z1av.cfi, .Lfunc_end0-_Z1av.cfi
+  .cfi_endproc
+
+  .p2align  4, 0x90
+  .type _Z1bv.cfi, at function
+_Z1bv.cfi:
+.Lfunc_begin1:
+  .loc  1 4 0
+  .cfi_startproc
+  pushq %rbp
+  .cfi_def_cfa_offset 16
+  .cfi_offset %rbp, -16
+  movq  %rsp, %rbp
+  .cfi_def_cfa_register %rbp
+.Ltmp2:
+  .loc  1 4 11 prologue_end
+  popq  %rbp
+  retq
+.Ltmp3:
+.Lfunc_end1:
+  .size _Z1bv.cfi, .Lfunc_end1-_Z1bv.cfi
+  .cfi_endproc
+
+  .hidden main
+  .globl  main
+  .p2align  4, 0x90
+  .type main, at function
+main:
+.Lfunc_begin2:
+  .loc  1 6 0
+  .cfi_startproc
+  pushq %rbp
+  .cfi_def_cfa_offset 16
+  .cfi_offset %rbp, -16
+  movq  %rsp, %rbp
+  .cfi_def_cfa_register %rbp
+  subq  $32, %rsp
+  movb  $32, -1(%rbp)
+  movl  $0, -12(%rbp)
+  movl  %edi, -8(%rbp)
+  movq  %rsi, -32(%rbp)
+.Ltmp4:
+  .loc  1 8 12 prologue_end
+  cmpl  $1, -8(%rbp)
+  .loc  1 8 7 is_stmt 0
+  jne .LBB2_2
+  .loc  1 0 7
+  leaq  _Z1av(%rip), %rax
+  .loc  1 9 9 is_stmt 1
+  movq  %rax, -24(%rbp)
+  .loc  1 9 5 is_stmt 0
+  jmp .LBB2_3
+.LBB2_2:
+  .loc  1 0 5
+  leaq  _Z1bv(%rip), %rax
+  .loc  1 11 9 is_stmt 1
+  movq  %rax, -24(%rbp)
+.LBB2_3:
+  .loc  1 0 9 is_stmt 0
+  leaq  .L.cfi.jumptable(%rip), %rcx
+  .loc  1 13 3 is_stmt 1
+  movq  -24(%rbp), %rax
+  movq  %rax, %rdx
+  subq  %rcx, %rdx
+  movq  %rdx, %rcx
+  shrq  $3, %rcx
+  shlq  $61, %rdx
+  orq %rcx, %rdx
+  cmpq  $1, %rdx
+  jbe .LBB2_5
+  ud2
+.LBB2_5:
+  callq *%rax
+  .loc  1 14 11
+  movb  $-1, -1(%rbp)
+  .loc  1 15 1
+  movl  -12(%rbp), %eax
+  addq  $32, %rsp
+  popq  %rbp
+  retq
+.Ltmp5:
+.Lfunc_end2:
+  .size main, .Lfunc_end2-main
+  .cfi_endproc
+
+  .p2align  3, 0x90
+  .type .L.cfi.jumptable, at function
+.L.cfi.jumptable:
+.Lfunc_begin3:
+  .cfi_startproc
+  #APP
+  jmp _Z1av.cfi at PLT
+  int3
+  int3
+  int3
+  jmp _Z1bv.cfi at PLT
+  int3
+  int3
+  int3
+
+  #NO_APP
+.Lfunc_end3:
+  .size .L.cfi.jumptable, .Lfunc_end3-.L.cfi.jumptable
+  .cfi_endproc
+
+  .section  .debug_str,"MS", at progbits,1
+.Linfo_string0:
+  .asciz  "clang version 6.0.0 (trunk 316774)"
+.Linfo_string1:
+  .asciz  "tiny.cc"
+.Linfo_string2:
+  .asciz  "/tmp/a/b"
+  .section  .debug_abbrev,"", at progbits
+  .byte 1
+  .byte 17
+  .byte 0
+  .byte 37
+  .byte 14
+  .byte 19
+  .byte 5
+  .byte 3
+  .byte 14
+  .byte 16
+  .byte 23
+  .byte 27
+  .byte 14
+  .byte 17
+  .byte 1
+  .byte 18
+  .byte 6
+  .byte 0
+  .byte 0
+  .byte 0
+  .section  .debug_info,"", at progbits
+.Lcu_begin0:
+  .long 38
+  .short  4
+  .long .debug_abbrev
+  .byte 8
+  .byte 1
+  .long .Linfo_string0
+  .short  4
+  .long .Linfo_string1
+  .long .Lline_table_start0
+  .long .Linfo_string2
+  .quad .Lfunc_begin0
+  .long .Lfunc_end2-.Lfunc_begin0
+  .section  .debug_ranges,"", at progbits
+  .section  .debug_macinfo,"", at progbits
+.Lcu_macro_begin0:
+  .byte 0
+
+  .type _Z1av, at function
+_Z1av = .L.cfi.jumptable
+  .type _Z1bv, at function
+_Z1bv = .L.cfi.jumptable+8
+  .ident  "clang version 6.0.0 (trunk 316774)"
+  .section  ".note.GNU-stack","", at progbits
+  .section  .debug_line,"", at progbits
+.Lline_table_start0:
+

Added: llvm/trunk/test/tools/llvm-cfi-verify/X86/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cfi-verify/X86/lit.local.cfg?rev=317050&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cfi-verify/X86/lit.local.cfg (added)
+++ llvm/trunk/test/tools/llvm-cfi-verify/X86/lit.local.cfg Tue Oct 31 16:20:05 2017
@@ -0,0 +1,2 @@
+if not 'X86' in config.root.targets:
+    config.unsupported = True

Added: llvm/trunk/test/tools/llvm-cfi-verify/X86/protected-lineinfo.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cfi-verify/X86/protected-lineinfo.s?rev=317050&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cfi-verify/X86/protected-lineinfo.s (added)
+++ llvm/trunk/test/tools/llvm-cfi-verify/X86/protected-lineinfo.s Tue Oct 31 16:20:05 2017
@@ -0,0 +1,203 @@
+# RUN: llvm-mc %s -filetype obj -triple x86_64-linux-elf -o %t.o
+# RUN: llvm-cfi-verify %t.o | FileCheck %s
+
+# CHECK-LABEL: P
+# CHECK-NEXT: tiny.cc:11
+
+# CHECK: Unprotected: 0 (0.00%), Protected: 1 (100.00%)
+
+# Source (tiny.cc):
+#   void a() {}
+#   void b() {}
+#   int main(int argc, char** argv) {
+#     void(*ptr)();
+#     if (argc == 1)
+#       ptr = &a;
+#     else
+#       ptr = &b;
+#     ptr();
+#   }
+# Compile with (output is in tiny.s.0):
+#    clang++ -flto -fsanitize=cfi -fvisibility=hidden -c tiny.cc -o tiny.o -gmlt
+#    clang++ tiny.o -o tiny -flto -fuse-ld=gold -Wl,-plugin-opt,save-temps
+#    clang++ -fsanitize=cfi -flto -fvisibility=hidden -c tiny.cc -o tiny.o -gmlt
+#    llvm-lto2 run @tiny.resolution.txt -o tiny.s -filetype=asm
+
+  .text
+  .file "ld-temp.o"
+  .p2align  4, 0x90
+  .type _Z1av.cfi, at function
+_Z1av.cfi:
+.Lfunc_begin0:
+  .file 1 "tiny.cc"
+  .loc  1 1 0
+  .cfi_startproc
+  pushq %rbp
+  .cfi_def_cfa_offset 16
+  .cfi_offset %rbp, -16
+  movq  %rsp, %rbp
+  .cfi_def_cfa_register %rbp
+.Ltmp0:
+  .loc  1 1 11 prologue_end
+  popq  %rbp
+  retq
+.Ltmp1:
+.Lfunc_end0:
+  .size _Z1av.cfi, .Lfunc_end0-_Z1av.cfi
+  .cfi_endproc
+
+  .p2align  4, 0x90
+  .type _Z1bv.cfi, at function
+_Z1bv.cfi:
+.Lfunc_begin1:
+  .loc  1 2 0
+  .cfi_startproc
+  pushq %rbp
+  .cfi_def_cfa_offset 16
+  .cfi_offset %rbp, -16
+  movq  %rsp, %rbp
+  .cfi_def_cfa_register %rbp
+.Ltmp2:
+  .loc  1 2 11 prologue_end
+  popq  %rbp
+  retq
+.Ltmp3:
+.Lfunc_end1:
+  .size _Z1bv.cfi, .Lfunc_end1-_Z1bv.cfi
+  .cfi_endproc
+
+  .hidden main
+  .globl  main
+  .p2align  4, 0x90
+  .type main, at function
+main:
+.Lfunc_begin2:
+  .loc  1 4 0
+  .cfi_startproc
+  pushq %rbp
+  .cfi_def_cfa_offset 16
+  .cfi_offset %rbp, -16
+  movq  %rsp, %rbp
+  .cfi_def_cfa_register %rbp
+  subq  $32, %rsp
+  movl  $0, -8(%rbp)
+  movl  %edi, -4(%rbp)
+  movq  %rsi, -24(%rbp)
+.Ltmp4:
+  .loc  1 6 12 prologue_end
+  cmpl  $1, -4(%rbp)
+  .loc  1 6 7 is_stmt 0
+  jne .LBB2_2
+  .loc  1 0 7
+  leaq  _Z1av(%rip), %rax
+  .loc  1 7 9 is_stmt 1
+  movq  %rax, -16(%rbp)
+  .loc  1 7 5 is_stmt 0
+  jmp .LBB2_3
+.LBB2_2:
+  .loc  1 0 5
+  leaq  _Z1bv(%rip), %rax
+  .loc  1 9 9 is_stmt 1
+  movq  %rax, -16(%rbp)
+.LBB2_3:
+  .loc  1 0 9 is_stmt 0
+  leaq  .L.cfi.jumptable(%rip), %rcx
+  .loc  1 11 3 is_stmt 1
+  movq  -16(%rbp), %rax
+  movq  %rax, %rdx
+  subq  %rcx, %rdx
+  movq  %rdx, %rcx
+  shrq  $3, %rcx
+  shlq  $61, %rdx
+  orq %rcx, %rdx
+  cmpq  $1, %rdx
+  jbe .LBB2_5
+  ud2
+.LBB2_5:
+  callq *%rax
+  .loc  1 12 1
+  movl  -8(%rbp), %eax
+  addq  $32, %rsp
+  popq  %rbp
+  retq
+.Ltmp5:
+.Lfunc_end2:
+  .size main, .Lfunc_end2-main
+  .cfi_endproc
+
+  .p2align  3, 0x90
+  .type .L.cfi.jumptable, at function
+.L.cfi.jumptable:
+.Lfunc_begin3:
+  .cfi_startproc
+  #APP
+  jmp _Z1av.cfi at PLT
+  int3
+  int3
+  int3
+  jmp _Z1bv.cfi at PLT
+  int3
+  int3
+  int3
+
+  #NO_APP
+.Lfunc_end3:
+  .size .L.cfi.jumptable, .Lfunc_end3-.L.cfi.jumptable
+  .cfi_endproc
+
+  .section  .debug_str,"MS", at progbits,1
+.Linfo_string0:
+  .asciz  "clang version 6.0.0 (trunk 316774)"
+.Linfo_string1:
+  .asciz  "tiny.cc"
+.Linfo_string2:
+  .asciz  ""
+  .section  .debug_abbrev,"", at progbits
+  .byte 1
+  .byte 17
+  .byte 0
+  .byte 37
+  .byte 14
+  .byte 19
+  .byte 5
+  .byte 3
+  .byte 14
+  .byte 16
+  .byte 23
+  .byte 27
+  .byte 14
+  .byte 17
+  .byte 1
+  .byte 18
+  .byte 6
+  .byte 0
+  .byte 0
+  .byte 0
+  .section  .debug_info,"", at progbits
+.Lcu_begin0:
+  .long 38
+  .short  4
+  .long .debug_abbrev
+  .byte 8
+  .byte 1
+  .long .Linfo_string0
+  .short  4
+  .long .Linfo_string1
+  .long .Lline_table_start0
+  .long .Linfo_string2
+  .quad .Lfunc_begin0
+  .long .Lfunc_end2-.Lfunc_begin0
+  .section  .debug_ranges,"", at progbits
+  .section  .debug_macinfo,"", at progbits
+.Lcu_macro_begin0:
+  .byte 0
+
+  .type _Z1av, at function
+_Z1av = .L.cfi.jumptable
+  .type _Z1bv, at function
+_Z1bv = .L.cfi.jumptable+8
+  .ident  "clang version 6.0.0 (trunk 316774)"
+  .section  ".note.GNU-stack","", at progbits
+  .section  .debug_line,"", at progbits
+.Lline_table_start0:
+

Added: llvm/trunk/test/tools/llvm-cfi-verify/X86/unprotected-lineinfo.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cfi-verify/X86/unprotected-lineinfo.s?rev=317050&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cfi-verify/X86/unprotected-lineinfo.s (added)
+++ llvm/trunk/test/tools/llvm-cfi-verify/X86/unprotected-lineinfo.s Tue Oct 31 16:20:05 2017
@@ -0,0 +1,167 @@
+# RUN: llvm-mc %s -filetype obj -triple x86_64-linux-elf -o %t.o
+# RUN: llvm-cfi-verify %t.o | FileCheck %s
+
+# CHECK-LABEL: U
+# CHECK-NEXT: tiny.cc:11
+
+# CHECK: Unprotected: 1 (100.00%), Protected: 0 (0.00%)
+
+# Source (tiny.cc):
+#   void a() {}
+#   void b() {}
+#   int main(int argc, char** argv) {
+#     void(*ptr)();
+#     if (argc == 1)
+#       ptr = &a;
+#     else
+#       ptr = &b;
+#     ptr();
+#   }
+# Compile with:
+#    clang++ -gmlt tiny.cc -S -o tiny.s
+
+  .text
+  .file "tiny.cc"
+  .globl  _Z1av                   # -- Begin function _Z1av
+  .p2align  4, 0x90
+  .type _Z1av, at function
+_Z1av:                                  # @_Z1av
+.Lfunc_begin0:
+  .file 1 "tiny.cc"
+  .loc  1 1 0                   # tiny.cc:1:0
+  .cfi_startproc
+# BB#0:
+  pushq %rbp
+  .cfi_def_cfa_offset 16
+  .cfi_offset %rbp, -16
+  movq  %rsp, %rbp
+  .cfi_def_cfa_register %rbp
+.Ltmp0:
+  .loc  1 1 11 prologue_end     # tiny.cc:1:11
+  popq  %rbp
+  retq
+.Ltmp1:
+.Lfunc_end0:
+  .size _Z1av, .Lfunc_end0-_Z1av
+  .cfi_endproc
+                                        # -- End function
+  .globl  _Z1bv                   # -- Begin function _Z1bv
+  .p2align  4, 0x90
+  .type _Z1bv, at function
+_Z1bv:                                  # @_Z1bv
+.Lfunc_begin1:
+  .loc  1 2 0                   # tiny.cc:2:0
+  .cfi_startproc
+# BB#0:
+  pushq %rbp
+  .cfi_def_cfa_offset 16
+  .cfi_offset %rbp, -16
+  movq  %rsp, %rbp
+  .cfi_def_cfa_register %rbp
+.Ltmp2:
+  .loc  1 2 11 prologue_end     # tiny.cc:2:11
+  popq  %rbp
+  retq
+.Ltmp3:
+.Lfunc_end1:
+  .size _Z1bv, .Lfunc_end1-_Z1bv
+  .cfi_endproc
+                                        # -- End function
+  .globl  main                    # -- Begin function main
+  .p2align  4, 0x90
+  .type main, at function
+main:                                   # @main
+.Lfunc_begin2:
+  .loc  1 4 0                   # tiny.cc:4:0
+  .cfi_startproc
+# BB#0:
+  pushq %rbp
+  .cfi_def_cfa_offset 16
+  .cfi_offset %rbp, -16
+  movq  %rsp, %rbp
+  .cfi_def_cfa_register %rbp
+  subq  $32, %rsp
+  movl  $0, -4(%rbp)
+  movl  %edi, -8(%rbp)
+  movq  %rsi, -16(%rbp)
+.Ltmp4:
+  .loc  1 6 12 prologue_end     # tiny.cc:6:12
+  cmpl  $1, -8(%rbp)
+  .loc  1 6 7 is_stmt 0         # tiny.cc:6:7
+  jne .LBB2_2
+# BB#1:
+  .loc  1 0 7                   # tiny.cc:0:7
+  movabsq $_Z1av, %rax
+  .loc  1 7 9 is_stmt 1         # tiny.cc:7:9
+  movq  %rax, -24(%rbp)
+  .loc  1 7 5 is_stmt 0         # tiny.cc:7:5
+  jmp .LBB2_3
+.LBB2_2:
+  .loc  1 0 5                   # tiny.cc:0:5
+  movabsq $_Z1bv, %rax
+  .loc  1 9 9 is_stmt 1         # tiny.cc:9:9
+  movq  %rax, -24(%rbp)
+.LBB2_3:
+  .loc  1 11 3                  # tiny.cc:11:3
+  callq *-24(%rbp)
+  .loc  1 12 1                  # tiny.cc:12:1
+  movl  -4(%rbp), %eax
+  addq  $32, %rsp
+  popq  %rbp
+  retq
+.Ltmp5:
+.Lfunc_end2:
+  .size main, .Lfunc_end2-main
+  .cfi_endproc
+                                        # -- End function
+  .section  .debug_str,"MS", at progbits,1
+.Linfo_string0:
+  .asciz  "clang version 6.0.0 (trunk 316774)" # string offset=0
+.Linfo_string1:
+  .asciz  "tiny.cc"               # string offset=35
+.Linfo_string2:
+  .asciz  "/tmp/a/b"              # string offset=43
+  .section  .debug_abbrev,"", at progbits
+  .byte 1                       # Abbreviation Code
+  .byte 17                      # DW_TAG_compile_unit
+  .byte 0                       # DW_CHILDREN_no
+  .byte 37                      # DW_AT_producer
+  .byte 14                      # DW_FORM_strp
+  .byte 19                      # DW_AT_language
+  .byte 5                       # DW_FORM_data2
+  .byte 3                       # DW_AT_name
+  .byte 14                      # DW_FORM_strp
+  .byte 16                      # DW_AT_stmt_list
+  .byte 23                      # DW_FORM_sec_offset
+  .byte 27                      # DW_AT_comp_dir
+  .byte 14                      # DW_FORM_strp
+  .byte 17                      # DW_AT_low_pc
+  .byte 1                       # DW_FORM_addr
+  .byte 18                      # DW_AT_high_pc
+  .byte 6                       # DW_FORM_data4
+  .byte 0                       # EOM(1)
+  .byte 0                       # EOM(2)
+  .byte 0                       # EOM(3)
+  .section  .debug_info,"", at progbits
+.Lcu_begin0:
+  .long 38                      # Length of Unit
+  .short  4                       # DWARF version number
+  .long .debug_abbrev           # Offset Into Abbrev. Section
+  .byte 8                       # Address Size (in bytes)
+  .byte 1                       # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit
+  .long .Linfo_string0          # DW_AT_producer
+  .short  4                       # DW_AT_language
+  .long .Linfo_string1          # DW_AT_name
+  .long .Lline_table_start0     # DW_AT_stmt_list
+  .long .Linfo_string2          # DW_AT_comp_dir
+  .quad .Lfunc_begin0           # DW_AT_low_pc
+  .long .Lfunc_end2-.Lfunc_begin0 # DW_AT_high_pc
+  .section  .debug_ranges,"", at progbits
+  .section  .debug_macinfo,"", at progbits
+.Lcu_macro_begin0:
+  .byte 0                       # End Of Macro List Mark
+
+  .ident  "clang version 6.0.0 (trunk 316774)"
+  .section  ".note.GNU-stack","", at progbits
+  .section  .debug_line,"", at progbits
+.Lline_table_start0:

Added: llvm/trunk/test/tools/llvm-cfi-verify/X86/unprotected-nolineinfo.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cfi-verify/X86/unprotected-nolineinfo.s?rev=317050&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cfi-verify/X86/unprotected-nolineinfo.s (added)
+++ llvm/trunk/test/tools/llvm-cfi-verify/X86/unprotected-nolineinfo.s Tue Oct 31 16:20:05 2017
@@ -0,0 +1,92 @@
+# RUN: llvm-mc %s -filetype obj -triple x86_64-linux-elf -o %t.o
+# RUN: not llvm-cfi-verify %t.o 2>&1 | FileCheck %s
+
+# CHECK: DWARF line information missing. Did you compile with '-g'?
+
+# Source (tiny.cc):
+#   void a() {}
+#   void b() {}
+#   int main(int argc, char** argv) {
+#     void(*ptr)();
+#     if (argc == 1)
+#       ptr = &a;
+#     else
+#       ptr = &b;
+#     ptr();
+#   }
+# Compile with:
+#    clang++ tiny.cc -S -o tiny.s
+
+  .text
+  .file "tiny.cc"
+  .globl  _Z1av                   # -- Begin function _Z1av
+  .p2align  4, 0x90
+  .type _Z1av, at function
+_Z1av:                                  # @_Z1av
+  .cfi_startproc
+# BB#0:
+  pushq %rbp
+  .cfi_def_cfa_offset 16
+  .cfi_offset %rbp, -16
+  movq  %rsp, %rbp
+  .cfi_def_cfa_register %rbp
+  popq  %rbp
+  retq
+.Lfunc_end0:
+  .size _Z1av, .Lfunc_end0-_Z1av
+  .cfi_endproc
+                                        # -- End function
+  .globl  _Z1bv                   # -- Begin function _Z1bv
+  .p2align  4, 0x90
+  .type _Z1bv, at function
+_Z1bv:                                  # @_Z1bv
+  .cfi_startproc
+# BB#0:
+  pushq %rbp
+  .cfi_def_cfa_offset 16
+  .cfi_offset %rbp, -16
+  movq  %rsp, %rbp
+  .cfi_def_cfa_register %rbp
+  popq  %rbp
+  retq
+.Lfunc_end1:
+  .size _Z1bv, .Lfunc_end1-_Z1bv
+  .cfi_endproc
+                                        # -- End function
+  .globl  main                    # -- Begin function main
+  .p2align  4, 0x90
+  .type main, at function
+main:                                   # @main
+  .cfi_startproc
+# BB#0:
+  pushq %rbp
+  .cfi_def_cfa_offset 16
+  .cfi_offset %rbp, -16
+  movq  %rsp, %rbp
+  .cfi_def_cfa_register %rbp
+  subq  $32, %rsp
+  movl  $0, -4(%rbp)
+  movl  %edi, -8(%rbp)
+  movq  %rsi, -16(%rbp)
+  cmpl  $1, -8(%rbp)
+  jne .LBB2_2
+# BB#1:
+  movabsq $_Z1av, %rax
+  movq  %rax, -24(%rbp)
+  jmp .LBB2_3
+.LBB2_2:
+  movabsq $_Z1bv, %rax
+  movq  %rax, -24(%rbp)
+.LBB2_3:
+  callq *-24(%rbp)
+  movl  -4(%rbp), %eax
+  addq  $32, %rsp
+  popq  %rbp
+  retq
+.Lfunc_end2:
+  .size main, .Lfunc_end2-main
+  .cfi_endproc
+                                        # -- End function
+
+  .ident  "clang version 6.0.0 (trunk 316774)"
+  .section  ".note.GNU-stack","", at progbits

Modified: llvm/trunk/tools/llvm-cfi-verify/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cfi-verify/CMakeLists.txt?rev=317050&r1=317049&r2=317050&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cfi-verify/CMakeLists.txt (original)
+++ llvm/trunk/tools/llvm-cfi-verify/CMakeLists.txt Tue Oct 31 16:20:05 2017
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
   AllTargetsDescs
   AllTargetsDisassemblers
   AllTargetsInfos
+  DebugInfoDWARF
   MC
   MCParser
   Object

Modified: llvm/trunk/tools/llvm-cfi-verify/LLVMBuild.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cfi-verify/LLVMBuild.txt?rev=317050&r1=317049&r2=317050&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cfi-verify/LLVMBuild.txt (original)
+++ llvm/trunk/tools/llvm-cfi-verify/LLVMBuild.txt Tue Oct 31 16:20:05 2017
@@ -19,4 +19,4 @@
 type = Tool
 name = llvm-cfi-verify
 parent = Tools
-required_libraries = all-targets MC MCDisassembler MCParser Support
+required_libraries = all-targets DebugInfoDWARF MC MCDisassembler MCParser Support

Modified: llvm/trunk/tools/llvm-cfi-verify/lib/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cfi-verify/lib/CMakeLists.txt?rev=317050&r1=317049&r2=317050&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cfi-verify/lib/CMakeLists.txt (original)
+++ llvm/trunk/tools/llvm-cfi-verify/lib/CMakeLists.txt Tue Oct 31 16:20:05 2017
@@ -7,6 +7,7 @@ add_library(LLVMCFIVerify
 
 llvm_update_compile_flags(LLVMCFIVerify)
 llvm_map_components_to_libnames(libs
+  DebugInfoDWARF
   MC
   MCParser
   Object

Modified: llvm/trunk/tools/llvm-cfi-verify/lib/FileAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cfi-verify/lib/FileAnalysis.cpp?rev=317050&r1=317049&r2=317050&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cfi-verify/lib/FileAnalysis.cpp (original)
+++ llvm/trunk/tools/llvm-cfi-verify/lib/FileAnalysis.cpp Tue Oct 31 16:20:05 2017
@@ -11,6 +11,7 @@
 #include "GraphBuilder.h"
 
 #include "llvm/BinaryFormat/ELF.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
@@ -42,6 +43,19 @@ using Instr = llvm::cfi_verify::FileAnal
 namespace llvm {
 namespace cfi_verify {
 
+static cl::opt<bool> IgnoreDWARF(
+    "ignore-dwarf",
+    cl::desc(
+        "Ignore all DWARF data. This relaxes the requirements for all "
+        "statically linked libraries to have been compiled with '-g', but "
+        "will result in false positives for 'CFI unprotected' instructions."),
+    cl::init(false));
+
+cl::opt<unsigned long long> DWARFSearchRange(
+    "dwarf-search-range",
+    cl::desc("Address search range used to determine if instruction is valid."),
+    cl::init(0x10));
+
 Expected<FileAnalysis> FileAnalysis::Create(StringRef Filename) {
   // Open the filename provided.
   Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
@@ -294,6 +308,28 @@ Error FileAnalysis::initialiseDisassembl
 }
 
 Error FileAnalysis::parseCodeSections() {
+  if (!IgnoreDWARF) {
+    DWARF.reset(DWARFContext::create(*Object).release());
+    if (!DWARF)
+      return make_error<StringError>("Could not create DWARF information.",
+                                     inconvertibleErrorCode());
+
+    bool LineInfoValid = false;
+
+    for (auto &Unit : DWARF->compile_units()) {
+      const auto &LineTable = DWARF->getLineTableForUnit(Unit.get());
+      if (LineTable && !LineTable->Rows.empty()) {
+        LineInfoValid = true;
+        break;
+      }
+    }
+
+    if (!LineInfoValid)
+      return make_error<StringError>(
+          "DWARF line information missing. Did you compile with '-g'?",
+          inconvertibleErrorCode());
+  }
+
   for (const object::SectionRef &Section : Object->sections()) {
     // Ensure only executable sections get analysed.
     if (!(object::ELFSectionRef(Section).getFlags() & ELF::SHF_EXECINSTR))
@@ -311,6 +347,19 @@ Error FileAnalysis::parseCodeSections()
   return Error::success();
 }
 
+DILineInfoTable FileAnalysis::getLineInfoForAddressRange(uint64_t Address) {
+  if (!hasLineTableInfo())
+    return DILineInfoTable();
+
+  return DWARF->getLineInfoForAddressRange(Address, DWARFSearchRange);
+}
+
+bool FileAnalysis::hasValidLineInfoForAddressRange(uint64_t Address) {
+  return !getLineInfoForAddressRange(Address).empty();
+}
+
+bool FileAnalysis::hasLineTableInfo() const { return DWARF != nullptr; }
+
 void FileAnalysis::parseSectionContents(ArrayRef<uint8_t> SectionBytes,
                                         uint64_t SectionAddress) {
   MCInst Instruction;
@@ -330,6 +379,11 @@ void FileAnalysis::parseSectionContents(
     InstrMeta.VMAddress = VMAddress;
     InstrMeta.InstructionSize = InstructionSize;
     InstrMeta.Valid = ValidInstruction;
+
+    // Check if this instruction exists in the range of the DWARF metadata.
+    if (hasLineTableInfo() && !hasValidLineInfoForAddressRange(VMAddress))
+      continue;
+
     addInstruction(InstrMeta);
 
     if (!ValidInstruction)

Modified: llvm/trunk/tools/llvm-cfi-verify/lib/FileAnalysis.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cfi-verify/lib/FileAnalysis.h?rev=317050&r1=317049&r2=317050&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cfi-verify/lib/FileAnalysis.h (original)
+++ llvm/trunk/tools/llvm-cfi-verify/lib/FileAnalysis.h Tue Oct 31 16:20:05 2017
@@ -12,6 +12,7 @@
 
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/BinaryFormat/ELF.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
@@ -120,6 +121,18 @@ public:
   const MCInstrInfo *getMCInstrInfo() const;
   const MCInstrAnalysis *getMCInstrAnalysis() const;
 
+  // Returns true if this class is using DWARF line tables for elimination.
+  bool hasLineTableInfo() const;
+
+  // Returns the line table information for the range {Address +-
+  // DWARFSearchRange}. Returns an empty table if the address has no valid line
+  // table information, or this analysis object has DWARF handling disabled.
+  DILineInfoTable getLineInfoForAddressRange(uint64_t Address);
+
+  // Returns whether the provided address has valid line information for
+  // instructions in the range of Address +- DWARFSearchRange.
+  bool hasValidLineInfoForAddressRange(uint64_t Address);
+
 protected:
   // Construct a blank object with the provided triple and features. Used in
   // testing, where a sub class will dependency inject protected methods to
@@ -162,8 +175,12 @@ private:
   std::unique_ptr<const MCInstrAnalysis> MIA;
   std::unique_ptr<MCInstPrinter> Printer;
 
+  // DWARF debug information.
+  std::unique_ptr<DWARFContext> DWARF;
+
   // A mapping between the virtual memory address to the instruction metadata
-  // struct.
+  // struct. TODO(hctim): Reimplement this as a sorted vector to avoid per-
+  // insertion allocation.
   std::map<uint64_t, Instr> Instructions;
 
   // Contains a mapping between a specific address, and a list of instructions

Modified: llvm/trunk/tools/llvm-cfi-verify/lib/GraphBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cfi-verify/lib/GraphBuilder.cpp?rev=317050&r1=317049&r2=317050&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cfi-verify/lib/GraphBuilder.cpp (original)
+++ llvm/trunk/tools/llvm-cfi-verify/lib/GraphBuilder.cpp Tue Oct 31 16:20:05 2017
@@ -221,6 +221,13 @@ void GraphBuilder::buildFlowGraphImpl(co
       continue;
     }
 
+    // Call instructions are not valid in the upwards traversal.
+    if (ParentDesc.isCall()) {
+      Result.IntermediateNodes[ParentMeta.VMAddress] = Address;
+      Result.OrphanedNodes.push_back(ParentMeta.VMAddress);
+      continue;
+    }
+
     // Evaluate the branch target to ascertain whether this XRef is the result
     // of a fallthrough or the target of a branch.
     uint64_t BranchTarget;

Modified: llvm/trunk/tools/llvm-cfi-verify/lib/LLVMBuild.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cfi-verify/lib/LLVMBuild.txt?rev=317050&r1=317049&r2=317050&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cfi-verify/lib/LLVMBuild.txt (original)
+++ llvm/trunk/tools/llvm-cfi-verify/lib/LLVMBuild.txt Tue Oct 31 16:20:05 2017
@@ -19,4 +19,4 @@
 type = Library
 name = CFIVerify
 parent = Libraries
-required_libraries = MC MCDisassembler MCParser Support
+required_libraries = DebugInfoDWARF MC MCDisassembler MCParser Support

Modified: llvm/trunk/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cfi-verify/llvm-cfi-verify.cpp?rev=317050&r1=317049&r2=317050&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cfi-verify/llvm-cfi-verify.cpp (original)
+++ llvm/trunk/tools/llvm-cfi-verify/llvm-cfi-verify.cpp Tue Oct 31 16:20:05 2017
@@ -22,6 +22,7 @@
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
 
 #include <cstdlib>
 
@@ -34,30 +35,62 @@ cl::opt<std::string> InputFilename(cl::P
 
 ExitOnError ExitOnErr;
 
-void printIndirectCFInstructions(const FileAnalysis &Verifier) {
-  for (uint64_t Address : Verifier.getIndirectInstructions()) {
-    const auto &InstrMeta = Verifier.getInstructionOrDie(Address);
-    outs() << format_hex(Address, 2) << " |"
-           << Verifier.getMCInstrInfo()->getName(
+void printIndirectCFInstructions(FileAnalysis &Analysis) {
+  uint64_t ProtectedCount = 0;
+  uint64_t UnprotectedCount = 0;
+
+  for (uint64_t Address : Analysis.getIndirectInstructions()) {
+    const auto &InstrMeta = Analysis.getInstructionOrDie(Address);
+
+    if (Analysis.isIndirectInstructionCFIProtected(Address)) {
+      outs() << "P ";
+      ProtectedCount++;
+    } else {
+      outs() << "U ";
+      UnprotectedCount++;
+    }
+
+    outs() << format_hex(Address, 2) << " | "
+           << Analysis.getMCInstrInfo()->getName(
                   InstrMeta.Instruction.getOpcode())
            << " ";
-    InstrMeta.Instruction.print(outs());
     outs() << "\n";
-    outs() << "  Protected? "
-           << Verifier.isIndirectInstructionCFIProtected(Address) << "\n";
+
+    if (Analysis.hasLineTableInfo()) {
+      for (const auto &LineKV : Analysis.getLineInfoForAddressRange(Address)) {
+        outs() << "  " << format_hex(LineKV.first, 2) << " = "
+               << LineKV.second.FileName << ":" << LineKV.second.Line << ":"
+               << LineKV.second.Column << " (" << LineKV.second.FunctionName
+               << ")\n";
+      }
+    }
   }
+
+  if (ProtectedCount || UnprotectedCount)
+    outs() << formatv(
+        "Unprotected: {0} ({1:P}), Protected: {2} ({3:P})\n", UnprotectedCount,
+        (((double)UnprotectedCount) / (UnprotectedCount + ProtectedCount)),
+        ProtectedCount,
+        (((double)ProtectedCount) / (UnprotectedCount + ProtectedCount)));
+  else
+    outs() << "No indirect CF instructions found.\n";
 }
 
 int main(int argc, char **argv) {
-  cl::ParseCommandLineOptions(argc, argv);
+  cl::ParseCommandLineOptions(
+      argc, argv,
+      "Identifies whether Control Flow Integrity protects all indirect control "
+      "flow instructions in the provided object file, DSO or binary.\nNote: "
+      "Anything statically linked into the provided file *must* be compiled "
+      "with '-g'. This can be relaxed through the '--ignore-dwarf' flag.");
 
   InitializeAllTargetInfos();
   InitializeAllTargetMCs();
   InitializeAllAsmParsers();
   InitializeAllDisassemblers();
 
-  FileAnalysis Verifier = ExitOnErr(FileAnalysis::Create(InputFilename));
-  printIndirectCFInstructions(Verifier);
+  FileAnalysis Analysis = ExitOnErr(FileAnalysis::Create(InputFilename));
+  printIndirectCFInstructions(Analysis);
 
   return EXIT_SUCCESS;
 }




More information about the llvm-commits mailing list