diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -1,5 +1,6 @@ include(CheckCXXSymbolExists) include(CheckTypeSize) +include(CMakeDependentOption) set(LLDB_PROJECT_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) set(LLDB_SOURCE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/source") @@ -384,6 +385,13 @@ set(LLDB_VERSION "${LLDB_VERSION_MAJOR}.${LLDB_VERSION_MINOR}.${LLDB_VERSION_PATCH}${LLDB_VERSION_SUFFIX}") message(STATUS "LLDB version: ${LLDB_VERSION}") +find_package(LibLZMA) +cmake_dependent_option(LLDB_ENABLE_LZMA "Support LZMA compression" ON "LIBLZMA_FOUND" OFF) +if (LLDB_ENABLE_LZMA) + include_directories(${LIBLZMA_INCLUDE_DIRS}) +endif() +llvm_canonicalize_cmake_booleans(LLDB_ENABLE_LZMA) + include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include diff --git a/lldb/include/lldb/Host/Config.h.cmake b/lldb/include/lldb/Host/Config.h.cmake --- a/lldb/include/lldb/Host/Config.h.cmake +++ b/lldb/include/lldb/Host/Config.h.cmake @@ -35,4 +35,6 @@ #cmakedefine HAVE_LIBCOMPRESSION #endif +#cmakedefine01 LLDB_ENABLE_LZMA + #endif // #ifndef LLDB_HOST_CONFIG_H diff --git a/lldb/include/lldb/Host/LZMA.h b/lldb/include/lldb/Host/LZMA.h new file mode 100644 --- /dev/null +++ b/lldb/include/lldb/Host/LZMA.h @@ -0,0 +1,34 @@ +//===-- LZMA.h --------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_LZMA_h_ +#define liblldb_Host_LZMA_h_ + +#include "llvm/ADT/ArrayRef.h" + +namespace llvm { +class Error; +} // End of namespace llvm + +namespace lldb_private { + +namespace lzma { + +bool isAvailable(); + +llvm::Expected +getUncompressedSize(llvm::ArrayRef InputBuffer); + +llvm::Error uncompress(llvm::ArrayRef InputBuffer, + llvm::SmallVectorImpl &Uncompressed); + +} // End of namespace lzma + +} // End of namespace lldb_private + +#endif // liblldb_Host_LZMA_h_ diff --git a/lldb/lit/CMakeLists.txt b/lldb/lit/CMakeLists.txt --- a/lldb/lit/CMakeLists.txt +++ b/lldb/lit/CMakeLists.txt @@ -56,9 +56,11 @@ lli llvm-config llvm-dwarfdump + llvm-nm llvm-mc llvm-objcopy llvm-readobj + llvm-strip ) if(TARGET lld) diff --git a/lldb/lit/Modules/ELF/Inputs/minidebuginfo-main.c b/lldb/lit/Modules/ELF/Inputs/minidebuginfo-main.c new file mode 100644 --- /dev/null +++ b/lldb/lit/Modules/ELF/Inputs/minidebuginfo-main.c @@ -0,0 +1,12 @@ +// This function will be embedded within the .symtab section of the +// .gnu_debugdata section. +int multiplyByFour(int num) { return num * 4; } + +// This function will be embedded within the .dynsym section of the main binary. +int multiplyByThree(int num) { return num * 3; } + +int main(int argc, char *argv[]) { + int x = multiplyByThree(argc); + int y = multiplyByFour(x); + return y; +} diff --git a/lldb/lit/Modules/ELF/minidebuginfo-corrupt-xz.yaml b/lldb/lit/Modules/ELF/minidebuginfo-corrupt-xz.yaml new file mode 100644 --- /dev/null +++ b/lldb/lit/Modules/ELF/minidebuginfo-corrupt-xz.yaml @@ -0,0 +1,29 @@ +# REQUIRES: lzma + +# This test checks that an error occurs when a corrupted +# .gnu_debugdata section is trying to be xz uncompressed. + +# RUN: yaml2obj %s > %t.obj + +# TODO(kwk): once yaml2obj doesn't auto-generate a .symtab section +# when there's none in YAML, remove the following line: + +# RUN: llvm-objcopy --remove-section=.symtab %t.obj + +# RUN: %lldb -b -o 'image dump symtab' %t.obj 2>&1 | FileCheck %s + +# CHECK: warning: (x86_64) {{.*}}.obj An error occurred while decompression the section .gnu_debugdata: lzma_stream_buffer_decode()=lzma error: LZMA_DATA_ERROR + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 + Entry: 0x00000000004004C0 +Sections: + - Name: .gnu_debugdata + Type: SHT_PROGBITS + AddressAlign: 0x0000000000000001 + Content: FD377A585A000004E6D6B4460200210116000000742FE5A3E0180F05BA5D003F914584683D89A6DA8ACC93E24ED90802EC1FE2A7102958F4A42B6A7134F23922F6F35F529E133A8B5588025CFAC876C68510A157DBBCF8CA75E9854DED10FDD5CE0CDC136F6459B13B9847AEF79E9B1C7CD70EF4F3AF709F5DA0C1F40780154D72120A6A62A3F1A216E20DC597CE55BB23B48785957321A15FEE48808C1428B925DBC8022541CC594BD0AF2B51C6BE2854C81611017704DF6E509D21013B80BEC27D8919ACD3157E89353A08F4C86781ED708E89AB322D010F0F1605DAD9B9CE2B13C387769C83F5F85C647FD9C551E0E9C7D4A5CBE297970E486CB94AC283F98A7C6412A57F9C37952327549EEC4634D2CFA55B0F99923A14992D4293E0D87CEEF7FB6160C45928DE25074EEBF5329B5579AF01DB23DF22CBD48C8037B68FFFBE5CEA6CD26A936DD07D9B2E6006B7C6E5CC751072185EFE995D3F3C8DACF9039D4BEFB1F376B491568F6F00DB50FF477F36B90413E4FA30AE7C561A1249FD45FDFF884F70247FC21E57195A764151D8E341267E724D856C512BD243CDB33AB313758443877B2CB58F7F8F0461DE9766647F333A3531BDC4A26E9537EB314708D31212FCF4C21E9CB139F4DBFD21BB16A126C35E2BB3F7E30BF5A54961CECD4DD4D91A3757356F618754B21533C34F2BD97D70A02B1F338588BDBA9CDF5FC9FBE973E550194F07EC7A1E8E3C005FD60F8853223427628987E82E701CA7E2FDFA1B0ED564C37D115A72C3EC01E29C85C3630D8A385C4AE12F4F75F9F0BC12F2698345DD62A1F546A5953AF5CF3C0F22C7DA510F6739EB8CDB0E8A5A3BC13CFC31C1875C313908EFF23678869B76A6E1C10FE699E43BFFDE8F0752ED994A4A84BC0AD9D7381131D457C4917C4F6656F5C95D3221A79166C802D5F5A7C68554E54C42CA535465D224C7B641CF3417C3EAFD03CE5709BEA33DC7C9155CAC9D3C8033AF7CDA622020606A7C139D77FF85BC19323BF956C9C4662F60079BC7FE5F67B46211716A1A6CE4AB8AAB307D6444310CBC101071703EECC0B4622D91D705F5DA2932DA8BCEDA8E1CB0CDB20AAD652B8F86A521D3421287F1C175AE3BE6458AE6F8F3FB6FB7ED97B616B580D791E5FE0B74973F8604F419039B5B9D9A14397EE509F2B33AE404FF96DD0551472C5302E67910F0794B15CFE837351C6AF89B2FE88488B557BE8ACFFA331FB7AD553D35CAEB7D8BCEFB6CFF4A58E91355FE931408CF4CAFA9B97518B9E5C02078F64CE81279801B090348213DCAA7D12DC098BFF58C5A3202EFC38F64AD894379747B54AB5A9843F82E5FF1F394C8B78344A8F1655DDEF8D5FE09EBB3E703853ABD716743507000696FB6B35216B088E499F53880375521442ED45DCDD1B31AAEBDAD3C7DA958593425206C4B2A0BC6CADE3B0B1598499E08016E84F33E3EB9D7B03B9C9DFA91B8CE5C74DEF2BC97FEE9982B0AEC16C75EEB7AE9A858A9C37F6C12B040C68A49111DCF0F3A4780F3879E93D904676BE908FDC66373D34AA715A39EFBC2795C6C8F058CA24392FB2591AD06ACD6AED8746F926886180C2B007ED58C9884A8BEF6CCA1F549F5C4FB411A3FF78770D1147363AC80B98B5A8FDB3DEC4E61709F66A622BDA835B1FD67B7C7CB166ABB163FB7C5204AE200C71C6A18B532C407647323B8F2FAC7ECB68C250877FC8DD5FE05B2B39E66F687EBB6EEFB7D5209E22F451B76F57D90BB6641DFFDE1A1821C4D783E4756F3CEE7F63B9BA284F8E114B0D9A086D83233BED4A8F5B60933DC16AF4DDE19C9FC59BCC1646343ECE7007B1C4DC65C4A939CDD47F6ED8855913183149BECE66D8FE7793AE607EB8E28513749B9548252764110D3B58D1D8B348DB18F7F24F8CA0C7D9CB515D90F7F1848FF58472B2EF52EBAB123AFC7F87890CE9FC55B31160014294A9B7F81638A27335E29E15A10B1068D5E049B1C239814DBBCC1BB30E11EEBAD5ACF8FB1B986C4F48D73FEA6129D9708A0B5AC435402BEC8C79C71DB94394811B9A604141A125A4669F9A139A0264E93E822117BE8E0D93A1487C51214E9FBF5763A3FBE9DA700B9C9B435472AF9F0B4446B000000003239307DD8B645100001D60B90300000CA1EC9E9B1C467FB020000000004595A +... diff --git a/lldb/lit/Modules/ELF/minidebuginfo-find-symbols.yaml b/lldb/lit/Modules/ELF/minidebuginfo-find-symbols.yaml new file mode 100644 --- /dev/null +++ b/lldb/lit/Modules/ELF/minidebuginfo-find-symbols.yaml @@ -0,0 +1,26 @@ +# REQUIRES: lzma + +# RUN: yaml2obj %s > %t.obj + +# TODO(kwk): once yaml2obj doesn't auto-generate a .symtab section +# when there's none in YAML, remove the following line: + +# RUN: llvm-objcopy --remove-section=.symtab %t.obj + +# RUN: %lldb -b -o 'image dump symtab' %t.obj | FileCheck %s + +# CHECK: [ 0] 1 X Code 0x00000000004005b0 0x000000000000000f 0x00000012 multiplyByFour + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 + Entry: 0x00000000004004C0 +Sections: + - Name: .gnu_debugdata + Type: SHT_PROGBITS + AddressAlign: 0x0000000000000001 + Content: FD377A585A000004E6D6B4460200210116000000742FE5A3E0180F05BA5D003F914584683D89A6DA8ACC93E24ED90802EC1FE2A7102958F4A42B6A7134F23922F6F35F529E133A8B5588025CFAC876C68510A157DBBCF8CA75E9854DED10FDD5CE0CDC136F6459B13B9847AEF79E9B1C7CD70EF4F3AF709F5DA0C1F40780154D72120A6A62A3F1A216E20DC597CE55BB23B48785957321A15FEE48808C1428B925DBC8022541CC594BD0AF2B51C6BE2854C81611017704DF6E509D21013B80BEC27D8919ACD3157E89353A08F4C86781ED708E89AB322D010F0F1605DAD9B9CE2B13C387769C83F5F85C647FD9C551E0E9C7D4A5CBE297970E486CB94AC283F98A7C6412A57F9C37952327549EEC4634D2CFA55B0F99923A14992D4293E0D87CEEF7FB6160C45928DE25074EEBF5329B5579AF01DB23DF22CBD48C8037B68FFFBE5CEA6CD26A936DD07D9B2E6006B7C6E5CC751072185EFE995D3F3C8DACF9039D4BEFB1F376B491568F6F00DB50FF477F36B90413E4FA30AE7C561A1249FD45FDFF884F70247FC21E57195A764151D8E341267E724D856C512BD243CDB33AB313758443877B2CB58F7F8F0461DE9766647F333A3531BDC4A26E9537EB314708D31212FCF4C21E9CB139F4DBFD21BB16A126C35E2BB3F7E30BF5A54961CECD4DD4D91A3757356F618754B21533C34F2BD97D70A02B1F338588BDBA9CDF5FC9FBE973E550194F07EC7A1E8E3C005FD60F8853223427628987E82E701CA7E2FDFA1B0ED564C37D115A72C3EC01E29C85C3630D8A385C4AE12F4F75F9F0BC12F2698345DD62A1F546A5953AF5CF3C0F22C7DA510F6739EB8CDB0E8A5A3BC13CFC31C1875C313908EFF23678869B76A6E1C10FE699E43BFFDE8F0752ED994A4A84BC0AD9D7381131D457C4917C4F6656F5C95D3221A79166C802D5F5A7C68554E54C42CA535465D224C7B641CF3417C3EAFD03CE5709BEA33DC7C9155CAC9D3C8033AF7CDA622020606A7C139D77FF85BC19323BF956C9C4662F60079BC7FE5F67B46211716A1A6CE4AB8AAB307D6444310CBC101071703EECC0B4622D91D705F5DA2932DA8BCEDA8E1CB0CDB20AAD652B8F86A521D3421287F1C175AE3BE6458AE6F8F3FB6FB7ED97B616B580D791E5FE0B74973F8604F419039B5B9D9A14397EE509F2B33AE404FF96DD0551472C5302E67910F0794B15CFE837351C6AF89B2FE88488B557BE8ACFFA331FB7AD553D35CAEB7D8BCEFB6CFF4A58E91355FE931408CF4CAFA9B97518B9E5C02078F64CE81279801B090348213DCAA7D12DC098BFF58C5A3202EFC38F64AD894379747B54AB5A9843F82E5FF1F394C8B783C3A8F1655DDEF8D5FE09EBB3E703853ABD716743507000696FB6B35216B088E499F53880375521442ED45DCDD1B31AAEBDAD3C7DA958593425206C4B2A0BC6CADE3B0B1598499E08016E84F33E3EB9D7B03B9C9DFA91B8CE5C74DEF2BC97FEE9982B0AEC16C75EEB7AE9A858A9C37F6C12B040C68A49111DCF0F3A4780F3879E93D904676BE908FDC66373D34AA715A39EFBC2795C6C8F058CA24392FB2591AD06ACD6AED8746F926886180C2B007ED58C9884A8BEF6CCA1F549F5C4FB411A3FF78770D1147363AC80B98B5A8FDB3DEC4E61709F66A622BDA835B1FD67B7C7CB166ABB163FB7C5204AE200C71C6A18B532C407647323B8F2FAC7ECB68C250877FC8DD5FE05B2B39E66F687EBB6EEFB7D5209E22F451B76F57D90BB6641DFFDE1A1821C4D783E4756F3CEE7F63B9BA284F8E114B0D9A086D83233BED4A8F5B60933DC16AF4DDE19C9FC59BCC1646343ECE7007B1C4DC65C4A939CDD47F6ED8855913183149BECE66D8FE7793AE607EB8E28513749B9548252764110D3B58D1D8B348DB18F7F24F8CA0C7D9CB515D90F7F1848FF58472B2EF52EBAB123AFC7F87890CE9FC55B31160014294A9B7F81638A27335E29E15A10B1068D5E049B1C239814DBBCC1BB30E11EEBAD5ACF8FB1B986C4F48D73FEA6129D9708A0B5AC435402BEC8C79C71DB94394811B9A604141A125A4669F9A139A0264E93E822117BE8E0D93A1487C51214E9FBF5763A3FBE9DA700B9C9B435472AF9F0B4446B000000003239307DD8B645100001D60B90300000CA1EC9E9B1C467FB020000000004595A +... diff --git a/lldb/lit/Modules/ELF/minidebuginfo-no-lzma.yaml b/lldb/lit/Modules/ELF/minidebuginfo-no-lzma.yaml new file mode 100644 --- /dev/null +++ b/lldb/lit/Modules/ELF/minidebuginfo-no-lzma.yaml @@ -0,0 +1,29 @@ +# REQUIRES: !lzma + +# This test checks that a warning is printed when we're trying +# to decompress a .gnu_debugdata section when no LZMA support was compiled in. + +# RUN: yaml2obj %s > %t.obj + +# TODO(kwk): once yaml2obj doesn't auto-generate a .symtab section +# when there's none in YAML, remove the following line: + +# RUN: llvm-objcopy --remove-section=.symtab %t.obj + +# RUN: %lldb -b -o 'image dump symtab' %t.obj 2>&1 | FileCheck %s + +# CHECK: warning: (x86_64) {{.*}}.obj No LZMA support found for reading .gnu_debugdata section + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 + Entry: 0x00000000004004C0 +Sections: + - Name: .gnu_debugdata + Type: SHT_PROGBITS + AddressAlign: 0x0000000000000001 + Content: FD377A585A000004E6D6B4460200210116000000742FE5A3E0180F05BA5D003F914584683D89A6DA8ACC93E24ED90802EC1FE2A7102958F4A42B6A7134F23922F6F35F529E133A8B5588025CFAC876C68510A157DBBCF8CA75E9854DED10FDD5CE0CDC136F6459B13B9847AEF79E9B1C7CD70EF4F3AF709F5DA0C1F40780154D72120A6A62A3F1A216E20DC597CE55BB23B48785957321A15FEE48808C1428B925DBC8022541CC594BD0AF2B51C6BE2854C81611017704DF6E509D21013B80BEC27D8919ACD3157E89353A08F4C86781ED708E89AB322D010F0F1605DAD9B9CE2B13C387769C83F5F85C647FD9C551E0E9C7D4A5CBE297970E486CB94AC283F98A7C6412A57F9C37952327549EEC4634D2CFA55B0F99923A14992D4293E0D87CEEF7FB6160C45928DE25074EEBF5329B5579AF01DB23DF22CBD48C8037B68FFFBE5CEA6CD26A936DD07D9B2E6006B7C6E5CC751072185EFE995D3F3C8DACF9039D4BEFB1F376B491568F6F00DB50FF477F36B90413E4FA30AE7C561A1249FD45FDFF884F70247FC21E57195A764151D8E341267E724D856C512BD243CDB33AB313758443877B2CB58F7F8F0461DE9766647F333A3531BDC4A26E9537EB314708D31212FCF4C21E9CB139F4DBFD21BB16A126C35E2BB3F7E30BF5A54961CECD4DD4D91A3757356F618754B21533C34F2BD97D70A02B1F338588BDBA9CDF5FC9FBE973E550194F07EC7A1E8E3C005FD60F8853223427628987E82E701CA7E2FDFA1B0ED564C37D115A72C3EC01E29C85C3630D8A385C4AE12F4F75F9F0BC12F2698345DD62A1F546A5953AF5CF3C0F22C7DA510F6739EB8CDB0E8A5A3BC13CFC31C1875C313908EFF23678869B76A6E1C10FE699E43BFFDE8F0752ED994A4A84BC0AD9D7381131D457C4917C4F6656F5C95D3221A79166C802D5F5A7C68554E54C42CA535465D224C7B641CF3417C3EAFD03CE5709BEA33DC7C9155CAC9D3C8033AF7CDA622020606A7C139D77FF85BC19323BF956C9C4662F60079BC7FE5F67B46211716A1A6CE4AB8AAB307D6444310CBC101071703EECC0B4622D91D705F5DA2932DA8BCEDA8E1CB0CDB20AAD652B8F86A521D3421287F1C175AE3BE6458AE6F8F3FB6FB7ED97B616B580D791E5FE0B74973F8604F419039B5B9D9A14397EE509F2B33AE404FF96DD0551472C5302E67910F0794B15CFE837351C6AF89B2FE88488B557BE8ACFFA331FB7AD553D35CAEB7D8BCEFB6CFF4A58E91355FE931408CF4CAFA9B97518B9E5C02078F64CE81279801B090348213DCAA7D12DC098BFF58C5A3202EFC38F64AD894379747B54AB5A9843F82E5FF1F394C8B783C3A8F1655DDEF8D5FE09EBB3E703853ABD716743507000696FB6B35216B088E499F53880375521442ED45DCDD1B31AAEBDAD3C7DA958593425206C4B2A0BC6CADE3B0B1598499E08016E84F33E3EB9D7B03B9C9DFA91B8CE5C74DEF2BC97FEE9982B0AEC16C75EEB7AE9A858A9C37F6C12B040C68A49111DCF0F3A4780F3879E93D904676BE908FDC66373D34AA715A39EFBC2795C6C8F058CA24392FB2591AD06ACD6AED8746F926886180C2B007ED58C9884A8BEF6CCA1F549F5C4FB411A3FF78770D1147363AC80B98B5A8FDB3DEC4E61709F66A622BDA835B1FD67B7C7CB166ABB163FB7C5204AE200C71C6A18B532C407647323B8F2FAC7ECB68C250877FC8DD5FE05B2B39E66F687EBB6EEFB7D5209E22F451B76F57D90BB6641DFFDE1A1821C4D783E4756F3CEE7F63B9BA284F8E114B0D9A086D83233BED4A8F5B60933DC16AF4DDE19C9FC59BCC1646343ECE7007B1C4DC65C4A939CDD47F6ED8855913183149BECE66D8FE7793AE607EB8E28513749B9548252764110D3B58D1D8B348DB18F7F24F8CA0C7D9CB515D90F7F1848FF58472B2EF52EBAB123AFC7F87890CE9FC55B31160014294A9B7F81638A27335E29E15A10B1068D5E049B1C239814DBBCC1BB30E11EEBAD5ACF8FB1B986C4F48D73FEA6129D9708A0B5AC435402BEC8C79C71DB94394811B9A604141A125A4669F9A139A0264E93E822117BE8E0D93A1487C51214E9FBF5763A3FBE9DA700B9C9B435472AF9F0B4446B000000003239307DD8B645100001D60B90300000CA1EC9E9B1C467FB020000000004595A +... diff --git a/lldb/lit/Modules/ELF/minidebuginfo-set-and-hit-breakpoint.test b/lldb/lit/Modules/ELF/minidebuginfo-set-and-hit-breakpoint.test new file mode 100644 --- /dev/null +++ b/lldb/lit/Modules/ELF/minidebuginfo-set-and-hit-breakpoint.test @@ -0,0 +1,86 @@ +# REQUIRES: system-linux, lzma, xz + +# We want to keep the symbol "multiplyByThree" in the .dynamic section and not +# have it put the default .symtab section. +# RUN: echo "{multiplyByThree;};" > %T/dynmic-symbols.txt +# RUN: %clang -Wl,--dynamic-list=%T/dynmic-symbols.txt -g -o %t.binary %p/Inputs/minidebuginfo-main.c + +# The following section is adapted from GDB's official documentation: +# http://sourceware.org/gdb/current/onlinedocs/gdb/MiniDebugInfo.html#MiniDebugInfo + +# Extract the dynamic symbols from the main binary, there is no need +# to also have these in the normal symbol table. + +# IGNORE: llvm-nm -D %t.binary --format=posix --defined-only | awk '{ print $1 }' | sort > %t.dynsyms + +# Extract all the text (i.e. function) symbols from the debuginfo. +# (Note that we actually also accept "D" symbols, for the benefit +# of platforms like PowerPC64 that use function descriptors.) + +# IGNORE: llvm-nm %t.binary --format=posix --defined-only | awk '{ if ($2 == "T" || $2 == "t" || $2 == "D") print $1 }' | sort > %t.funcsyms + +# Keep all the function symbols not already in the dynamic symbol +# table. + +# IGNORE: comm -13 %t.dynsyms %t.funcsyms > %t.keep_symbols +# The result of the preceeding command can be preprocessed in %p/Inputs/minidebuginfo.keep_symbols +# because we know what symbol to keep. +# RUN: echo "multiplyByFour" > %p/Inputs/minidebuginfo.keep_symbols + +# Separate full debug info into debug binary. + +# RUN: llvm-objcopy --only-keep-debug %t.binary %t.debug + +# Copy the full debuginfo, keeping only a minimal set of symbols and +# removing some unnecessary sections. + +# RUN: llvm-objcopy -S --remove-section .gdb_index --remove-section .comment --keep-symbols=%p/Inputs/minidebuginfo.keep_symbols %t.debug %t.mini_debuginfo + +# This command is not from the GDB manual but it slims down embedded minidebug +# info. On top if that, it ensures that we only have the multiplyByThree symbol +# in the .dynsym section of the main binary. +# RUN: llvm-objcopy --remove-section=.rela.dyn --remove-section=.gnu.version --remove-section=.gnu.hash --remove-section=.dynsym %t.mini_debuginfo + +# Drop the full debug info from the original binary. + +# RUN: llvm-strip --strip-all -R .comment %t.binary + +# Inject the compressed data into the .gnu_debugdata section of the +# original binary. + +# RUN: xz --force --keep %t.mini_debuginfo + +# RUN: llvm-objcopy --add-section .gnu_debugdata=%t.mini_debuginfo.xz %t.binary + +# Now run the binary and see that we can set and hit a breakpoint +# from within the .dynsym section (multiplyByThree) and one from +# the .symtab section embedded in the .gnu_debugdata section (multiplyByFour). + +# RUN: %lldb -b -o 'b multiplyByThree' -o 'b multiplyByFour' -o 'run' -o 'continue' -o 'breakpoint list -v' %t.binary | FileCheck %s + +# CHECK: (lldb) b multiplyByThree +# CHECK-NEXT: Breakpoint 1: where = minidebuginfo-set-and-hit-breakpoint.test.tmp.binary`multiplyByThree, address = 0x{{.*}} + +# CHECK: (lldb) b multiplyByFour +# CHECK-NEXT: Breakpoint 2: where = minidebuginfo-set-and-hit-breakpoint.test.tmp.binary`multiplyByFour, address = 0x{{.*}} + +# CHECK: * thread #1, name = 'minidebuginfo-s', stop reason = breakpoint 1.1 +# CHECK: * thread #1, name = 'minidebuginfo-s', stop reason = breakpoint 2.1 + +# CHECK: (lldb) breakpoint list -v +# CHECK-NEXT: Current breakpoints: +# CHECK-NEXT: 1: name = 'multiplyByThree' +# CHECK-NEXT: 1.1: +# CHECK-NEXT: module = {{.*}}/minidebuginfo-set-and-hit-breakpoint.test.tmp.binary +# CHECK-NEXT: symbol = multiplyByThree +# CHECK-NEXT: address = 0x{{.*}} +# CHECK-NEXT: resolved = true +# CHECK-NEXT: hit count = 1 + +# CHECK: 2: name = 'multiplyByFour' +# CHECK-NEXT: 2.1: +# CHECK-NEXT: module = {{.*}}/minidebuginfo-set-and-hit-breakpoint.test.tmp.binary +# CHECK-NEXT: symbol = multiplyByFour +# CHECK-NEXT: address = 0x{{.*}} +# CHECK-NEXT: resolved = true +# CHECK-NEXT: hit count = 1 diff --git a/lldb/lit/lit.cfg.py b/lldb/lit/lit.cfg.py --- a/lldb/lit/lit.cfg.py +++ b/lldb/lit/lit.cfg.py @@ -11,6 +11,7 @@ from lit.llvm import llvm_config from lit.llvm.subst import FindTool from lit.llvm.subst import ToolSubst +from distutils.spawn import find_executable site.addsitedir(os.path.dirname(__file__)) from helper import toolchain @@ -98,3 +99,9 @@ if not config.lldb_disable_python: config.available_features.add('python') + +if config.lldb_enable_lzma: + config.available_features.add('lzma') + +if find_executable('xz') != None: + config.available_features.add('xz') diff --git a/lldb/lit/lit.site.cfg.py.in b/lldb/lit/lit.site.cfg.py.in --- a/lldb/lit/lit.site.cfg.py.in +++ b/lldb/lit/lit.site.cfg.py.in @@ -15,6 +15,7 @@ config.target_triple = "@TARGET_TRIPLE@" config.python_executable = "@PYTHON_EXECUTABLE@" config.have_zlib = @LLVM_ENABLE_ZLIB@ +config.lldb_enable_lzma = @LLDB_ENABLE_LZMA@ config.host_triple = "@LLVM_HOST_TRIPLE@" config.lldb_bitness = 64 if @LLDB_IS_64_BITS@ else 32 config.lldb_disable_python = @LLDB_DISABLE_PYTHON@ diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -29,6 +29,7 @@ common/HostProcess.cpp common/HostThread.cpp common/LockFileBase.cpp + common/LZMA.cpp common/MainLoop.cpp common/MonitoringProcessLauncher.cpp common/NativeProcessProtocol.cpp @@ -157,6 +158,9 @@ if (NOT LLDB_DISABLE_LIBEDIT) list(APPEND EXTRA_LIBS ${libedit_LIBRARIES}) endif() +if (LLDB_ENABLE_LZMA) + list(APPEND EXTRA_LIBS ${LIBLZMA_LIBRARIES}) +endif() if (NOT LLDB_DISABLE_LIBEDIT) list(APPEND LLDB_LIBEDIT_LIBS ${libedit_LIBRARIES}) diff --git a/lldb/source/Host/common/LZMA.cpp b/lldb/source/Host/common/LZMA.cpp new file mode 100644 --- /dev/null +++ b/lldb/source/Host/common/LZMA.cpp @@ -0,0 +1,146 @@ +//===-- LZMA.cpp ------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/Config.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + +#if LLDB_ENABLE_LZMA +#include +#endif // LLDB_ENABLE_LZMA + +namespace lldb_private { + +namespace lzma { + +#if !LLDB_ENABLE_LZMA +bool isAvailable() { return false; } +llvm::Expected +getUncompressedSize(llvm::ArrayRef InputBuffer) { + llvm_unreachable("lzma::getUncompressedSize is unavailable"); +} + +llvm::Error uncompress(llvm::ArrayRef InputBuffer, + llvm::SmallVectorImpl &Uncompressed) { + llvm_unreachable("lzma::uncompress is unavailable"); +} + +#else // LLDB_ENABLE_LZMA + +bool isAvailable() { return true; } + +static const char *convertLZMACodeToString(lzma_ret Code) { + switch (Code) { + case LZMA_STREAM_END: + return "lzma error: LZMA_STREAM_END"; + case LZMA_NO_CHECK: + return "lzma error: LZMA_NO_CHECK"; + case LZMA_UNSUPPORTED_CHECK: + return "lzma error: LZMA_UNSUPPORTED_CHECK"; + case LZMA_GET_CHECK: + return "lzma error: LZMA_GET_CHECK"; + case LZMA_MEM_ERROR: + return "lzma error: LZMA_MEM_ERROR"; + case LZMA_MEMLIMIT_ERROR: + return "lzma error: LZMA_MEMLIMIT_ERROR"; + case LZMA_FORMAT_ERROR: + return "lzma error: LZMA_FORMAT_ERROR"; + case LZMA_OPTIONS_ERROR: + return "lzma error: LZMA_OPTIONS_ERROR"; + case LZMA_DATA_ERROR: + return "lzma error: LZMA_DATA_ERROR"; + case LZMA_BUF_ERROR: + return "lzma error: LZMA_BUF_ERROR"; + case LZMA_PROG_ERROR: + return "lzma error: LZMA_PROG_ERROR"; + default: + llvm_unreachable("unknown or unexpected lzma status code"); + } +} + +llvm::Expected +getUncompressedSize(llvm::ArrayRef InputBuffer) { + lzma_stream_flags opts{}; + if (InputBuffer.size() < LZMA_STREAM_HEADER_SIZE) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "size of xz-compressed blob (%lu bytes) is smaller than the " + "LZMA_STREAM_HEADER_SIZE (%lu bytes)", + InputBuffer.size(), LZMA_STREAM_HEADER_SIZE); + } + + // Decode xz footer. + lzma_ret xzerr = lzma_stream_footer_decode( + &opts, InputBuffer.data() + InputBuffer.size() - LZMA_STREAM_HEADER_SIZE); + if (xzerr != LZMA_OK) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "lzma_stream_footer_decode()=%s", + convertLZMACodeToString(xzerr)); + } + if (InputBuffer.size() < (opts.backward_size + LZMA_STREAM_HEADER_SIZE)) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "xz-compressed buffer size (%lu bytes) too small (required at " + "least %lu bytes) ", + InputBuffer.size(), (opts.backward_size + LZMA_STREAM_HEADER_SIZE)); + } + + // Decode xz index. + lzma_index *xzindex; + uint64_t memlimit(UINT64_MAX); + size_t inpos = 0; + xzerr = + lzma_index_buffer_decode(&xzindex, &memlimit, nullptr, + InputBuffer.data() + InputBuffer.size() - + LZMA_STREAM_HEADER_SIZE - opts.backward_size, + &inpos, InputBuffer.size()); + if (xzerr != LZMA_OK) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "lzma_index_buffer_decode()=%s", + convertLZMACodeToString(xzerr)); + } + + // Get size of uncompressed file to construct an in-memory buffer of the + // same size on the calling end (if needed). + uint64_t uncompressedSize = lzma_index_uncompressed_size(xzindex); + + // Deallocate xz index as it is no longer needed. + lzma_index_end(xzindex, nullptr); + + return uncompressedSize; +} + +llvm::Error uncompress(llvm::ArrayRef InputBuffer, + llvm::SmallVectorImpl &Uncompressed) { + llvm::Expected uncompressedSize = getUncompressedSize(InputBuffer); + + if (auto err = uncompressedSize.takeError()) + return err; + + Uncompressed.resize(*uncompressedSize); + + // Decompress xz buffer to buffer. + uint64_t memlimit = UINT64_MAX; + size_t inpos = 0; + size_t outpos = 0; + lzma_ret ret = lzma_stream_buffer_decode( + &memlimit, 0, nullptr, InputBuffer.data(), &inpos, InputBuffer.size(), + Uncompressed.data(), &outpos, Uncompressed.size()); + if (ret != LZMA_OK) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "lzma_stream_buffer_decode()=%s", + convertLZMACodeToString(ret)); + } + + return llvm::Error::success(); +} + +#endif // LLDB_ENABLE_LZMA + +} // end of namespace lzma +} // namespace lldb_private diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -208,6 +208,10 @@ /// Collection of symbols from the dynamic table. DynamicSymbolColl m_dynamic_symbols; + /// Object file parsed from .gnu_debugdata section (\sa + /// GetGnuDebugDataObjectFile()) + std::shared_ptr m_gnu_debug_data_object_file; + /// List of file specifications corresponding to the modules (shared /// libraries) on which this object file depends. mutable std::unique_ptr m_filespec_up; @@ -383,6 +387,14 @@ lldb_private::UUID &uuid); bool AnySegmentHasPhysicalAddress(); + + /// Takes the .gnu_debugdata and returns the decompressed object file that is + /// stored within that section. + /// + /// \returns either the decompressed object file stored within the + /// .gnu_debugdata section or \c nullptr if an error occured or if there's no + /// section with that name. + std::shared_ptr GetGnuDebugDataObjectFile(); }; #endif // liblldb_ObjectFileELF_h_ diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -18,6 +18,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/LZMA.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/SectionLoadList.h" @@ -1842,6 +1843,70 @@ // unified section list. if (GetType() != eTypeDebugInfo) unified_section_list = *m_sections_up; + + // If there's a .gnu_debugdata section, we'll try to read the .symtab that's + // embedded in there and replace the one in the original object file (if any). + // If there's none in the orignal object file, we add it to it. + if (auto gdd_obj_file = GetGnuDebugDataObjectFile()) { + if (auto gdd_objfile_section_list = gdd_obj_file->GetSectionList()) { + if (SectionSP symtab_section_sp = + gdd_objfile_section_list->FindSectionByType( + eSectionTypeELFSymbolTable, true)) { + SectionSP module_section_sp = unified_section_list.FindSectionByType( + eSectionTypeELFSymbolTable, true); + if (module_section_sp) + unified_section_list.ReplaceSection(module_section_sp->GetID(), + symtab_section_sp); + else + unified_section_list.AddSection(symtab_section_sp); + } + } + } +} + +std::shared_ptr ObjectFileELF::GetGnuDebugDataObjectFile() { + if (m_gnu_debug_data_object_file != nullptr) + return m_gnu_debug_data_object_file; + + SectionSP section = + GetSectionList()->FindSectionByName(ConstString(".gnu_debugdata")); + if (!section) + return nullptr; + + if (!lldb_private::lzma::isAvailable()) { + GetModule()->ReportWarning( + "No LZMA support found for reading .gnu_debugdata section"); + return nullptr; + } + + // Uncompress the data + DataExtractor data; + section->GetSectionData(data); + llvm::SmallVector uncompressedData; + auto err = lldb_private::lzma::uncompress(data.GetData(), uncompressedData); + if (err) { + GetModule()->ReportWarning( + "An error occurred while decompression the section %s: %s", + section->GetName().AsCString(), llvm::toString(std::move(err)).c_str()); + return nullptr; + } + + // Construct ObjectFileELF object from decompressed buffer + DataBufferSP gdd_data_buf( + new DataBufferHeap(uncompressedData.data(), uncompressedData.size())); + auto fspec = GetFileSpec().CopyByAppendingPathComponent( + llvm::StringRef("gnu_debugdata")); + m_gnu_debug_data_object_file.reset(new ObjectFileELF( + GetModule(), gdd_data_buf, 0, &fspec, 0, gdd_data_buf->GetByteSize())); + + // This line is essential; otherwise a breakpoint can be set but not hit. + m_gnu_debug_data_object_file->SetType(ObjectFile::eTypeDebugInfo); + + ArchSpec spec = m_gnu_debug_data_object_file->GetArchitecture(); + if (spec && m_gnu_debug_data_object_file->SetModulesArchitecture(spec)) + return m_gnu_debug_data_object_file; + + return nullptr; } // Find the arm/aarch64 mapping symbol character in the given symbol name. @@ -2649,19 +2714,29 @@ // while the reverse is not necessarily true. Section *symtab = section_list->FindSectionByType(eSectionTypeELFSymbolTable, true).get(); - if (!symtab) { - // The symtab section is non-allocable and can be stripped, so if it - // doesn't exist then use the dynsym section which should always be - // there. - symtab = - section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true) - .get(); - } if (symtab) { m_symtab_up.reset(new Symtab(symtab->GetObjectFile())); symbol_id += ParseSymbolTable(m_symtab_up.get(), symbol_id, symtab); } + // The symtab section is non-allocable and can be stripped, while the + // .dynsym section which should always be always be there. To support the + // minidebuginfo case we parse .dynsym when there's a .gnu_debuginfo + // section, nomatter if .symtab was already parsed or not. This is because + // minidebuginfo normally removes the .symtab symbols which have their + // matching .dynsym counterparts. + if (!symtab || + GetSectionList()->FindSectionByName(ConstString(".gnu_debugdata"))) { + Section *dynsym = + section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true) + .get(); + if (dynsym) { + if (!m_symtab_up) + m_symtab_up.reset(new Symtab(dynsym->GetObjectFile())); + symbol_id += ParseSymbolTable(m_symtab_up.get(), symbol_id, dynsym); + } + } + // DT_JMPREL // If present, this entry's d_ptr member holds the address of // relocation