Blob Blame History Raw
From 256a67e6a5a07e37997d3a5ef64204a99b8e5a50 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mark@klomp.org>
Date: Mon, 25 Jan 2021 15:33:34 +0100
Subject: [PATCH] DWARF5

---
 coregrind/m_debuginfo/d3basics.c        |  99 ++++
 coregrind/m_debuginfo/priv_d3basics.h   | 195 +++++-
 coregrind/m_debuginfo/priv_readdwarf.h  |   3 +-
 coregrind/m_debuginfo/priv_readdwarf3.h |   3 +-
 coregrind/m_debuginfo/readdwarf.c       | 465 ++++++++++++---
 coregrind/m_debuginfo/readdwarf3.c      | 748 +++++++++++++++++++-----
 coregrind/m_debuginfo/readelf.c         |  33 +-
 coregrind/m_debuginfo/readmacho.c       |  14 +-
 8 files changed, 1304 insertions(+), 256 deletions(-)

diff --git a/coregrind/m_debuginfo/d3basics.c b/coregrind/m_debuginfo/d3basics.c
index b6d13c118..e1127ffe2 100644
--- a/coregrind/m_debuginfo/d3basics.c
+++ b/coregrind/m_debuginfo/d3basics.c
@@ -128,6 +128,16 @@ const HChar* ML_(pp_DW_TAG) ( DW_TAG tag )
       case DW_TAG_type_unit:          return "DW_TAG_type_unit";
       case DW_TAG_rvalue_reference_type: return "DW_TAG_rvalue_reference_type";
       case DW_TAG_template_alias:     return "DW_TAG_template_alias";
+      /* DWARF 5.  */
+      case DW_TAG_coarray_type:       return "DW_TAG_coarray_type";
+      case DW_TAG_generic_subrange:   return "DW_TAG_generic_subrange";
+      case DW_TAG_dynamic_type:       return "DW_TAG_dynamic_type";
+      case DW_TAG_atomic_type:        return "DW_TAG_atomic_type";
+      case DW_TAG_call_site:          return "DW_TAG_call_site";
+      case DW_TAG_call_site_parameter:
+         return "DW_TAG_call_site_parameter";
+      case DW_TAG_skeleton_unit:      return "DW_TAG_skeleton_unit";
+      case DW_TAG_immutable_type:     return "DW_TAG_immutable_type";
       /* SGI/MIPS Extensions.  */
       case DW_TAG_MIPS_loop:          return "DW_TAG_MIPS_loop";
       /* HP extensions.  See:
@@ -140,6 +150,16 @@ const HChar* ML_(pp_DW_TAG) ( DW_TAG tag )
       case DW_TAG_class_template:     return "DW_TAG_class_template";
       case DW_TAG_GNU_BINCL:          return "DW_TAG_GNU_BINCL";
       case DW_TAG_GNU_EINCL:          return "DW_TAG_GNU_EINCL";
+      case DW_TAG_GNU_template_template_param:
+         return "DW_TAG_GNU_template_template_param";
+      case DW_TAG_GNU_template_parameter_pack:
+         return"DW_TAG_GNU_template_parameter_pack";
+      case DW_TAG_GNU_formal_parameter_pack:
+         return "DW_TAG_GNU_formal_parameter_pack";
+      case DW_TAG_GNU_call_site:
+         return "DW_TAG_GNU_call_site";
+      case DW_TAG_GNU_call_site_parameter:
+         return "DW_TAG_GNU_call_site_parameter";
       /* Extensions for UPC.  See: http://upc.gwu.edu/~upc.  */
       case DW_TAG_upc_shared_type:    return "DW_TAG_upc_shared_type";
       case DW_TAG_upc_strict_type:    return "DW_TAG_upc_strict_type";
@@ -180,6 +200,27 @@ const HChar* ML_(pp_DW_FORM) ( DW_FORM form )
       case DW_FORM_exprloc:   return "DW_FORM_exprloc";
       case DW_FORM_flag_present:return "DW_FORM_flag_present";
       case DW_FORM_ref_sig8:  return "DW_FORM_ref_sig8";
+      case DW_FORM_strx:      return "DW_FORM_strx";
+      case DW_FORM_addrx:     return "DW_FORM_addrx";
+      case DW_FORM_ref_sup4:  return "DW_FORM_ref_sup4";
+      case DW_FORM_strp_sup:  return "DW_FORM_strp_sup";
+      case DW_FORM_data16:    return "DW_FORM_data16";
+      case DW_FORM_line_strp: return "DW_FORM_line_strp";
+      case DW_FORM_implicit_const:return "DW_FORM_implicit_const";
+      case DW_FORM_loclistx:  return "DW_FORM_loclistx";
+      case DW_FORM_rnglistx:  return "DW_FORM_rnglistx";
+      case DW_FORM_ref_sup8:  return "DW_FORM_ref_sup8";
+      case DW_FORM_strx1:     return "DW_FORM_strx1";
+      case DW_FORM_strx2:     return "DW_FORM_strx2";
+      case DW_FORM_strx3:     return "DW_FORM_strx3";
+      case DW_FORM_strx4:     return "DW_FORM_strx4";
+      case DW_FORM_addrx1:    return "DW_FORM_addrx1";
+      case DW_FORM_addrx2:    return "DW_FORM_addrx2";
+      case DW_FORM_addrx3:    return "DW_FORM_addrx3";
+      case DW_FORM_addrx4:    return "DW_FORM_addrx4";
+      /* GNU Debug Fission extensions.  */
+      case DW_FORM_GNU_addr_index:return "DW_FORM_GNU_addr_index";
+      case DW_FORM_GNU_str_index:return "DW_FORM_GNU_str_index";
       case DW_FORM_GNU_ref_alt:return "DW_FORM_GNU_ref_alt";
       case DW_FORM_GNU_strp_alt:return "DW_FORM_GNU_strp_alt";
    }
@@ -286,6 +327,36 @@ const HChar* ML_(pp_DW_AT) ( DW_AT attr )
       case DW_AT_const_expr: return "DW_AT_const_expr";
       case DW_AT_enum_class: return "DW_AT_enum_class";
       case DW_AT_linkage_name: return "DW_AT_linkage_name";
+      /* DWARF 5 values.  */
+      case DW_AT_string_length_bit_size: return "DW_AT_string_length_bit_size";
+      case DW_AT_string_length_byte_size: return "DW_AT_string_length_byte_size";
+      case DW_AT_rank: return "DW_AT_rank";
+      case DW_AT_str_offsets_base: return "DW_AT_str_offsets_base";
+      case DW_AT_addr_base: return "DW_AT_addr_base";
+      case DW_AT_rnglists_base: return "DW_AT_rnglists_base";
+      case DW_AT_dwo_name: return "DW_AT_dwo_name";
+      case DW_AT_reference: return "DW_AT_reference";
+      case DW_AT_rvalue_reference: return "DW_AT_rvalue_reference";
+      case DW_AT_macros: return "DW_AT_macros";
+      case DW_AT_call_all_calls: return "DW_AT_call_all_calls";
+      case DW_AT_call_all_source_calls: return "DW_AT_call_all_source_calls";
+      case DW_AT_call_all_tail_calls: return "DW_AT_call_all_tail_calls";
+      case DW_AT_call_return_pc: return "DW_AT_call_return_pc";
+      case DW_AT_call_value: return "DW_AT_call_value";
+      case DW_AT_call_origin: return "DW_AT_call_origin";
+      case DW_AT_call_parameter: return "DW_AT_call_parameter";
+      case DW_AT_call_pc: return "DW_AT_call_pc";
+      case DW_AT_call_tail_call: return "DW_AT_call_tail_call";
+      case DW_AT_call_target: return "DW_AT_call_target";
+      case DW_AT_call_target_clobbered: return "DW_AT_call_target_clobbered";
+      case DW_AT_call_data_location: return "DW_AT_call_data_location";
+      case DW_AT_call_data_value: return "DW_AT_call_data_value";
+      case DW_AT_noreturn: return "DW_AT_noreturn";
+      case DW_AT_alignment: return "DW_AT_alignment";
+      case DW_AT_export_symbols: return "DW_AT_export_symbols";
+      case DW_AT_deleted: return "DW_AT_deleted";
+      case DW_AT_defaulted: return "DW_AT_defaulted";
+      case DW_AT_loclists_base: return "DW_AT_loclists_base";
       /* SGI/MIPS extensions.  */
       /* case DW_AT_MIPS_fde: return "DW_AT_MIPS_fde"; */
       /* DW_AT_MIPS_fde == DW_AT_HP_unmodifiable */
@@ -322,8 +393,36 @@ const HChar* ML_(pp_DW_AT) ( DW_AT attr )
       case DW_AT_body_begin: return "DW_AT_body_begin";
       case DW_AT_body_end: return "DW_AT_body_end";
       case DW_AT_GNU_vector: return "DW_AT_GNU_vector";
+      case DW_AT_GNU_guarded_by: return "DW_AT_GNU_guarded_by";
+      case DW_AT_GNU_pt_guarded_by: return "DW_AT_GNU_pt_guarded_by";
+      case DW_AT_GNU_guarded: return "DW_AT_GNU_guarded";
+      case DW_AT_GNU_pt_guarded: return "DW_AT_GNU_pt_guarded";
+      case DW_AT_GNU_locks_excluded: return "DW_AT_GNU_locks_excluded";
+      case DW_AT_GNU_exclusive_locks_required: return "DW_AT_GNU_exclusive_locks_required";
+      case DW_AT_GNU_shared_locks_required: return "DW_AT_GNU_shared_locks_required";
+      case DW_AT_GNU_odr_signature: return "DW_AT_GNU_odr_signature";
+      case DW_AT_GNU_template_name: return "DW_AT_GNU_template_name";
+      case DW_AT_GNU_call_site_value: return "DW_AT_GNU_call_site_value";
+      case DW_AT_GNU_call_site_data_value: return "DW_AT_GNU_call_site_data_value";
+      case DW_AT_GNU_call_site_target: return "DW_AT_GNU_call_site_target";
+      case DW_AT_GNU_call_site_target_clobbered: return "DW_AT_GNU_call_site_target_clobbered";
+      case DW_AT_GNU_tail_call: return "DW_AT_GNU_tail_call";
       case DW_AT_GNU_all_tail_call_sites: return "DW_AT_GNU_all_tail_call_sites";
       case DW_AT_GNU_all_call_sites: return "DW_AT_GNU_all_call_sites";
+      case DW_AT_GNU_all_source_call_sites: return "DW_AT_GNU_all_source_call_sites";
+      case DW_AT_GNU_locviews: return "DW_AT_GNU_locviews";
+      case DW_AT_GNU_entry_view: return "DW_AT_GNU_entry_view";
+      case DW_AT_GNU_macros: return "DW_AT_GNU_macros";
+      case DW_AT_GNU_deleted: return "DW_AT_GNU_deleted";
+      case DW_AT_GNU_dwo_name: return "DW_AT_GNU_dwo_name";
+      case DW_AT_GNU_dwo_id: return "DW_AT_GNU_dwo_id";
+      case DW_AT_GNU_ranges_base: return "DW_AT_GNU_ranges_base";
+      case DW_AT_GNU_addr_base: return "DW_AT_GNU_addr_base";
+      case DW_AT_GNU_pubnames: return "DW_AT_GNU_pubnames";
+      case DW_AT_GNU_pubtypes: return "DW_AT_GNU_pubtypes";
+      case DW_AT_GNU_numerator: return "DW_AT_GNU_numerator";
+      case DW_AT_GNU_denominator: return "DW_AT_GNU_denominator";
+      case DW_AT_GNU_bias: return "DW_AT_GNU_bias";
       /* VMS extensions.  */
       case DW_AT_VMS_rtnbeg_pd_address: return "DW_AT_VMS_rtnbeg_pd_address";
       /* UPC extension.  */
diff --git a/coregrind/m_debuginfo/priv_d3basics.h b/coregrind/m_debuginfo/priv_d3basics.h
index b60e3e8eb..9d825e39e 100644
--- a/coregrind/m_debuginfo/priv_d3basics.h
+++ b/coregrind/m_debuginfo/priv_d3basics.h
@@ -108,6 +108,15 @@ typedef enum
     DW_TAG_type_unit = 0x41,
     DW_TAG_rvalue_reference_type = 0x42,
     DW_TAG_template_alias = 0x43,
+    /* DWARF 5.  */
+    DW_TAG_coarray_type = 0x44,
+    DW_TAG_generic_subrange = 0x45,
+    DW_TAG_dynamic_type = 0x46,
+    DW_TAG_atomic_type = 0x47,
+    DW_TAG_call_site = 0x48,
+    DW_TAG_call_site_parameter = 0x49,
+    DW_TAG_skeleton_unit = 0x4a,
+    DW_TAG_immutable_type = 0x4b,
     /* SGI/MIPS Extensions.  */
     DW_TAG_MIPS_loop = 0x4081,
     /* HP extensions.  See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz .  */
@@ -118,6 +127,11 @@ typedef enum
     DW_TAG_class_template = 0x4103,	/* For C++.  */
     DW_TAG_GNU_BINCL = 0x4104,
     DW_TAG_GNU_EINCL = 0x4105,
+    DW_TAG_GNU_template_template_param = 0x4106,
+    DW_TAG_GNU_template_parameter_pack = 0x4107,
+    DW_TAG_GNU_formal_parameter_pack = 0x4108,
+    DW_TAG_GNU_call_site = 0x4109,
+    DW_TAG_GNU_call_site_parameter = 0x410a,
     /* Extensions for UPC.  See: http://upc.gwu.edu/~upc.  */
     DW_TAG_upc_shared_type = 0x8765,
     DW_TAG_upc_strict_type = 0x8766,
@@ -164,13 +178,23 @@ typedef enum dwarf_source_language
     DW_LANG_D = 0x0013,
     /* DWARF 4.  */
     DW_LANG_Python = 0x0014,
