--- a/addr2line.c
+++ b/addr2line.c
@@ -160,10 +160,11 @@
     struct dwarf_section debug_line;
     struct dwarf_section debug_ranges;
     struct dwarf_section debug_str;
+    struct dwarf_section debug_line_str;
     struct obj_info *next;
 } obj_info_t;
 
-#define DWARF_SECTION_COUNT 5
+#define DWARF_SECTION_COUNT 6
 
 static struct dwarf_section *
 obj_dwarf_section_at(obj_info_t *obj, int n)
@@ -173,7 +174,8 @@
         &obj->debug_info,
         &obj->debug_line,
         &obj->debug_ranges,
-        &obj->debug_str
+        &obj->debug_str,
+        &obj->debug_line_str,
     };
     if (n < 0 || DWARF_SECTION_COUNT <= n) {
         abort();
@@ -228,9 +230,14 @@
     return r;
 }
 
+static const char *get_nth_dirname_5(unsigned long, uint16_t, uint8_t, uint8_t, obj_info_t *, char *);
 static const char *
-get_nth_dirname(unsigned long dir, char *p)
+get_nth_dirname(unsigned long dir, uint16_t version, uint8_t format, uint8_t address_size, obj_info_t *obj, char *p)
 {
+    if (version >= 5) {
+	return get_nth_dirname_5(dir, version, format, address_size, obj, p);
+    }
+
     if (!dir--) {
 	return "";
     }
@@ -246,13 +253,20 @@
     return p;
 }
 
+static void fill_filename_5(int, uint16_t, uint8_t, uint8_t, char *, char *, line_info_t *, obj_info_t *);
 static void
-fill_filename(int file, char *include_directories, char *filenames, line_info_t *line, obj_info_t *obj)
+fill_filename(int file, uint16_t version, uint8_t format, uint8_t address_size, char *include_directories, char *filenames, line_info_t *line, obj_info_t *obj)
 {
     int i;
     char *p = filenames;
     char *filename;
     unsigned long dir;
+
+    if (version >= 5) {
+	fill_filename_5(file, version, format, address_size, include_directories, filenames, line, obj);
+	return;
+    }
+
     for (i = 1; i <= file; i++) {
 	filename = p;
 	if (!*p) {
@@ -271,13 +285,14 @@
 
 	if (i == file) {
 	    line->filename = filename;
-	    line->dirname = get_nth_dirname(dir, include_directories);
+	    line->dirname = get_nth_dirname(dir, version, format, address_size, obj, include_directories);
 	}
     }
 }
 
 static void
 fill_line(int num_traces, void **traces, uintptr_t addr, int file, int line,
+	  uint16_t version, uint8_t format, uint8_t address_size,
 	  char *include_directories, char *filenames,
 	  obj_info_t *obj, line_info_t *lines, int offset)
 {
@@ -288,7 +303,7 @@
 	/* We assume one line code doesn't result >100 bytes of native code.
        We may want more reliable way eventually... */
 	if (addr < a && a < addr + 100) {
-	    fill_filename(file, include_directories, filenames, &lines[i], obj);
+	    fill_filename(file, version, format, address_size, include_directories, filenames, &lines[i], obj);
 	    lines[i].line = line;
 	}
     }
@@ -298,6 +313,8 @@
     uint64_t unit_length;
     uint16_t version;
     uint8_t format; /* 4 or 8 */
+    uint8_t address_size;
+    uint8_t segment_selector_size;
     uint64_t header_length;
     uint8_t minimum_instruction_length;
     uint8_t maximum_operations_per_instruction;
@@ -312,6 +329,7 @@
     const char *cu_end;
 };
 
