diff --git a/llvm/test/tools/llvm-readobj/ELF/file-headers.test b/llvm/test/tools/llvm-readobj/ELF/file-headers.test --- a/llvm/test/tools/llvm-readobj/ELF/file-headers.test +++ b/llvm/test/tools/llvm-readobj/ELF/file-headers.test @@ -147,6 +147,9 @@ # RUN: not llvm-readelf --file-headers %t.invalid1 2>&1 \ # RUN: | FileCheck %s --implicit-check-not=warning: -DFILE=%t.invalid1 \ # RUN: -DSECHDRCOUNT=8192 -DSECHDRSTRTABINDEX=12288 --check-prefix=INVALID-GNU +# RUN: not llvm-readelf --elf-output-style=JSON --file-headers %t.invalid1 2>&1 \ +# RUN: | FileCheck %s --implicit-check-not=warning: -DFILE=%t.invalid1 \ +# RUN: -DSECHDRCOUNT=8192 -DSECHDRSTRTABINDEX=12288 --check-prefix=INVALID-JSON # INVALID-LLVM: File: [[FILE]] # INVALID-LLVM-NEXT: Format: elf64-unknown @@ -202,6 +205,45 @@ # INVALID-GNU-NEXT: Section header string table index: [[SECHDRSTRTABINDEX]] # INVALID-GNU-NEXT: error: '[[FILE]]': unable to continue dumping, the file is corrupt: section header table goes past the end of the file: e_shoff = 0x1000 +# INVALID-JSON: { +# INVALID-JSON-NEXT: "ElfHeader": { +# INVALID-JSON-NEXT: "Ident": { +# INVALID-JSON-NEXT: "Magic": [ +# INVALID-JSON-NEXT: "7F", +# INVALID-JSON-NEXT: "45", +# INVALID-JSON-NEXT: "4C", +# INVALID-JSON-NEXT: "46" +# INVALID-JSON-NEXT: ], +# INVALID-JSON-NEXT: "Class": "ELF64", +# INVALID-JSON-NEXT: "DataEncoding": "2's complement, little endian", +# INVALID-JSON-NEXT: "FileVersion": 1, +# INVALID-JSON-NEXT: "OS/ABI": "UNIX - System V", +# INVALID-JSON-NEXT: "ABIVersion": 0, +# INVALID-JSON-NEXT: "Unused": [ +# INVALID-JSON-NEXT: "0", +# INVALID-JSON-NEXT: "0", +# INVALID-JSON-NEXT: "0", +# INVALID-JSON-NEXT: "0", +# INVALID-JSON-NEXT: "0", +# INVALID-JSON-NEXT: "0", +# INVALID-JSON-NEXT: "0" +# INVALID-JSON-NEXT: ] +# INVALID-JSON-NEXT: }, +# INVALID-JSON-NEXT: "Type": "Relocatable", +# INVALID-JSON-NEXT: "Machine": "None", +# INVALID-JSON-NEXT: "Version": "0x1", +# INVALID-JSON-NEXT: "Entry": "0", +# INVALID-JSON-NEXT: "ProgramHeaderOffset": "0", +# INVALID-JSON-NEXT: "SectionHeaderOffset": "4096", +# INVALID-JSON-NEXT: "FlagsRaw": "0x0", +# INVALID-JSON-NEXT: "HeaderSize": "64", +# INVALID-JSON-NEXT: "ProgramHeaderEntrySize": "0", +# INVALID-JSON-NEXT: "ProgramHeaderCount": "0", +# INVALID-JSON-NEXT: "SectionHeaderEntrySize": "64", +# INVALID-JSON-NEXT: "SectionHeaderCount": "[[SECHDRCOUNT]]", +# INVALID-JSON-NEXT: "StringTableSectionIndex": "[[SECHDRSTRTABINDEX]]" +# INVALID-JSON-NEXT: error: '[[FILE]]': unable to continue dumping, the file is corrupt: section header table goes past the end of the file: e_shoff = 0x1000 + --- !ELF FileHeader: Class: ELFCLASS64 @@ -225,6 +267,8 @@ # RUN: | FileCheck %s -DFILE=%t.invalid1 -DSECHDRCOUNT=8192 -DSECHDRSTRTABINDEX=12288 --check-prefix=INVALID-LLVM # RUN: not llvm-readelf -a %t.invalid1 2>&1 \ # RUN: | FileCheck %s -DFILE=%t.invalid1 -DSECHDRCOUNT=8192 -DSECHDRSTRTABINDEX=12288 --check-prefix=INVALID-GNU +# RUN: not llvm-readelf --elf-output-style=JSON -a %t.invalid1 2>&1 \ +# RUN: | FileCheck %s -DFILE=%t.invalid1 -DSECHDRCOUNT=8192 -DSECHDRSTRTABINDEX=12288 --check-prefix=INVALID-JSON ## Check what we print when e_shnum == 0, e_shstrndx == SHN_XINDEX and the section header table can't be read. @@ -233,3 +277,5 @@ # RUN: | FileCheck %s -DFILE=%t.invalid2 -DSECHDRCOUNT="" -DSECHDRSTRTABINDEX="" --check-prefix=INVALID-LLVM # RUN: not llvm-readelf --file-headers %t.invalid2 2>&1 \ # RUN: | FileCheck %s -DFILE=%t.invalid2 -DSECHDRCOUNT="" -DSECHDRSTRTABINDEX="" --check-prefix=INVALID-GNU +# RUN: not llvm-readelf --elf-output-style=JSON --file-headers %t.invalid2 2>&1 \ +# RUN: | FileCheck %s -DFILE=%t.invalid2 -DSECHDRCOUNT="" -DSECHDRSTRTABINDEX="" --check-prefix=INVALID-JSON diff --git a/llvm/test/tools/llvm-readobj/ELF/groups.test b/llvm/test/tools/llvm-readobj/ELF/groups.test --- a/llvm/test/tools/llvm-readobj/ELF/groups.test +++ b/llvm/test/tools/llvm-readobj/ELF/groups.test @@ -5,6 +5,7 @@ # RUN: llvm-readobj -g %t.o | FileCheck %s # RUN: llvm-readobj --elf-section-groups %t.o | FileCheck %s # RUN: llvm-readelf -g %t.o | FileCheck --check-prefix=GNU %s +# RUN: llvm-readelf --elf-output-style=JSON -g %t.o | FileCheck --check-prefix=JSON %s # CHECK: Groups { # CHECK-NEXT: Group { @@ -41,6 +42,49 @@ # GNU-NEXT: [ 5] .text.bar # GNU-NEXT: [ 6] .rela.text.bar +# JSON: "Groups": [ +# JSON-NEXT: { +# JSON-NEXT: "Group": { +# JSON-NEXT: "Name": ".group", +# JSON-NEXT: "Index": "1", +# JSON-NEXT: "Link": 7, +# JSON-NEXT: "Info": 1, +# JSON-NEXT: "Type": "COMDAT", +# JSON-NEXT: "Signature": "foo", +# JSON-NEXT: "SectionsInGroup": [ +# JSON-NEXT: { +# JSON-NEXT: "Name": ".text.foo", +# JSON-NEXT: "Index": "3" +# JSON-NEXT: }, +# JSON-NEXT: { +# JSON-NEXT: "Name": ".rela.text.foo", +# JSON-NEXT: "Index": "4" +# JSON-NEXT: } +# JSON-NEXT: ] +# JSON-NEXT: } +# JSON-NEXT: }, +# JSON-NEXT: { +# JSON-NEXT: "Group": { +# JSON-NEXT: "Name": ".group1", +# JSON-NEXT: "Index": "2", +# JSON-NEXT: "Link": 7, +# JSON-NEXT: "Info": 2, +# JSON-NEXT: "Type": "COMDAT", +# JSON-NEXT: "Signature": "bar", +# JSON-NEXT: "SectionsInGroup": [ +# JSON-NEXT: { +# JSON-NEXT: "Name": ".text.bar", +# JSON-NEXT: "Index": "5" +# JSON-NEXT: }, +# JSON-NEXT: { +# JSON-NEXT: "Name": ".rela.text.bar", +# JSON-NEXT: "Index": "6" +# JSON-NEXT: } +# JSON-NEXT: ] +# JSON-NEXT: } +# JSON-NEXT: } +# JSON-NEXT: ] + --- !ELF FileHeader: Class: ELFCLASS64 @@ -99,6 +143,7 @@ # RUN: yaml2obj %s -DMEMBER2=.text.foo -o %t.dup.o # RUN: llvm-readobj --section-groups %t.dup.o 2>&1 | FileCheck %s -DFILE=%t.dup.o --check-prefix=DUP-LLVM # RUN: llvm-readelf --section-groups %t.dup.o 2>&1 | FileCheck %s -DFILE=%t.dup.o --check-prefix=DUP-GNU +# RUN: llvm-readelf --elf-output-style=JSON --section-groups %t.dup.o 2>&1 | FileCheck %s -DFILE=%t.dup.o --check-prefix=DUP-JSON # DUP-LLVM: Group { # DUP-LLVM-NEXT: Name: .group @@ -137,6 +182,44 @@ # DUP-GNU-NEXT: [ 3] .text.foo # DUP-GNU-NEXT: [ 6] .rela.text.bar +# DUP-JSON: "Group": { +# DUP-JSON-NEXT: "Name": ".group", +# DUP-JSON-NEXT: "Index": "1", +# DUP-JSON-NEXT: "Link": 7, +# DUP-JSON-NEXT: "Info": 1, +# DUP-JSON-NEXT: "Type": "COMDAT", +# DUP-JSON-NEXT: "Signature": "foo", +# DUP-JSON-NEXT: "SectionsInGroup": [ +# DUP-JSON-NEXT: { +# DUP-JSON-NEXT: "Name": ".text.foo", +# DUP-JSON-NEXT: "Index": "3" +# DUP-JSON-NEXT: }, +# DUP-JSON-NEXT: { +# DUP-JSON-NEXT: "Name": ".rela.text.foo", +# DUP-JSON-NEXT: "Index": "4" +# DUP-JSON-NEXT: } +# DUP-JSON-NEXT: ] +# DUP-JSON-NEXT: } +# DUP-JSON: "Group": { +# DUP-JSON-NEXT: "Name": ".group1", +# DUP-JSON-NEXT: "Index": "2", +# DUP-JSON-NEXT: "Link": 7, +# DUP-JSON-NEXT: "Info": 2, +# DUP-JSON-NEXT: "Type": "COMDAT", +# DUP-JSON-NEXT: "Signature": "bar", +# DUP-JSON-NEXT: "SectionsInGroup": [ +# DUP-JSON-NEXT: warning: '[[FILE]]': section with index 3, included in the group section with index 1, was also found in the group section with index 2 +# DUP-JSON-EMPTY: +# DUP-JSON-NEXT: "Name": ".text.foo", +# DUP-JSON-NEXT: "Index": "3" +# DUP-JSON-NEXT: }, +# DUP-JSON-NEXT: { +# DUP-JSON-NEXT: "Name": ".rela.text.bar", +# DUP-JSON-NEXT: "Index": "6" +# DUP-JSON-NEXT: } +# DUP-JSON-NEXT: ] +# DUP-JSON-NEXT: } + ## Check what we do when we are unable to dump the signature symbol name. ## In this case the index of the string table section, linked to the symbol table used by a group section, ## is broken (section does not exist). @@ -147,6 +230,8 @@ # RUN: FileCheck -DFILE=%t.symtab.o %s --check-prefix=SYMTAB-LLVM --implicit-check-not=warning: # RUN: llvm-readelf --section-groups %t.symtab.o 2>&1 | \ # RUN: FileCheck -DFILE=%t.symtab.o %s --check-prefix=SYMTAB-GNU --implicit-check-not=warning: +# RUN: llvm-readelf --elf-output-style=JSON --section-groups %t.symtab.o 2>&1 | \ +# RUN: FileCheck -DFILE=%t.symtab.o %s --check-prefix=SYMTAB-JSON --implicit-check-not=warning: # SYMTAB-LLVM: Groups { # SYMTAB-LLVM-NEXT: warning: '[[FILE]]': unable to get the string table for SHT_SYMTAB section with index 7: invalid section index: 255 @@ -188,6 +273,44 @@ # SYMTAB-GNU-NEXT: [ 5] .text.bar # SYMTAB-GNU-NEXT: [ 6] .rela.text.bar +# SYMTAB-JSON: warning: '[[FILE]]': unable to get the string table for SHT_SYMTAB section with index 7: invalid section index: 255 +# SYMTAB-JSON: "Group": { +# SYMTAB-JSON-NEXT: "Name": ".group", +# SYMTAB-JSON-NEXT: "Index": "1", +# SYMTAB-JSON-NEXT: "Link": 7, +# SYMTAB-JSON-NEXT: "Info": 1, +# SYMTAB-JSON-NEXT: "Type": "COMDAT", +# SYMTAB-JSON-NEXT: "Signature": "", +# SYMTAB-JSON-NEXT: "SectionsInGroup": [ +# SYMTAB-JSON-NEXT: { +# SYMTAB-JSON-NEXT: "Name": ".text.foo", +# SYMTAB-JSON-NEXT: "Index": "3" +# SYMTAB-JSON-NEXT: }, +# SYMTAB-JSON-NEXT: { +# SYMTAB-JSON-NEXT: "Name": ".rela.text.foo", +# SYMTAB-JSON-NEXT: "Index": "4" +# SYMTAB-JSON-NEXT: } +# SYMTAB-JSON-NEXT: ] +# SYMTAB-JSON-NEXT: } +# SYMTAB-JSON: "Group": { +# SYMTAB-JSON-NEXT: "Name": ".group1", +# SYMTAB-JSON-NEXT: "Index": "2", +# SYMTAB-JSON-NEXT: "Link": 7, +# SYMTAB-JSON-NEXT: "Info": 2, +# SYMTAB-JSON-NEXT: "Type": "COMDAT", +# SYMTAB-JSON-NEXT: "Signature": "", +# SYMTAB-JSON-NEXT: "SectionsInGroup": [ +# SYMTAB-JSON-NEXT: { +# SYMTAB-JSON-NEXT: "Name": ".text.bar", +# SYMTAB-JSON-NEXT: "Index": "5" +# SYMTAB-JSON-NEXT: }, +# SYMTAB-JSON-NEXT: { +# SYMTAB-JSON-NEXT: "Name": ".rela.text.bar", +# SYMTAB-JSON-NEXT: "Index": "6" +# SYMTAB-JSON-NEXT: } +# SYMTAB-JSON-NEXT: ] +# SYMTAB-JSON-NEXT: } + ## This tests the behavior for two more cases when we are unable to dump the signature symbol name. ## In the first case we link the group section to the section with index 255, which does not exist. ## We check that a warning is reported when we are unable to locate the symbol table. @@ -200,6 +323,8 @@ # RUN: FileCheck -DFILE=%t.symtab2.o %s --check-prefix=SIGNATURE-LLVM --implicit-check-not=warning: # RUN: llvm-readelf --section-groups %t.symtab2.o 2>&1 | \ # RUN: FileCheck -DFILE=%t.symtab2.o %s --check-prefix=SIGNATURE-GNU --implicit-check-not=warning: +# RUN: llvm-readelf --elf-output-style=JSON --section-groups %t.symtab2.o 2>&1 | \ +# RUN: FileCheck -DFILE=%t.symtab2.o %s --check-prefix=SIGNATURE-JSON --implicit-check-not=warning: # SIGNATURE: Groups { # SIGNATURE-LLVM: warning: '[[FILE]]': unable to get the symbol table for SHT_GROUP section with index 1: invalid section index: 255 @@ -243,6 +368,45 @@ # SIGNATURE-GNU-NEXT: [ 5] .text.bar # SIGNATURE-GNU-NEXT: [ 6] .rela.text.bar +# SIGNATURE-JSON: warning: '[[FILE]]': unable to get the symbol table for SHT_GROUP section with index 1: invalid section index: 255 +# SIGNATURE-JSON-NEXT: warning: '[[FILE]]': unable to get the signature symbol for SHT_GROUP section with index 2: section [index 1] has invalid sh_entsize: expected 24, but got 4 +# SIGNATURE-JSON: "Group": { +# SIGNATURE-JSON-NEXT: "Name": ".group", +# SIGNATURE-JSON-NEXT: "Index": "1", +# SIGNATURE-JSON-NEXT: "Link": 255, +# SIGNATURE-JSON-NEXT: "Info": 1, +# SIGNATURE-JSON-NEXT: "Type": "COMDAT", +# SIGNATURE-JSON-NEXT: "Signature": "", +# SIGNATURE-JSON-NEXT: "SectionsInGroup": [ +# SIGNATURE-JSON-NEXT: { +# SIGNATURE-JSON-NEXT: "Name": ".text.foo", +# SIGNATURE-JSON-NEXT: "Index": "3" +# SIGNATURE-JSON-NEXT: }, +# SIGNATURE-JSON-NEXT: { +# SIGNATURE-JSON-NEXT: "Name": ".rela.text.foo", +# SIGNATURE-JSON-NEXT: "Index": "4" +# SIGNATURE-JSON-NEXT: } +# SIGNATURE-JSON-NEXT: ] +# SIGNATURE-JSON-NEXT: } +# SIGNATURE-JSON: "Group": { +# SIGNATURE-JSON-NEXT: "Name": ".group1", +# SIGNATURE-JSON-NEXT: "Index": "2", +# SIGNATURE-JSON-NEXT: "Link": 1, +# SIGNATURE-JSON-NEXT: "Info": 2, +# SIGNATURE-JSON-NEXT: "Type": "COMDAT", +# SIGNATURE-JSON-NEXT: "Signature": "", +# SIGNATURE-JSON-NEXT: "SectionsInGroup": [ +# SIGNATURE-JSON-NEXT: { +# SIGNATURE-JSON-NEXT: "Name": ".text.bar", +# SIGNATURE-JSON-NEXT: "Index": "5" +# SIGNATURE-JSON-NEXT: }, +# SIGNATURE-JSON-NEXT: { +# SIGNATURE-JSON-NEXT: "Name": ".rela.text.bar", +# SIGNATURE-JSON-NEXT: "Index": "6" +# SIGNATURE-JSON-NEXT: } +# SIGNATURE-JSON-NEXT: ] +# SIGNATURE-JSON-NEXT: } + ## Check we report a warning when the content of the group section is empty or can't be read. ## In both cases we are unable to read the section group flag and dump it as 0. @@ -251,6 +415,8 @@ # RUN: FileCheck -DFILE=%t.secsize.o %s --check-prefix=CONTENT-LLVM --implicit-check-not=warning: # RUN: llvm-readelf --section-groups %t.secsize.o 2>&1 | \ # RUN: FileCheck -DFILE=%t.secsize.o %s --check-prefix=CONTENT-GNU --implicit-check-not=warning: +# RUN: llvm-readelf --elf-output-style=JSON --section-groups %t.secsize.o 2>&1 | \ +# RUN: FileCheck -DFILE=%t.secsize.o %s --check-prefix=CONTENT-JSON --implicit-check-not=warning: # CONTENT-LLVM: Groups { # CONTENT-LLVM-NEXT: warning: '[[FILE]]': unable to read the section group flag from the SHT_GROUP section with index 1: the section is empty @@ -286,6 +452,27 @@ # CONTENT-GNU-NEXT: (unknown) group section [ 2] `.group1' [bar] contains 0 sections: # CONTENT-GNU-NEXT: [Index] Name +# CONTENT-JSON: warning: '[[FILE]]': unable to read the section group flag from the SHT_GROUP section with index 1: the section is empty +# CONTENT-JSON-NEXT: warning: '[[FILE]]': unable to get the content of the SHT_GROUP section with index 2: section [index 2] has an invalid sh_size (1) which is not a multiple of its sh_entsize (4) +# CONTENT-JSON: "Group": { +# CONTENT-JSON-NEXT: "Name": ".group", +# CONTENT-JSON-NEXT: "Index": "1", +# CONTENT-JSON-NEXT: "Link": 7, +# CONTENT-JSON-NEXT: "Info": 1, +# CONTENT-JSON-NEXT: "Type": "(unknown)", +# CONTENT-JSON-NEXT: "Signature": "foo", +# CONTENT-JSON-NEXT: "SectionsInGroup": [] +# CONTENT-JSON-NEXT: } +# CONTENT-JSON: "Group": { +# CONTENT-JSON-NEXT: "Name": ".group1", +# CONTENT-JSON-NEXT: "Index": "2", +# CONTENT-JSON-NEXT: "Link": 7, +# CONTENT-JSON-NEXT: "Info": 2, +# CONTENT-JSON-NEXT: "Type": "(unknown)", +# CONTENT-JSON-NEXT: "Signature": "bar", +# CONTENT-JSON-NEXT: "SectionsInGroup": [] +# CONTENT-JSON-NEXT: } + ## Check that we emit a warning when we are unable to read the group section name or the name of a member. # RUN: yaml2obj %s -DGROUP1SHNAME=0xAAAA -DTEXTBARSHNAME=0xBBBB -o %t.name.o @@ -293,6 +480,8 @@ # RUN: FileCheck -DFILE=%t.name.o %s --check-prefix=NAME-LLVM --implicit-check-not=warning: # RUN: llvm-readelf --section-groups %t.name.o 2>&1 | \ # RUN: FileCheck -DFILE=%t.name.o %s --check-prefix=NAME-GNU --implicit-check-not=warning: +# RUN: llvm-readelf --elf-output-style=JSON --section-groups %t.name.o 2>&1 | \ +# RUN: FileCheck -DFILE=%t.name.o %s --check-prefix=NAME-JSON --implicit-check-not=warning: # NAME-LLVM: Groups { # NAME-LLVM-NEXT: warning: '[[FILE]]': unable to get the name of SHT_GROUP section with index 1: a section [index 1] has an invalid sh_name (0xaaaa) offset which goes past the end of the section name string table @@ -336,6 +525,45 @@ # NAME-GNU-NEXT: [ 5] # NAME-GNU-NEXT: [ 6] .rela.text.bar +# NAME-JSON: warning: '[[FILE]]': unable to get the name of SHT_GROUP section with index 1: a section [index 1] has an invalid sh_name (0xaaaa) offset which goes past the end of the section name string table +# NAME-JSON-NEXT: warning: '[[FILE]]': unable to get the name of SHT_PROGBITS section with index 5: a section [index 5] has an invalid sh_name (0xbbbb) offset which goes past the end of the section name string table +# NAME-JSON: "Group": { +# NAME-JSON-NEXT: "Name": "", +# NAME-JSON-NEXT: "Index": "1", +# NAME-JSON-NEXT: "Link": 7, +# NAME-JSON-NEXT: "Info": 1, +# NAME-JSON-NEXT: "Type": "COMDAT", +# NAME-JSON-NEXT: "Signature": "foo", +# NAME-JSON-NEXT: "SectionsInGroup": [ +# NAME-JSON-NEXT: { +# NAME-JSON-NEXT: "Name": ".text.foo", +# NAME-JSON-NEXT: "Index": "3" +# NAME-JSON-NEXT: }, +# NAME-JSON-NEXT: { +# NAME-JSON-NEXT: "Name": ".rela.text.foo", +# NAME-JSON-NEXT: "Index": "4" +# NAME-JSON-NEXT: } +# NAME-JSON-NEXT: ] +# NAME-JSON-NEXT: } +# NAME-JSON: "Group": { +# NAME-JSON-NEXT: "Name": ".group1", +# NAME-JSON-NEXT: "Index": "2", +# NAME-JSON-NEXT: "Link": 7, +# NAME-JSON-NEXT: "Info": 2, +# NAME-JSON-NEXT: "Type": "COMDAT", +# NAME-JSON-NEXT: "Signature": "bar", +# NAME-JSON-NEXT: "SectionsInGroup": [ +# NAME-JSON-NEXT: { +# NAME-JSON-NEXT: "Name": "", +# NAME-JSON-NEXT: "Index": "5" +# NAME-JSON-NEXT: }, +# NAME-JSON-NEXT: { +# NAME-JSON-NEXT: "Name": ".rela.text.bar", +# NAME-JSON-NEXT: "Index": "6" +# NAME-JSON-NEXT: } +# NAME-JSON-NEXT: ] +# NAME-JSON-NEXT: } + ## Check we report a warning then the section index of a section group member is invalid. # RUN: yaml2obj %s -DMEMBER1=0xEE -DMEMBER2=0xFF -o %t.member.index.o @@ -343,6 +571,8 @@ # RUN: FileCheck -DFILE=%t.member.index.o %s --check-prefix=MEMBER-LLVM --implicit-check-not=warning: # RUN: llvm-readelf --section-groups %t.member.index.o 2>&1 | \ # RUN: FileCheck -DFILE=%t.member.index.o %s --check-prefix=MEMBER-GNU --implicit-check-not=warning: +# RUN: llvm-readelf --elf-output-style=JSON --section-groups %t.member.index.o 2>&1 | \ +# RUN: FileCheck -DFILE=%t.member.index.o %s --check-prefix=MEMBER-JSON --implicit-check-not=warning: # MEMBER-LLVM: Groups { # MEMBER-LLVM-NEXT: warning: '[[FILE]]': unable to get the section with index 238 when dumping the SHT_GROUP section with index 1: invalid section index: 238 @@ -386,6 +616,45 @@ # MEMBER-GNU-NEXT: [ 255] # MEMBER-GNU-NEXT: [ 6] .rela.text.bar +# MEMBER-JSON: warning: '[[FILE]]': unable to get the section with index 238 when dumping the SHT_GROUP section with index 1: invalid section index: 238 +# MEMBER-JSON-NEXT: warning: '[[FILE]]': unable to get the section with index 255 when dumping the SHT_GROUP section with index 2: invalid section index: 255 +# MEMBER-JSON: "Group": { +# MEMBER-JSON-NEXT: "Name": ".group", +# MEMBER-JSON-NEXT: "Index": "1", +# MEMBER-JSON-NEXT: "Link": 7, +# MEMBER-JSON-NEXT: "Info": 1, +# MEMBER-JSON-NEXT: "Type": "COMDAT", +# MEMBER-JSON-NEXT: "Signature": "foo", +# MEMBER-JSON-NEXT: "SectionsInGroup": [ +# MEMBER-JSON-NEXT: { +# MEMBER-JSON-NEXT: "Name": ".text.foo", +# MEMBER-JSON-NEXT: "Index": "3" +# MEMBER-JSON-NEXT: }, +# MEMBER-JSON-NEXT: { +# MEMBER-JSON-NEXT: "Name": "", +# MEMBER-JSON-NEXT: "Index": "238" +# MEMBER-JSON-NEXT: } +# MEMBER-JSON-NEXT: ] +# MEMBER-JSON-NEXT: } +# MEMBER-JSON: "Group": { +# MEMBER-JSON-NEXT: "Name": ".group1", +# MEMBER-JSON-NEXT: "Index": "2", +# MEMBER-JSON-NEXT: "Link": 7, +# MEMBER-JSON-NEXT: "Info": 2, +# MEMBER-JSON-NEXT: "Type": "COMDAT", +# MEMBER-JSON-NEXT: "Signature": "bar", +# MEMBER-JSON-NEXT: "SectionsInGroup": [ +# MEMBER-JSON-NEXT: { +# MEMBER-JSON-NEXT: "Name": "", +# MEMBER-JSON-NEXT: "Index": "255" +# MEMBER-JSON-NEXT: }, +# MEMBER-JSON-NEXT: { +# MEMBER-JSON-NEXT: "Name": ".rela.text.bar", +# MEMBER-JSON-NEXT: "Index": "6" +# MEMBER-JSON-NEXT: } +# MEMBER-JSON-NEXT: ] +# MEMBER-JSON-NEXT: } + ## Check warnings that are reported when the st_name field of the signature symbol goes past the end of the string table. ## We set the content of the string table to '0061626300' ('\0abc\0') to fixup the size of the string table. @@ -395,6 +664,8 @@ # RUN: FileCheck -DFILE=%t.signame.o %s --check-prefixes=SIGNAME1-WARN,SIGNAME1-LLVM --implicit-check-not=warning: # RUN: llvm-readelf --section-groups %t.signame.o 2>&1 | \ # RUN: FileCheck -DFILE=%t.signame.o %s --check-prefixes=SIGNAME1-WARN,SIGNAME1-GNU --implicit-check-not=warning: +# RUN: llvm-readelf --elf-output-style=JSON --section-groups %t.signame.o 2>&1 | \ +# RUN: FileCheck -DFILE=%t.signame.o %s --check-prefixes=SIGNAME1-WARN,SIGNAME1-JSON --implicit-check-not=warning: # SIGNAME1-WARN: warning: '[[FILE]]': unable to get the name of the symbol with index 2: st_name (0x5) is past the end of the string table of size 0x5 @@ -404,6 +675,9 @@ # SIGNAME1-GNU: COMDAT group section [ 1] `.group' [] contains 2 sections: # SIGNAME1-GNU: COMDAT group section [ 2] `.group1' [] contains 2 sections: +# SIGNAME1-JSON: "Signature": "" +# SIGNAME1-JSON: "Signature": "" + ## Check we report a warning when the string table that contains the signature symbol name is not null-terminated. # RUN: yaml2obj %s -DSTRTABCONTENT="0061626361" -DSYM1STNAME=4 -DSYM2STNAME=5 -o %t.signame2.o @@ -411,6 +685,8 @@ # RUN: FileCheck -DFILE=%t.signame2.o %s --check-prefixes=SIGNAME2-WARN,SIGNAME2-LLVM --implicit-check-not=warning: # RUN: llvm-readelf --section-groups %t.signame2.o 2>&1 | \ # RUN: FileCheck -DFILE=%t.signame2.o %s --check-prefixes=SIGNAME2-WARN,SIGNAME2-GNU --implicit-check-not=warning: +# RUN: llvm-readelf --elf-output-style=JSON --section-groups %t.signame2.o 2>&1 | \ +# RUN: FileCheck -DFILE=%t.signame2.o %s --check-prefixes=SIGNAME2-WARN,SIGNAME2-JSON --implicit-check-not=warning: # SIGNAME2-WARN: warning: '[[FILE]]': unable to get the string table for SHT_SYMTAB section with index 7: SHT_STRTAB string table section [index 8] is non-null terminated @@ -419,3 +695,6 @@ # SIGNAME2-GNU: COMDAT group section [ 1] `.group' [] contains 2 sections: # SIGNAME2-GNU: COMDAT group section [ 2] `.group1' [] contains 2 sections: + +# SIGNAME2-JSON: "Signature": "" +# SIGNAME2-JSON: "Signature": "" diff --git a/llvm/test/tools/llvm-readobj/ELF/output-style.test b/llvm/test/tools/llvm-readobj/ELF/output-style.test --- a/llvm/test/tools/llvm-readobj/ELF/output-style.test +++ b/llvm/test/tools/llvm-readobj/ELF/output-style.test @@ -1,4 +1,4 @@ ## Error for an unknown output style. RUN: not llvm-readobj --elf-output-style=unknown 2>&1 | FileCheck %s -CHECK: error: --elf-output-style value should be either 'LLVM' or 'GNU' +CHECK: error: --elf-output-style value should be either 'LLVM', 'GNU', or 'JSON' diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -48,6 +48,7 @@ #include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MSP430AttributeParser.h" #include "llvm/Support/MSP430Attributes.h" @@ -708,6 +709,97 @@ ScopedPrinter &W; }; +template class JSONELFDumper : public ELFDumper { + json::OStream JOS; + +public: + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + + JSONELFDumper(const object::ELFObjectFile &ObjF, ScopedPrinter &Writer) + : ELFDumper(ObjF, Writer), JOS(Writer.getOStream(), 2) { + assert(&this->W.getOStream() == &llvm::fouts()); + JOS.objectBegin(); + } + ~JSONELFDumper() { JOS.objectEnd(); } + + void printFileHeaders() override; + void printGroupSections() override; + void printRelocations() override; + void printSectionHeaders() override; + void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override; + void printHashSymbols() override; + void printSectionDetails() override; + void printDependentLibs() override; + void printDynamicTable() override; + void printDynamicRelocations() override; + void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset, + bool NonVisibilityBitsUsed) const override; + void printProgramHeaders(bool PrintProgramHeaders, + cl::boolOrDefault PrintSectionMapping) override; + void printVersionSymbolSection(const Elf_Shdr *Sec) override; + void printVersionDefinitionSection(const Elf_Shdr *Sec) override; + void printVersionDependencySection(const Elf_Shdr *Sec) override; + void printHashHistograms() override; + void printCGProfile() override; + void printBBAddrMaps() override; + void printAddrsig() override; + void printNotes() override; + void printELFLinkerOptions() override; + void printStackSizes() override; + +private: + void printRelrReloc(const Elf_Relr &R) override; + void printRelRelaReloc(const Relocation &R, + const RelSymbol &RelSym) override; + void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, + Optional StrTable, bool IsDynamic, + bool NonVisibilityBitsUsed) const override; + void printDynamicRelocHeader(unsigned Type, StringRef Name, + const DynRegionInfo &Reg) override; + + void printProgramHeaders() override; + void printSectionMapping() override; + + void printStackSizeEntry(uint64_t Size, + ArrayRef FuncNames) override; + void printMipsGOT(const MipsGOTParser &Parser) override; + void printMipsPLT(const MipsGOTParser &Parser) override; + void printMipsABIFlags() override; + + template + std::string printEnum(T Value, ArrayRef> EnumValues) const { + for (const EnumEntry &EnumItem : EnumValues) + if (EnumItem.Value == Value) + return std::string(EnumItem.AltName); + return to_hexString(Value, false); + } + + template + void printFlags(T Value, ArrayRef> EnumValues, + TEnum EnumMask1 = {}, TEnum EnumMask2 = {}, + TEnum EnumMask3 = {}) { + JOS.attributeArray("Flags", [&]() { + for (const EnumEntry &Flag : EnumValues) { + if (Flag.Value == 0) + continue; + TEnum EnumMask{}; + if (Flag.Value & EnumMask1) + EnumMask = EnumMask1; + else if (Flag.Value & EnumMask2) + EnumMask = EnumMask2; + else if (Flag.Value & EnumMask3) + EnumMask = EnumMask3; + bool IsEnum = (Flag.Value & EnumMask) != 0; + if ((!IsEnum && (Value & Flag.Value) == Flag.Value) || + (IsEnum && (Value & EnumMask) == Flag.Value)) { + JOS.value(Flag.AltName); + } + } + }); + } +}; + } // end anonymous namespace namespace llvm { @@ -717,6 +809,8 @@ createELFDumper(const ELFObjectFile &Obj, ScopedPrinter &Writer) { if (opts::Output == opts::GNU) return std::make_unique>(Obj, Writer); + else if (opts::Output == opts::JSON) + return std::make_unique>(Obj, Writer); return std::make_unique>(Obj, Writer); } @@ -7268,3 +7362,288 @@ W.printFlags("Flags 1", Flags->flags1, makeArrayRef(ElfMipsFlags1)); W.printHex("Flags 2", Flags->flags2); } + +template void JSONELFDumper::printFileHeaders() { + const Elf_Ehdr &E = this->Obj.getHeader(); + JOS.attributeBegin("ElfHeader"); + JOS.objectBegin(); + { + JOS.attributeBegin("Ident"); + JOS.objectBegin(); + JOS.attributeArray("Magic", [&]() { + for (const unsigned char &MagicByte : + makeArrayRef(E.e_ident).slice(ELF::EI_MAG0, 4)) { + JOS.value(to_hexString(MagicByte)); + } + }); + JOS.attribute("Class", + printEnum(E.e_ident[ELF::EI_CLASS], makeArrayRef(ElfClass))); + JOS.attribute("DataEncoding", printEnum(E.e_ident[ELF::EI_DATA], + makeArrayRef(ElfDataEncoding))); + JOS.attribute("FileVersion", E.e_ident[ELF::EI_VERSION]); + + auto OSABI = makeArrayRef(ElfOSABI); + if (E.e_ident[ELF::EI_OSABI] >= ELF::ELFOSABI_FIRST_ARCH && + E.e_ident[ELF::EI_OSABI] <= ELF::ELFOSABI_LAST_ARCH) { + switch (E.e_machine) { + case ELF::EM_AMDGPU: + OSABI = makeArrayRef(AMDGPUElfOSABI); + break; + case ELF::EM_ARM: + OSABI = makeArrayRef(ARMElfOSABI); + break; + case ELF::EM_TI_C6000: + OSABI = makeArrayRef(C6000ElfOSABI); + break; + } + } + JOS.attribute("OS/ABI", printEnum(E.e_ident[ELF::EI_OSABI], OSABI)); + JOS.attribute("ABIVersion", E.e_ident[ELF::EI_ABIVERSION]); + JOS.attributeArray("Unused", [&]() { + for (const auto &byte : makeArrayRef(E.e_ident).slice(ELF::EI_PAD)) { + JOS.value(to_hexString(byte)); + } + }); + JOS.objectEnd(); + JOS.attributeEnd(); + } + std::string TypeStr; + if (const EnumEntry *Ent = getObjectFileEnumEntry(E.e_type)) { + TypeStr = Ent->Name.str(); + } else { + if (E.e_type >= ET_LOPROC) + TypeStr = "Processor Specific"; + else if (E.e_type >= ET_LOOS) + TypeStr = "OS Specific"; + else + TypeStr = "Unknown"; + } + JOS.attribute("Type", TypeStr); + JOS.attribute("Machine", + printEnum(E.e_machine, makeArrayRef(ElfMachineType))); + JOS.attribute("Version", "0x" + to_hexString(E.e_version)); + JOS.attribute("Entry", to_hexString(E.e_entry)); + JOS.attribute("ProgramHeaderOffset", to_string(E.e_phoff)); + JOS.attribute("SectionHeaderOffset", to_string(E.e_shoff)); + + if (E.e_machine == EM_MIPS) { + printFlags(E.e_flags, makeArrayRef(ElfHeaderMipsFlags), + unsigned(ELF::EF_MIPS_ARCH), unsigned(ELF::EF_MIPS_ABI), + unsigned(ELF::EF_MIPS_MACH)); + } else if (E.e_machine == EM_AMDGPU) { + switch (E.e_ident[ELF::EI_ABIVERSION]) { + case 0: + // ELFOSABI_AMDGPU_PAL, ELFOSABI_AMDGPU_MESA3D support *_V3 flags. + LLVM_FALLTHROUGH; + case ELF::ELFABIVERSION_AMDGPU_HSA_V3: + printFlags(E.e_flags, makeArrayRef(ElfHeaderAMDGPUFlagsABIVersion3), + unsigned(ELF::EF_AMDGPU_MACH)); + break; + case ELF::ELFABIVERSION_AMDGPU_HSA_V4: + printFlags(E.e_flags, makeArrayRef(ElfHeaderAMDGPUFlagsABIVersion4), + unsigned(ELF::EF_AMDGPU_MACH), + unsigned(ELF::EF_AMDGPU_FEATURE_XNACK_V4), + unsigned(ELF::EF_AMDGPU_FEATURE_SRAMECC_V4)); + break; + } + } else if (E.e_machine == EM_RISCV) + printFlags(E.e_flags, makeArrayRef(ElfHeaderRISCVFlags)); + else if (E.e_machine == EM_AVR) + printFlags(E.e_flags, makeArrayRef(ElfHeaderAVRFlags)); + + JOS.attribute("FlagsRaw", "0x" + to_hexString(E.e_flags)); + // TODO: Handle uint16_t + JOS.attribute("HeaderSize", to_string(E.e_ehsize)); + JOS.attribute("ProgramHeaderEntrySize", to_string(E.e_phentsize)); + JOS.attribute("ProgramHeaderCount", to_string(E.e_phnum)); + JOS.attribute("SectionHeaderEntrySize", to_string(E.e_shentsize)); + JOS.attribute("SectionHeaderCount", + getSectionHeadersNumString(this->Obj, this->FileName)); + JOS.attribute("StringTableSectionIndex", + getSectionHeaderTableIndexString(this->Obj, this->FileName)); + JOS.objectEnd(); + JOS.attributeEnd(); +} + +template void JSONELFDumper::printGroupSections() { + std::vector V = this->getGroups(); + DenseMap Map = mapSectionsToGroups(V); + JOS.attributeArray("Groups", [&]() { + for (const GroupSection &G : V) { + JOS.objectBegin(); + JOS.attributeBegin("Group"); + JOS.objectBegin(); + JOS.attribute("Name", G.Name); + // TODO: handle uint64_t + JOS.attribute("Index", to_string(G.Index)); + JOS.attribute("Link", G.Link); + JOS.attribute("Info", G.Info); + JOS.attribute("Type", getGroupType(G.Type)); + JOS.attribute("Signature", G.Signature); + JOS.attributeArray("SectionsInGroup", [&]() { + for (const GroupMember &GM : G.Members) { + const GroupSection *MainGroup = Map[GM.Index]; + JOS.objectBegin(); + if (MainGroup != &G) + this->reportUniqueWarning( + "section with index " + Twine(GM.Index) + + ", included in the group section with index " + + Twine(MainGroup->Index) + + ", was also found in the group section with index " + + Twine(G.Index)); + JOS.attribute("Name", GM.Name); + // TODO: handle uint64_t + JOS.attribute("Index", to_string(GM.Index)); + JOS.objectEnd(); + } + }); + JOS.objectEnd(); + JOS.attributeEnd(); + JOS.objectEnd(); + } + }); +} + +template void JSONELFDumper::printRelocations() { + // TODO: Implement +} + +template void JSONELFDumper::printSectionHeaders() { + // TODO: Implement +} + +template +void JSONELFDumper::printSymbols(bool PrintSymbols, + bool PrintDynamicSymbols) { + // TODO: Implement +} + +template void JSONELFDumper::printHashSymbols() { + // TODO: Implement +} + +template void JSONELFDumper::printSectionDetails() { + // TODO: Implement +} + +template void JSONELFDumper::printDependentLibs() { + // TODO: Implement +} + +template void JSONELFDumper::printDynamicTable() { + // TODO: Implement +} + +template void JSONELFDumper::printDynamicRelocations() { + // TODO: Implement +} + +template +void JSONELFDumper::printSymtabMessage(const Elf_Shdr *Symtab, + size_t Offset, + bool NonVisibilityBitsUsed) const { + // TODO: Implement +} + +template +void JSONELFDumper::printProgramHeaders( + bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) { + // TODO: Implement +} + +template +void JSONELFDumper::printVersionSymbolSection(const Elf_Shdr *Sec) { + // TODO: Implement +} + +template +void JSONELFDumper::printVersionDefinitionSection(const Elf_Shdr *Sec) { + // TODO: Implement +} + +template +void JSONELFDumper::printVersionDependencySection(const Elf_Shdr *Sec) { + // TODO: Implement +} + +template void JSONELFDumper::printHashHistograms() { + // TODO: Implement +} + +template void JSONELFDumper::printCGProfile() { + // TODO: Implement +} + +template void JSONELFDumper::printBBAddrMaps() { + // TODO: Implement +} + +template void JSONELFDumper::printAddrsig() { + // TODO: Implement +} + +template void JSONELFDumper::printNotes() { + // TODO: Implement +} + +template void JSONELFDumper::printELFLinkerOptions() { + // TODO: Implement +} + +template void JSONELFDumper::printStackSizes() { + // TODO: Implement +} + +template +void JSONELFDumper::printMipsGOT(const MipsGOTParser &Parser) { + // TODO: Implement +} + +template +void JSONELFDumper::printMipsPLT(const MipsGOTParser &Parser) { + // TODO: Implement +} + +template void JSONELFDumper::printMipsABIFlags() { + // TODO: Implement +} + +template +void JSONELFDumper::printRelrReloc(const Elf_Relr &R) { + // TODO: Implement +} + +template +void JSONELFDumper::printRelRelaReloc(const Relocation &R, + const RelSymbol &RelSym) { + // TODO: Implement +} + +template +void JSONELFDumper::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable, + Optional StrTable, + bool IsDynamic, + bool NonVisibilityBitsUsed) const { + // TODO: Implement +} + +template +void JSONELFDumper::printDynamicRelocHeader(unsigned Type, StringRef Name, + const DynRegionInfo &Reg) { + // TODO: Implement +} + +template void JSONELFDumper::printProgramHeaders() { + // TODO: Implement +} + +template void JSONELFDumper::printSectionMapping() { + // TODO: Implement +} + +template +void JSONELFDumper::printStackSizeEntry(uint64_t Size, + ArrayRef FuncNames) { + // TODO: Implement +} diff --git a/llvm/tools/llvm-readobj/llvm-readobj.h b/llvm/tools/llvm-readobj/llvm-readobj.h --- a/llvm/tools/llvm-readobj/llvm-readobj.h +++ b/llvm/tools/llvm-readobj/llvm-readobj.h @@ -39,7 +39,7 @@ extern bool RawRelr; extern bool CodeViewSubsectionBytes; extern bool Demangle; -enum OutputStyleTy { LLVM, GNU }; +enum OutputStyleTy { LLVM, GNU, JSON }; extern OutputStyleTy Output; } // namespace opts diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -232,8 +232,10 @@ opts::Output = opts::OutputStyleTy::LLVM; else if (V == "GNU") opts::Output = opts::OutputStyleTy::GNU; + else if (V == "JSON") + opts::Output = opts::OutputStyleTy::JSON; else - error("--elf-output-style value should be either 'LLVM' or 'GNU'"); + error("--elf-output-style value should be either 'LLVM', 'GNU', or 'JSON'"); } opts::GnuHashTable = Args.hasArg(OPT_gnu_hash_table); opts::HashSymbols = Args.hasArg(OPT_hash_symbols);