llvm.org GIT mirror llvm / b2fffde
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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@317050 91177308-0d34-0410-b5e6-96231b3b80d8 Mitch Phillips 2 years ago
13 changed file(s) with 797 addition(s) and 14 deletion(s). Raw diff Collapse all Expand all
0 # RUN: llvm-mc %s -filetype obj -triple x86_64-linux-elf -o %t.o
1 # RUN: llvm-cfi-verify %t.o 2>&1 | FileCheck %s
2
3 # This is the same file as protected-lineinfo.s, however contains a hand-
4 # assembled function (fake_function) that has no line table information
5 # associated with it. Because there is no LT info, the indirect call made in the
6 # function should not be reported at all by llvm-cfi-verify.
7
8 # We can test that this indirect call is ignored from the final statistics
9 # reporting of the cfi-verify program. It should only find a single indirect CF
10 # instruction at `tiny.cc:11` (see protected-lineinfo.s for the source).
11
12 # CHECK: Unprotected: 0 (0.00%), Protected: 1 (100.00%)
13
14 .text
15 .file "ld-temp.o"
16 .p2align 4, 0x90
17 .type fake_function,@function
18 fake_function:
19 nop
20 nop
21 nop
22 nop
23 callq *%rax
24 nop
25 nop
26 nop
27 nop
28 .type _Z1av.cfi,@function
29 _Z1av.cfi:
30 .Lfunc_begin0:
31 .file 1 "tiny.cc"
32 .loc 1 3 0
33 .cfi_startproc
34 pushq %rbp
35 .cfi_def_cfa_offset 16
36 .cfi_offset %rbp, -16
37 movq %rsp, %rbp
38 .cfi_def_cfa_register %rbp
39 .Ltmp0:
40 .loc 1 3 11 prologue_end
41 popq %rbp
42 retq
43 .Ltmp1:
44 .Lfunc_end0:
45 .size _Z1av.cfi, .Lfunc_end0-_Z1av.cfi
46 .cfi_endproc
47
48 .p2align 4, 0x90
49 .type _Z1bv.cfi,@function
50 _Z1bv.cfi:
51 .Lfunc_begin1:
52 .loc 1 4 0
53 .cfi_startproc
54 pushq %rbp
55 .cfi_def_cfa_offset 16
56 .cfi_offset %rbp, -16
57 movq %rsp, %rbp
58 .cfi_def_cfa_register %rbp
59 .Ltmp2:
60 .loc 1 4 11 prologue_end
61 popq %rbp
62 retq
63 .Ltmp3:
64 .Lfunc_end1:
65 .size _Z1bv.cfi, .Lfunc_end1-_Z1bv.cfi
66 .cfi_endproc
67
68 .hidden main
69 .globl main
70 .p2align 4, 0x90
71 .type main,@function
72 main:
73 .Lfunc_begin2:
74 .loc 1 6 0
75 .cfi_startproc
76 pushq %rbp
77 .cfi_def_cfa_offset 16
78 .cfi_offset %rbp, -16
79 movq %rsp, %rbp
80 .cfi_def_cfa_register %rbp
81 subq $32, %rsp
82 movb $32, -1(%rbp)
83 movl $0, -12(%rbp)
84 movl %edi, -8(%rbp)
85 movq %rsi, -32(%rbp)
86 .Ltmp4:
87 .loc 1 8 12 prologue_end
88 cmpl $1, -8(%rbp)
89 .loc 1 8 7 is_stmt 0
90 jne .LBB2_2
91 .loc 1 0 7
92 leaq _Z1av(%rip), %rax
93 .loc 1 9 9 is_stmt 1
94 movq %rax, -24(%rbp)
95 .loc 1 9 5 is_stmt 0
96 jmp .LBB2_3
97 .LBB2_2:
98 .loc 1 0 5
99 leaq _Z1bv(%rip), %rax
100 .loc 1 11 9 is_stmt 1
101 movq %rax, -24(%rbp)
102 .LBB2_3:
103 .loc 1 0 9 is_stmt 0
104 leaq .L.cfi.jumptable(%rip), %rcx
105 .loc 1 13 3 is_stmt 1
106 movq -24(%rbp), %rax
107 movq %rax, %rdx
108 subq %rcx, %rdx
109 movq %rdx, %rcx
110 shrq $3, %rcx
111 shlq $61, %rdx
112 orq %rcx, %rdx
113 cmpq $1, %rdx
114 jbe .LBB2_5
115 ud2
116 .LBB2_5:
117 callq *%rax
118 .loc 1 14 11
119 movb $-1, -1(%rbp)
120 .loc 1 15 1
121 movl -12(%rbp), %eax
122 addq $32, %rsp
123 popq %rbp
124 retq
125 .Ltmp5:
126 .Lfunc_end2:
127 .size main, .Lfunc_end2-main
128 .cfi_endproc
129
130 .p2align 3, 0x90
131 .type .L.cfi.jumptable,@function
132 .L.cfi.jumptable:
133 .Lfunc_begin3:
134 .cfi_startproc
135 #APP
136 jmp _Z1av.cfi@PLT
137 int3
138 int3
139 int3
140 jmp _Z1bv.cfi@PLT
141 int3
142 int3
143 int3
144
145 #NO_APP
146 .Lfunc_end3:
147 .size .L.cfi.jumptable, .Lfunc_end3-.L.cfi.jumptable
148 .cfi_endproc
149
150 .section .debug_str,"MS",@progbits,1
151 .Linfo_string0:
152 .asciz "clang version 6.0.0 (trunk 316774)"
153 .Linfo_string1:
154 .asciz "tiny.cc"
155 .Linfo_string2:
156 .asciz "/tmp/a/b"
157 .section .debug_abbrev,"",@progbits
158 .byte 1
159 .byte 17
160 .byte 0
161 .byte 37
162 .byte 14
163 .byte 19
164 .byte 5
165 .byte 3
166 .byte 14
167 .byte 16
168 .byte 23
169 .byte 27
170 .byte 14
171 .byte 17
172 .byte 1
173 .byte 18
174 .byte 6
175 .byte 0
176 .byte 0
177 .byte 0
178 .section .debug_info,"",@progbits
179 .Lcu_begin0:
180 .long 38
181 .short 4
182 .long .debug_abbrev
183 .byte 8
184 .byte 1
185 .long .Linfo_string0
186 .short 4
187 .long .Linfo_string1
188 .long .Lline_table_start0
189 .long .Linfo_string2
190 .quad .Lfunc_begin0
191 .long .Lfunc_end2-.Lfunc_begin0
192 .section .debug_ranges,"",@progbits
193 .section .debug_macinfo,"",@progbits
194 .Lcu_macro_begin0:
195 .byte 0
196
197 .type _Z1av,@function
198 _Z1av = .L.cfi.jumptable
199 .type _Z1bv,@function
200 _Z1bv = .L.cfi.jumptable+8
201 .ident "clang version 6.0.0 (trunk 316774)"
202 .section ".note.GNU-stack","",@progbits
203 .section .debug_line,"",@progbits
204 .Lline_table_start0:
205
0 if not 'X86' in config.root.targets:
1 config.unsupported = True
0 # RUN: llvm-mc %s -filetype obj -triple x86_64-linux-elf -o %t.o
1 # RUN: llvm-cfi-verify %t.o | FileCheck %s
2
3 # CHECK-LABEL: P
4 # CHECK-NEXT: tiny.cc:11
5
6 # CHECK: Unprotected: 0 (0.00%), Protected: 1 (100.00%)
7
8 # Source (tiny.cc):
9 # void a() {}
10 # void b() {}
11 # int main(int argc, char** argv) {
12 # void(*ptr)();
13 # if (argc == 1)
14 # ptr = &a;
15 # else
16 # ptr = &b;
17 # ptr();
18 # }
19 # Compile with (output is in tiny.s.0):
20 # clang++ -flto -fsanitize=cfi -fvisibility=hidden -c tiny.cc -o tiny.o -gmlt
21 # clang++ tiny.o -o tiny -flto -fuse-ld=gold -Wl,-plugin-opt,save-temps
22 # clang++ -fsanitize=cfi -flto -fvisibility=hidden -c tiny.cc -o tiny.o -gmlt
23 # llvm-lto2 run @tiny.resolution.txt -o tiny.s -filetype=asm
24
25 .text
26 .file "ld-temp.o"
27 .p2align 4, 0x90
28 .type _Z1av.cfi,@function
29 _Z1av.cfi:
30 .Lfunc_begin0:
31 .file 1 "tiny.cc"
32 .loc 1 1 0
33 .cfi_startproc
34 pushq %rbp
35 .cfi_def_cfa_offset 16
36 .cfi_offset %rbp, -16
37 movq %rsp, %rbp
38 .cfi_def_cfa_register %rbp
39 .Ltmp0:
40 .loc 1 1 11 prologue_end
41 popq %rbp
42 retq
43 .Ltmp1:
44 .Lfunc_end0:
45 .size _Z1av.cfi, .Lfunc_end0-_Z1av.cfi
46 .cfi_endproc
47
48 .p2align 4, 0x90
49 .type _Z1bv.cfi,@function
50 _Z1bv.cfi:
51 .Lfunc_begin1:
52 .loc 1 2 0
53 .cfi_startproc
54 pushq %rbp
55 .cfi_def_cfa_offset 16
56 .cfi_offset %rbp, -16
57 movq %rsp, %rbp
58 .cfi_def_cfa_register %rbp
59 .Ltmp2:
60 .loc 1 2 11 prologue_end
61 popq %rbp
62 retq
63 .Ltmp3:
64 .Lfunc_end1:
65 .size _Z1bv.cfi, .Lfunc_end1-_Z1bv.cfi
66 .cfi_endproc
67
68 .hidden main
69 .globl main
70 .p2align 4, 0x90
71 .type main,@function
72 main:
73 .Lfunc_begin2:
74 .loc 1 4 0
75 .cfi_startproc
76 pushq %rbp
77 .cfi_def_cfa_offset 16
78 .cfi_offset %rbp, -16
79 movq %rsp, %rbp
80 .cfi_def_cfa_register %rbp
81 subq $32, %rsp
82 movl $0, -8(%rbp)
83 movl %edi, -4(%rbp)
84 movq %rsi, -24(%rbp)
85 .Ltmp4:
86 .loc 1 6 12 prologue_end
87 cmpl $1, -4(%rbp)
88 .loc 1 6 7 is_stmt 0
89 jne .LBB2_2
90 .loc 1 0 7
91 leaq _Z1av(%rip), %rax
92 .loc 1 7 9 is_stmt 1
93 movq %rax, -16(%rbp)
94 .loc 1 7 5 is_stmt 0
95 jmp .LBB2_3
96 .LBB2_2:
97 .loc 1 0 5
98 leaq _Z1bv(%rip), %rax
99 .loc 1 9 9 is_stmt 1
100 movq %rax, -16(%rbp)
101 .LBB2_3:
102 .loc 1 0 9 is_stmt 0
103 leaq .L.cfi.jumptable(%rip), %rcx
104 .loc 1 11 3 is_stmt 1
105 movq -16(%rbp), %rax
106 movq %rax, %rdx
107 subq %rcx, %rdx
108 movq %rdx, %rcx
109 shrq $3, %rcx
110 shlq $61, %rdx
111 orq %rcx, %rdx
112 cmpq $1, %rdx
113 jbe .LBB2_5
114 ud2
115 .LBB2_5:
116 callq *%rax
117 .loc 1 12 1
118 movl -8(%rbp), %eax
119 addq $32, %rsp
120 popq %rbp
121 retq
122 .Ltmp5:
123 .Lfunc_end2:
124 .size main, .Lfunc_end2-main
125 .cfi_endproc
126
127 .p2align 3, 0x90
128 .type .L.cfi.jumptable,@function
129 .L.cfi.jumptable:
130 .Lfunc_begin3:
131 .cfi_startproc
132 #APP
133 jmp _Z1av.cfi@PLT
134 int3
135 int3
136 int3
137 jmp _Z1bv.cfi@PLT
138 int3
139 int3
140 int3
141
142 #NO_APP
143 .Lfunc_end3:
144 .size .L.cfi.jumptable, .Lfunc_end3-.L.cfi.jumptable
145 .cfi_endproc
146
147 .section .debug_str,"MS",@progbits,1
148 .Linfo_string0:
149 .asciz "clang version 6.0.0 (trunk 316774)"
150 .Linfo_string1:
151 .asciz "tiny.cc"
152 .Linfo_string2:
153 .asciz ""
154 .section .debug_abbrev,"",@progbits
155 .byte 1
156 .byte 17
157 .byte 0
158 .byte 37
159 .byte 14
160 .byte 19
161 .byte 5
162 .byte 3
163 .byte 14
164 .byte 16
165 .byte 23
166 .byte 27
167 .byte 14
168 .byte 17
169 .byte 1
170 .byte 18
171 .byte 6
172 .byte 0
173 .byte 0
174 .byte 0
175 .section .debug_info,"",@progbits
176 .Lcu_begin0:
177 .long 38
178 .short 4
179 .long .debug_abbrev
180 .byte 8
181 .byte 1
182 .long .Linfo_string0
183 .short 4
184 .long .Linfo_string1
185 .long .Lline_table_start0
186 .long .Linfo_string2
187 .quad .Lfunc_begin0
188 .long .Lfunc_end2-.Lfunc_begin0
189 .section .debug_ranges,"",@progbits
190 .section .debug_macinfo,"",@progbits
191 .Lcu_macro_begin0:
192 .byte 0
193
194 .type _Z1av,@function
195 _Z1av = .L.cfi.jumptable
196 .type _Z1bv,@function
197 _Z1bv = .L.cfi.jumptable+8
198 .ident "clang version 6.0.0 (trunk 316774)"
199 .section ".note.GNU-stack","",@progbits
200 .section .debug_line,"",@progbits
201 .Lline_table_start0:
202
0 # RUN: llvm-mc %s -filetype obj -triple x86_64-linux-elf -o %t.o
1 # RUN: llvm-cfi-verify %t.o | FileCheck %s
2
3 # CHECK-LABEL: U
4 # CHECK-NEXT: tiny.cc:11
5
6 # CHECK: Unprotected: 1 (100.00%), Protected: 0 (0.00%)
7
8 # Source (tiny.cc):
9 # void a() {}
10 # void b() {}
11 # int main(int argc, char** argv) {
12 # void(*ptr)();
13 # if (argc == 1)
14 # ptr = &a;
15 # else
16 # ptr = &b;
17 # ptr();
18 # }
19 # Compile with:
20 # clang++ -gmlt tiny.cc -S -o tiny.s
21
22 .text
23 .file "tiny.cc"
24 .globl _Z1av # -- Begin function _Z1av
25 .p2align 4, 0x90
26 .type _Z1av,@function
27 _Z1av: # @_Z1av
28 .Lfunc_begin0:
29 .file 1 "tiny.cc"
30 .loc 1 1 0 # tiny.cc:1:0
31 .cfi_startproc
32 # BB#0:
33 pushq %rbp
34 .cfi_def_cfa_offset 16
35 .cfi_offset %rbp, -16
36 movq %rsp, %rbp
37 .cfi_def_cfa_register %rbp
38 .Ltmp0:
39 .loc 1 1 11 prologue_end # tiny.cc:1:11
40 popq %rbp
41 retq
42 .Ltmp1:
43 .Lfunc_end0:
44 .size _Z1av, .Lfunc_end0-_Z1av
45 .cfi_endproc
46 # -- End function
47 .globl _Z1bv # -- Begin function _Z1bv
48 .p2align 4, 0x90
49 .type _Z1bv,@function
50 _Z1bv: # @_Z1bv
51 .Lfunc_begin1:
52 .loc 1 2 0 # tiny.cc:2:0
53 .cfi_startproc
54 # BB#0:
55 pushq %rbp
56 .cfi_def_cfa_offset 16
57 .cfi_offset %rbp, -16
58 movq %rsp, %rbp
59 .cfi_def_cfa_register %rbp
60 .Ltmp2:
61 .loc 1 2 11 prologue_end # tiny.cc:2:11
62 popq %rbp
63 retq
64 .Ltmp3:
65 .Lfunc_end1:
66 .size _Z1bv, .Lfunc_end1-_Z1bv
67 .cfi_endproc
68 # -- End function
69 .globl main # -- Begin function main
70 .p2align 4, 0x90
71 .type main,@function
72 main: # @main
73 .Lfunc_begin2:
74 .loc 1 4 0 # tiny.cc:4:0
75 .cfi_startproc
76 # BB#0:
77 pushq %rbp
78 .cfi_def_cfa_offset 16
79 .cfi_offset %rbp, -16
80 movq %rsp, %rbp
81 .cfi_def_cfa_register %rbp
82 subq $32, %rsp
83 movl $0, -4(%rbp)
84 movl %edi, -8(%rbp)
85 movq %rsi, -16(%rbp)
86 .Ltmp4:
87 .loc 1 6 12 prologue_end # tiny.cc:6:12
88 cmpl $1, -8(%rbp)
89 .loc 1 6 7 is_stmt 0 # tiny.cc:6:7
90 jne .LBB2_2
91 # BB#1:
92 .loc 1 0 7 # tiny.cc:0:7
93 movabsq $_Z1av, %rax
94 .loc 1 7 9 is_stmt 1 # tiny.cc:7:9
95 movq %rax, -24(%rbp)
96 .loc 1 7 5 is_stmt 0 # tiny.cc:7:5
97 jmp .LBB2_3
98 .LBB2_2:
99 .loc 1 0 5 # tiny.cc:0:5
100 movabsq $_Z1bv, %rax
101 .loc 1 9 9 is_stmt 1 # tiny.cc:9:9
102 movq %rax, -24(%rbp)
103 .LBB2_3:
104 .loc 1 11 3 # tiny.cc:11:3
105 callq *-24(%rbp)
106 .loc 1 12 1 # tiny.cc:12:1
107 movl -4(%rbp), %eax
108 addq $32, %rsp
109 popq %rbp
110 retq
111 .Ltmp5:
112 .Lfunc_end2:
113 .size main, .Lfunc_end2-main
114 .cfi_endproc
115 # -- End function
116 .section .debug_str,"MS",@progbits,1
117 .Linfo_string0:
118 .asciz "clang version 6.0.0 (trunk 316774)" # string offset=0
119 .Linfo_string1:
120 .asciz "tiny.cc" # string offset=35
121 .Linfo_string2:
122 .asciz "/tmp/a/b" # string offset=43
123 .section .debug_abbrev,"",@progbits
124 .byte 1 # Abbreviation Code
125 .byte 17 # DW_TAG_compile_unit
126 .byte 0 # DW_CHILDREN_no
127 .byte 37 # DW_AT_producer
128 .byte 14 # DW_FORM_strp
129 .byte 19 # DW_AT_language
130 .byte 5 # DW_FORM_data2
131 .byte 3 # DW_AT_name
132 .byte 14 # DW_FORM_strp
133 .byte 16 # DW_AT_stmt_list
134 .byte 23 # DW_FORM_sec_offset
135 .byte 27 # DW_AT_comp_dir
136 .byte 14 # DW_FORM_strp
137 .byte 17 # DW_AT_low_pc
138 .byte 1 # DW_FORM_addr
139 .byte 18 # DW_AT_high_pc
140 .byte 6 # DW_FORM_data4
141 .byte 0 # EOM(1)
142 .byte 0 # EOM(2)
143 .byte 0 # EOM(3)
144 .section .debug_info,"",@progbits
145 .Lcu_begin0:
146 .long 38 # Length of Unit
147 .short 4 # DWARF version number
148 .long .debug_abbrev # Offset Into Abbrev. Section
149 .byte 8 # Address Size (in bytes)
150 .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit
151 .long .Linfo_string0 # DW_AT_producer
152 .short 4 # DW_AT_language
153 .long .Linfo_string1 # DW_AT_name
154 .long .Lline_table_start0 # DW_AT_stmt_list
155 .long .Linfo_string2 # DW_AT_comp_dir
156 .quad .Lfunc_begin0 # DW_AT_low_pc
157 .long .Lfunc_end2-.Lfunc_begin0 # DW_AT_high_pc
158 .section .debug_ranges,"",@progbits
159 .section .debug_macinfo,"",@progbits
160 .Lcu_macro_begin0:
161 .byte 0 # End Of Macro List Mark
162
163 .ident "clang version 6.0.0 (trunk 316774)"
164 .section ".note.GNU-stack","",@progbits
165 .section .debug_line,"",@progbits
166 .Lline_table_start0:
0 # RUN: llvm-mc %s -filetype obj -triple x86_64-linux-elf -o %t.o
1 # RUN: not llvm-cfi-verify %t.o 2>&1 | FileCheck %s
2
3 # CHECK: DWARF line information missing. Did you compile with '-g'?
4
5 # Source (tiny.cc):
6 # void a() {}
7 # void b() {}
8 # int main(int argc, char** argv) {
9 # void(*ptr)();
10 # if (argc == 1)
11 # ptr = &a;
12 # else
13 # ptr = &b;
14 # ptr();
15 # }
16 # Compile with:
17 # clang++ tiny.cc -S -o tiny.s
18
19 .text
20 .file "tiny.cc"
21 .globl _Z1av # -- Begin function _Z1av
22 .p2align 4, 0x90
23 .type _Z1av,@function
24 _Z1av: # @_Z1av
25 .cfi_startproc
26 # BB#0:
27 pushq %rbp
28 .cfi_def_cfa_offset 16
29 .cfi_offset %rbp, -16
30 movq %rsp, %rbp
31 .cfi_def_cfa_register %rbp
32 popq %rbp
33 retq
34 .Lfunc_end0:
35 .size _Z1av, .Lfunc_end0-_Z1av
36 .cfi_endproc
37 # -- End function
38 .globl _Z1bv # -- Begin function _Z1bv
39 .p2align 4, 0x90
40 .type _Z1bv,@function
41 _Z1bv: # @_Z1bv
42 .cfi_startproc
43 # BB#0:
44 pushq %rbp
45 .cfi_def_cfa_offset 16
46 .cfi_offset %rbp, -16
47 movq %rsp, %rbp
48 .cfi_def_cfa_register %rbp
49 popq %rbp
50 retq
51 .Lfunc_end1:
52 .size _Z1bv, .Lfunc_end1-_Z1bv
53 .cfi_endproc
54 # -- End function
55 .globl main # -- Begin function main
56 .p2align 4, 0x90
57 .type main,@function
58 main: # @main
59 .cfi_startproc
60 # BB#0:
61 pushq %rbp
62 .cfi_def_cfa_offset 16
63 .cfi_offset %rbp, -16
64 movq %rsp, %rbp
65 .cfi_def_cfa_register %rbp
66 subq $32, %rsp
67 movl $0, -4(%rbp)
68 movl %edi, -8(%rbp)
69 movq %rsi, -16(%rbp)
70 cmpl $1, -8(%rbp)
71 jne .LBB2_2
72 # BB#1:
73 movabsq $_Z1av, %rax
74 movq %rax, -24(%rbp)
75 jmp .LBB2_3
76 .LBB2_2:
77 movabsq $_Z1bv, %rax
78 movq %rax, -24(%rbp)
79 .LBB2_3:
80 callq *-24(%rbp)
81 movl -4(%rbp), %eax
82 addq $32, %rsp
83 popq %rbp
84 retq
85 .Lfunc_end2:
86 .size main, .Lfunc_end2-main
87 .cfi_endproc
88 # -- End function
89
90 .ident "clang version 6.0.0 (trunk 316774)"
91 .section ".note.GNU-stack","",@progbits
33 AllTargetsDescs
44 AllTargetsDisassemblers
55 AllTargetsInfos
6 DebugInfoDWARF
67 MC
78 MCParser
89 Object
1818 type = Tool
1919 name = llvm-cfi-verify
2020 parent = Tools
21 required_libraries = all-targets MC MCDisassembler MCParser Support
21 required_libraries = all-targets DebugInfoDWARF MC MCDisassembler MCParser Support
66
77 llvm_update_compile_flags(LLVMCFIVerify)
88 llvm_map_components_to_libnames(libs
9 DebugInfoDWARF
910 MC
1011 MCParser
1112 Object
1010 #include "GraphBuilder.h"
1111
1212 #include "llvm/BinaryFormat/ELF.h"
13 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
1314 #include "llvm/MC/MCAsmInfo.h"
1415 #include "llvm/MC/MCContext.h"
1516 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
4142 namespace llvm {
4243 namespace cfi_verify {
4344
45 static cl::opt IgnoreDWARF(
46 "ignore-dwarf",
47 cl::desc(
48 "Ignore all DWARF data. This relaxes the requirements for all "
49 "statically linked libraries to have been compiled with '-g', but "
50 "will result in false positives for 'CFI unprotected' instructions."),
51 cl::init(false));
52
53 cl::opt DWARFSearchRange(
54 "dwarf-search-range",
55 cl::desc("Address search range used to determine if instruction is valid."),
56 cl::init(0x10));
57
4458 Expected FileAnalysis::Create(StringRef Filename) {
4559 // Open the filename provided.
4660 Expected> BinaryOrErr =
293307 }
294308
295309 Error FileAnalysis::parseCodeSections() {
310 if (!IgnoreDWARF) {
311 DWARF.reset(DWARFContext::create(*Object).release());
312 if (!DWARF)
313 return make_error("Could not create DWARF information.",
314 inconvertibleErrorCode());
315
316 bool LineInfoValid = false;
317
318 for (auto &Unit : DWARF->compile_units()) {
319 const auto &LineTable = DWARF->getLineTableForUnit(Unit.get());
320 if (LineTable && !LineTable->Rows.empty()) {
321 LineInfoValid = true;
322 break;
323 }
324 }
325
326 if (!LineInfoValid)
327 return make_error(
328 "DWARF line information missing. Did you compile with '-g'?",
329 inconvertibleErrorCode());
330 }
331
296332 for (const object::SectionRef &Section : Object->sections()) {
297333 // Ensure only executable sections get analysed.
298334 if (!(object::ELFSectionRef(Section).getFlags() & ELF::SHF_EXECINSTR))
309345 }
310346 return Error::success();
311347 }
348
349 DILineInfoTable FileAnalysis::getLineInfoForAddressRange(uint64_t Address) {
350 if (!hasLineTableInfo())
351 return DILineInfoTable();
352
353 return DWARF->getLineInfoForAddressRange(Address, DWARFSearchRange);
354 }
355
356 bool FileAnalysis::hasValidLineInfoForAddressRange(uint64_t Address) {
357 return !getLineInfoForAddressRange(Address).empty();
358 }
359
360 bool FileAnalysis::hasLineTableInfo() const { return DWARF != nullptr; }
312361
313362 void FileAnalysis::parseSectionContents(ArrayRef SectionBytes,
314363 uint64_t SectionAddress) {
329378 InstrMeta.VMAddress = VMAddress;
330379 InstrMeta.InstructionSize = InstructionSize;
331380 InstrMeta.Valid = ValidInstruction;
381
382 // Check if this instruction exists in the range of the DWARF metadata.
383 if (hasLineTableInfo() && !hasValidLineInfoForAddressRange(VMAddress))
384 continue;
385
332386 addInstruction(InstrMeta);
333387
334388 if (!ValidInstruction)
1111
1212 #include "llvm/ADT/DenseMap.h"
1313 #include "llvm/BinaryFormat/ELF.h"
14 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
1415 #include "llvm/MC/MCAsmInfo.h"
1516 #include "llvm/MC/MCContext.h"
1617 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
119120 const MCInstrInfo *getMCInstrInfo() const;
120121 const MCInstrAnalysis *getMCInstrAnalysis() const;
121122
123 // Returns true if this class is using DWARF line tables for elimination.
124 bool hasLineTableInfo() const;
125
126 // Returns the line table information for the range {Address +-
127 // DWARFSearchRange}. Returns an empty table if the address has no valid line
128 // table information, or this analysis object has DWARF handling disabled.
129 DILineInfoTable getLineInfoForAddressRange(uint64_t Address);
130
131 // Returns whether the provided address has valid line information for
132 // instructions in the range of Address +- DWARFSearchRange.
133 bool hasValidLineInfoForAddressRange(uint64_t Address);
134
122135 protected:
123136 // Construct a blank object with the provided triple and features. Used in
124137 // testing, where a sub class will dependency inject protected methods to
161174 std::unique_ptr MIA;
162175 std::unique_ptr Printer;
163176
177 // DWARF debug information.
178 std::unique_ptr DWARF;
179
164180 // A mapping between the virtual memory address to the instruction metadata
165 // struct.
181 // struct. TODO(hctim): Reimplement this as a sorted vector to avoid per-
182 // insertion allocation.
166183 std::map Instructions;
167184
168185 // Contains a mapping between a specific address, and a list of instructions
220220 continue;
221221 }
222222
223 // Call instructions are not valid in the upwards traversal.
224 if (ParentDesc.isCall()) {
225 Result.IntermediateNodes[ParentMeta.VMAddress] = Address;
226 Result.OrphanedNodes.push_back(ParentMeta.VMAddress);
227 continue;
228 }
229
223230 // Evaluate the branch target to ascertain whether this XRef is the result
224231 // of a fallthrough or the target of a branch.
225232 uint64_t BranchTarget;
1818 type = Library
1919 name = CFIVerify
2020 parent = Libraries
21 required_libraries = MC MCDisassembler MCParser Support
21 required_libraries = DebugInfoDWARF MC MCDisassembler MCParser Support
2121 #include "llvm/BinaryFormat/ELF.h"
2222 #include "llvm/Support/CommandLine.h"
2323 #include "llvm/Support/Error.h"
24 #include "llvm/Support/FormatVariadic.h"
2425
2526 #include
2627
3334
3435 ExitOnError ExitOnErr;
3536
36 void printIndirectCFInstructions(const FileAnalysis &Verifier) {
37 for (uint64_t Address : Verifier.getIndirectInstructions()) {
38 const auto &InstrMeta = Verifier.getInstructionOrDie(Address);
39 outs() << format_hex(Address, 2) << " |"
40 << Verifier.getMCInstrInfo()->getName(
37 void printIndirectCFInstructions(FileAnalysis &Analysis) {
38 uint64_t ProtectedCount = 0;
39 uint64_t UnprotectedCount = 0;
40
41 for (uint64_t Address : Analysis.getIndirectInstructions()) {
42 const auto &InstrMeta = Analysis.getInstructionOrDie(Address);
43
44 if (Analysis.isIndirectInstructionCFIProtected(Address)) {
45 outs() << "P ";
46 ProtectedCount++;
47 } else {
48 outs() << "U ";
49 UnprotectedCount++;
50 }
51
52 outs() << format_hex(Address, 2) << " | "
53 << Analysis.getMCInstrInfo()->getName(
4154 InstrMeta.Instruction.getOpcode())
4255 << " ";
43 InstrMeta.Instruction.print(outs());
4456 outs() << "\n";
45 outs() << " Protected? "
46 << Verifier.isIndirectInstructionCFIProtected(Address) << "\n";
57
58 if (Analysis.hasLineTableInfo()) {
59 for (const auto &LineKV : Analysis.getLineInfoForAddressRange(Address)) {
60 outs() << " " << format_hex(LineKV.first, 2) << " = "
61 << LineKV.second.FileName << ":" << LineKV.second.Line << ":"
62 << LineKV.second.Column << " (" << LineKV.second.FunctionName
63 << ")\n";
64 }
65 }
4766 }
67
68 if (ProtectedCount || UnprotectedCount)
69 outs() << formatv(
70 "Unprotected: {0} ({1:P}), Protected: {2} ({3:P})\n", UnprotectedCount,
71 (((double)UnprotectedCount) / (UnprotectedCount + ProtectedCount)),
72 ProtectedCount,
73 (((double)ProtectedCount) / (UnprotectedCount + ProtectedCount)));
74 else
75 outs() << "No indirect CF instructions found.\n";
4876 }
4977
5078 int main(int argc, char **argv) {
51 cl::ParseCommandLineOptions(argc, argv);
79 cl::ParseCommandLineOptions(
80 argc, argv,
81 "Identifies whether Control Flow Integrity protects all indirect control "
82 "flow instructions in the provided object file, DSO or binary.\nNote: "
83 "Anything statically linked into the provided file *must* be compiled "
84 "with '-g'. This can be relaxed through the '--ignore-dwarf' flag.");
5285
5386 InitializeAllTargetInfos();
5487 InitializeAllTargetMCs();
5588 InitializeAllAsmParsers();
5689 InitializeAllDisassemblers();
5790
58 FileAnalysis Verifier = ExitOnErr(FileAnalysis::Create(InputFilename));
59 printIndirectCFInstructions(Verifier);
91 FileAnalysis Analysis = ExitOnErr(FileAnalysis::Create(InputFilename));
92 printIndirectCFInstructions(Analysis);
6093
6194 return EXIT_SUCCESS;
6295 }