+static int debug_line_header_skip_directories_5(char **, struct LineNumberProgramHeader *);
 static int
 parse_debug_line_header(const char **pp, struct LineNumberProgramHeader *header)
 {
@@ -330,7 +348,16 @@
 
     header->version = *(uint16_t *)p;
     p += sizeof(uint16_t);
-    if (header->version > 4) return -1;
+    if (header->version > 5) return -1;
+
+    if (header->version >= 5) {
+	header->address_size = *(uint8_t *)p++;
+	/* header->segment_selector_size = *(uint8_t *)p; */
+	if (*p != 0) return -1;
+	p++;
+    } else {
+	header->address_size = 0;
+    }
 
     header->header_length = header->format == 4 ? *(uint32_t *)p : *(uint64_t *)p;
     p += header->format;
@@ -357,12 +384,16 @@
     if (p >= header->cu_end) return -1;
 
     /* skip include directories */
-    while (*p) {
-	p = memchr(p, '\0', header->cu_end - p);
-	if (!p) return -1;
+    if (header->version >= 5) {
+	if (debug_line_header_skip_directories_5((char **)&p, header)) return -1;
+    } else {
+	while (*p) {
+	    p = memchr(p, '\0', header->cu_end - p);
+	    if (!p) return -1;
+	    p++;
+	}
 	p++;
-    }
-    p++;
+    } 
 
     header->filenames = p;
 
@@ -397,6 +428,9 @@
 #define FILL_LINE()						    \
     do {							    \
 	fill_line(num_traces, traces, addr, file, line,		    \
+		  header.version,				    \
+		  header.format,				    \
+		  header.address_size,				    \
                   (char *)header.include_directories,               \
                   (char *)header.filenames,                         \
 		  obj, lines, offset);				    \
@@ -808,6 +842,16 @@
     DW_FORM_addrx4 = 0x2c
 };
 
+/* Content type codes */
+enum
+{
+    DW_LNCT_path = 0x01,
+    DW_LNCT_directory_index = 0x02,
+    DW_LNCT_timestamp = 0x03,
+    DW_LNCT_size = 0x04,
+    DW_LNCT_MD5 = 0x05
+};
+
 enum {
     VAL_none = 0,
     VAL_cstr = 1,
@@ -822,6 +866,9 @@
     char *file;
     char *current_cu;
     uint64_t current_low_pc;
+    uint16_t debug_line_version;
+    uint8_t debug_line_format;
+    uint8_t debug_line_address_size;
     char *debug_line_cu_end;
     char *debug_line_files;
     char *debug_line_directories;
@@ -1006,6 +1053,9 @@
     if (parse_debug_line_header(&p, &header))
         return -1;
 
+    reader->debug_line_version = header.version;
+    reader->debug_line_format = header.format;
+    reader->debug_line_address_size = header.address_size;
     reader->debug_line_cu_end = (char *)header.cu_end;
     reader->debug_line_directories = (char *)header.include_directories;
     reader->debug_line_files = (char *)header.filenames;
@@ -1053,10 +1103,15 @@
 static const char *
 get_cstr_value(DebugInfoValue *v)
 {
-    if (v->as.ptr) {
-        return v->as.ptr + v->off;
-    } else {
-        return NULL;
+    switch (v->form) {
+      case DW_FORM_strp:
+	if (v->as.ptr) {
+	    return v->as.ptr + v->off;
+	} else {
+	    return NULL;
+	}
+      default:
+	return NULL;
     }
 }
 
@@ -1578,7 +1633,7 @@
                 line.sname = get_cstr_value(&v);
                 break;
               case DW_AT_call_file:
-                fill_filename((int)v.as.uint64, reader->debug_line_directories, reader->debug_line_files, &line, reader->obj);
+                fill_filename((int)v.as.uint64, reader->debug_line_version, reader->debug_line_format, reader->debug_line_address_size, reader->debug_line_directories, reader->debug_line_files, &line, reader->obj);
                 break;
               case DW_AT_call_line:
                 line.line = (int)v.as.uint64;
@@ -1752,7 +1807,8 @@
                     ".debug_info",
                     ".debug_line",
                     ".debug_ranges",
-                    ".debug_str"
+                    ".debug_str",
+                    ".debug_line_str",
                 };
 
                 for (j=0; j < DWARF_SECTION_COUNT; j++) {
@@ -1817,6 +1873,7 @@
             if (di_read_cu(&reader)) goto use_symtab;
             debug_info_read(&reader, num_traces, traces, lines, offset);
         }
+        if (reader.debug_line_version >= 5) goto use_symtab;
     }
     else {
         /* This file doesn't have dwarf, use symtab or dynsym */
@@ -2008,7 +2065,8 @@
                     "__debug_info",
                     "__debug_line",
                     "__debug_ranges",
-                    "__debug_str"
+                    "__debug_str",
+                    "__debug_line_str",
                 };
                 struct LP(segment_command) *scmd = (struct LP(segment_command) *)lcmd;
                 if (strcmp(scmd->segname, "__TEXT") == 0) {
@@ -2291,6 +2349,122 @@
     free(dladdr_fbases);
 }
 
+static const char *
+get_nth_dirname_5(unsigned long dir, uint16_t version, uint8_t format, uint8_t address_size, obj_info_t *obj, char *p)
+{
+	const char *ret = "";
+	uint64_t i, j;
+	DebugInfoReader reader = {
+	    .format = format,
+	    .address_size = address_size,
+	    .p = p
+	};
+	uint8_t format_count = read_uint8(&reader.p);
+	uint64_t *content_types = calloc(format_count, sizeof(uint64_t)); 
+	uint64_t *forms = calloc(format_count, sizeof(uint64_t)); 
+	if (content_types == NULL || forms == NULL) return "";
+	for (i = 0; i < format_count; ++i) {
+	    content_types[i] = uleb128(&reader.p);
+	    forms[i] = uleb128(&reader.p);
+	}
+	uint64_t directories_count = uleb128(&reader.p);
+	DebugInfoValue v = {{}};
+	for (j = 0; j < directories_count; ++j) {
+	    for (i = 0; i < format_count; ++i) {
+		debug_info_reader_read_value(&reader, forms[i], &v);
+		if (j == dir && content_types[i] == DW_LNCT_path) {
+		    switch (forms[i]) {
+		      case DW_FORM_line_strp:
+			ret = &obj->debug_line_str.ptr[v.as.uint64];
+			break;
+		    }
+		}
+	    }
+	}
+	free(forms);
+	free(content_types);
+	return ret;
+}
+
+static void
+fill_filename_5(int file, uint16_t version, uint8_t format, uint8_t address_size, char *include_directories, char *filenames, line_info_t *line, obj_info_t *obj)
+{
+	char *p = filenames;
+	unsigned long dir;
+
+	uint64_t i, j;
+	DebugInfoReader reader = {
+	    .format = format,
+	    .address_size = address_size,
+	    .p = p
+	};
+	uint8_t format_count = read_uint8(&reader.p);
+	uint64_t *content_types = calloc(format_count, sizeof(uint64_t)); 
+	uint64_t *forms = calloc(format_count, sizeof(uint64_t)); 
+	if (content_types == NULL || forms == NULL) return;
+	for (i = 0; i < format_count; ++i) {
+	    content_types[i] = uleb128(&reader.p);
+	    forms[i] = uleb128(&reader.p);
+	}
+	uint64_t file_names_count = uleb128(&reader.p);
+	DebugInfoValue v = {{}};
+	for (j = 0; j < file_names_count; ++j) {
+	    for (i = 0; i < format_count; ++i) {
+		debug_info_reader_read_value(&reader, forms[i], &v);
+		if ((int)j == file) {
+		    switch (content_types[i]) {
+		      case DW_LNCT_path:
+			switch (forms[i]) {
+			  case DW_FORM_line_strp:
+			    line->filename = &obj->debug_line_str.ptr[v.as.uint64];
+			    break;
+			}
+			break;
+		      case DW_LNCT_directory_index:
+			switch (forms[i]) {
+			  case DW_FORM_udata:
+			    dir = v.as.uint64;
+			    break;
+			}
+			break;
+		    }
+		}
+	    }
+	}
+	free(forms);
+	free(content_types);
+	line->dirname = get_nth_dirname_5(dir, version, format, address_size, obj, include_directories);
+	return;
+}
+
+static int
+debug_line_header_skip_directories_5(char **p, struct LineNumberProgramHeader *header)
+{
+	uint64_t i, j;
+	DebugInfoReader reader = {
+	    .format = header->format,
+	    .address_size = header->address_size,
+	    .p = *p
+	};
+	uint8_t format_count = read_uint8(&reader.p);
+	uint64_t *forms = calloc(format_count, sizeof(uint64_t)); 
+	if (forms == NULL) return -1;
+	for (i = 0; i < format_count; ++i) {
+	    uleb128(&reader.p); /* content type code */
+	    forms[i] = uleb128(&reader.p);
+	}
+	uint64_t directories_count = uleb128(&reader.p);
+	DebugInfoValue v = {{}};
+	for (j = 0; j < directories_count; ++j) {
+	    for (i = 0; i < format_count; ++i) {
+		debug_info_reader_read_value(&reader, forms[i], &v);
+	    }
+	}
+	free(forms);
+	*p = reader.p;
+	return 0;
+}
+
 /* From FreeBSD's lib/libstand/printf.c */
 /*-
  * Copyright (c) 1986, 1988, 1991, 1993