-    /* DWARF 5-pre. Only what GCC already outputs. */
+    /* DWARF 5.  */
     DW_LANG_Go = 0x0016,
+    DW_LANG_Modula3 = 0x0017,
+    DW_LANG_Haskell = 0x0018,
+    DW_LANG_C_plus_plus_03 = 0x0019,
     DW_LANG_C_plus_plus_11 = 0x001a,
+    DW_LANG_OCaml = 0x001b,
+    DW_LANG_Rust = 0x001c,
     DW_LANG_C11 = 0x001d,
+    DW_LANG_Swift = 0x001e,
+    DW_LANG_Julia = 0x001f,
+    DW_LANG_Dylan = 0x0020,
     DW_LANG_C_plus_plus_14 = 0x0021,
     DW_LANG_Fortran03 = 0x0022,
     DW_LANG_Fortran08 = 0x0023,
+    DW_LANG_RenderScript = 0x0024,
+    DW_LANG_BLISS = 0x0025,
     /* MIPS.  */
     DW_LANG_Mips_Assembler = 0x8001,
     /* UPC.  */
@@ -207,6 +231,28 @@ typedef enum
     DW_FORM_exprloc = 0x18,
     DW_FORM_flag_present = 0x19,
     DW_FORM_ref_sig8 = 0x20,
+    /* DWARF 5 values.  */
+    DW_FORM_strx = 0x1a,
+    DW_FORM_addrx = 0x1b,
+    DW_FORM_ref_sup4 = 0x1c,
+    DW_FORM_strp_sup = 0x1d,
+    DW_FORM_data16 = 0x1e,
+    DW_FORM_line_strp = 0x1f,
+    DW_FORM_implicit_const = 0x21,
+    DW_FORM_loclistx = 0x22,
+    DW_FORM_rnglistx = 0x23,
+    DW_FORM_ref_sup8 = 0x24,
+    DW_FORM_strx1 = 0x25,
+    DW_FORM_strx2 = 0x26,
+    DW_FORM_strx3 = 0x27,
+    DW_FORM_strx4 = 0x28,
+    DW_FORM_addrx1 = 0x29,
+    DW_FORM_addrx2 = 0x2a,
+    DW_FORM_addrx3 = 0x2b,
+    DW_FORM_addrx4 = 0x2c,
+    /* GNU Debug Fission extensions.  */
+    DW_FORM_GNU_addr_index = 0x1f01,
+    DW_FORM_GNU_str_index = 0x1f02,
     /* Extensions for DWZ multifile.
        See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open .  */
     DW_FORM_GNU_ref_alt = 0x1f20,
@@ -314,6 +360,36 @@ typedef enum
     DW_AT_const_expr      = 0x6c,
     DW_AT_enum_class      = 0x6d,
     DW_AT_linkage_name    = 0x6e,
+    DW_AT_string_length_bit_size = 0x6f,
+    DW_AT_string_length_byte_size = 0x70,
+    DW_AT_rank = 0x71,
+    DW_AT_str_offsets_base = 0x72,
+    DW_AT_addr_base = 0x73,
+    DW_AT_rnglists_base = 0x74,
+    /* 0x75 reserved.  */
+    DW_AT_dwo_name = 0x76,
+    DW_AT_reference = 0x77,
+    DW_AT_rvalue_reference = 0x78,
+    DW_AT_macros = 0x79,
+    DW_AT_call_all_calls = 0x7a,
+    DW_AT_call_all_source_calls = 0x7b,
+    DW_AT_call_all_tail_calls = 0x7c,
+    DW_AT_call_return_pc = 0x7d,
+    DW_AT_call_value = 0x7e,
+    DW_AT_call_origin = 0x7f,
+    DW_AT_call_parameter = 0x80,
+    DW_AT_call_pc = 0x81,
+    DW_AT_call_tail_call = 0x82,
+    DW_AT_call_target = 0x83,
+    DW_AT_call_target_clobbered = 0x84,
+    DW_AT_call_data_location = 0x85,
+    DW_AT_call_data_value = 0x86,
+    DW_AT_noreturn = 0x87,
+    DW_AT_alignment = 0x88,
+    DW_AT_export_symbols = 0x89,
+    DW_AT_deleted = 0x8a,
+    DW_AT_defaulted = 0x8b,
+    DW_AT_loclists_base = 0x8c,
     /* SGI/MIPS extensions.  */
     DW_AT_MIPS_fde = 0x2001,
     DW_AT_MIPS_loop_begin = 0x2002,
@@ -349,8 +425,39 @@ typedef enum
     DW_AT_body_begin = 0x2105,
     DW_AT_body_end   = 0x2106,
     DW_AT_GNU_vector = 0x2107,
+    DW_AT_GNU_guarded_by = 0x2108,
+    DW_AT_GNU_pt_guarded_by = 0x2109,
+    DW_AT_GNU_guarded = 0x210a,
+    DW_AT_GNU_pt_guarded = 0x210b,
+    DW_AT_GNU_locks_excluded = 0x210c,
+    DW_AT_GNU_exclusive_locks_required = 0x210d,
+    DW_AT_GNU_shared_locks_required = 0x210e,
+    DW_AT_GNU_odr_signature = 0x210f,
+    DW_AT_GNU_template_name = 0x2110,
+    DW_AT_GNU_call_site_value = 0x2111,
+    DW_AT_GNU_call_site_data_value = 0x2112,
+    DW_AT_GNU_call_site_target = 0x2113,
+    DW_AT_GNU_call_site_target_clobbered = 0x2114,
+    DW_AT_GNU_tail_call = 0x2115,
     DW_AT_GNU_all_tail_call_sites = 0x2116,
     DW_AT_GNU_all_call_sites = 0x2117,
+    DW_AT_GNU_all_source_call_sites = 0x2118,
+    DW_AT_GNU_locviews = 0x2137,
+    DW_AT_GNU_entry_view = 0x2138,
+    DW_AT_GNU_macros = 0x2119,
+    DW_AT_GNU_deleted = 0x211a,
+    /* GNU Debug Fission extensions.  */
+    DW_AT_GNU_dwo_name = 0x2130,
+    DW_AT_GNU_dwo_id = 0x2131,
+    DW_AT_GNU_ranges_base = 0x2132,
+    DW_AT_GNU_addr_base = 0x2133,
+    DW_AT_GNU_pubnames = 0x2134,
+    DW_AT_GNU_pubtypes = 0x2135,
+    /* https://gcc.gnu.org/wiki/DW_AT_GNU_numerator_denominator  */
+    DW_AT_GNU_numerator = 0x2303,
+    DW_AT_GNU_denominator = 0x2304,
+    /* https://gcc.gnu.org/wiki/DW_AT_GNU_bias  */
+    DW_AT_GNU_bias = 0x2305,
     /* VMS extensions.  */
     DW_AT_VMS_rtnbeg_pd_address = 0x2201,
     /* UPC extension.  */
@@ -387,6 +494,9 @@ typedef enum
     DW_ATE_decimal_float = 0xf,
     /* DWARF 4.  */
     DW_ATE_UTF = 0x10,
+    /* DWARF 5.  */
+    DW_ATE_UCS = 0x11,
+    DW_ATE_ASCII = 0x12,
     /* HP extensions.  */
     DW_ATE_HP_float80            = 0x80, /* Floating-point (80 bit).  */
     DW_ATE_HP_complex_float80    = 0x81, /* Complex floating-point (80 bit).  */
@@ -558,8 +668,35 @@ typedef enum
     /* DWARF 4 extensions.  */
     DW_OP_implicit_value = 0x9e,
     DW_OP_stack_value = 0x9f,
+    /* DWARF 5 extensions.  */
+    DW_OP_implicit_pointer = 0xa0,
+    DW_OP_addrx = 0xa1,
+    DW_OP_constx = 0xa2,
+    DW_OP_entry_value = 0xa3,
+    DW_OP_const_type = 0xa4,
+    DW_OP_regval_type = 0xa5,
+    DW_OP_deref_type = 0xa6,
+    DW_OP_xderef_type = 0xa7,
+    DW_OP_convert = 0xa8,
+    DW_OP_reinterpret = 0xa9,
     /* GNU extensions.  */
     DW_OP_GNU_push_tls_address = 0xe0,
+    DW_OP_GNU_uninit = 0xf0,
+    DW_OP_GNU_encoded_addr = 0xf1,
+    DW_OP_GNU_implicit_pointer = 0xf2,
+    DW_OP_GNU_entry_value = 0xf3,
+    DW_OP_GNU_const_type = 0xf4,
+    DW_OP_GNU_regval_type = 0xf5,
+    DW_OP_GNU_deref_type = 0xf6,
+    DW_OP_GNU_convert = 0xf7,
+    DW_OP_GNU_reinterpret = 0xf9,
+    DW_OP_GNU_parameter_ref = 0xfa,
+    /* GNU Debug Fission extensions.  */
+    DW_OP_GNU_addr_index = 0xfb,
+    DW_OP_GNU_const_index = 0xfc,
+    /* The GNU variable value extension.
+       See http://dwarfstd.org/ShowIssue.php?issue=161109.2 . */
+    DW_OP_GNU_variable_value = 0xfd,
     /* HP extensions.  */
     DW_OP_HP_unknown     = 0xe0, /* Ouch, the same as GNU_push_tls_address.  */
     DW_OP_HP_is_value    = 0xe1,
@@ -571,6 +708,62 @@ typedef enum
   }
   DW_OP;
 
+typedef enum
+  {
+    DW_UT_compile = 0x01,
+    DW_UT_type = 0x02,
+    DW_UT_partial = 0x03,
+    DW_UT_skeleton = 0x04,
+    DW_UT_split_compile = 0x05,
+    DW_UT_split_type = 0x06,
+
+    DW_UT_lo_user = 0x80,
+    DW_UT_hi_user = 0xff
+  }
+  DW_UT;
+
+typedef enum
+  {
+    DW_LNCT_path = 0x1,
+    DW_LNCT_directory_index = 0x2,
+    DW_LNCT_timestamp = 0x3,
+    DW_LNCT_size = 0x4,
+    DW_LNCT_MD5 = 0x5,
+
+    DW_LNCT_lo_user = 0x2000,
+    DW_LNCT_hi_user = 0x3fff
+  }
+  DW_LNCT;
+
+typedef enum
+  {
+    DW_RLE_end_of_list = 0x00,
+    DW_RLE_base_addressx = 0x01,
+    DW_RLE_startx_endx = 0x02,
+    DW_RLE_startx_length = 0x03,
+    DW_RLE_offset_pair = 0x04,
+    DW_RLE_base_address = 0x05,
+    DW_RLE_start_end = 0x06,
+    DW_RLE_start_length = 0x07
+  }
+  DW_RLE;
+
+typedef enum
+  {
+    DW_LLE_end_of_list = 0x00,
+    DW_LLE_base_addressx = 0x01,
+    DW_LLE_startx_endx = 0x02,
+    DW_LLE_startx_length = 0x03,
+    DW_LLE_offset_pair = 0x04,
+    DW_LLE_default_location = 0x05,
+    DW_LLE_base_address = 0x06,
+    DW_LLE_start_end = 0x07,
+    DW_LLE_start_length = 0x08,
+
+    DW_LLE_GNU_view_pair = 0x09
+  }
+  DW_LLE;
+
 const HChar* ML_(pp_DW_children) ( DW_children hashch );
 const HChar* ML_(pp_DW_TAG)      ( DW_TAG tag );
 const HChar* ML_(pp_DW_FORM)     ( DW_FORM form );
diff --git a/coregrind/m_debuginfo/priv_readdwarf.h b/coregrind/m_debuginfo/priv_readdwarf.h
index 1e3f24c2a..302266924 100644
--- a/coregrind/m_debuginfo/priv_readdwarf.h
+++ b/coregrind/m_debuginfo/priv_readdwarf.h
@@ -50,7 +50,8 @@ void ML_(read_debuginfo_dwarf3)
           DiSlice escn_debug_abbv,      /* .debug_abbrev */
           DiSlice escn_debug_line,      /* .debug_line */
           DiSlice escn_debug_str,       /* .debug_str */
-          DiSlice escn_debug_str_alt ); /* .debug_str */
+          DiSlice escn_debug_str_alt,   /* .debug_str */
+          DiSlice escn_debug_line_str );/* .debug_line_str */
 
 /* --------------------
    DWARF1 reader
diff --git a/coregrind/m_debuginfo/priv_readdwarf3.h b/coregrind/m_debuginfo/priv_readdwarf3.h
index 1a5bd61c3..f6d1dd1ee 100644
--- a/coregrind/m_debuginfo/priv_readdwarf3.h
+++ b/coregrind/m_debuginfo/priv_readdwarf3.h
@@ -45,9 +45,10 @@ ML_(new_dwarf3_reader) (
    DiSlice escn_debug_info,      DiSlice escn_debug_types,
    DiSlice escn_debug_abbv,      DiSlice escn_debug_line,
    DiSlice escn_debug_str,       DiSlice escn_debug_ranges,
+   DiSlice escn_debug_rnglists,  DiSlice escn_debug_loclists,
    DiSlice escn_debug_loc,       DiSlice escn_debug_info_alt,
    DiSlice escn_debug_abbv_alt,  DiSlice escn_debug_line_alt,
-   DiSlice escn_debug_str_alt
+   DiSlice escn_debug_str_alt,   DiSlice escn_debug_line_str
 );
 
 #endif /* ndef __PRIV_READDWARF3_H */
diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c
index 5701c504b..88d5d99f1 100644
--- a/coregrind/m_debuginfo/readdwarf.c
+++ b/coregrind/m_debuginfo/readdwarf.c
@@ -322,6 +322,123 @@ void process_extended_line_op( struct _DebugInfo* di,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
+static
+HChar * get_line_str (struct _DebugInfo* di, const UnitInfo* ui,
+                      DiCursor *data, const UInt form,
+                      DiCursor debugstr_img, DiCursor debuglinestr_img)
+{
+   HChar *str = NULL;
+   switch (form) {
+   case DW_FORM_string:
+      str = ML_(cur_step_strdup)(data, "di.gls.string");
+      break;
+   case DW_FORM_strp:
+      if (!ui->dw64)
+         str = ML_(cur_read_strdup)(ML_(cur_plus)(debugstr_img,
+                                                  ML_(cur_step_UInt)(data)),
+                                    "di.gls.strp.dw32");
+      else
+         str = ML_(cur_read_strdup)(ML_(cur_plus)(debugstr_img,
+                                                  ML_(cur_step_ULong)(data)),
+                                    "di.gls.strp.dw64");
+      break;
+   case DW_FORM_line_strp:
+      if (!ui->dw64)
+         str = ML_(cur_read_strdup)(ML_(cur_plus)(debuglinestr_img,
+                                                  ML_(cur_step_UInt)(data)),
+                                    "di.gls.line_strp.dw32");
+      else
+         str = ML_(cur_read_strdup)(ML_(cur_plus)(debuglinestr_img,
+                                                  ML_(cur_step_ULong)(data)),
+                                    "di.gls.line_strp.dw64");
+      break;
+   default:
+      ML_(symerr)(di, True,
+                  "Unknown path string FORM in .debug_line");
+      break;
+   }
+   return str;
+}
+
+static
+Int get_line_ndx (struct _DebugInfo* di,
+                  DiCursor *data, const UInt form)
+{
+   Int res = 0;
+   switch (form) {
+   case DW_FORM_data1:
+      res = ML_(cur_step_UChar)(data);
+      break;
+   case DW_FORM_data2:
+      res = ML_(cur_step_UShort)(data);
+      break;
+   case DW_FORM_udata:
+      res = step_leb128U(data);
+      break;
+   default:
+      ML_(symerr)(di, True,
+                  "Unknown directory_index value FORM in .debug_line");
+      break;
+   }
+   return res;
+}
+
+static
+DiCursor skip_line_form (struct _DebugInfo* di, const UnitInfo* ui,
+                         DiCursor d, const UInt form)
+{
+   switch (form) {
+   case DW_FORM_block: {
+      ULong len = step_leb128U(&d);
+      d = ML_(cur_plus)(d, len);
+      break;
+   }
+   case DW_FORM_block1:
+      d = ML_(cur_plus)(d, ML_(cur_read_UChar)(d) + 1);
+      break;
+   case DW_FORM_block2:
+      d = ML_(cur_plus)(d, ML_(cur_read_UShort)(d) + 2);
+      break;
+   case DW_FORM_block4:
+      d = ML_(cur_plus)(d, ML_(cur_read_UInt)(d) + 4);
+      break;
+   case DW_FORM_flag:
+   case DW_FORM_data1:
+      d = ML_(cur_plus)(d, 1);
+      break;
+   case DW_FORM_data2:
+      d = ML_(cur_plus)(d, 2);
+      break;
+   case DW_FORM_data4:
+      d = ML_(cur_plus)(d, 4);
+      break;
+   case DW_FORM_data8:
+      d = ML_(cur_plus)(d, 8);
+      break;
+   case DW_FORM_data16:
+      d = ML_(cur_plus)(d, 16);
+      break;
+   case DW_FORM_string:
+      d = ML_(cur_plus)(d, ML_(cur_strlen)(d) + 1);
+      break;
+   case DW_FORM_strp:
+   case DW_FORM_line_strp:
+   case DW_FORM_sec_offset:
+      d = ML_(cur_plus)(d, ui->dw64 ? 8 : 4);
+      break;
+   case DW_FORM_udata:
+      (void)step_leb128U(&d);
+      break;
+   case DW_FORM_sdata:
+      (void)step_leb128S(&d);
+      break;
+   default:
+      ML_(symerr)(di, True, "Unknown FORM in .debug_line");
+      break;
+   }
+   return d;
+}
+
 /* read a .debug_line section block for a compilation unit
  *
  * Input:   - theBlock must point to the start of the block
@@ -335,7 +452,9 @@ static
 void read_dwarf2_lineblock ( struct _DebugInfo* di,
                              const UnitInfo* ui, 
                              DiCursor  theBlock, /* IMAGE */
-                             Int       noLargerThan )
+                             Int       noLargerThan,
+                             DiCursor  debugstr_img,
+                             DiCursor  debuglinestr_img)
 {
    Int            i;
    DebugLineInfo  info;
@@ -348,6 +467,9 @@ void read_dwarf2_lineblock ( struct _DebugInfo* di,
    DiCursor       external = theBlock;
    DiCursor       data = theBlock;
 
+   UChar          p_ndx = 0, d_ndx = 0; /* DWARF5 path and dir index. */
+   UInt           forms[256];           /* DWARF5 forms. */
+
    /* fndn_ix_xa is an xarray of fndn_ix (indexes in di->fndnpool) which
       are build from file names harvested from the DWARF2
       info.  Entry [0] is the "null" pool index and is never referred to
@@ -372,17 +494,6 @@ void read_dwarf2_lineblock ( struct _DebugInfo* di,
    fndn_ix_xa = VG_(newXA) (ML_(dinfo_zalloc), "di.rd2l.2", ML_(dinfo_free),
                             sizeof(UInt) );
 
-   /* DWARF2 starts numbering filename entries at 1, so we need to
-      add a dummy zeroth entry to the table. */
-   fndn_ix = 0; // 0 is the "null" index in a fixed pool.
-   VG_(addToXA) (fndn_ix_xa, &fndn_ix);
-
-   if (ML_(cur_is_valid)(ui->compdir))
-      dirname = ML_(addStrFromCursor)(di, ui->compdir);
-   else
-      dirname = ML_(addStr)(di, ".", -1);
-   VG_(addToXA) (dirname_xa, &dirname);
-
    info.li_length = step_initial_length_field( &external, &is64 );
    if (di->ddump_line)
       VG_(printf)("  Length:                      %llu\n", 
@@ -402,13 +513,19 @@ void read_dwarf2_lineblock ( struct _DebugInfo* di,
       VG_(printf)("  DWARF Version:               %d\n", 
                   (Int)info.li_version);
 
-   if (info.li_version != 2 && info.li_version != 3 && info.li_version != 4) {
+   if (info.li_version != 2 && info.li_version != 3 && info.li_version != 4
+       && info.li_version != 5) {
       ML_(symerr)(di, True,
-                  "Only DWARF version 2, 3 and 4 line info "
+                  "Only DWARF version 2, 3, 4 and 5 line info "
                   "is currently supported.");
       goto out;
    }
 
+   if (info.li_version >= 5) {
+      /* UChar addr_size = */ ML_(cur_step_UChar)(&external);
+      /* UChar seg_size = */  ML_(cur_step_UChar)(&external);
+   }
+
    info.li_header_length = is64 ? ML_(cur_step_ULong)(&external) 
                                 : (ULong)(ML_(cur_step_UInt)(&external));
    if (di->ddump_line)
@@ -485,60 +602,141 @@ void read_dwarf2_lineblock ( struct _DebugInfo* di,
    /* skip over "standard_opcode_lengths" */
    data = ML_(cur_plus)(standard_opcodes, info.li_opcode_base - 1);
 
-   /* Read the contents of the Directory table.  */
-   if (di->ddump_line)
-      VG_(printf)(" The Directory Table%s\n", 
-                  ML_(cur_read_UChar)(data) == 0 ? " is empty." : ":" );
-
-   while (ML_(cur_read_UChar)(data) != 0) {
+   if (ML_(cur_is_valid)(ui->compdir))
+      dirname = ML_(addStrFromCursor)(di, ui->compdir);
+   else
+      dirname = ML_(addStr)(di, ".", -1);
 
-      HChar* data_str = ML_(cur_read_strdup)(data, "di.rd2l.1");
+   if (info.li_version < 5) {
+      /* Read the contents of the Directory table.  */
       if (di->ddump_line)
-         VG_(printf)("  %s\n", data_str);
-
-      /* If data[0] is '/', then 'data' is an absolute path and we
-         don't mess with it.  Otherwise, construct the
-         path 'ui->compdir' ++ "/" ++ 'data'. */
-
-      if (data_str[0] != '/' 
-          /* not an absolute path */
-          && ML_(cur_is_valid)(ui->compdir)
-          /* actually got something sensible for compdir */
-          && ML_(cur_strlen)(ui->compdir))
-      {
-         HChar* compdir_str = ML_(cur_read_strdup)(ui->compdir, "di.rd2l.1b");
-         SizeT  len = VG_(strlen)(compdir_str) + 1 + VG_(strlen)(data_str);
-         HChar *buf = ML_(dinfo_zalloc)("di.rd2l.1c", len + 1);
-
-         VG_(strcpy)(buf, compdir_str);
-         VG_(strcat)(buf, "/");
-         VG_(strcat)(buf, data_str);
-
-         dirname = ML_(addStr)(di, buf, len);
-         VG_(addToXA) (dirname_xa, &dirname);
-         if (0) VG_(printf)("rel path  %s\n", buf);
-         ML_(dinfo_free)(compdir_str);
-         ML_(dinfo_free)(buf);
-      } else {
-         /* just use 'data'. */
-         dirname = ML_(addStr)(di,data_str,-1);
-         VG_(addToXA) (dirname_xa, &dirname);
-         if (0) VG_(printf)("abs path  %s\n", data_str);
+         VG_(printf)("The Directory Table%s\n",
+                     ML_(cur_read_UChar)(data) == 0 ? " is empty." : ":" );
+
+      /* DWARF2 starts numbering filename entries at 1, so we need to
+         add a dummy zeroth entry to the table.  */
+      fndn_ix = 0; // 0 is the "null" index in a fixed pool.
+      VG_(addToXA) (fndn_ix_xa, &fndn_ix);
+      VG_(addToXA) (dirname_xa, &dirname);
+
+      while (ML_(cur_read_UChar)(data) != 0) {
+
+         HChar* data_str = ML_(cur_read_strdup)(data, "di.rd2l.1");
+         if (di->ddump_line)
+            VG_(printf)("  %s\n", data_str);
+
+         /* If data[0] is '/', then 'data' is an absolute path and we
+            don't mess with it.  Otherwise, construct the
+            path 'ui->compdir' ++ "/" ++ 'data'. */
+
+         if (data_str[0] != '/'
+             /* not an absolute path */
+             && ML_(cur_is_valid)(ui->compdir)
+             /* actually got something sensible for compdir */
+             && ML_(cur_strlen)(ui->compdir))
+         {
+            HChar* compdir_str = ML_(cur_read_strdup)(ui->compdir,
+                                                      "di.rd2l.1b");
+            SizeT  len = VG_(strlen)(compdir_str) + 1 + VG_(strlen)(data_str);
+            HChar *buf = ML_(dinfo_zalloc)("di.rd2l.1c", len + 1);
+
+            VG_(strcpy)(buf, compdir_str);
+            VG_(strcat)(buf, "/");
+            VG_(strcat)(buf, data_str);
+
+            dirname = ML_(addStr)(di, buf, len);
+            VG_(addToXA) (dirname_xa, &dirname);
+            if (0) VG_(printf)("rel path  %s\n", buf);
+            ML_(dinfo_free)(compdir_str);
+            ML_(dinfo_free)(buf);
+         } else {
+            /* just use 'data'. */
+            dirname = ML_(addStr)(di,data_str,-1);
+            VG_(addToXA) (dirname_xa, &dirname);
+            if (0) VG_(printf)("abs path  %s\n", data_str);
+         }
+
+         data = ML_(cur_plus)(data, VG_(strlen)(data_str) + 1);
+         ML_(dinfo_free)(data_str);
       }
 
-      data = ML_(cur_plus)(data, VG_(strlen)(data_str) + 1);
-      ML_(dinfo_free)(data_str);
-   }
+      if (di->ddump_line)
+         VG_(printf)("\n");
 
-   if (di->ddump_line)
-      VG_(printf)("\n");
+      if (ML_(cur_read_UChar)(data) != 0) {
+         ML_(symerr)(di, True,
+                     "can't find NUL at end of DWARF2 directory table");
+         goto out;
+      }
+      data = ML_(cur_plus)(data, 1);
+   } else {
+      UInt directories_count;
+      UChar directory_entry_format_count = ML_(cur_step_UChar)(&data);
+      UInt n;
+      for (n = 0; n < directory_entry_format_count; n++) {
+         UInt lnct = step_leb128U(&data);
+         UInt form = step_leb128U(&data);
+         if (lnct == DW_LNCT_path)
+            p_ndx = n;
+         forms[n] = form;
+      }
+      directories_count = step_leb128U(&data);
+      /* Read the contents of the Directory table.  */
+      if (di->ddump_line)
+         VG_(printf)(" dwarf The Directory Table%s\n",
+                     directories_count == 0 ? " is empty." : ":" );
+
+      for (n = 0; n < directories_count; n++) {
+         UInt f;
+         for (f = 0; f < directory_entry_format_count; f++) {
+            UInt form = forms[f];
+            if (f == p_ndx) {
+               HChar *data_str = get_line_str (di, ui, &data, form,
+                                               debugstr_img,
+                                               debuglinestr_img);
+               if (di->ddump_line)
+                  VG_(printf)("  %s\n", data_str);
+
+               /* If data[0] is '/', then 'data' is an absolute path and we
+                  don't mess with it.  Otherwise, construct the
+                  path 'ui->compdir' ++ "/" ++ 'data'. */
+
+               if (data_str[0] != '/'
+                   /* not an absolute path */
+                   && ML_(cur_is_valid)(ui->compdir)
+                   /* actually got something sensible for compdir */
+                   && ML_(cur_strlen)(ui->compdir))
+               {
+                  HChar* compdir_str = ML_(cur_read_strdup)(ui->compdir,
+                                                            "di.rd2l.1b");
+                  SizeT  len = VG_(strlen)(compdir_str) + 1
+                     + VG_(strlen)(data_str);
+                  HChar *buf = ML_(dinfo_zalloc)("di.rd2l.1c", len + 1);
+
+                  VG_(strcpy)(buf, compdir_str);
+                  VG_(strcat)(buf, "/");
+                  VG_(strcat)(buf, data_str);
+
+                  dirname = ML_(addStr)(di, buf, len);
+                  VG_(addToXA) (dirname_xa, &dirname);
+                  if (0) VG_(printf)("rel path  %s\n", buf);
+                  ML_(dinfo_free)(compdir_str);
+                  ML_(dinfo_free)(buf);
+               } else {
+                  /* just use 'data'. */
+                  dirname = ML_(addStr)(di,data_str,-1);
+                  VG_(addToXA) (dirname_xa, &dirname);
+                  if (0) VG_(printf)("abs path  %s\n", data_str);
+               }
 
-   if (ML_(cur_read_UChar)(data) != 0) {
-      ML_(symerr)(di, True,
-                  "can't find NUL at end of DWARF2 directory table");
-      goto out;
+               ML_(dinfo_free)(data_str);
+
+            } else {
+               data = skip_line_form (di, ui, data, form);
+            }
+         }
+      }
    }
-   data = ML_(cur_plus)(data, 1);
 
    /* Read the contents of the File Name table.  This produces a bunch
       of fndn_ix in fndn_ix_xa. */
@@ -547,33 +745,76 @@ void read_dwarf2_lineblock ( struct _DebugInfo* di,
       VG_(printf)("  Entry	Dir	Time	Size	Name\n");
    }
 
-   i = 1;
-   while (ML_(cur_read_UChar)(data) != 0) {
-      HChar* name    = ML_(cur_step_strdup)(&data, "di.rd2l.2");
-      Int    diridx  = step_leb128U(&data);
-      Int    uu_time = step_leb128U(&data); /* unused */
-      Int    uu_size = step_leb128U(&data); /* unused */
+   if (info.li_version < 5) {
+      i = 1;
+      while (ML_(cur_read_UChar)(data) != 0) {
+         HChar* name    = ML_(cur_step_strdup)(&data, "di.rd2l.2");
+         Int    diridx  = step_leb128U(&data);
+         Int    uu_time = step_leb128U(&data); /* unused */
+         Int    uu_size = step_leb128U(&data); /* unused */
+
+         dirname = safe_dirname_ix( dirname_xa, diridx );
+         fndn_ix = ML_(addFnDn) (di, name, dirname);
+         VG_(addToXA) (fndn_ix_xa, &fndn_ix);
+         if (0) VG_(printf)("file %s diridx %d\n", name, diridx );
+         if (di->ddump_line)
+            VG_(printf)("  %d\t%d\t%d\t%d\t%s\n",
+                        i, diridx, uu_time, uu_size, name);
+         i++;
+         ML_(dinfo_free)(name);
+      }
 
-      dirname = safe_dirname_ix( dirname_xa, diridx );
-      fndn_ix = ML_(addFnDn) (di, name, dirname);
-      VG_(addToXA) (fndn_ix_xa, &fndn_ix);
-      if (0) VG_(printf)("file %s diridx %d\n", name, diridx );
       if (di->ddump_line)
-         VG_(printf)("  %d\t%d\t%d\t%d\t%s\n", 
-                     i, diridx, uu_time, uu_size, name);
-      i++;
-      ML_(dinfo_free)(name);
-   }
+         VG_(printf)("\n");
 
-   if (di->ddump_line)
-      VG_(printf)("\n");
+      if (ML_(cur_read_UChar)(data) != 0) {
+         ML_(symerr)(di, True,
+                     "can't find NUL at end of DWARF2 file name table");
+         goto out;
+      }
+      data = ML_(cur_plus)(data, 1);
+   } else {
+      UInt file_names_count;
+      UChar file_names_entry_format_count = ML_(cur_step_UChar)(&data);
+      UInt n;
+      for (n = 0; n < file_names_entry_format_count; n++) {
+         UInt lnct = step_leb128U(&data);
+         UInt form = step_leb128U(&data);
+         if (lnct == DW_LNCT_path)
+            p_ndx = n;
+         if (lnct == DW_LNCT_directory_index)
+            d_ndx = n;
+         forms[n] = form;
+      }
+      file_names_count = step_leb128U(&data);
+      for (n = 0; n < file_names_count; n++) {
+         UInt f;
+         HChar* name = NULL;
+         Int diridx  = 0;
+         for (f = 0; f < file_names_entry_format_count; f++) {
+            UInt form = forms[f];
+            if (f == p_ndx)
+               name = get_line_str (di, ui, &data, form,
+                                    debugstr_img, debuglinestr_img);
+            else if (n == d_ndx)
+               diridx = get_line_ndx (di, &data, form);
+            else
+               data = skip_line_form (di, ui, data, form);
+         }
 
-   if (ML_(cur_read_UChar)(data) != 0) {
-      ML_(symerr)(di, True,
-                  "can't find NUL at end of DWARF2 file name table");
-      goto out;
+         dirname = safe_dirname_ix( dirname_xa, diridx );
+         fndn_ix = ML_(addFnDn) (di, name, dirname);
+         VG_(addToXA) (fndn_ix_xa, &fndn_ix);
+         if (0) VG_(printf)("file %s diridx %d\n", name, diridx );
+         if (di->ddump_line)
+            VG_(printf)("  %u\t%d\t%d\t%d\t%s\n",
+                        n, diridx, 0, 0, name);
+         ML_(dinfo_free)(name);
+      }
+
+      if (di->ddump_line)
+         VG_(printf)("\n");
    }
-   data = ML_(cur_plus)(data, 1);
 
    if (di->ddump_line)
       VG_(printf)(" Line Number Statements:\n");
@@ -772,9 +1013,12 @@ static DiCursor lookup_abbrev( DiCursor p, ULong acode )
       (void)step_leb128U(&p);  /* skip tag */
       p = ML_(cur_plus)(p,1);  /* skip has_children flag */
       ULong name;
+      ULong form;
       do {
          name = step_leb128U(&p); /* name */
-         (void)step_leb128U(&p);  /* form */
+         form = step_leb128U(&p);  /* form */
+         if (form == 0x21) /* DW_FORM_implicit_const */
+            step_leb128S(&p);
       }
       while (name != 0); /* until name == form == 0 */
    }
@@ -804,13 +1048,14 @@ void read_unitinfo_dwarf2( /*OUT*/UnitInfo* ui,
                                   DiCursor  unitblock_img,
                                   DiCursor  debugabbrev_img,
                                   DiCursor  debugstr_img,
-                                  DiCursor  debugstr_alt_img )
+                                  DiCursor  debugstr_alt_img,
+                                  DiCursor  debuglinestr_img)
 {
    UInt   acode, abcode;
    ULong  atoffs, blklen;
    UShort ver;
 
-   UChar    addr_size;
+   UChar    addr_size = 0;
    DiCursor p = unitblock_img;
    DiCursor end_img;
    DiCursor abbrev_img;
@@ -823,16 +1068,25 @@ void read_unitinfo_dwarf2( /*OUT*/UnitInfo* ui,
    /* This block length */
    blklen = step_initial_length_field( &p, &ui->dw64 );
 
-   /* version should be 2, 3 or 4 */
+   /* version should be 2, 3, 4 or 5 */
    ver = ML_(cur_step_UShort)(&p);
 
-   /* get offset in abbrev */
-   atoffs = ui->dw64 ? ML_(cur_step_ULong)(&p)
-                     : (ULong)(ML_(cur_step_UInt)(&p));
+   if (ver >= 5)
+      /* unit_type for DWARF5 */
+      /* unit_type = */ ML_(cur_step_UChar)(&p);
+   else
+      /* get offset in abbrev */
+      atoffs = ui->dw64 ? ML_(cur_step_ULong)(&p)
+                        : (ULong)(ML_(cur_step_UInt)(&p));
 
    /* Address size */
    addr_size = ML_(cur_step_UChar)(&p);
 
+   if (ver >= 5)
+      /* get offset in abbrev */
+      atoffs = ui->dw64 ? ML_(cur_step_ULong)(&p)
+                        : (ULong)(ML_(cur_step_UInt)(&p));
+
    /* End of this block */
    end_img = ML_(cur_plus)(unitblock_img, blklen + (ui->dw64 ? 12 : 4)); 
 
@@ -909,6 +1163,17 @@ void read_unitinfo_dwarf2( /*OUT*/UnitInfo* ui,
                   sval = ML_(cur_plus)(debugstr_img, ML_(cur_read_ULong)(p));
                p = ML_(cur_plus)(p, ui->dw64 ? 8 : 4);
                break;
+            case 0x1f: /* FORM_line_strp */ /* pointer in .debug_line_str */
+               /* 2006-01-01: only generate a value if a debug_str
+                  section was found) */
+               if (ML_(cur_is_valid)(debuglinestr_img) && !ui->dw64)
+                  sval = ML_(cur_plus)(debuglinestr_img,
+                                       ML_(cur_read_UInt)(p));
+               if (ML_(cur_is_valid)(debuglinestr_img) && ui->dw64)
+                  sval = ML_(cur_plus)(debuglinestr_img,
+                                       ML_(cur_read_ULong)(p));
+               p = ML_(cur_plus)(p, ui->dw64 ? 8 : 4);
+               break;
             case 0x08: /* FORM_string */
                sval = p;
                p = ML_(cur_plus)(p, ML_(cur_strlen)(p) + 1);
@@ -928,7 +1193,13 @@ void read_unitinfo_dwarf2( /*OUT*/UnitInfo* ui,
                p = ML_(cur_plus)(p, 8);
                /* perhaps should assign unconditionally to cval? */
                break;
+            case 0x21: /* FORM_implicit_const */
+               cval = step_leb128S (&abbrev_img);
+               break;
             /* TODO : Following ones just skip data - implement if you need */
+            case 0x1e: /* FORM_data16 */
+               p = ML_(cur_plus)(p, 16);
+               break;
             case 0x01: /* FORM_addr */
                p = ML_(cur_plus)(p, addr_size);
                break;
@@ -1028,7 +1299,8 @@ void ML_(read_debuginfo_dwarf3)
           DiSlice escn_debug_abbv,      /* .debug_abbrev */
           DiSlice escn_debug_line,      /* .debug_line */
           DiSlice escn_debug_str,       /* .debug_str */
-          DiSlice escn_debug_str_alt )  /* .debug_str */
+          DiSlice escn_debug_str_alt,   /* .debug_str */
+          DiSlice escn_debug_line_str)  /* .debug_line_str */
 {
    UnitInfo ui;
    UShort   ver;
@@ -1067,9 +1339,9 @@ void ML_(read_debuginfo_dwarf3)
 
       /* version should be 2 */
       ver = ML_(cur_read_UShort)( ML_(cur_plus)(block_img, blklen_len) );
-      if ( ver != 2 && ver != 3 && ver != 4 ) {
+      if ( ver != 2 && ver != 3 && ver != 4 && ver != 5) {
          ML_(symerr)( di, True,
-                      "Ignoring non-Dwarf2/3/4 block in .debug_info" );
+                      "Ignoring non-Dwarf2/3/4/5 block in .debug_info" );
          continue;
       }
       
@@ -1082,7 +1354,8 @@ void ML_(read_debuginfo_dwarf3)
       read_unitinfo_dwarf2( &ui, block_img, 
                                  ML_(cur_from_sli)(escn_debug_abbv),
                                  ML_(cur_from_sli)(escn_debug_str),
-                                 ML_(cur_from_sli)(escn_debug_str_alt) );
+                                 ML_(cur_from_sli)(escn_debug_str_alt),
+                                 ML_(cur_from_sli)(escn_debug_line_str));
       if (0) {
          HChar* str_name    = ML_(cur_read_strdup)(ui.name,    "di.rdd3.1");
          HChar* str_compdir = ML_(cur_read_strdup)(ui.compdir, "di.rdd3.2");
@@ -1107,7 +1380,9 @@ void ML_(read_debuginfo_dwarf3)
       read_dwarf2_lineblock(
          di, &ui,
          ML_(cur_plus)(ML_(cur_from_sli)(escn_debug_line), ui.stmt_list),
-         escn_debug_line.szB  - ui.stmt_list
+         escn_debug_line.szB  - ui.stmt_list,
+         ML_(cur_from_sli)(escn_debug_str),
+         ML_(cur_from_sli)(escn_debug_line_str)
       );
    }
 }
diff --git a/coregrind/m_debuginfo/readdwarf3.c b/coregrind/m_debuginfo/readdwarf3.c
index c4d529bc6..82bc8f241 100644
--- a/coregrind/m_debuginfo/readdwarf3.c
+++ b/coregrind/m_debuginfo/readdwarf3.c
@@ -384,6 +384,7 @@ typedef
    struct _name_form {
       ULong at_name;  // Dwarf Attribute name
       ULong at_form;  // Dwarf Attribute form
+      Long  at_val;   // Dwarf Attribute value (for implicit_const)
       UInt  skip_szB; // Nr of bytes skippable from here ...
       UInt  next_nf;  // ... to reach this attr/form index in the g_abbv.nf
    } name_form;
@@ -423,7 +424,7 @@ typedef
       void (*barf)( const HChar* ) __attribute__((noreturn));
       /* Is this 64-bit DWARF ? */
       Bool   is_dw64;
-      /* Which DWARF version ?  (2, 3 or 4) */
+      /* Which DWARF version ?  (2, 3, 4 or 5) */
       UShort version;
       /* Length of this Compilation Unit, as stated in the
          .unit_length :: InitialLength field of the CU Header.
@@ -452,12 +453,15 @@ typedef
       /* Image information for various sections. */
       DiSlice escn_debug_str;
       DiSlice escn_debug_ranges;
+      DiSlice escn_debug_rnglists;
+      DiSlice escn_debug_loclists;
       DiSlice escn_debug_loc;
       DiSlice escn_debug_line;
       DiSlice escn_debug_info;
       DiSlice escn_debug_types;
       DiSlice escn_debug_info_alt;
       DiSlice escn_debug_str_alt;
+      DiSlice escn_debug_line_str;
       /* How much to add to .debug_types resp. alternate .debug_info offsets
          in cook_die*.  */
       UWord  types_cuOff_bias;
@@ -651,25 +655,35 @@ static GExpr* make_singleton_GX ( DiCursor block, ULong nbytes )
 __attribute__((noinline))
 static GExpr* make_general_GX ( const CUConst* cc,
                                 Bool     td3,
-                                ULong    debug_loc_offset,
+                                ULong    offset,
                                 Addr     svma_of_referencing_CU )
 {
+   Bool      done;
    Addr      base;
    Cursor    loc;
    XArray*   xa; /* XArray of UChar */
    GExpr*    gx;
    Word      nbytes;
+   Bool      addBase = cc->version < 5;
 
    vg_assert(sizeof(UWord) == sizeof(Addr));
-   if (!ML_(sli_is_valid)(cc->escn_debug_loc) || cc->escn_debug_loc.szB == 0)
+   if (cc->version < 5 && (!ML_(sli_is_valid)(cc->escn_debug_loc)
+                           || cc->escn_debug_loc.szB == 0))
       cc->barf("make_general_GX: .debug_loc is empty/missing");
+   if (cc->version >= 5 && (!ML_(sli_is_valid)(cc->escn_debug_loclists)
+                           || cc->escn_debug_loclists.szB == 0))
+      cc->barf("make_general_GX: .debug_loclists is empty/missing");
 
-   init_Cursor( &loc, cc->escn_debug_loc, 0, cc->barf,
-                "Overrun whilst reading .debug_loc section(2)" );
-   set_position_of_Cursor( &loc, debug_loc_offset );
+   if (cc->version < 5)
+      init_Cursor( &loc, cc->escn_debug_loc, 0, cc->barf,
+                   "Overrun whilst reading .debug_loc section(2)" );
+   else
+      init_Cursor( &loc, cc->escn_debug_loclists, 0, cc->barf,
+                   "Overrun whilst reading .debug_loclists section(2)" );
+   set_position_of_Cursor( &loc, offset );
 
-   TRACE_D3("make_general_GX (.debug_loc_offset = %llu, ioff = %llu) {\n",
-            debug_loc_offset, get_DiCursor_from_Cursor(&loc).ioff );
+   TRACE_D3("make_general_GX (offset = %llu, ioff = %llu) {\n",
+            offset, get_DiCursor_from_Cursor(&loc).ioff );
 
    /* Who frees this xa?  It is freed before this fn exits. */
    xa = VG_(newXA)( ML_(dinfo_zalloc), "di.readdwarf3.mgGX.1", 
@@ -679,40 +693,86 @@ static GExpr* make_general_GX ( const CUConst* cc,
    { UChar c = 1; /*biasMe*/ VG_(addBytesToXA)( xa, &c, sizeof(c) ); }
 
    base = 0;
-   while (True) {
+   done = False;
+   while (!done) {
       Bool  acquire;
       UWord len;
-      /* Read a (host-)word pair.  This is something of a hack since
-         the word size to read is really dictated by the ELF file;
-         however, we assume we're reading a file with the same
-         word-sizeness as the host.  Reasonably enough. */
-      UWord w1 = get_UWord( &loc );
-      UWord w2 = get_UWord( &loc );
-
-      TRACE_D3("   %08lx %08lx\n", w1, w2);
-      if (w1 == 0 && w2 == 0)
-         break; /* end of list */
-
-      if (w1 == -1UL) {
-         /* new value for 'base' */
-         base = w2;
-         continue;
+      UWord w1;
+      UWord w2;
+      if (cc->version < 5) {
+         /* Read a (host-)word pair.  This is something of a hack since
+            the word size to read is really dictated by the ELF file;
+            however, we assume we're reading a file with the same
+            word-sizeness as the host.  Reasonably enough. */
+         w1 = get_UWord( &loc );
+         w2 = get_UWord( &loc );
+
+         TRACE_D3("   %08lx %08lx\n", w1, w2);
+         if (w1 == 0 && w2 == 0) {
+            done = True;
+            break; /* end of list */
+         }
+
+         if (w1 == -1UL) {
+            /* new value for 'base' */
+            base = w2;
+            continue;
+         }
+         /* else a location expression follows */
+         len = (UWord)get_UShort( &loc );
+      } else {
+         w1 = 0;
+         w2 = 0;
+         len = 0;
+         DW_LLE r = get_UChar( &loc );
+         switch (r) {
+         case DW_LLE_end_of_list:
+            done = True;
+            break;
+         case DW_LLE_base_address:
+            base = get_UWord( &loc );
+            break;
+         case DW_LLE_start_length:
+            w1 = get_UWord( &loc );
+            w2 = w1 + get_ULEB128( &loc );
+            len = get_ULEB128( &loc );
+            break;
+         case DW_LLE_offset_pair:
+            w1 = base + get_ULEB128( &loc );
+            w2 = base + get_ULEB128( &loc );
+            len = get_ULEB128( &loc );
+            break;
+         case DW_LLE_start_end:
+            w1 = get_UWord ( &loc );
+            w2 = get_UWord ( &loc );
+            len = get_ULEB128( &loc );
+            break;
+         case DW_LLE_GNU_view_pair:
+            get_ULEB128( &loc );
+            get_ULEB128( &loc );
+            break;
+         case DW_LLE_base_addressx:
+         case DW_LLE_startx_endx:
+         case DW_LLE_startx_length:
+         case DW_LLE_default_location:
+         default:
+            cc->barf( "Unhandled or unknown loclists entry" );
+            done = True;
+         }
       }
 
-      /* else a location expression follows */
       /* else enumerate [w1+base, w2+base) */
       /* w2 is 1 past end of range, as per D3 defn for "DW_AT_high_pc"
          (sec 2.17.2) */
       if (w1 > w2) {
          TRACE_D3("negative range is for .debug_loc expr at "
                   "file offset %llu\n", 
-                  debug_loc_offset);
+                  offset);
          cc->barf( "negative range in .debug_loc section" );
       }
 
       /* ignore zero length ranges */
       acquire = w1 < w2;
-      len     = (UWord)get_UShort( &loc );
 
       if (acquire) {
          UWord  w;
@@ -720,9 +780,9 @@ static GExpr* make_general_GX ( const CUConst* cc,
          UChar  c;
          c = 0; /* !isEnd*/
          VG_(addBytesToXA)( xa, &c, sizeof(c) );
-         w = w1    + base + svma_of_referencing_CU;
+         w = w1    + (addBase ? base : 0) + svma_of_referencing_CU;
          VG_(addBytesToXA)( xa, &w, sizeof(w) );
-         w = w2 -1 + base + svma_of_referencing_CU;
+         w = w2 -1 + (addBase ? base : 0) + svma_of_referencing_CU;
          VG_(addBytesToXA)( xa, &w, sizeof(w) );
          s = (UShort)len;
          VG_(addBytesToXA)( xa, &s, sizeof(s) );
@@ -839,45 +899,96 @@ get_range_list ( const CUConst* cc,
    XArray*   xa; /* XArray of AddrRange */
    AddrRange pair;
 
-   if (!ML_(sli_is_valid)(cc->escn_debug_ranges)
-       || cc->escn_debug_ranges.szB == 0)
+   if (cc->version < 5 && (!ML_(sli_is_valid)(cc->escn_debug_ranges)
+                           || cc->escn_debug_ranges.szB == 0))
       cc->barf("get_range_list: .debug_ranges is empty/missing");
+   if (cc->version >= 5 && (!ML_(sli_is_valid)(cc->escn_debug_rnglists)
+                            || cc->escn_debug_rnglists.szB == 0))
+      cc->barf("get_range_list: .debug_rnglists is empty/missing");
+
+   if (cc->version < 5)
+      init_Cursor( &ranges, cc->escn_debug_ranges, 0, cc->barf,
+                   "Overrun whilst reading .debug_ranges section(2)" );
+   else
+      init_Cursor( &ranges, cc->escn_debug_rnglists, 0, cc->barf,
+                   "Overrun whilst reading .debug_rnglists section(2)" );
 
-   init_Cursor( &ranges, cc->escn_debug_ranges, 0, cc->barf,
-                "Overrun whilst reading .debug_ranges section(2)" );
    set_position_of_Cursor( &ranges, debug_ranges_offset );
 
    /* Who frees this xa?  varstack_preen() does. */
    xa = VG_(newXA)( ML_(dinfo_zalloc), "di.readdwarf3.grl.1", ML_(dinfo_free),
                     sizeof(AddrRange) );
    base = 0;
-   while (True) {
-      /* Read a (host-)word pair.  This is something of a hack since
-         the word size to read is really dictated by the ELF file;
-         however, we assume we're reading a file with the same
-         word-sizeness as the host.  Reasonably enough. */
-      UWord w1 = get_UWord( &ranges );
-      UWord w2 = get_UWord( &ranges );
-
-      if (w1 == 0 && w2 == 0)
-         break; /* end of list. */
-
-      if (w1 == -1UL) {
-         /* new value for 'base' */
-         base = w2;
-         continue;
-      }
+   if (cc->version < 5) {
+      while (True) {
+         /* Read a (host-)word pair.  This is something of a hack since
+            the word size to read is really dictated by the ELF file;
+            however, we assume we're reading a file with the same
+            word-sizeness as the host.  Reasonably enough. */
+         UWord w1 = get_UWord( &ranges );
+         UWord w2 = get_UWord( &ranges );
 
-      /* else enumerate [w1+base, w2+base) */
-      /* w2 is 1 past end of range, as per D3 defn for "DW_AT_high_pc"
-         (sec 2.17.2) */
-      if (w1 > w2)
-         cc->barf( "negative range in .debug_ranges section" );
-      if (w1 < w2) {
-         pair.aMin = w1     + base + svma_of_referencing_CU;
-         pair.aMax = w2 - 1 + base + svma_of_referencing_CU;
-         vg_assert(pair.aMin <= pair.aMax);
-         VG_(addToXA)( xa, &pair );
+         if (w1 == 0 && w2 == 0)
+            break; /* end of list. */
+
+         if (w1 == -1UL) {
+            /* new value for 'base' */
+            base = w2;
+            continue;
+         }
+
+         /* else enumerate [w1+base, w2+base) */
+         /* w2 is 1 past end of range, as per D3 defn for "DW_AT_high_pc"
+            (sec 2.17.2) */
+         if (w1 > w2)
+            cc->barf( "negative range in .debug_ranges section" );
+         if (w1 < w2) {
+            pair.aMin = w1     + base + svma_of_referencing_CU;
+            pair.aMax = w2 - 1 + base + svma_of_referencing_CU;
+            vg_assert(pair.aMin <= pair.aMax);
+            VG_(addToXA)( xa, &pair );
+         }
+      }
+   } else {
+      Bool done = False;
+      while (!done) {
+         UWord w1 = 0;
+         UWord w2 = 0;
+         DW_RLE r = get_UChar( &ranges );
+         switch (r) {
+         case DW_RLE_end_of_list:
+            done = True;
+            break;
+         case DW_RLE_base_address:
+            base = get_UWord( &ranges );
+            break;
+         case DW_RLE_start_length:
+            w1 = get_UWord( &ranges );
+            w2 = w1 + get_ULEB128( &ranges );
+            break;
+         case DW_RLE_offset_pair:
+            w1 = base + get_ULEB128( &ranges );
+            w2 = base + get_ULEB128( &ranges );
+            break;
+         case DW_RLE_start_end:
+            w1 = get_UWord ( &ranges );
+            w2 = get_UWord ( &ranges );
+            break;
+         case DW_RLE_base_addressx:
+         case DW_RLE_startx_endx:
+         case DW_RLE_startx_length:
+         default:
+            cc->barf( "Unhandled or unknown range list entry" );
+            done = True;
+         }
+         if (w1 > w2)
+            cc->barf( "negative range in .debug_rnglists section" );
+         if (w1 < w2) {
+            pair.aMin = w1     + svma_of_referencing_CU;
+            pair.aMax = w2 - 1 + svma_of_referencing_CU;
+            vg_assert(pair.aMin <= pair.aMax);
+            VG_(addToXA)( xa, &pair );
+         }
       }
    }
    return xa;
@@ -930,6 +1041,8 @@ static void init_ht_abbvs (CUConst* cc,
          }
          ta->nf[ta_nf_n].at_name = get_ULEB128( &c );
          ta->nf[ta_nf_n].at_form = get_ULEB128( &c );
+         if (ta->nf[ta_nf_n].at_form == DW_FORM_implicit_const)
+            ta->nf[ta_nf_n].at_val = get_SLEB128( &c );
          if (ta->nf[ta_nf_n].at_name == 0 && ta->nf[ta_nf_n].at_form == 0) {
             ta_nf_n++;
             break; 
@@ -1005,7 +1118,7 @@ void parse_CU_Header ( /*OUT*/CUConst* cc,
 		       Bool type_unit,
                        Bool alt_info )
 {
-   UChar  address_size;
+   UChar  address_size, unit_type;
    ULong  debug_abbrev_offset;
 
    VG_(memset)(cc, 0, sizeof(*cc));
@@ -1021,10 +1134,21 @@ void parse_CU_Header ( /*OUT*/CUConst* cc,
 
    /* version */
    cc->version = get_UShort( c );
-   if (cc->version != 2 && cc->version != 3 && cc->version != 4)
-      cc->barf( "parse_CU_Header: is neither DWARF2 nor DWARF3 nor DWARF4" );
+   if (cc->version != 2 && cc->version != 3 && cc->version != 4
+       && cc->version != 5)
+      cc->barf( "parse_CU_Header: "
+                "is neither DWARF2 nor DWARF3 nor DWARF4 nor DWARF5" );
    TRACE_D3("   Version:       %d\n", (Int)cc->version );
 
+   /* unit type */
+   if (cc->version >= 5) {
+      unit_type = get_UChar( c );
+      address_size = get_UChar( c );
+   } else {
+      unit_type = type_unit ? DW_UT_type : DW_UT_compile;
+      address_size = 0; /* Will be read later. */
+   }
+
    /* debug_abbrev_offset */
    debug_abbrev_offset = get_Dwarfish_UWord( c, cc->is_dw64 );
    if (debug_abbrev_offset >= escn_debug_abbv.szB)
@@ -1035,7 +1159,9 @@ void parse_CU_Header ( /*OUT*/CUConst* cc,
       give up.  This makes it safe to assume elsewhere that
       DW_FORM_addr and DW_FORM_ref_addr can be treated as a host
       word. */
-   address_size = get_UChar( c );
+   if (cc->version < 5)
+      address_size = get_UChar( c );
+
    if (address_size != sizeof(void*))
       cc->barf( "parse_CU_Header: invalid address_size" );
    TRACE_D3("   Pointer Size:  %d\n", (Int)address_size );
@@ -1043,7 +1169,7 @@ void parse_CU_Header ( /*OUT*/CUConst* cc,
    cc->is_type_unit = type_unit;
    cc->is_alt_info = alt_info;
 
-   if (type_unit) {
+   if (type_unit || (cc->version >= 5 && unit_type == DW_UT_type)) {
       cc->type_signature = get_ULong( c );
       cc->type_offset = get_Dwarfish_UWord( c, cc->is_dw64 );
    }
@@ -1130,8 +1256,9 @@ typedef
 static
 void get_Form_contents ( /*OUT*/FormContents* cts,
                          const CUConst* cc, Cursor* c,
-                         Bool td3, DW_FORM form )
+                         Bool td3, const name_form *abbv )
 {
+   DW_FORM form = abbv->at_form;
    VG_(bzero_inline)(cts, sizeof(*cts));
    // !!! keep switch in sync with get_Form_szB. The nr of characters read below
    // must be computed similarly in get_Form_szB.
@@ -1157,6 +1284,19 @@ void get_Form_contents ( /*OUT*/FormContents* cts,
          cts->szB   = 8;
          TRACE_D3("%llu", cts->u.val);
          break;
+     case DW_FORM_data16: {
+         /* This is more like a block than an integral value.  */
+         ULong    u64b;
+         DiCursor data16 = get_DiCursor_from_Cursor(c);
+         TRACE_D3("data16: ");
+         for (u64b = 16; u64b > 0; u64b--) {
+            UChar u8 = get_UChar(c);
+            TRACE_D3("%x ", (UInt)u8);
+         }
+         cts->u.cur = data16;
+         cts->szB   = - (Long)16;
+         break;
+         }
       case DW_FORM_sec_offset:
          cts->u.val = (ULong)get_Dwarfish_UWord( c, cc->is_dw64 );
          cts->szB   = cc->is_dw64 ? 8 : 4;
@@ -1242,6 +1382,26 @@ void get_Form_contents ( /*OUT*/FormContents* cts,
          cts->szB   = - (Long)(1 + (ULong)ML_(cur_strlen)(str));
          break;
       }
+      case DW_FORM_line_strp: {
+         /* this is an offset into .debug_line_str */
+         UWord uw = (UWord)get_Dwarfish_UWord( c, cc->is_dw64 );
+         if (!ML_(sli_is_valid)(cc->escn_debug_line_str)
+             || uw >= cc->escn_debug_line_str.szB)
+            cc->barf("get_Form_contents: DW_FORM_line_strp "
+                     "points outside .debug_line_str");
+         /* FIXME: check the entire string lies inside debug_line_str,
+            not just the first byte of it. */
+         DiCursor line_str
+            = ML_(cur_plus)( ML_(cur_from_sli)(cc->escn_debug_line_str), uw );
+         if (TD3) {
+            HChar* tmp = ML_(cur_read_strdup)(line_str, "di.getFC.1.5");
+            TRACE_D3("(indirect line string, offset: 0x%lx): %s", uw, tmp);
+            ML_(dinfo_free)(tmp);
+         }
+         cts->u.cur = line_str;
+         cts->szB   = - (Long)(1 + (ULong)ML_(cur_strlen)(line_str));
+         break;
+      }
       case DW_FORM_string: {
          DiCursor str = get_AsciiZ(c);
          if (TD3) {
@@ -1307,6 +1467,11 @@ void get_Form_contents ( /*OUT*/FormContents* cts,
          cts->u.val = 1;
          cts->szB   = 1;
          break;
+      case DW_FORM_implicit_const:
+         cts->u.val = (ULong)abbv->at_val;
+         cts->szB   = 8;
+         TRACE_D3("%llu", cts->u.val);
+         break;
       case DW_FORM_block1: {
          ULong    u64b;
          ULong    u64   = (ULong)get_UChar(c);
@@ -1396,9 +1561,14 @@ void get_Form_contents ( /*OUT*/FormContents* cts,
          cts->szB   = sizeof(UWord);
          break;
       }
-      case DW_FORM_indirect:
-         get_Form_contents (cts, cc, c, td3, (DW_FORM)get_ULEB128(c));
+      case DW_FORM_indirect: {
+         /* Urgh, this is ugly and somewhat unclear how it works
+            with DW_FORM_implicit_const. HACK.  */
+         name_form nfi = *abbv;
+         nfi.at_form = (DW_FORM)get_ULEB128(c);
+         get_Form_contents (cts, cc, c, td3, &nfi);
          return;
+      }
 
       case DW_FORM_GNU_ref_alt:
          cts->u.val = get_Dwarfish_UWord(c, cc->is_dw64);
@@ -1471,6 +1641,7 @@ UInt get_Form_szB (const CUConst* cc, DW_FORM form )
       case DW_FORM_data2: return 2;
       case DW_FORM_data4: return 4;
       case DW_FORM_data8: return 8;
+      case DW_FORM_data16: return 16;
       case DW_FORM_sec_offset:
          if (cc->is_dw64)
             return 8;
@@ -1488,6 +1659,7 @@ UInt get_Form_szB (const CUConst* cc, DW_FORM form )
          else 
             return sizeof_Dwarfish_UWord (cc->is_dw64);
       case DW_FORM_strp:
+      case DW_FORM_line_strp:
          return sizeof_Dwarfish_UWord (cc->is_dw64);
       case DW_FORM_string: 
          return VARSZ_FORM;
@@ -1522,6 +1694,8 @@ UInt get_Form_szB (const CUConst* cc, DW_FORM form )
          return sizeof_Dwarfish_UWord(cc->is_dw64);
       case DW_FORM_GNU_strp_alt:
          return sizeof_Dwarfish_UWord(cc->is_dw64);
+      case DW_FORM_implicit_const:
+	 return 0; /* Value inside abbrev. */
       default:
          VG_(printf)(
             "get_Form_szB: unhandled %u (%s)\n",
@@ -1544,13 +1718,13 @@ void skip_DIE (UWord  *sibling,
    while (True) {
       if (abbv->nf[nf_i].at_name == DW_AT_sibling) {
          get_Form_contents( &cts, cc, c_die, False /*td3*/,
-                            (DW_FORM)abbv->nf[nf_i].at_form );
+                            &abbv->nf[nf_i] );
          if ( cts.szB > 0 ) 
             *sibling = cts.u.val;
          nf_i++;
       } else if (abbv->nf[nf_i].skip_szB == VARSZ_FORM) {
          get_Form_contents( &cts, cc, c_die, False /*td3*/,
-                            (DW_FORM)abbv->nf[nf_i].at_form );
+                            &abbv->nf[nf_i] );
          nf_i++;
       } else {
          advance_position_of_Cursor (c_die, (ULong)abbv->nf[nf_i].skip_szB);
@@ -1778,6 +1952,124 @@ static GExpr* get_GX ( const CUConst* cc, Bool td3, const FormContents* cts )
    return gexpr;
 }
 
+static
+HChar * get_line_str (struct _DebugInfo* di, Bool is_dw64,
+                      Cursor *data, const UInt form,
+                      DiSlice debugstr_img, DiSlice debuglinestr_img)
+{
+   HChar *str = NULL;
+   switch (form) {
+   case DW_FORM_string: {
+      DiCursor distr = get_AsciiZ(data);
+      str = ML_(cur_step_strdup)(&distr, "di.gls.string");
+      break;
+   }
+   case DW_FORM_strp: {
+      UWord uw = (UWord)get_Dwarfish_UWord( data, is_dw64 );
+      DiCursor distr
+         = ML_(cur_plus)( ML_(cur_from_sli)(debugstr_img), uw );
+      str = ML_(cur_read_strdup)(distr, "di.gls.strp");
+      break;
+   }
+   case DW_FORM_line_strp: {
+      UWord uw = (UWord)get_Dwarfish_UWord( data, is_dw64 );
+      DiCursor distr
+         = ML_(cur_plus)( ML_(cur_from_sli)(debuglinestr_img), uw );
+      str = ML_(cur_read_strdup)(distr, "di.gls.line_strp");
+      break;
+   }
+   default:
+      ML_(symerr)(di, True,
+                  "Unknown path string FORM in .debug_line");
+      break;
+   }
+   return str;
+}
+
+static
+Int get_line_ndx (struct _DebugInfo* di,
+                  Cursor *data, const UInt form)
+{
+   Int res = 0;
+   switch (form) {
+   case DW_FORM_data1:
+      res = get_UChar(data);
+      break;
+   case DW_FORM_data2:
+      res = get_UShort(data);
+      break;
+   case DW_FORM_udata:
+      res = get_ULEB128(data);
+      break;
+   default:
+      ML_(symerr)(di, True,
+                  "Unknown directory_index value FORM in .debug_line");
+      break;
+   }
+   return res;
+}
+
+static
+void skip_line_form (struct _DebugInfo* di, Bool is_dw64,
+                         Cursor *d, const UInt form)
+{
+   switch (form) {
+   case DW_FORM_block: {
+      ULong len = get_ULEB128(d);
+      advance_position_of_Cursor (d, len);
+      break;
+   }
+   case DW_FORM_block1: {
+      UChar len = get_UChar(d);
+      advance_position_of_Cursor (d, len);
+      break;
+   }
+   case DW_FORM_block2: {
+      UShort len = get_UShort(d);
+      advance_position_of_Cursor (d, len);
+      break;
+   }
+   case DW_FORM_block4: {
+      UInt len = get_UInt(d);
+      advance_position_of_Cursor (d, len);
+      break;
+   }
+   case DW_FORM_flag:
+   case DW_FORM_data1:
+      advance_position_of_Cursor (d, 1);
+      break;
+   case DW_FORM_data2:
+      advance_position_of_Cursor (d, 2);
+      break;
+   case DW_FORM_data4:
+      advance_position_of_Cursor (d, 4);
+      break;
+   case DW_FORM_data8:
+      advance_position_of_Cursor (d, 8);
+      break;
+   case DW_FORM_data16:
+      advance_position_of_Cursor (d, 16);
+      break;
+   case DW_FORM_string:
+      (void)get_AsciiZ (d);
+      break;
+   case DW_FORM_strp:
+   case DW_FORM_line_strp:
+   case DW_FORM_sec_offset:
+      advance_position_of_Cursor (d, is_dw64 ? 8 : 4);
+      break;
+   case DW_FORM_udata:
+      (void)get_ULEB128(d);
+      break;
+   case DW_FORM_sdata:
+      (void)get_SLEB128(d);
+      break;
+   default:
+      ML_(symerr)(di, True, "Unknown FORM in .debug_line");
+      break;
+   }
+}
+
 /* Returns an xarray* of directory names (indexed by the dwarf dirname
    integer).
    If 'compdir' is NULL, entry [0] will be set to "."
@@ -1786,8 +2078,8 @@ static GExpr* get_GX ( const CUConst* cc, Bool td3, const FormContents* cts )
    whatever that means, according to the DWARF3 spec.
    FIXME??? readdwarf3.c/readdwarf.c have a lot of duplicated code */
 static
-XArray* read_dirname_xa (DebugInfo* di, const HChar *compdir,
-                         Cursor *c,
+XArray* read_dirname_xa (DebugInfo* di, UShort version, const HChar *compdir,
+                         Cursor *c, const CUConst *cc,
                          Bool td3 )
 {
    XArray*        dirname_xa;   /* xarray of HChar* dirname */
@@ -1804,51 +2096,121 @@ XArray* read_dirname_xa (DebugInfo* di, const HChar *compdir,
       dirname = compdir;
       compdir_len = VG_(strlen)(compdir);
    }
-   VG_(addToXA) (dirname_xa, &dirname);
-
-   TRACE_D3(" The Directory Table%s\n", 
-            peek_UChar(c) == 0 ? " is empty." : ":" );
-
-   while (peek_UChar(c) != 0) {
-
-      DiCursor cur = get_AsciiZ(c);
-      HChar* data_str = ML_(cur_read_strdup)( cur, "dirname_xa.1" );
-      TRACE_D3("  %s\n", data_str);
-
-      /* If data_str[0] is '/', then 'data' is an absolute path and we
-         don't mess with it.  Otherwise, construct the
-         path 'compdir' ++ "/" ++ 'data'. */
-
-      if (data_str[0] != '/' 
-          /* not an absolute path */
-          && compdir
-          /* actually got something sensible for compdir */
-          && compdir_len)
-      {
-         SizeT  len = compdir_len + 1 + VG_(strlen)(data_str);
-         HChar *buf = ML_(dinfo_zalloc)("dirname_xa.2", len + 1);
-
-         VG_(strcpy)(buf, compdir);
-         VG_(strcat)(buf, "/");
-         VG_(strcat)(buf, data_str);
-
-         dirname = ML_(addStr)(di, buf, len);
-         VG_(addToXA) (dirname_xa, &dirname);
-         if (0) VG_(printf)("rel path  %s\n", buf);
-         ML_(dinfo_free)(buf);
-      } else {
-         /* just use 'data'. */
-         dirname = ML_(addStr)(di,data_str,-1);
-         VG_(addToXA) (dirname_xa, &dirname);
-         if (0) VG_(printf)("abs path  %s\n", data_str);
+
+   /* For version 5, the compdir is the first (zero) entry. */
+   if (version < 5)
+      VG_(addToXA) (dirname_xa, &dirname);
+
+   if (version < 5) {
+      TRACE_D3("The Directory Table%s\n",
+               peek_UChar(c) == 0 ? " is empty." : ":" );
+
+      while (peek_UChar(c) != 0) {
+
+         DiCursor cur = get_AsciiZ(c);
+         HChar* data_str = ML_(cur_read_strdup)( cur, "dirname_xa.1" );
+         TRACE_D3("  %s\n", data_str);
+
+         /* If data_str[0] is '/', then 'data' is an absolute path and we
+            don't mess with it.  Otherwise, construct the
+            path 'compdir' ++ "/" ++ 'data'. */
+
+         if (data_str[0] != '/'
+             /* not an absolute path */
+             && compdir
+             /* actually got something sensible for compdir */
+             && compdir_len)
+         {
+            SizeT  len = compdir_len + 1 + VG_(strlen)(data_str);
+            HChar *buf = ML_(dinfo_zalloc)("dirname_xa.2", len + 1);
+
+            VG_(strcpy)(buf, compdir);
+            VG_(strcat)(buf, "/");
+            VG_(strcat)(buf, data_str);
+
+            dirname = ML_(addStr)(di, buf, len);
+            VG_(addToXA) (dirname_xa, &dirname);
+            if (0) VG_(printf)("rel path  %s\n", buf);
+            ML_(dinfo_free)(buf);
+         } else {
+            /* just use 'data'. */
+            dirname = ML_(addStr)(di,data_str,-1);
+            VG_(addToXA) (dirname_xa, &dirname);
+            if (0) VG_(printf)("abs path  %s\n", data_str);
+         }
+
+         ML_(dinfo_free)(data_str);
+      }
+   } else {
+      UChar forms[256];
+      UChar p_ndx = 0;
+      UInt directories_count;
+      UChar directory_entry_format_count;
+      UInt n;
+      DiSlice debugstr_img = cc->escn_debug_str;
+      DiSlice debuglinestr_img = cc->escn_debug_line_str;
+
+      directory_entry_format_count = get_UChar(c);
+      for (n = 0; n < directory_entry_format_count; n++) {
+         UInt lnct = get_ULEB128(c);
+         UInt form = get_ULEB128(c);
+         if (lnct == DW_LNCT_path)
+            p_ndx = n;
+         forms[n] = form;
       }
+      directories_count = get_ULEB128(c);
+      TRACE_D3("The Directory Table%s\n",
+               directories_count == 0 ? " is empty." : ":" );
+
+      for (n = 0; n < directories_count; n++) {
+         UInt f;
+         for (f = 0; f < directory_entry_format_count; f++) {
+            UInt form = forms[f];
+            if (f == p_ndx) {
+               HChar *data_str = get_line_str (di, cc->is_dw64, c, form,
+                                               debugstr_img,
+                                               debuglinestr_img);
+               TRACE_D3("  %s\n", data_str);
+
+               /* If data_str[0] is '/', then 'data' is an absolute path and we
+                  don't mess with it.  Otherwise, construct the
+                  path 'compdir' ++ "/" ++ 'data'. */
+
+               if (data_str[0] != '/'
+                   /* not an absolute path */
+                   && compdir
+                   /* actually got something sensible for compdir */
+                   && compdir_len)
+               {
+                  SizeT  len = compdir_len + 1 + VG_(strlen)(data_str);
+                  HChar *buf = ML_(dinfo_zalloc)("dirname_xa.2", len + 1);
+
+                  VG_(strcpy)(buf, compdir);
+                  VG_(strcat)(buf, "/");
+                  VG_(strcat)(buf, data_str);
+
+                  dirname = ML_(addStr)(di, buf, len);
+                  VG_(addToXA) (dirname_xa, &dirname);
+                  if (0) VG_(printf)("rel path  %s\n", buf);
+                  ML_(dinfo_free)(buf);
+               } else {
+                  /* just use 'data'. */
+                  dirname = ML_(addStr)(di,data_str,-1);
+                  VG_(addToXA) (dirname_xa, &dirname);
+                  if (0) VG_(printf)("abs path  %s\n", data_str);
+               }
 
-      ML_(dinfo_free)(data_str);
+               ML_(dinfo_free)(data_str);
+            } else {
+               skip_line_form (di, cc->is_dw64, c, form);
+            }
+         }
+      }
    }
 
    TRACE_D3 ("\n");
 
-   if (get_UChar (c) != 0) {
+   if (version < 5 && get_UChar (c) != 0) {
       ML_(symerr)(NULL, True,
                   "could not get NUL at end of DWARF directory table");
       VG_(deleteXA)(dirname_xa);
@@ -1888,9 +2250,13 @@ void read_filename_table( /*MOD*/XArray* /* of UInt* */ fndn_ix_Table,
    get_Initial_Length( &is_dw64, &c,
                        "read_filename_table: invalid initial-length field" );
    version = get_UShort( &c );
-   if (version != 2 && version != 3 && version != 4)
-     cc->barf("read_filename_table: Only DWARF version 2, 3 and 4 line info "
-              "is currently supported.");
+   if (version != 2 && version != 3 && version != 4 && version != 5)
+     cc->barf("read_filename_table: Only DWARF version 2, 3, 4 and 5 "
+              "line info is currently supported.");
+   if (version >= 5) {
+      /* addrs_size = */ get_UChar( &c );
+      /* seg_size =   */ get_UChar( &c );
+   }
    /*header_length              = (ULong)*/ get_Dwarfish_UWord( &c, is_dw64 );
    /*minimum_instruction_length = */ get_UChar( &c );
    if (version >= 4)
@@ -1903,30 +2269,77 @@ void read_filename_table( /*MOD*/XArray* /* of UInt* */ fndn_ix_Table,
    for (i = 1; i < (Word)opcode_base; i++)
      (void)get_UChar( &c );
 
-   dirname_xa = read_dirname_xa(cc->di, compdir, &c, td3);
+   dirname_xa = read_dirname_xa(cc->di, version, compdir, &c, cc, td3);
 
    /* Read and record the file names table */
    vg_assert( VG_(sizeXA)( fndn_ix_Table ) == 0 );
-   /* Add a dummy index-zero entry.  DWARF3 numbers its files
-      from 1, for some reason. */
-   fndn_ix = ML_(addFnDn) ( cc->di, "<unknown_file>", NULL );
-   VG_(addToXA)( fndn_ix_Table, &fndn_ix );
-   while (peek_UChar(&c) != 0) {
-      DiCursor cur = get_AsciiZ(&c);
-      str = ML_(addStrFromCursor)( cc->di, cur );
-      dir_xa_ix = get_ULEB128( &c );
-      if (dirname_xa != NULL 
-          && dir_xa_ix >= 0 && dir_xa_ix < VG_(sizeXA) (dirname_xa))
-         dirname = *(HChar**)VG_(indexXA) ( dirname_xa, dir_xa_ix );
-      else
-         dirname = NULL;
-      fndn_ix = ML_(addFnDn)( cc->di, str, dirname);
-      TRACE_D3("  read_filename_table: %ld fndn_ix %u %s %s\n",
-               VG_(sizeXA)(fndn_ix_Table), fndn_ix, 
-               dirname, str);
+   if (version < 5) {
+      /* Add a dummy index-zero entry.  DWARF3 numbers its files
+         from 1, for some reason. */
+      fndn_ix = ML_(addFnDn) ( cc->di, "<unknown_file>", NULL );
       VG_(addToXA)( fndn_ix_Table, &fndn_ix );
-      (void)get_ULEB128( &c ); /* skip last mod time */
-      (void)get_ULEB128( &c ); /* file size */
+      while (peek_UChar(&c) != 0) {
+         DiCursor cur = get_AsciiZ(&c);
+         str = ML_(addStrFromCursor)( cc->di, cur );
+         dir_xa_ix = get_ULEB128( &c );
+         if (dirname_xa != NULL
+             && dir_xa_ix >= 0 && dir_xa_ix < VG_(sizeXA) (dirname_xa))
+            dirname = *(HChar**)VG_(indexXA) ( dirname_xa, dir_xa_ix );
+         else
+            dirname = NULL;
+         fndn_ix = ML_(addFnDn)( cc->di, str, dirname);
+         TRACE_D3("  read_filename_table: %ld fndn_ix %u %s %s\n",
+                  VG_(sizeXA)(fndn_ix_Table), fndn_ix,
+                  dirname, str);
+         VG_(addToXA)( fndn_ix_Table, &fndn_ix );
+         (void)get_ULEB128( &c ); /* skip last mod time */
+         (void)get_ULEB128( &c ); /* file size */
+      }
+   } else {
+      UChar forms[256];
+      UChar p_ndx = 0, d_ndx = 0;
+      UInt file_names_count;
+      UChar file_names_entry_format_count;
+      UInt n;
+      DiSlice debugstr_img = cc->escn_debug_str;
+      DiSlice debuglinestr_img = cc->escn_debug_line_str;
+      file_names_entry_format_count = get_UChar( &c );
+      for (n = 0; n < file_names_entry_format_count; n++) {
+         UInt lnct = get_ULEB128( &c );
+         UInt form = get_ULEB128( &c );
+         if (lnct == DW_LNCT_path)
+            p_ndx = n;
+         if (lnct == DW_LNCT_directory_index)
+            d_ndx = n;
+         forms[n] = form;
+      }
+      file_names_count = get_ULEB128( &c );
+      for (n = 0; n < file_names_count; n++) {
+         UInt f;
+         dir_xa_ix  = 0;
+         str = NULL;
+         for (f = 0; f < file_names_entry_format_count; f++) {
+            UInt form = forms[f];
+            if (f == p_ndx)
+               str = get_line_str (cc->di, cc->is_dw64, &c, form,
+                                   debugstr_img, debuglinestr_img);
+            else if (n == d_ndx)
+               dir_xa_ix = get_line_ndx (cc->di, &c, form);
+            else
+               skip_line_form (cc->di, cc->is_dw64, &c, form);
+         }
+
+         if (dirname_xa != NULL
+             && dir_xa_ix >= 0 && dir_xa_ix < VG_(sizeXA) (dirname_xa))
+            dirname = *(HChar**)VG_(indexXA) ( dirname_xa, dir_xa_ix );
+         else
+            dirname = NULL;
+         fndn_ix = ML_(addFnDn)( cc->di, str, dirname);
+         TRACE_D3("  read_filename_table: %ld fndn_ix %u %s %s\n",
+                  VG_(sizeXA)(fndn_ix_Table), fndn_ix,
+                  dirname, str);
+         VG_(addToXA)( fndn_ix_Table, &fndn_ix );
+      }
    }
    /* We're done!  The rest of it is not interesting. */
    if (dirname_xa != NULL)
@@ -2011,11 +2424,12 @@ static void trace_DIE(
    while (True) {
       DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
       DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+      const name_form *nf = &abbv->nf[nf_i];
       nf_i++;
       if (attr == 0 && form == 0) break;
       VG_(printf)("     %-18s: ", ML_(pp_DW_AT)(attr));
       /* Get the form contents, so as to print them */
-      get_Form_contents( &cts, cc, &c, True, form );
+      get_Form_contents( &cts, cc, &c, True, nf );
       if (attr == DW_AT_sibling && cts.szB > 0) {
          sibling = cts.u.val;
       }
@@ -2094,9 +2508,10 @@ static void parse_var_DIE (
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr == DW_AT_low_pc && cts.szB > 0) {
             ip_lo   = cts.u.val;
             have_lo = True;
@@ -2196,9 +2611,10 @@ static void parse_var_DIE (
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr == DW_AT_low_pc && cts.szB > 0) {
             ip_lo   = cts.u.val;
             have_lo = True;
@@ -2282,9 +2698,10 @@ static void parse_var_DIE (
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          n_attrs++;
          if (attr == DW_AT_name && cts.szB < 0) {
             name = ML_(addStrFromCursor)( cc->di, cts.u.cur );
@@ -2646,9 +3063,10 @@ static const HChar* get_inlFnName (Int absori, const CUConst* cc, Bool td3)
    while (True) {
       DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
       DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+      const name_form *nf = &abbv->nf[nf_i];
       nf_i++;
       if (attr == 0 && form == 0) break;
-      get_Form_contents( &cts, cc, &c, False/*td3*/, form );
+      get_Form_contents( &cts, cc, &c, False/*td3*/, nf );
       if (attr == DW_AT_name) {
          HChar *fnname;
          if (cts.szB >= 0)
@@ -2720,9 +3138,10 @@ static Bool parse_inl_DIE (
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr == DW_AT_low_pc && cts.szB > 0) {
             ip_lo   = cts.u.val;
             have_lo = True;
@@ -2764,9 +3183,10 @@ static Bool parse_inl_DIE (
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr == DW_AT_call_file && cts.szB > 0) {
             Int ftabIx = (Int)cts.u.val;
             if (ftabIx >= 1
@@ -3090,9 +3510,10 @@ static void parse_type_DIE ( /*MOD*/XArray* /* of TyEnt */ tyents,
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr != DW_AT_language)
             continue;
          if (cts.szB <= 0)
@@ -3132,9 +3553,10 @@ static void parse_type_DIE ( /*MOD*/XArray* /* of TyEnt */ tyents,
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr == DW_AT_name && cts.szB < 0) {
             typeE.Te.TyBase.name
                = ML_(cur_read_strdup)( cts.u.cur,
@@ -3243,9 +3665,10 @@ static void parse_type_DIE ( /*MOD*/XArray* /* of TyEnt */ tyents,
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr == DW_AT_byte_size && cts.szB > 0) {
             typeE.Te.TyPorR.szB = cts.u.val;
          }
@@ -3275,9 +3698,10 @@ static void parse_type_DIE ( /*MOD*/XArray* /* of TyEnt */ tyents,
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr == DW_AT_name && cts.szB < 0) {
             typeE.Te.TyEnum.name
                = ML_(cur_read_strdup)( cts.u.cur,
@@ -3356,9 +3780,10 @@ static void parse_type_DIE ( /*MOD*/XArray* /* of TyEnt */ tyents,
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr == DW_AT_name && cts.szB < 0) {
             atomE.Te.Atom.name 
               = ML_(cur_read_strdup)( cts.u.cur,
@@ -3411,9 +3836,10 @@ static void parse_type_DIE ( /*MOD*/XArray* /* of TyEnt */ tyents,
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr == DW_AT_name && cts.szB < 0) {
             typeE.Te.TyStOrUn.name
                = ML_(cur_read_strdup)( cts.u.cur,
@@ -3498,9 +3924,10 @@ static void parse_type_DIE ( /*MOD*/XArray* /* of TyEnt */ tyents,
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr == DW_AT_name && cts.szB < 0) {
             fieldE.Te.Field.name
                = ML_(cur_read_strdup)( cts.u.cur,
@@ -3585,9 +4012,10 @@ static void parse_type_DIE ( /*MOD*/XArray* /* of TyEnt */ tyents,
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr == DW_AT_type && cts.szB > 0) {
             typeE.Te.TyArray.typeR
                = cook_die_using_form( cc, (UWord)cts.u.val, form );
@@ -3626,9 +4054,10 @@ static void parse_type_DIE ( /*MOD*/XArray* /* of TyEnt */ tyents,
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr == DW_AT_lower_bound && cts.szB > 0 
              && form_expected_for_bound (form)) {
             lower      = (Long)cts.u.val;
@@ -3714,9 +4143,10 @@ static void parse_type_DIE ( /*MOD*/XArray* /* of TyEnt */ tyents,
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr == DW_AT_name && cts.szB < 0) {
             typeE.Te.TyTyDef.name
                = ML_(cur_read_strdup)( cts.u.cur,
@@ -3764,9 +4194,10 @@ static void parse_type_DIE ( /*MOD*/XArray* /* of TyEnt */ tyents,
       while (True) {
          DW_AT   attr = (DW_AT)  abbv->nf[nf_i].at_name;
          DW_FORM form = (DW_FORM)abbv->nf[nf_i].at_form;
+         const name_form *nf = &abbv->nf[nf_i];
          nf_i++;
          if (attr == 0 && form == 0) break;
-         get_Form_contents( &cts, cc, c_die, False/*td3*/, form );
+         get_Form_contents( &cts, cc, c_die, False/*td3*/, nf );
          if (attr == DW_AT_type && cts.szB > 0) {
             typeE.Te.TyQual.typeR
                = cook_die_using_form( cc, (UWord)cts.u.val, form );
@@ -4486,6 +4917,9 @@ static void trace_debug_abbrev (const DebugInfo* di,
             while (True) {
                ULong at_name = get_ULEB128( &abbv );
                ULong at_form = get_ULEB128( &abbv );
+               if (at_form == DW_FORM_implicit_const) {
+                  /* Long at_val = */ get_SLEB128 ( &abbv );
+               }
                if (at_name == 0 && at_form == 0) break;
                TRACE_D3("    %-18s %s\n", 
                         ML_(pp_DW_AT)(at_name), ML_(pp_DW_FORM)(at_form));
@@ -4502,9 +4936,10 @@ void new_dwarf3_reader_wrk (
    DiSlice escn_debug_info,      DiSlice escn_debug_types,
    DiSlice escn_debug_abbv,      DiSlice escn_debug_line,
    DiSlice escn_debug_str,       DiSlice escn_debug_ranges,
+   DiSlice escn_debug_rnglists,  DiSlice escn_debug_loclists,
    DiSlice escn_debug_loc,       DiSlice escn_debug_info_alt,
    DiSlice escn_debug_abbv_alt,  DiSlice escn_debug_line_alt,
-   DiSlice escn_debug_str_alt
+   DiSlice escn_debug_str_alt,   DiSlice escn_debug_line_str
 )
 {
    XArray* /* of TyEnt */     tyents = NULL;
@@ -4738,6 +5173,8 @@ void new_dwarf3_reader_wrk (
          cc.escn_debug_str      = pass == 0 ? escn_debug_str_alt
                                             : escn_debug_str;
          cc.escn_debug_ranges   = escn_debug_ranges;
+         cc.escn_debug_rnglists = escn_debug_rnglists;
+         cc.escn_debug_loclists = escn_debug_loclists;
          cc.escn_debug_loc      = escn_debug_loc;
          cc.escn_debug_line     = pass == 0 ? escn_debug_line_alt
                                             : escn_debug_line;
@@ -4746,6 +5183,7 @@ void new_dwarf3_reader_wrk (
          cc.escn_debug_types    = escn_debug_types;
          cc.escn_debug_info_alt = escn_debug_info_alt;
          cc.escn_debug_str_alt  = escn_debug_str_alt;
+         cc.escn_debug_line_str = escn_debug_line_str;
          cc.types_cuOff_bias    = escn_debug_info.szB;
          cc.alt_cuOff_bias      = escn_debug_info.szB + escn_debug_types.szB;
          cc.cu_start_offset     = cu_start_offset;
@@ -5216,9 +5654,10 @@ ML_(new_dwarf3_reader) (
    DiSlice escn_debug_info,      DiSlice escn_debug_types,
    DiSlice escn_debug_abbv,      DiSlice escn_debug_line,
    DiSlice escn_debug_str,       DiSlice escn_debug_ranges,
+   DiSlice escn_debug_rnglists,  DiSlice escn_debug_loclists,
    DiSlice escn_debug_loc,       DiSlice escn_debug_info_alt,
    DiSlice escn_debug_abbv_alt,  DiSlice escn_debug_line_alt,
-   DiSlice escn_debug_str_alt
+   DiSlice escn_debug_str_alt,   DiSlice escn_debug_line_str
 )
 {
    volatile Int  jumped;
@@ -5239,9 +5678,10 @@ ML_(new_dwarf3_reader) (
                              escn_debug_info,     escn_debug_types,
                              escn_debug_abbv,     escn_debug_line,
                              escn_debug_str,      escn_debug_ranges,
+                             escn_debug_rnglists, escn_debug_loclists,
                              escn_debug_loc,      escn_debug_info_alt,
                              escn_debug_abbv_alt, escn_debug_line_alt,
-                             escn_debug_str_alt );
+                             escn_debug_str_alt,  escn_debug_line_str );
       d3rd_jmpbuf_valid = False;
       TRACE_D3("\n------ .debug_info reading was successful ------\n");
    } else {
diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c
index bc5a732d7..404034df0 100644
--- a/coregrind/m_debuginfo/readelf.c
+++ b/coregrind/m_debuginfo/readelf.c
@@ -2577,7 +2577,10 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di )
       DiSlice debug_types_escn    = DiSlice_INVALID; // .debug_types  (dwarf4)
       DiSlice debug_abbv_escn     = DiSlice_INVALID; // .debug_abbrev (dwarf2)
       DiSlice debug_str_escn      = DiSlice_INVALID; // .debug_str    (dwarf2)
+      DiSlice debug_line_str_escn = DiSlice_INVALID; // .debug_line_str(dwarf5)
       DiSlice debug_ranges_escn   = DiSlice_INVALID; // .debug_ranges (dwarf2)
+      DiSlice debug_rnglists_escn = DiSlice_INVALID; // .debug_rnglists(dwarf5)
+      DiSlice debug_loclists_escn = DiSlice_INVALID; // .debug_loclists(dwarf5)
       DiSlice debug_loc_escn      = DiSlice_INVALID; // .debug_loc    (dwarf2)
       DiSlice debug_frame_escn    = DiSlice_INVALID; // .debug_frame  (dwarf2)
       DiSlice debug_line_alt_escn = DiSlice_INVALID; // .debug_line   (alt)
@@ -2683,10 +2686,22 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di )
          if (!ML_(sli_is_valid)(debug_str_escn))
             FIND(".zdebug_str",        debug_str_escn)
 
+         FIND(   ".debug_line_str",    debug_line_str_escn)
+         if (!ML_(sli_is_valid)(debug_line_str_escn))
+            FIND(".zdebug_str",        debug_line_str_escn)
+
          FIND(   ".debug_ranges",      debug_ranges_escn)
          if (!ML_(sli_is_valid)(debug_ranges_escn))
             FIND(".zdebug_ranges",     debug_ranges_escn)
 
+         FIND(   ".debug_rnglists",    debug_rnglists_escn)
+         if (!ML_(sli_is_valid)(debug_rnglists_escn))
+            FIND(".zdebug_rnglists",   debug_rnglists_escn)
+
+         FIND(   ".debug_loclists",    debug_loclists_escn)
+         if (!ML_(sli_is_valid)(debug_loclists_escn))
+            FIND(".zdebug_loclists",   debug_loclists_escn)
+
          FIND(   ".debug_loc",         debug_loc_escn)
          if (!ML_(sli_is_valid)(debug_loc_escn))
             FIND(".zdebug_loc",    debug_loc_escn)
@@ -2994,10 +3009,22 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di )
             if (!ML_(sli_is_valid)(debug_str_escn))
                FIND(need_dwarf2,     ".zdebug_str",       debug_str_escn)
 
+            FIND(   need_dwarf2,     ".debug_line_str",   debug_line_str_escn)
+            if (!ML_(sli_is_valid)(debug_line_str_escn))
+               FIND(need_dwarf2,     ".zdebug_line_str",  debug_line_str_escn)
+
             FIND(   need_dwarf2,     ".debug_ranges",     debug_ranges_escn)
             if (!ML_(sli_is_valid)(debug_ranges_escn))
                FIND(need_dwarf2,     ".zdebug_ranges",    debug_ranges_escn)
 
+            FIND(   need_dwarf2,     ".debug_rnglists",   debug_rnglists_escn)
+            if (!ML_(sli_is_valid)(debug_rnglists_escn))
+               FIND(need_dwarf2,     ".zdebug_rnglists",  debug_rnglists_escn)
+
+            FIND(   need_dwarf2,     ".debug_loclists",   debug_loclists_escn)
+            if (!ML_(sli_is_valid)(debug_loclists_escn))
+               FIND(need_dwarf2,     ".zdebug_loclists",  debug_loclists_escn)
+
             FIND(   need_dwarf2,     ".debug_loc",        debug_loc_escn)
             if (!ML_(sli_is_valid)(debug_loc_escn))
                FIND(need_dwarf2,     ".zdebug_loc",       debug_loc_escn)
@@ -3231,7 +3258,8 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di )
                                       debug_abbv_escn,
                                       debug_line_escn,
                                       debug_str_escn,
-                                      debug_str_alt_escn );
+                                      debug_str_alt_escn,
+                                      debug_line_str_escn);
          /* The new reader: read the DIEs in .debug_info to acquire
             information on variable types and locations or inline info.
             But only if the tool asks for it, or the user requests it on
@@ -3242,9 +3270,10 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di )
                di, debug_info_escn,     debug_types_escn,
                    debug_abbv_escn,     debug_line_escn,
                    debug_str_escn,      debug_ranges_escn,
+                   debug_rnglists_escn, debug_loclists_escn,
                    debug_loc_escn,      debug_info_alt_escn,
                    debug_abbv_alt_escn, debug_line_alt_escn,
-                   debug_str_alt_escn
+                   debug_str_alt_escn,  debug_line_str_escn
             );
          }
       }
diff --git a/coregrind/m_debuginfo/readmacho.c b/coregrind/m_debuginfo/readmacho.c
index f39ee006f..9153a74ca 100644
--- a/coregrind/m_debuginfo/readmacho.c
+++ b/coregrind/m_debuginfo/readmacho.c
@@ -1103,8 +1103,14 @@ Bool ML_(read_macho_debug_info)( struct _DebugInfo* di )
          = getsectdata(dsli, "__DWARF", "__debug_line", NULL);
       DiSlice debug_str_mscn
          = getsectdata(dsli, "__DWARF", "__debug_str", NULL);
+      DiSlice debug_line_str_mscn
+         = getsectdata(dsli, "__DWARF", "__debug_line_str", NULL);
       DiSlice debug_ranges_mscn
          = getsectdata(dsli, "__DWARF", "__debug_ranges", NULL);
+      DiSlice debug_rnglists_mscn
+         = getsectdata(dsli, "__DWARF", "__debug_rnglists", NULL);
+      DiSlice debug_loclists_mscn
+         = getsectdata(dsli, "__DWARF", "__debug_loclists", NULL);
       DiSlice debug_loc_mscn
          = getsectdata(dsli, "__DWARF", "__debug_loc", NULL);
 
@@ -1145,7 +1151,8 @@ Bool ML_(read_macho_debug_info)( struct _DebugInfo* di )
                                       debug_abbv_mscn,
                                       debug_line_mscn,
                                       debug_str_mscn,
-                                      DiSlice_INVALID /* ALT .debug_str */ );
+                                      DiSlice_INVALID, /* ALT .debug_str */
+                                      debug_line_str );
 
          /* The new reader: read the DIEs in .debug_info to acquire
             information on variable types and locations or inline info.
@@ -1160,11 +1167,14 @@ Bool ML_(read_macho_debug_info)( struct _DebugInfo* di )
                    debug_line_mscn,
                    debug_str_mscn,
                    debug_ranges_mscn,
+                   debug_rnglists_mscn,
+                   debug_loclists_mscn,
                    debug_loc_mscn,
                    DiSlice_INVALID, /* ALT .debug_info */
                    DiSlice_INVALID, /* ALT .debug_abbv */
                    DiSlice_INVALID, /* ALT .debug_line */
-                   DiSlice_INVALID  /* ALT .debug_str */
+                   DiSlice_INVALID, /* ALT .debug_str */
+                   debug_line_str_mscn  /* .debug_line_str */
             );
          }
       }
-- 
2.18.4