--- /dev/null
+# 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,@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,@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,@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,@function
+.L.cfi.jumptable:
+.Lfunc_begin3:
+ .cfi_startproc
+ #APP
+ jmp _Z1av.cfi@PLT
+ int3
+ int3
+ int3
+ jmp _Z1bv.cfi@PLT
+ int3
+ int3
+ int3
+
+ #NO_APP
+.Lfunc_end3:
+ .size .L.cfi.jumptable, .Lfunc_end3-.L.cfi.jumptable
+ .cfi_endproc
+
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 6.0.0 (trunk 316774)"
+.Linfo_string1:
+ .asciz "tiny.cc"
+.Linfo_string2:
+ .asciz ""
+ .section .debug_abbrev,"",@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,"",@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,"",@progbits
+ .section .debug_macinfo,"",@progbits
+.Lcu_macro_begin0:
+ .byte 0
+
+ .type _Z1av,@function
+_Z1av = .L.cfi.jumptable
+ .type _Z1bv,@function
+_Z1bv = .L.cfi.jumptable+8
+ .ident "clang version 6.0.0 (trunk 316774)"
+ .section ".note.GNU-stack","",@progbits
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
+
--- /dev/null
+# 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++ -g tiny.cc -S -o tiny.s
+
+ .text
+ .file "tiny.cc"
+ .globl _Z1av # -- Begin function _Z1av
+ .p2align 4, 0x90
+ .type _Z1av,@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
+ .cfi_def_cfa %rsp, 8
+ retq
+.Ltmp1:
+.Lfunc_end0:
+ .size _Z1av, .Lfunc_end0-_Z1av
+ .cfi_endproc
+ # -- End function
+ .globl _Z1bv # -- Begin function _Z1bv
+ .p2align 4, 0x90
+ .type _Z1bv,@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
+ .cfi_def_cfa %rsp, 8
+ retq
+.Ltmp3:
+.Lfunc_end1:
+ .size _Z1bv, .Lfunc_end1-_Z1bv
+ .cfi_endproc
+ # -- End function
+ .globl main # -- Begin function main
+ .p2align 4, 0x90
+ .type main,@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)
+.Ltmp5:
+ .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
+.Ltmp6:
+ .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)
+.Ltmp7:
+.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
+ .cfi_def_cfa %rsp, 8
+ retq
+.Ltmp8:
+.Lfunc_end2:
+ .size main, .Lfunc_end2-main
+ .cfi_endproc
+ # -- End function
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 6.0.0 (trunk 317104)" # string offset=0
+.Linfo_string1:
+ .asciz "tiny.cc" # string offset=35
+.Linfo_string2:
+ .asciz "/tmp/a/b" # string offset=43
+.Linfo_string3:
+ .asciz "_Z1av" # string offset=52
+.Linfo_string4:
+ .asciz "a" # string offset=58
+.Linfo_string5:
+ .asciz "_Z1bv" # string offset=60
+.Linfo_string6:
+ .asciz "b" # string offset=66
+.Linfo_string7:
+ .asciz "main" # string offset=68
+.Linfo_string8:
+ .asciz "int" # string offset=73
+.Linfo_string9:
+ .asciz "argc" # string offset=77
+.Linfo_string10:
+ .asciz "argv" # string offset=82
+.Linfo_string11:
+ .asciz "char" # string offset=87
+.Linfo_string12:
+ .asciz "ptr" # string offset=92
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .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
+ .ascii "\264B" # DW_AT_GNU_pubnames
+ .byte 25 # DW_FORM_flag_present
+ .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 2 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 0 # DW_CHILDREN_no
+ .byte 17 # DW_AT_low_pc
+ .byte 1 # DW_FORM_addr
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 110 # DW_AT_linkage_name
+ .byte 14 # DW_FORM_strp
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 1 # DW_FORM_addr
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 6 # Abbreviation Code
+ .byte 36 # DW_TAG_base_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 62 # DW_AT_encoding
+ .byte 11 # DW_FORM_data1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 7 # Abbreviation Code
+ .byte 15 # DW_TAG_pointer_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 8 # Abbreviation Code
+ .byte 21 # DW_TAG_subroutine_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long 187 # 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:0xb4 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
+ # DW_AT_GNU_pubnames
+ .quad .Lfunc_begin0 # DW_AT_low_pc
+ .long .Lfunc_end2-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 2 # Abbrev [2] 0x2a:0x19 DW_TAG_subprogram
+ .quad .Lfunc_begin0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .long .Linfo_string3 # DW_AT_linkage_name
+ .long .Linfo_string4 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ # DW_AT_external
+ .byte 2 # Abbrev [2] 0x43:0x19 DW_TAG_subprogram
+ .quad .Lfunc_begin1 # DW_AT_low_pc
+ .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .long .Linfo_string5 # DW_AT_linkage_name
+ .long .Linfo_string6 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 2 # DW_AT_decl_line
+ # DW_AT_external
+ .byte 3 # Abbrev [3] 0x5c:0x44 DW_TAG_subprogram
+ .quad .Lfunc_begin2 # DW_AT_low_pc
+ .long .Lfunc_end2-.Lfunc_begin2 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .long .Linfo_string7 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 4 # DW_AT_decl_line
+ .long 160 # DW_AT_type
+ # DW_AT_external
+ .byte 4 # Abbrev [4] 0x75:0xe DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 120
+ .long .Linfo_string9 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 4 # DW_AT_decl_line
+ .long 160 # DW_AT_type
+ .byte 4 # Abbrev [4] 0x83:0xe DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 112
+ .long .Linfo_string10 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 4 # DW_AT_decl_line
+ .long 167 # DW_AT_type
+ .byte 5 # Abbrev [5] 0x91:0xe DW_TAG_variable
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 104
+ .long .Linfo_string12 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 5 # DW_AT_decl_line
+ .long 184 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 6 # Abbrev [6] 0xa0:0x7 DW_TAG_base_type
+ .long .Linfo_string8 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 7 # Abbrev [7] 0xa7:0x5 DW_TAG_pointer_type
+ .long 172 # DW_AT_type
+ .byte 7 # Abbrev [7] 0xac:0x5 DW_TAG_pointer_type
+ .long 177 # DW_AT_type
+ .byte 6 # Abbrev [6] 0xb1:0x7 DW_TAG_base_type
+ .long .Linfo_string11 # DW_AT_name
+ .byte 6 # DW_AT_encoding
+ .byte 1 # DW_AT_byte_size
+ .byte 7 # Abbrev [7] 0xb8:0x5 DW_TAG_pointer_type
+ .long 189 # DW_AT_type
+ .byte 8 # Abbrev [8] 0xbd:0x1 DW_TAG_subroutine_type
+ .byte 0 # End Of Children Mark
+ .section .debug_ranges,"",@progbits
+ .section .debug_macinfo,"",@progbits
+.Lcu_macro_begin0:
+ .byte 0 # End Of Macro List Mark
+ .section .debug_pubnames,"",@progbits
+ .long .LpubNames_end0-.LpubNames_begin0 # Length of Public Names Info
+.LpubNames_begin0:
+ .short 2 # DWARF Version
+ .long .Lcu_begin0 # Offset of Compilation Unit Info
+ .long 191 # Compilation Unit Length
+ .long 42 # DIE offset
+ .asciz "a" # External Name
+ .long 67 # DIE offset
+ .asciz "b" # External Name
+ .long 92 # DIE offset
+ .asciz "main" # External Name
+ .long 0 # End Mark
+.LpubNames_end0:
+ .section .debug_pubtypes,"",@progbits
+ .long .LpubTypes_end0-.LpubTypes_begin0 # Length of Public Types Info
+.LpubTypes_begin0:
+ .short 2 # DWARF Version
+ .long .Lcu_begin0 # Offset of Compilation Unit Info
+ .long 191 # Compilation Unit Length
+ .long 160 # DIE offset
+ .asciz "int" # External Name
+ .long 177 # DIE offset
+ .asciz "char" # External Name
+ .long 0 # End Mark
+.LpubTypes_end0:
+
+ .ident "clang version 6.0.0 (trunk 317104)"
+ .section ".note.GNU-stack","",@progbits
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
--- /dev/null
+# 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,@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,@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,@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",@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,"",@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,"",@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,"",@progbits
+ .section .debug_macinfo,"",@progbits
+.Lcu_macro_begin0:
+ .byte 0 # End Of Macro List Mark
+
+ .ident "clang version 6.0.0 (trunk 316774)"
+ .section ".note.GNU-stack","",@progbits
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
--- /dev/null
+# 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,@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,@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,@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","",@progbits
--- /dev/null
+# RUN: llvm-mc %S/Inputs/unprotected-lineinfo.s -filetype obj \
+# RUN: -triple x86_64-linux-elf -o %t.o
+# RUN: echo "src:*tiny*" > %t.blacklist.txt
+# RUN: llvm-cfi-verify %t.o %t.blacklist.txt | FileCheck %s
+
+# CHECK-LABEL: U
+# CHECK-NEXT: tiny.cc:11
+# CHECK-NEXT: BLACKLIST MATCH, 'src'
+# CHECK-NEXT: ====> Expected Unprotected
+
+# CHECK: Expected Protected: 0 (0.00%)
+# CHECK: Unexpected Protected: 0 (0.00%)
+# CHECK: Expected Unprotected: 1 (100.00%)
+# CHECK: Unexpected Unprotected (BAD): 0 (0.00%)
+
+# Source: (blacklist.txt):
+# src:*tiny*
--- /dev/null
+# RUN: llvm-mc %S/Inputs/unprotected-fullinfo.s -filetype obj \
+# RUN: -triple x86_64-linux-elf -o %t.o
+# RUN: echo "fun:*main*" > %t.blacklist.txt
+# RUN: llvm-cfi-verify %t.o %t.blacklist.txt | FileCheck %s
+
+# CHECK-LABEL: U
+# CHECK-NEXT: tiny.cc:11
+# CHECK-NEXT: BLACKLIST MATCH, 'fun'
+# CHECK-NEXT: ====> Expected Unprotected
+
+# CHECK: Expected Protected: 0 (0.00%)
+# CHECK: Unexpected Protected: 0 (0.00%)
+# CHECK: Expected Unprotected: 1 (100.00%)
+# CHECK: Unexpected Unprotected (BAD): 0 (0.00%)
+
+# Source: (blacklist.txt):
+# fun:*main*
--- /dev/null
+# RUN: llvm-mc %S/Inputs/protected-lineinfo.s -filetype obj \
+# RUN: -triple x86_64-linux-elf -o %t.o
+# RUN: echo "src:*tiny*" > %t.blacklist.txt
+# RUN: llvm-cfi-verify %t.o %t.blacklist.txt | FileCheck %s
+
+# CHECK-LABEL: P
+# CHECK-NEXT: tiny.cc:11
+# CHECK-NEXT: BLACKLIST MATCH, 'src'
+# CHECK-NEXT: ====> Unexpected Protected
+
+# CHECK: Expected Protected: 0 (0.00%)
+# CHECK: Unexpected Protected: 1 (100.00%)
+# CHECK: Expected Unprotected: 0 (0.00%)
+# CHECK: Unexpected Unprotected (BAD): 0 (0.00%)
+
+# Source: (blacklist.txt):
+# src:*tiny*
# 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%)
+# CHECK: Expected Protected: 1 (100.00%)
+# CHECK: Unexpected Protected: 0 (0.00%)
+# CHECK: Expected Unprotected: 0 (0.00%)
+# CHECK: Unexpected Unprotected (BAD): 0 (0.00%)
.text
.file "ld-temp.o"
-# RUN: llvm-mc %s -filetype obj -triple x86_64-linux-elf -o %t.o
+# RUN: llvm-mc %S/Inputs/protected-lineinfo.s -filetype obj \
+# RUN: -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,@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,@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,@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,@function
-.L.cfi.jumptable:
-.Lfunc_begin3:
- .cfi_startproc
- #APP
- jmp _Z1av.cfi@PLT
- int3
- int3
- int3
- jmp _Z1bv.cfi@PLT
- int3
- int3
- int3
-
- #NO_APP
-.Lfunc_end3:
- .size .L.cfi.jumptable, .Lfunc_end3-.L.cfi.jumptable
- .cfi_endproc
-
- .section .debug_str,"MS",@progbits,1
-.Linfo_string0:
- .asciz "clang version 6.0.0 (trunk 316774)"
-.Linfo_string1:
- .asciz "tiny.cc"
-.Linfo_string2:
- .asciz ""
- .section .debug_abbrev,"",@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,"",@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,"",@progbits
- .section .debug_macinfo,"",@progbits
-.Lcu_macro_begin0:
- .byte 0
-
- .type _Z1av,@function
-_Z1av = .L.cfi.jumptable
- .type _Z1bv,@function
-_Z1bv = .L.cfi.jumptable+8
- .ident "clang version 6.0.0 (trunk 316774)"
- .section ".note.GNU-stack","",@progbits
- .section .debug_line,"",@progbits
-.Lline_table_start0:
-
+# CHECK: Expected Protected: 1 (100.00%)
+# CHECK: Unexpected Protected: 0 (0.00%)
+# CHECK: Expected Unprotected: 0 (0.00%)
+# CHECK: Unexpected Unprotected (BAD): 0 (0.00%)
-# RUN: llvm-mc %s -filetype obj -triple x86_64-linux-elf -o %t.o
+# RUN: llvm-mc %S/Inputs/unprotected-lineinfo.s -filetype obj \
+# RUN: -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,@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,@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,@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",@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,"",@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,"",@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,"",@progbits
- .section .debug_macinfo,"",@progbits
-.Lcu_macro_begin0:
- .byte 0 # End Of Macro List Mark
-
- .ident "clang version 6.0.0 (trunk 316774)"
- .section ".note.GNU-stack","",@progbits
- .section .debug_line,"",@progbits
-.Lline_table_start0:
+# CHECK: Expected Protected: 0 (0.00%)
+# CHECK: Unexpected Protected: 0 (0.00%)
+# CHECK: Expected Unprotected: 0 (0.00%)
+# CHECK: Unexpected Unprotected (BAD): 1 (100.00%)
-# RUN: llvm-mc %s -filetype obj -triple x86_64-linux-elf -o %t.o
+# RUN: llvm-mc %S/Inputs/unprotected-nolineinfo.s -filetype obj \
+# RUN: -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,@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,@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,@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","",@progbits
AllTargetsDescs
AllTargetsDisassemblers
AllTargetsInfos
- DebugInfoDWARF
MC
MCParser
Object
Support
+ Symbolize
)
add_llvm_tool(llvm-cfi-verify
type = Tool
name = llvm-cfi-verify
parent = Tools
-required_libraries = all-targets DebugInfoDWARF MC MCDisassembler MCParser Support
+required_libraries = all-targets MC MCDisassembler MCParser Support Symbolize
MC
MCParser
Object
- Support)
+ Support
+ Symbolize)
target_link_libraries(LLVMCFIVerify ${libs})
#include <functional>
using Instr = llvm::cfi_verify::FileAnalysis::Instr;
+using LLVMSymbolizer = llvm::symbolize::LLVMSymbolizer;
namespace llvm {
namespace cfi_verify {
-static cl::opt<bool> IgnoreDWARF(
+bool IgnoreDWARFFlag;
+
+static cl::opt<bool, true> IgnoreDWARFArg(
"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));
+ cl::location(IgnoreDWARFFlag), cl::init(false));
Expected<FileAnalysis> FileAnalysis::Create(StringRef Filename) {
// Open the filename provided.
return MIA.get();
}
+LLVMSymbolizer &FileAnalysis::getSymbolizer() { return *Symbolizer; }
+
Error FileAnalysis::initialiseDisassemblyMembers() {
std::string TripleName = ObjectTriple.getTriple();
ArchName = "";
MCPU = "";
std::string ErrorString;
+ Symbolizer.reset(new LLVMSymbolizer());
+
ObjectTarget =
TargetRegistry::lookupTarget(ArchName, ObjectTriple, ErrorString);
if (!ObjectTarget)
}
Error FileAnalysis::parseCodeSections() {
- if (!IgnoreDWARF) {
- DWARF.reset(DWARFContext::create(*Object).release());
+ if (!IgnoreDWARFFlag) {
+ std::unique_ptr<DWARFContext> DWARF = DWARFContext::create(*Object);
if (!DWARF)
return make_error<StringError>("Could not create DWARF information.",
inconvertibleErrorCode());
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) {
+ assert(Symbolizer && "Symbolizer is uninitialised.");
MCInst Instruction;
Instr InstrMeta;
uint64_t InstructionSize;
InstrMeta.Valid = ValidInstruction;
// Check if this instruction exists in the range of the DWARF metadata.
- if (hasLineTableInfo() && !hasValidLineInfoForAddressRange(VMAddress))
- continue;
+ if (!IgnoreDWARFFlag) {
+ auto LineInfo =
+ Symbolizer->symbolizeCode(Object->getFileName(), VMAddress);
+ if (!LineInfo) {
+ handleAllErrors(LineInfo.takeError(), [](const ErrorInfoBase &E) {
+ errs() << "Symbolizer failed to get line: " << E.message() << "\n";
+ });
+ continue;
+ }
+
+ if (LineInfo->FileName == "<invalid>")
+ continue;
+ }
addInstruction(InstrMeta);
#include "llvm/ADT/DenseMap.h"
#include "llvm/BinaryFormat/ELF.h"
-#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/Symbolize/Symbolize.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
namespace llvm {
namespace cfi_verify {
+extern bool IgnoreDWARFFlag;
+
// Disassembler and analysis tool for machine code files. Keeps track of non-
// sequential control flows, including indirect control flow instructions.
class FileAnalysis {
const MCRegisterInfo *getRegisterInfo() const;
const MCInstrInfo *getMCInstrInfo() const;
const MCInstrAnalysis *getMCInstrAnalysis() const;
+ symbolize::LLVMSymbolizer &getSymbolizer();
// Returns true if this class is using DWARF line tables for elimination.
bool hasLineTableInfo() const;
std::unique_ptr<const MCInstrAnalysis> MIA;
std::unique_ptr<MCInstPrinter> Printer;
- // DWARF debug information.
- std::unique_ptr<DWARFContext> DWARF;
+ // Symbolizer used for debug information parsing.
+ std::unique_ptr<symbolize::LLVMSymbolizer> Symbolizer;
// A mapping between the virtual memory address to the instruction metadata
// struct. TODO(hctim): Reimplement this as a sorted vector to avoid per-
type = Library
name = CFIVerify
parent = Libraries
-required_libraries = DebugInfoDWARF MC MCDisassembler MCParser Support
+required_libraries = DebugInfoDWARF MC MCDisassembler MCParser Support Symbolize
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/SpecialCaseList.h"
#include <cstdlib>
cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input file>"),
cl::Required);
+cl::opt<std::string> BlacklistFilename(cl::Positional,
+ cl::desc("[blacklist file]"),
+ cl::init("-"));
ExitOnError ExitOnErr;
-void printIndirectCFInstructions(FileAnalysis &Analysis) {
- uint64_t ProtectedCount = 0;
- uint64_t UnprotectedCount = 0;
+void printIndirectCFInstructions(FileAnalysis &Analysis,
+ const SpecialCaseList *SpecialCaseList) {
+ uint64_t ExpectedProtected = 0;
+ uint64_t UnexpectedProtected = 0;
+ uint64_t ExpectedUnprotected = 0;
+ uint64_t UnexpectedUnprotected = 0;
+
+ symbolize::LLVMSymbolizer &Symbolizer = Analysis.getSymbolizer();
for (uint64_t Address : Analysis.getIndirectInstructions()) {
const auto &InstrMeta = Analysis.getInstructionOrDie(Address);
- if (Analysis.isIndirectInstructionCFIProtected(Address)) {
+ bool CFIProtected = Analysis.isIndirectInstructionCFIProtected(Address);
+
+ if (CFIProtected)
outs() << "P ";
- ProtectedCount++;
- } else {
+ else
outs() << "U ";
- UnprotectedCount++;
- }
outs() << format_hex(Address, 2) << " | "
<< Analysis.getMCInstrInfo()->getName(
InstrMeta.Instruction.getOpcode())
- << " ";
- outs() << "\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";
+ << " \n";
+
+ if (IgnoreDWARFFlag) {
+ if (CFIProtected)
+ ExpectedProtected++;
+ else
+ UnexpectedUnprotected++;
+ continue;
+ }
+
+ auto InliningInfo = Symbolizer.symbolizeInlinedCode(InputFilename, Address);
+ if (!InliningInfo || InliningInfo->getNumberOfFrames() == 0) {
+ errs() << "Failed to symbolise " << format_hex(Address, 2)
+ << " with line tables from " << InputFilename << "\n";
+ exit(EXIT_FAILURE);
+ }
+
+ const auto &LineInfo =
+ InliningInfo->getFrame(InliningInfo->getNumberOfFrames() - 1);
+
+ // Print the inlining symbolisation of this instruction.
+ for (uint32_t i = 0; i < InliningInfo->getNumberOfFrames(); ++i) {
+ const auto &Line = InliningInfo->getFrame(i);
+ outs() << " " << format_hex(Address, 2) << " = " << Line.FileName << ":"
+ << Line.Line << ":" << Line.Column << " (" << Line.FunctionName
+ << ")\n";
+ }
+
+ if (!SpecialCaseList) {
+ if (CFIProtected)
+ ExpectedProtected++;
+ else
+ UnexpectedUnprotected++;
+ continue;
+ }
+
+ bool MatchesBlacklistRule = false;
+ if (SpecialCaseList->inSection("cfi-icall", "src", LineInfo.FileName) ||
+ SpecialCaseList->inSection("cfi-vcall", "src", LineInfo.FileName)) {
+ outs() << "BLACKLIST MATCH, 'src'\n";
+ MatchesBlacklistRule = true;
+ }
+
+ if (SpecialCaseList->inSection("cfi-icall", "fun", LineInfo.FunctionName) ||
+ SpecialCaseList->inSection("cfi-vcall", "fun", LineInfo.FunctionName)) {
+ outs() << "BLACKLIST MATCH, 'fun'\n";
+ MatchesBlacklistRule = true;
+ }
+
+ if (MatchesBlacklistRule) {
+ if (CFIProtected) {
+ UnexpectedProtected++;
+ outs() << "====> Unexpected Protected\n";
+ } else {
+ ExpectedUnprotected++;
+ outs() << "====> Expected Unprotected\n";
+ }
+ } else {
+ if (CFIProtected) {
+ ExpectedProtected++;
+ outs() << "====> Expected Protected\n";
+ } else {
+ UnexpectedUnprotected++;
+ outs() << "====> Unexpected Unprotected\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
+ uint64_t IndirectCFInstructions = ExpectedProtected + UnexpectedProtected +
+ ExpectedUnprotected + UnexpectedUnprotected;
+
+ if (IndirectCFInstructions == 0)
outs() << "No indirect CF instructions found.\n";
+
+ outs() << formatv("Expected Protected: {0} ({1:P})\n"
+ "Unexpected Protected: {2} ({3:P})\n"
+ "Expected Unprotected: {4} ({5:P})\n"
+ "Unexpected Unprotected (BAD): {6} ({7:P})\n",
+ ExpectedProtected,
+ ((double)ExpectedProtected) / IndirectCFInstructions,
+ UnexpectedProtected,
+ ((double)UnexpectedProtected) / IndirectCFInstructions,
+ ExpectedUnprotected,
+ ((double)ExpectedUnprotected) / IndirectCFInstructions,
+ UnexpectedUnprotected,
+ ((double)UnexpectedUnprotected) / IndirectCFInstructions);
}
int main(int argc, char **argv) {
InitializeAllAsmParsers();
InitializeAllDisassemblers();
+ std::unique_ptr<SpecialCaseList> SpecialCaseList;
+ if (BlacklistFilename != "-") {
+ std::string Error;
+ SpecialCaseList = SpecialCaseList::create({BlacklistFilename}, Error);
+ if (!SpecialCaseList) {
+ errs() << "Failed to get blacklist: " << Error << "\n";
+ exit(EXIT_FAILURE);
+ }
+ }
+
FileAnalysis Analysis = ExitOnErr(FileAnalysis::Create(InputFilename));
- printIndirectCFInstructions(Analysis);
+ printIndirectCFInstructions(Analysis, SpecialCaseList.get());
return EXIT_SUCCESS;
}
MCParser
Object
Support
+ Symbolize
)
add_llvm_unittest(CFIVerifyTests
class BasicFileAnalysisTest : public ::testing::Test {
protected:
virtual void SetUp() {
+ IgnoreDWARFFlag = true;
SuccessfullyInitialised = true;
if (auto Err = Analysis.initialiseDisassemblyMembers()) {
handleAllErrors(std::move(Err), [&](const UnsupportedDisassembly &E) {
class BasicGraphBuilderTest : public ::testing::Test {
protected:
virtual void SetUp() {
+ IgnoreDWARFFlag = true;
SuccessfullyInitialised = true;
if (auto Err = Analysis.initialiseDisassemblyMembers()) {
handleAllErrors(std::move(Err), [&](const UnsupportedDisassembly &E) {