Add support for parsing the DW_AT_ranges attributes

This enables the DWARF reader to properly parse DW_AT_ranges attributes
in compilation units and functions. Code covered by a function is now
represented by a vector of ranges instead of a single contiguous range
and DW_AT_ranges entries are used to populate it. All the code and tests
that assumed functions to be contiguous entities has been updated to
reflect the change. DW_AT_ranges attributes found in compilation units
are parsed but no data is generated for them as it is not currently needed.

BUG=754

Change-Id: I310391b525aaba0dd329f1e3187486f2e0c6d442
Reviewed-on: https://chromium-review.googlesource.com/1124721
Reviewed-by: Ted Mielczarek <ted.mielczarek@gmail.com>
diff --git a/Makefile.am b/Makefile.am
index 139fce3..649db2f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -574,6 +574,7 @@
 	src/common/dwarf_cfi_to_module.cc \
 	src/common/dwarf_cu_to_module.cc \
 	src/common/dwarf_line_to_module.cc \
+	src/common/dwarf_range_list_handler.cc \
 	src/common/language.cc \
 	src/common/module.cc \
 	src/common/path_helper.cc \
@@ -622,6 +623,7 @@
 	src/common/dwarf_cfi_to_module.cc \
 	src/common/dwarf_cu_to_module.cc \
 	src/common/dwarf_line_to_module.cc \
+	src/common/dwarf_range_list_handler.cc \
 	src/common/language.cc \
 	src/common/md5.cc \
 	src/common/module.cc \
@@ -661,6 +663,7 @@
 	src/common/dwarf_cu_to_module_unittest.cc \
 	src/common/dwarf_line_to_module.cc \
 	src/common/dwarf_line_to_module_unittest.cc \
+	src/common/dwarf_range_list_handler.cc \
 	src/common/language.cc \
 	src/common/memory_range_unittest.cc \
 	src/common/module.cc \
diff --git a/Makefile.in b/Makefile.in
index 1381bf9..46822d4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -694,10 +694,10 @@
 	src/common/dwarf_cu_to_module_unittest.cc \
 	src/common/dwarf_line_to_module.cc \
 	src/common/dwarf_line_to_module_unittest.cc \
-	src/common/language.cc src/common/memory_range_unittest.cc \
-	src/common/module.cc src/common/module_unittest.cc \
-	src/common/path_helper.cc src/common/stabs_reader.cc \
-	src/common/stabs_reader_unittest.cc \
+	src/common/dwarf_range_list_handler.cc src/common/language.cc \
+	src/common/memory_range_unittest.cc src/common/module.cc \
+	src/common/module_unittest.cc src/common/path_helper.cc \
+	src/common/stabs_reader.cc src/common/stabs_reader_unittest.cc \
 	src/common/stabs_to_module.cc \
 	src/common/stabs_to_module_unittest.cc \
 	src/common/test_assembler.cc src/common/dwarf/bytereader.cc \
@@ -740,6 +740,7 @@
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-dwarf_cu_to_module_unittest.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-dwarf_line_to_module.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.$(OBJEXT) \
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-dwarf_range_list_handler.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-language.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-memory_range_unittest.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-module.$(OBJEXT) \
@@ -1402,7 +1403,8 @@
 am__src_tools_linux_dump_syms_dump_syms_SOURCES_DIST =  \
 	src/common/dwarf_cfi_to_module.cc \
 	src/common/dwarf_cu_to_module.cc \
-	src/common/dwarf_line_to_module.cc src/common/language.cc \
+	src/common/dwarf_line_to_module.cc \
+	src/common/dwarf_range_list_handler.cc src/common/language.cc \
 	src/common/module.cc src/common/path_helper.cc \
 	src/common/stabs_reader.cc src/common/stabs_to_module.cc \
 	src/common/dwarf/bytereader.cc \
@@ -1421,6 +1423,7 @@
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_dump_syms_dump_syms_OBJECTS = src/common/src_tools_linux_dump_syms_dump_syms-dwarf_cfi_to_module.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_tools_linux_dump_syms_dump_syms-dwarf_cu_to_module.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_tools_linux_dump_syms_dump_syms-dwarf_line_to_module.$(OBJEXT) \
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_tools_linux_dump_syms_dump_syms-language.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_tools_linux_dump_syms_dump_syms-module.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_tools_linux_dump_syms_dump_syms-path_helper.$(OBJEXT) \
@@ -1486,7 +1489,8 @@
 am__src_tools_mac_dump_syms_dump_syms_mac_SOURCES_DIST =  \
 	src/common/dwarf_cfi_to_module.cc \
 	src/common/dwarf_cu_to_module.cc \
-	src/common/dwarf_line_to_module.cc src/common/language.cc \
+	src/common/dwarf_line_to_module.cc \
+	src/common/dwarf_range_list_handler.cc src/common/language.cc \
 	src/common/md5.cc src/common/module.cc \
 	src/common/path_helper.cc src/common/stabs_reader.cc \
 	src/common/stabs_to_module.cc src/common/dwarf/bytereader.cc \
@@ -1505,6 +1509,7 @@
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_mac_dump_syms_dump_syms_mac_OBJECTS = src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.$(OBJEXT) \
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_tools_mac_dump_syms_dump_syms_mac-language.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_tools_mac_dump_syms_dump_syms_mac-md5.$(OBJEXT) \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_tools_mac_dump_syms_dump_syms_mac-module.$(OBJEXT) \
@@ -2413,6 +2418,7 @@
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_cfi_to_module.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_cu_to_module.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_line_to_module.cc \
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_range_list_handler.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/language.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/module.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/path_helper.cc \
@@ -2463,6 +2469,7 @@
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_cfi_to_module.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_cu_to_module.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_line_to_module.cc \
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_range_list_handler.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/language.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/md5.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/module.cc \
@@ -2504,6 +2511,7 @@
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_cu_to_module_unittest.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_line_to_module.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_line_to_module_unittest.cc \
+@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_range_list_handler.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/language.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/memory_range_unittest.cc \
 @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/module.cc \
@@ -4053,6 +4061,9 @@
 src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.$(OBJEXT):  \
 	src/common/$(am__dirstamp) \
 	src/common/$(DEPDIR)/$(am__dirstamp)
+src/common/src_common_dumper_unittest-dwarf_range_list_handler.$(OBJEXT):  \
+	src/common/$(am__dirstamp) \
+	src/common/$(DEPDIR)/$(am__dirstamp)
 src/common/src_common_dumper_unittest-language.$(OBJEXT):  \
 	src/common/$(am__dirstamp) \
 	src/common/$(DEPDIR)/$(am__dirstamp)
@@ -4560,6 +4571,9 @@
 src/common/src_tools_linux_dump_syms_dump_syms-dwarf_line_to_module.$(OBJEXT):  \
 	src/common/$(am__dirstamp) \
 	src/common/$(DEPDIR)/$(am__dirstamp)
+src/common/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.$(OBJEXT):  \
+	src/common/$(am__dirstamp) \
+	src/common/$(DEPDIR)/$(am__dirstamp)
 src/common/src_tools_linux_dump_syms_dump_syms-language.$(OBJEXT):  \
 	src/common/$(am__dirstamp) \
 	src/common/$(DEPDIR)/$(am__dirstamp)
@@ -4681,6 +4695,9 @@
 src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.$(OBJEXT):  \
 	src/common/$(am__dirstamp) \
 	src/common/$(DEPDIR)/$(am__dirstamp)
+src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.$(OBJEXT):  \
+	src/common/$(am__dirstamp) \
+	src/common/$(DEPDIR)/$(am__dirstamp)
 src/common/src_tools_mac_dump_syms_dump_syms_mac-language.$(OBJEXT):  \
 	src/common/$(am__dirstamp) \
 	src/common/$(DEPDIR)/$(am__dirstamp)
@@ -4811,6 +4828,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module_unittest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_range_list_handler.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-language.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-memory_range_unittest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-module.Po@am__quote@
@@ -4845,6 +4863,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-dwarf_cfi_to_module.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-dwarf_cu_to_module.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-dwarf_line_to_module.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-language.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-module.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-path_helper.Po@am__quote@
@@ -4853,6 +4872,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-language.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-md5.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-module.Po@am__quote@
@@ -5660,6 +5680,20 @@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.obj `if test -f 'src/common/dwarf_line_to_module_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf_line_to_module_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_line_to_module_unittest.cc'; fi`
 
+src/common/src_common_dumper_unittest-dwarf_range_list_handler.o: src/common/dwarf_range_list_handler.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-dwarf_range_list_handler.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_range_list_handler.Tpo -c -o src/common/src_common_dumper_unittest-dwarf_range_list_handler.o `test -f 'src/common/dwarf_range_list_handler.cc' || echo '$(srcdir)/'`src/common/dwarf_range_list_handler.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_range_list_handler.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_range_list_handler.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/common/dwarf_range_list_handler.cc' object='src/common/src_common_dumper_unittest-dwarf_range_list_handler.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_range_list_handler.o `test -f 'src/common/dwarf_range_list_handler.cc' || echo '$(srcdir)/'`src/common/dwarf_range_list_handler.cc
+
+src/common/src_common_dumper_unittest-dwarf_range_list_handler.obj: src/common/dwarf_range_list_handler.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-dwarf_range_list_handler.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_range_list_handler.Tpo -c -o src/common/src_common_dumper_unittest-dwarf_range_list_handler.obj `if test -f 'src/common/dwarf_range_list_handler.cc'; then $(CYGPATH_W) 'src/common/dwarf_range_list_handler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_range_list_handler.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_range_list_handler.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_range_list_handler.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/common/dwarf_range_list_handler.cc' object='src/common/src_common_dumper_unittest-dwarf_range_list_handler.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_range_list_handler.obj `if test -f 'src/common/dwarf_range_list_handler.cc'; then $(CYGPATH_W) 'src/common/dwarf_range_list_handler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_range_list_handler.cc'; fi`
+
 src/common/src_common_dumper_unittest-language.o: src/common/language.cc
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-language.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-language.Tpo -c -o src/common/src_common_dumper_unittest-language.o `test -f 'src/common/language.cc' || echo '$(srcdir)/'`src/common/language.cc
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-language.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-language.Po
@@ -7116,6 +7150,20 @@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_linux_dump_syms_dump_syms_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_linux_dump_syms_dump_syms-dwarf_line_to_module.obj `if test -f 'src/common/dwarf_line_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_line_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_line_to_module.cc'; fi`
 
+src/common/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.o: src/common/dwarf_range_list_handler.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_linux_dump_syms_dump_syms_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.o -MD -MP -MF src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.Tpo -c -o src/common/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.o `test -f 'src/common/dwarf_range_list_handler.cc' || echo '$(srcdir)/'`src/common/dwarf_range_list_handler.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.Tpo src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/common/dwarf_range_list_handler.cc' object='src/common/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_linux_dump_syms_dump_syms_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.o `test -f 'src/common/dwarf_range_list_handler.cc' || echo '$(srcdir)/'`src/common/dwarf_range_list_handler.cc
+
+src/common/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.obj: src/common/dwarf_range_list_handler.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_linux_dump_syms_dump_syms_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.obj -MD -MP -MF src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.Tpo -c -o src/common/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.obj `if test -f 'src/common/dwarf_range_list_handler.cc'; then $(CYGPATH_W) 'src/common/dwarf_range_list_handler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_range_list_handler.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.Tpo src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/common/dwarf_range_list_handler.cc' object='src/common/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_linux_dump_syms_dump_syms_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_linux_dump_syms_dump_syms-dwarf_range_list_handler.obj `if test -f 'src/common/dwarf_range_list_handler.cc'; then $(CYGPATH_W) 'src/common/dwarf_range_list_handler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_range_list_handler.cc'; fi`
+
 src/common/src_tools_linux_dump_syms_dump_syms-language.o: src/common/language.cc
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_linux_dump_syms_dump_syms_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_linux_dump_syms_dump_syms-language.o -MD -MP -MF src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-language.Tpo -c -o src/common/src_tools_linux_dump_syms_dump_syms-language.o `test -f 'src/common/language.cc' || echo '$(srcdir)/'`src/common/language.cc
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-language.Tpo src/common/$(DEPDIR)/src_tools_linux_dump_syms_dump_syms-language.Po
@@ -7424,6 +7472,20 @@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.obj `if test -f 'src/common/dwarf_line_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_line_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_line_to_module.cc'; fi`
 
+src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.o: src/common/dwarf_range_list_handler.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.o -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.o `test -f 'src/common/dwarf_range_list_handler.cc' || echo '$(srcdir)/'`src/common/dwarf_range_list_handler.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/common/dwarf_range_list_handler.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.o `test -f 'src/common/dwarf_range_list_handler.cc' || echo '$(srcdir)/'`src/common/dwarf_range_list_handler.cc
+
+src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.obj: src/common/dwarf_range_list_handler.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.obj -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.obj `if test -f 'src/common/dwarf_range_list_handler.cc'; then $(CYGPATH_W) 'src/common/dwarf_range_list_handler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_range_list_handler.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/common/dwarf_range_list_handler.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_range_list_handler.obj `if test -f 'src/common/dwarf_range_list_handler.cc'; then $(CYGPATH_W) 'src/common/dwarf_range_list_handler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_range_list_handler.cc'; fi`
+
 src/common/src_tools_mac_dump_syms_dump_syms_mac-language.o: src/common/language.cc
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-language.o -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-language.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-language.o `test -f 'src/common/language.cc' || echo '$(srcdir)/'`src/common/language.cc
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-language.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-language.Po
diff --git a/configure b/configure
index e0187dd..d8099cd 100755
--- a/configure
+++ b/configure
@@ -6098,7 +6098,7 @@
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -6144,7 +6144,7 @@
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -6168,7 +6168,7 @@
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -6213,7 +6213,7 @@
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -6237,7 +6237,7 @@
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc
index f2dc4af..27f3a83 100644
--- a/src/common/dwarf/dwarf2reader.cc
+++ b/src/common/dwarf/dwarf2reader.cc
@@ -1247,6 +1247,41 @@
   after_header_ = lengthstart + header_.total_length;
 }
 
+RangeListReader::RangeListReader(const uint8_t *buffer, uint64 size,
+                                 ByteReader *reader, RangeListHandler *handler)
+    : buffer_(buffer), size_(size), reader_(reader), handler_(handler) { }
+
+bool RangeListReader::ReadRangeList(uint64 offset) {
+  const uint64 max_address =
+    (reader_->AddressSize() == 4) ? 0xffffffffUL
+                                  : 0xffffffffffffffffULL;
+  const uint64 entry_size = reader_->AddressSize() * 2;
+  bool list_end = false;
+
+  do {
+    if (offset > size_ - entry_size) {
+      return false; // Invalid range detected
+    }
+
+    uint64 start_address = reader_->ReadAddress(buffer_ + offset);
+    uint64 end_address =
+      reader_->ReadAddress(buffer_ + offset + reader_->AddressSize());
+
+    if (start_address == max_address) { // Base address selection
+      handler_->SetBaseAddress(end_address);
+    } else if (start_address == 0 && end_address == 0) { // End-of-list
+      handler_->Finish();
+      list_end = true;
+    } else { // Add a range entry
+      handler_->AddRange(start_address, end_address);
+    }
+
+    offset += entry_size;
+  } while (!list_end);
+
+  return true;
+}
+
 // A DWARF rule for recovering the address or value of a register, or
 // computing the canonical frame address. There is one subclass of this for
 // each '*Rule' member function in CallFrameInfo::Handler.
diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h
index 5d2d7f6..cf3ba3c 100644
--- a/src/common/dwarf/dwarf2reader.h
+++ b/src/common/dwarf/dwarf2reader.h
@@ -187,6 +187,36 @@
                        uint32 file_num, uint32 line_num, uint32 column_num) { }
 };
 
+class RangeListHandler {
+ public:
+  RangeListHandler() { }
+
+  virtual ~RangeListHandler() { }
+
+  // Add a range.
+  virtual void AddRange(uint64 begin, uint64 end) { };
+
+  // A new base address must be set for computing the ranges' addresses.
+  virtual void SetBaseAddress(uint64 base_address) { };
+
+  // Finish processing the range list.
+  virtual void Finish() { };
+};
+
+class RangeListReader {
+ public:
+  RangeListReader(const uint8_t *buffer, uint64 size, ByteReader *reader,
+                  RangeListHandler *handler);
+
+  bool ReadRangeList(uint64 offset);
+
+ private:
+  const uint8_t *buffer_;
+  uint64 size_;
+  ByteReader* reader_;
+  RangeListHandler *handler_;
+};
+
 // This class is the main interface between the reader and the
 // client.  The virtual functions inside this get called for
 // interesting events that happen during DWARF2 reading.
diff --git a/src/common/dwarf/functioninfo.cc b/src/common/dwarf/functioninfo.cc
index 55a255e..a0def62 100644
--- a/src/common/dwarf/functioninfo.cc
+++ b/src/common/dwarf/functioninfo.cc
@@ -184,6 +184,9 @@
       case DW_AT_decl_file:
         current_function_info_->file = files_->at(data).name;
         break;
+      case DW_AT_ranges:
+        current_function_info->ranges = data;
+        break;
       default:
         break;
     }
diff --git a/src/common/dwarf/functioninfo.h b/src/common/dwarf/functioninfo.h
index 0b08a5f..9efae6d 100644
--- a/src/common/dwarf/functioninfo.h
+++ b/src/common/dwarf/functioninfo.h
@@ -58,6 +58,8 @@
   uint64 lowpc;
   // End address for this function.
   uint64 highpc;
+  // Ranges offset
+  uint64 ranges;
 };
 
 struct SourceFileInfo {
diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc
index 38fc4c1..f5a03b4 100644
--- a/src/common/dwarf_cu_to_module.cc
+++ b/src/common/dwarf_cu_to_module.cc
@@ -44,6 +44,7 @@
 #include <stdio.h>
 
 #include <algorithm>
+#include <numeric>
 #include <utility>
 
 #include "common/dwarf_line_to_module.h"
@@ -51,6 +52,7 @@
 
 namespace google_breakpad {
 
+using std::accumulate;
 using std::map;
 using std::pair;
 using std::sort;
@@ -167,10 +169,15 @@
 // parsing. This is for data shared across the CU's entire DIE tree,
 // and parameters from the code invoking the CU parser.
 struct DwarfCUToModule::CUContext {
-  CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg)
+  CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg,
+            RangesHandler *ranges_handler_arg)
       : file_context(file_context_arg),
         reporter(reporter_arg),
-        language(Language::CPlusPlus) {}
+        ranges_handler(ranges_handler_arg),
+        language(Language::CPlusPlus),
+        low_pc(0),
+        high_pc(0),
+        ranges(0) {}
 
   ~CUContext() {
     for (vector<Module::Function *>::iterator it = functions.begin();
@@ -185,9 +192,19 @@
   // For printing error messages.
   WarningReporter *reporter;
 
+  // For reading ranges from the .debug_ranges section
+  RangesHandler *ranges_handler;
+
   // The source language of this compilation unit.
   const Language *language;
 
+  // Addresses covered by this CU. If high_pc_ is non-zero then the CU covers
+  // low_pc to high_pc, otherwise ranges is non-zero and low_pc represents
+  // the base address of the ranges covered by the CU.
+  uint64 low_pc;
+  uint64 high_pc;
+  uint64 ranges;
+
   // The functions defined in this compilation unit. We accumulate
   // them here during parsing. Then, in DwarfCUToModule::Finish, we
   // assign them lines and add them to file_context->module.
@@ -445,7 +462,7 @@
               uint64 offset)
       : GenericDIEHandler(cu_context, parent_context, offset),
         low_pc_(0), high_pc_(0), high_pc_form_(dwarf2reader::DW_FORM_addr),
-        abstract_origin_(NULL), inline_(false) { }
+        ranges_(0), abstract_origin_(NULL), inline_(false) { }
   void ProcessAttributeUnsigned(enum DwarfAttribute attr,
                                 enum DwarfForm form,
                                 uint64 data);
@@ -465,6 +482,7 @@
   string name_;
   uint64 low_pc_, high_pc_; // DW_AT_low_pc, DW_AT_high_pc
   DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address.
+  uint64 ranges_; // DW_AT_ranges
   const AbstractOrigin* abstract_origin_;
   bool inline_;
 };
@@ -484,6 +502,9 @@
       high_pc_form_ = form;
       high_pc_ = data;
       break;
+    case dwarf2reader::DW_AT_ranges:
+      ranges_ = data;
+      break;
 
     default:
       GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data);
@@ -537,17 +558,47 @@
   return true;
 }
 
+static bool IsEmptyRange(vector<Module::Range> ranges) {
+  uint64 size = accumulate(ranges.cbegin(), ranges.cend(), 0,
+    [](uint64 total, Module::Range entry) {
+      return total + entry.size;
+    }
+  );
+
+  return size == 0;
+}
+
 void DwarfCUToModule::FuncHandler::Finish() {
-  // Make high_pc_ an address, if it isn't already.
-  if (high_pc_form_ != dwarf2reader::DW_FORM_addr) {
-    high_pc_ += low_pc_;
+  vector<Module::Range> ranges;
+
+  if (!ranges_) {
+    // Make high_pc_ an address, if it isn't already.
+    if (high_pc_form_ != dwarf2reader::DW_FORM_addr) {
+      high_pc_ += low_pc_;
+    }
+
+    Module::Range range(low_pc_, high_pc_ - low_pc_);
+    ranges.push_back(range);
+  } else {
+    RangesHandler *ranges_handler = cu_context_->ranges_handler;
+
+    if (ranges_handler) {
+      if (!ranges_handler->ReadRanges(ranges_, cu_context_->low_pc, &ranges)) {
+        ranges.clear();
+        cu_context_->reporter->MalformedRangeList(ranges_);
+      }
+    } else {
+      cu_context_->reporter->MissingRanges();
+    }
   }
 
   // Did we collect the information we need?  Not all DWARF function
-  // entries have low and high addresses (for example, inlined
-  // functions that were never used), but all the ones we're
-  // interested in cover a non-empty range of bytes.
-  if (low_pc_ < high_pc_) {
+  // entries are non-empty (for example, inlined functions that were never
+  // used), but all the ones we're interested in cover a non-empty range of
+  // bytes.
+  if (!IsEmptyRange(ranges)) {
+    low_pc_ = ranges.front().address;
+
     // Malformed DWARF may omit the name, but all Module::Functions must
     // have names.
     string name;
@@ -561,7 +612,7 @@
     // Create a Module::Function based on the data we've gathered, and
     // add it to the functions_ list.
     scoped_ptr<Module::Function> func(new Module::Function(name, low_pc_));
-    func->size = high_pc_ - low_pc_;
+    func->ranges = ranges;
     func->parameter_size = 0;
     if (func->address) {
        // If the function address is zero this is a sign that this function
@@ -663,7 +714,7 @@
     return;
   UncoveredHeading();
   fprintf(stderr, "    function%s: %s\n",
-          function.size == 0 ? " (zero-length)" : "",
+          IsEmptyRange(function.ranges) ? " (zero-length)" : "",
           function.name.c_str());
 }
 
@@ -697,11 +748,25 @@
                   filename_.c_str(), offset, target);
 }
 
+void DwarfCUToModule::WarningReporter::MalformedRangeList(uint64 offset) {
+  CUHeading();
+  fprintf(stderr, "%s: warning: the range list at offset 0x%llx falls out of "
+                  "the .debug_ranges section.\n",
+                  filename_.c_str(), offset);
+}
+
+void DwarfCUToModule::WarningReporter::MissingRanges() {
+  CUHeading();
+  fprintf(stderr, "%s: warning: A DW_AT_ranges attribute was encountered but "
+                  "the .debug_ranges section is missing.\n", filename_.c_str());
+}
+
 DwarfCUToModule::DwarfCUToModule(FileContext *file_context,
                                  LineToModuleHandler *line_reader,
+                                 RangesHandler *ranges_handler,
                                  WarningReporter *reporter)
     : line_reader_(line_reader),
-      cu_context_(new CUContext(file_context, reporter)),
+      cu_context_(new CUContext(file_context, reporter, ranges_handler)),
       child_context_(new DIEContext()),
       has_source_line_info_(false) {
 }
@@ -732,6 +797,16 @@
     case dwarf2reader::DW_AT_language: // source language of this CU
       SetLanguage(static_cast<DwarfLanguage>(data));
       break;
+    case dwarf2reader::DW_AT_low_pc:
+      cu_context_->low_pc  = data;
+      break;
+    case dwarf2reader::DW_AT_high_pc:
+      cu_context_->high_pc  = data;
+      break;
+    case dwarf2reader::DW_AT_ranges:
+      cu_context_->ranges = data;
+      break;
+
     default:
       break;
   }
@@ -841,6 +916,46 @@
 }
 
 namespace {
+class FunctionRange {
+ public:
+  FunctionRange(const Module::Range &range, Module::Function *function) :
+      address(range.address), size(range.size), function(function) { }
+
+  void AddLine(Module::Line &line) {
+    function->lines.push_back(line);
+  }
+
+  Module::Address address;
+  Module::Address size;
+  Module::Function *function;
+};
+
+// Fills an array of ranges with pointers to the functions which owns them.
+// The array is sorted in ascending order and the ranges are non-overlapping.
+
+static void FillSortedFunctionRanges(vector<FunctionRange> &dest_ranges,
+                                     vector<Module::Function *> *functions) {
+  for (vector<Module::Function *>::const_iterator func_it = functions->cbegin();
+       func_it != functions->cend();
+       func_it++)
+  {
+    Module::Function *func = *func_it;
+    vector<Module::Range> &ranges = func->ranges;
+    for (vector<Module::Range>::const_iterator ranges_it = ranges.cbegin();
+         ranges_it != ranges.cend();
+         ++ranges_it) {
+      FunctionRange range(*ranges_it, func);
+      dest_ranges.push_back(range);
+    }
+  }
+
+  sort(dest_ranges.begin(), dest_ranges.end(),
+    [](const FunctionRange &fr1, const FunctionRange &fr2) {
+      return fr1.address < fr2.address;
+    }
+  );
+}
+
 // Return true if ADDRESS falls within the range of ITEM.
 template <class T>
 inline bool within(const T &item, Module::Address address) {
@@ -880,47 +995,50 @@
   const Module::Function *last_function_cited = NULL;
   const Module::Line *last_line_cited = NULL;
 
-  // Make a single pass through both vectors from lower to higher
-  // addresses, populating each Function's lines vector with lines
-  // from our lines_ vector that fall within the function's address
-  // range.
-  vector<Module::Function *>::iterator func_it = functions->begin();
+  // Prepare a sorted list of ranges with range-to-function mapping
+  vector<FunctionRange> sorted_ranges;
+  FillSortedFunctionRanges(sorted_ranges, functions);
+
+  // Make a single pass through both the range and line vectors from lower to
+  // higher addresses, populating each range's function lines vector with lines
+  // from our lines_ vector that fall within the range.
+  vector<FunctionRange>::iterator range_it = sorted_ranges.begin();
   vector<Module::Line>::const_iterator line_it = lines_.begin();
 
   Module::Address current;
 
   // Pointers to the referents of func_it and line_it, or NULL if the
   // iterator is at the end of the sequence.
-  Module::Function *func;
+  FunctionRange *range;
   const Module::Line *line;
 
   // Start current at the beginning of the first line or function,
   // whichever is earlier.
-  if (func_it != functions->end() && line_it != lines_.end()) {
-    func = *func_it;
+  if (range_it != sorted_ranges.end() && line_it != lines_.end()) {
+    range = &*range_it;
     line = &*line_it;
-    current = std::min(func->address, line->address);
+    current = std::min(range->address, line->address);
   } else if (line_it != lines_.end()) {
-    func = NULL;
+    range = NULL;
     line = &*line_it;
     current = line->address;
-  } else if (func_it != functions->end()) {
-    func = *func_it;
+  } else if (range_it != sorted_ranges.end()) {
+    range = &*range_it;
     line = NULL;
-    current = (*func_it)->address;
+    current = range->address;
   } else {
     return;
   }
 
-  while (func || line) {
+  while (range || line) {
     // This loop has two invariants that hold at the top.
     //
     // First, at least one of the iterators is not at the end of its
     // sequence, and those that are not refer to the earliest
-    // function or line that contains or starts after CURRENT.
+    // range or line that contains or starts after CURRENT.
     //
     // Note that every byte is in one of four states: it is covered
-    // or not covered by a function, and, independently, it is
+    // or not covered by a range, and, independently, it is
     // covered or not covered by a line.
     //
     // The second invariant is that CURRENT refers to a byte whose
@@ -930,7 +1048,7 @@
     //
     // Note that, although each iteration advances CURRENT from one
     // transition address to the next in each iteration, it might
-    // not advance the iterators. Suppose we have a function that
+    // not advance the iterators. Suppose we have a range that
     // starts with a line, has a gap, and then a second line, and
     // suppose that we enter an iteration with CURRENT at the end of
     // the first line. The next transition address is the start of
@@ -938,11 +1056,11 @@
     // advance CURRENT to that point. At the head of that iteration,
     // the invariants require that the line iterator be pointing at
     // the second line. But this is also true at the head of the
-    // next. And clearly, the iteration must not change the function
+    // next. And clearly, the iteration must not change the range
     // iterator. So neither iterator moves.
 
     // Assert the first invariant (see above).
-    assert(!func || current < func->address || within(*func, current));
+    assert(!range || current < range->address || within(*range, current));
     assert(!line || current < line->address || within(*line, current));
 
     // The next transition after CURRENT.
@@ -950,33 +1068,33 @@
 
     // Figure out which state we're in, add lines or warn, and compute
     // the next transition address.
-    if (func && current >= func->address) {
+    if (range && current >= range->address) {
       if (line && current >= line->address) {
-        // Covered by both a line and a function.
-        Module::Address func_left = func->size - (current - func->address);
+        // Covered by both a line and a range.
+        Module::Address range_left = range->size - (current - range->address);
         Module::Address line_left = line->size - (current - line->address);
         // This may overflow, but things work out.
-        next_transition = current + std::min(func_left, line_left);
+        next_transition = current + std::min(range_left, line_left);
         Module::Line l = *line;
         l.address = current;
         l.size = next_transition - current;
-        func->lines.push_back(l);
+        range->AddLine(l);
         last_line_used = line;
       } else {
-        // Covered by a function, but no line.
-        if (func != last_function_cited) {
-          reporter->UncoveredFunction(*func);
-          last_function_cited = func;
+        // Covered by a range, but no line.
+        if (range->function != last_function_cited) {
+          reporter->UncoveredFunction(*(range->function));
+          last_function_cited = range->function;
         }
-        if (line && within(*func, line->address))
+        if (line && within(*range, line->address))
           next_transition = line->address;
         else
           // If this overflows, we'll catch it below.
-          next_transition = func->address + func->size;
+          next_transition = range->address + range->size;
       }
     } else {
       if (line && current >= line->address) {
-        // Covered by a line, but no function.
+        // Covered by a line, but no range.
         //
         // If GCC emits padding after one function to align the start
         // of the next, then it will attribute the padding
@@ -988,27 +1106,27 @@
         // start of the next function, then assume this is what
         // happened, and don't warn.
         if (line != last_line_cited
-            && !(func
+            && !(range
                  && line == last_line_used
-                 && func->address - line->address == line->size)) {
+                 && range->address - line->address == line->size)) {
           reporter->UncoveredLine(*line);
           last_line_cited = line;
         }
-        if (func && within(*line, func->address))
-          next_transition = func->address;
+        if (range && within(*line, range->address))
+          next_transition = range->address;
         else
           // If this overflows, we'll catch it below.
           next_transition = line->address + line->size;
       } else {
-        // Covered by neither a function nor a line. By the invariant,
-        // both func and line begin after CURRENT. The next transition
-        // is the start of the next function or next line, whichever
+        // Covered by neither a range nor a line. By the invariant,
+        // both range and line begin after CURRENT. The next transition
+        // is the start of the next range or next line, whichever
         // is earliest.
-        assert(func || line);
-        if (func && line)
-          next_transition = std::min(func->address, line->address);
-        else if (func)
-          next_transition = func->address;
+        assert(range || line);
+        if (range && line)
+          next_transition = std::min(range->address, line->address);
+        else if (range)
+          next_transition = range->address;
         else
           next_transition = line->address;
       }
@@ -1025,11 +1143,11 @@
     // then we could go around more than once. We don't worry too much
     // about what result we produce in that case, just as long as we don't
     // hang or crash.
-    while (func_it != functions->end()
-           && next_transition >= (*func_it)->address
-           && !within(**func_it, next_transition))
-      func_it++;
-    func = (func_it != functions->end()) ? *func_it : NULL;
+    while (range_it != sorted_ranges.end()
+           && next_transition >= range_it->address
+           && !within(*range_it, next_transition))
+      range_it++;
+    range = (range_it != sorted_ranges.end()) ? &(*range_it) : NULL;
     while (line_it != lines_.end()
            && next_transition >= line_it->address
            && !within(*line_it, next_transition))
diff --git a/src/common/dwarf_cu_to_module.h b/src/common/dwarf_cu_to_module.h
index a36b82b..c1135dd 100644
--- a/src/common/dwarf_cu_to_module.h
+++ b/src/common/dwarf_cu_to_module.h
@@ -123,6 +123,22 @@
     scoped_ptr<FilePrivate> file_private_;
   };
 
+  // An abstract base class for handlers that handle DWARF range lists for
+  // DwarfCUToModule.
+  class RangesHandler {
+   public:
+    RangesHandler() { }
+    virtual ~RangesHandler() { }
+
+    // Called when finishing a function to populate the function's ranges.
+    // The ranges' entries are read starting from offset in the .debug_ranges
+    // section, base_address holds the base PC the range list values are
+    // offsets off. Return false if the rangelist falls out of the
+    // .debug_ranges section.
+    virtual bool ReadRanges(uint64 offset, Module::Address base_address,
+                            vector<Module::Range>* ranges) = 0;
+  };
+
   // An abstract base class for handlers that handle DWARF line data
   // for DwarfCUToModule. DwarfCUToModule could certainly just use
   // dwarf2reader::LineInfo itself directly, but decoupling things
@@ -208,6 +224,14 @@
     // FilePrivate did not retain the inter-CU specification data.
     virtual void UnhandledInterCUReference(uint64 offset, uint64 target);
 
+    // The DW_AT_ranges at offset is malformed (truncated or outside of the
+    // .debug_ranges section's bound).
+    virtual void MalformedRangeList(uint64 offset);
+
+    // A DW_AT_ranges attribute was encountered but the no .debug_ranges
+    // section was found.
+    virtual void MissingRanges();
+
     uint64 cu_offset() const {
       return cu_offset_;
     }
@@ -235,6 +259,7 @@
   // data we find.
   DwarfCUToModule(FileContext *file_context,
                   LineToModuleHandler *line_reader,
+                  RangesHandler *ranges_handler,
                   WarningReporter *reporter);
   ~DwarfCUToModule();
 
@@ -296,6 +321,9 @@
   // The handler to use to handle line number data.
   LineToModuleHandler *line_reader_;
 
+  // The handler to use to handle range lists.
+  RangesHandler *ranges_handler_;
+
   // This compilation unit's context.
   scoped_ptr<CUContext> cu_context_;
 
diff --git a/src/common/dwarf_cu_to_module_unittest.cc b/src/common/dwarf_cu_to_module_unittest.cc
index 2ce4a60..aef6922 100644
--- a/src/common/dwarf_cu_to_module_unittest.cc
+++ b/src/common/dwarf_cu_to_module_unittest.cc
@@ -128,7 +128,8 @@
         language_signed_(false),
         appender_(&lines_),
         reporter_("dwarf-filename", 0xcf8f9bb6443d29b5LL),
-        root_handler_(&file_context_, &line_reader_, &reporter_),
+        root_handler_(&file_context_, &line_reader_,
+                      /* ranges_reader */ nullptr, &reporter_),
         functions_filled_(false) {
     // By default, expect no warnings to be reported, and expect the
     // compilation unit's name to be provided. The test can override
@@ -597,7 +598,7 @@
   Module::Function *function = functions_[i];
   EXPECT_EQ(name,    function->name);
   EXPECT_EQ(address, function->address);
-  EXPECT_EQ(size,    function->size);
+  EXPECT_EQ(size,    function->ranges[0].size);
   EXPECT_EQ(0U,      function->parameter_size);
 }
 
@@ -1515,7 +1516,7 @@
 
   // First CU.  Declares class_A.
   {
-    DwarfCUToModule root1_handler(&fc, &lr, &reporter_);
+    DwarfCUToModule root1_handler(&fc, &lr, nullptr, &reporter_);
     ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3));
     ASSERT_TRUE(root1_handler.StartRootDIE(1,
                                            dwarf2reader::DW_TAG_compile_unit));
@@ -1528,7 +1529,7 @@
 
   // Second CU.  Defines class_A, declares member_func_B.
   {
-    DwarfCUToModule root2_handler(&fc, &lr, &reporter_);
+    DwarfCUToModule root2_handler(&fc, &lr, nullptr, &reporter_);
     ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3));
     ASSERT_TRUE(root2_handler.StartRootDIE(1,
                                            dwarf2reader::DW_TAG_compile_unit));
@@ -1545,7 +1546,7 @@
 
   // Third CU.  Defines member_func_B.
   {
-    DwarfCUToModule root3_handler(&fc, &lr, &reporter_);
+    DwarfCUToModule root3_handler(&fc, &lr, nullptr, &reporter_);
     ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3));
     ASSERT_TRUE(root3_handler.StartRootDIE(1,
                                            dwarf2reader::DW_TAG_compile_unit));
@@ -1574,7 +1575,7 @@
 
   // First CU.  Declares class_A.
   {
-    DwarfCUToModule root1_handler(&fc, &lr, &reporter_);
+    DwarfCUToModule root1_handler(&fc, &lr, nullptr, &reporter_);
     ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3));
     ASSERT_TRUE(root1_handler.StartRootDIE(1,
                                            dwarf2reader::DW_TAG_compile_unit));
@@ -1587,7 +1588,7 @@
 
   // Second CU.  Defines class_A, declares member_func_B.
   {
-    DwarfCUToModule root2_handler(&fc, &lr, &reporter_);
+    DwarfCUToModule root2_handler(&fc, &lr, nullptr, &reporter_);
     ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3));
     ASSERT_TRUE(root2_handler.StartRootDIE(1,
                                            dwarf2reader::DW_TAG_compile_unit));
@@ -1605,7 +1606,7 @@
 
   // Third CU.  Defines member_func_B.
   {
-    DwarfCUToModule root3_handler(&fc, &lr, &reporter_);
+    DwarfCUToModule root3_handler(&fc, &lr, nullptr, &reporter_);
     ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3));
     ASSERT_TRUE(root3_handler.StartRootDIE(1,
                                            dwarf2reader::DW_TAG_compile_unit));
@@ -1791,7 +1792,8 @@
         file("source file name") {
     reporter.SetCUName("compilation-unit-name");
 
-    function.size = 0x89808a5bdfa0a6a3ULL;
+    Module::Range range(0x19c45c30770c1eb0ULL, 0x89808a5bdfa0a6a3ULL);
+    function.ranges.push_back(range);
     function.parameter_size = 0x6a329f18683dcd51ULL;
 
     line.address = 0x3606ac6267aebeccULL;
diff --git a/src/common/dwarf_range_list_handler.cc b/src/common/dwarf_range_list_handler.cc
new file mode 100644
index 0000000..8733df3
--- /dev/null
+++ b/src/common/dwarf_range_list_handler.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2018 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Gabriele Svelto <gsvelto@mozilla.com>
+//                                  <gabriele.svelto@gmail.com>
+
+// dwarf_range_list_handler.cc: Implementation of DwarfRangeListHandler class.
+// See dwarf_range_list_handler.h for details.
+
+#include <algorithm>
+
+#include "common/dwarf_range_list_handler.h"
+
+namespace google_breakpad {
+
+void DwarfRangeListHandler::AddRange(uint64 begin, uint64 end) {
+  Module::Range r(begin + base_address_, end - begin);
+
+  ranges_->push_back(r);
+}
+
+void DwarfRangeListHandler::SetBaseAddress(uint64 base_address) {
+  base_address_ = base_address;
+}
+
+void DwarfRangeListHandler::Finish() {
+  std::sort(ranges_->begin(), ranges_->end(),
+    [](const Module::Range &a, const Module::Range &b) {
+      return a.address < b.address;
+    }
+  );
+}
+
+} // namespace google_breakpad
diff --git a/src/common/dwarf_range_list_handler.h b/src/common/dwarf_range_list_handler.h
new file mode 100644
index 0000000..bd09968
--- /dev/null
+++ b/src/common/dwarf_range_list_handler.h
@@ -0,0 +1,79 @@
+// -*- mode: c++ -*-
+
+// Copyright (c) 2018 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Gabriele Svelto <gsvelto@mozilla.com>
+//                                  <gabriele.svelto@gmail.com>
+
+// The DwarfRangeListHandler class accepts rangelist data from a DWARF parser
+// and adds it to a google_breakpad::Function or other objects supporting
+// ranges.
+
+#ifndef COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H
+#define COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H
+
+#include <vector>
+
+#include "common/module.h"
+#include "common/dwarf/dwarf2reader.h"
+
+namespace google_breakpad {
+
+// A class for producing a vector of google_breakpad::Module::Range
+// instances from a parsed DWARF range list.
+
+class DwarfRangeListHandler: public dwarf2reader::RangeListHandler {
+ public:
+  DwarfRangeListHandler(uint64 base_address, vector<Module::Range> *ranges)
+      : base_address_(base_address), ranges_(ranges) { }
+
+  ~DwarfRangeListHandler() { }
+
+  // Add a range to the list
+  void AddRange(uint64 begin, uint64 end);
+
+  // Record the new base address and use it for the following entries
+  void SetBaseAddress(uint64 base_address);
+
+  // Sort the ranges so that they are in ascending order of starting address
+  void Finish();
+
+ private:
+  // The current PC to add to every entry, this can be overridden by a special
+  // list entry
+  uint64 base_address_;
+
+  // The list of ranges to be populated
+  vector<Module::Range> *ranges_;
+};
+
+} // namespace google_breakpad
+
+#endif // COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H
diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
index e7a74cc..1110cb9 100644
--- a/src/common/linux/dump_symbols.cc
+++ b/src/common/linux/dump_symbols.cc
@@ -58,6 +58,7 @@
 #include "common/dwarf_cfi_to_module.h"
 #include "common/dwarf_cu_to_module.h"
 #include "common/dwarf_line_to_module.h"
+#include "common/dwarf_range_list_handler.h"
 #include "common/linux/crc32.h"
 #include "common/linux/eintr_wrapper.h"
 #include "common/linux/elfutils.h"
@@ -81,6 +82,7 @@
 using google_breakpad::DwarfCFIToModule;
 using google_breakpad::DwarfCUToModule;
 using google_breakpad::DwarfLineToModule;
+using google_breakpad::DwarfRangeListHandler;
 using google_breakpad::ElfClass;
 using google_breakpad::ElfClass32;
 using google_breakpad::ElfClass64;
@@ -207,6 +209,30 @@
 }
 #endif  // NO_STABS_SUPPORT
 
+// A range handler that accepts rangelist data parsed by
+// dwarf2reader::RangeListReader and populates a range vector (typically
+// owned by a function) with the results.
+class DumperRangesHandler : public DwarfCUToModule::RangesHandler {
+ public:
+  DumperRangesHandler(const uint8_t *buffer, uint64 size,
+                      dwarf2reader::ByteReader* reader)
+      : buffer_(buffer), size_(size), reader_(reader) { }
+
+  bool ReadRanges(uint64 offset, Module::Address base_address,
+                  vector<Module::Range>* ranges) {
+    DwarfRangeListHandler handler(base_address, ranges);
+    dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_,
+                                                   &handler);
+
+    return rangelist_reader.ReadRangeList(offset);
+  }
+
+ private:
+  const uint8_t *buffer_;
+  uint64 size_;
+  dwarf2reader::ByteReader* reader_;
+};
+
 // A line-to-module loader that accepts line number info parsed by
 // dwarf2reader::LineInfo and populates a Module and a line vector
 // with the results.
@@ -261,6 +287,18 @@
     file_context.AddSectionToSectionMap(name, contents, section->sh_size);
   }
 
+  // Optional .debug_ranges reader
+  scoped_ptr<DumperRangesHandler> ranges_handler;
+  dwarf2reader::SectionMap::const_iterator ranges_entry =
+      file_context.section_map().find(".debug_ranges");
+  if (ranges_entry != file_context.section_map().end()) {
+    const std::pair<const uint8_t *, uint64>& ranges_section =
+      ranges_entry->second;
+    ranges_handler.reset(
+      new DumperRangesHandler(ranges_section.first, ranges_section.second,
+                              &byte_reader));
+  }
+
   // Parse all the compilation units in the .debug_info section.
   DumperLineToModule line_to_module(&byte_reader);
   dwarf2reader::SectionMap::const_iterator debug_info_entry =
@@ -276,7 +314,8 @@
     // Make a handler for the root DIE that populates MODULE with the
     // data that was found.
     DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset);
-    DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter);
+    DwarfCUToModule root_handler(&file_context, &line_to_module,
+                                 ranges_handler.get(), &reporter);
     // Make a Dwarf2Handler that drives the DIEHandler.
     dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
     // Make a DWARF parser for the compilation unit at OFFSET.
diff --git a/src/common/mac/dump_syms.cc b/src/common/mac/dump_syms.cc
index 66757cd..fef489d 100644
--- a/src/common/mac/dump_syms.cc
+++ b/src/common/mac/dump_syms.cc
@@ -55,6 +55,7 @@
 #include "common/dwarf_cfi_to_module.h"
 #include "common/dwarf_cu_to_module.h"
 #include "common/dwarf_line_to_module.h"
+#include "common/dwarf_range_list_handler.h"
 #include "common/mac/file_id.h"
 #include "common/mac/arch_utilities.h"
 #include "common/mac/macho_reader.h"
@@ -76,6 +77,7 @@
 using dwarf2reader::ByteReader;
 using google_breakpad::DwarfCUToModule;
 using google_breakpad::DwarfLineToModule;
+using google_breakpad::DwarfRangeListHandler;
 using google_breakpad::FileID;
 using google_breakpad::mach_o::FatReader;
 using google_breakpad::mach_o::Section;
@@ -303,6 +305,31 @@
   return compacted;
 }
 
+// A range handler that accepts rangelist data parsed by
+// dwarf2reader::RangeListReader and populates a range vector (typically
+// owned by a function) with the results.
+class DumpSymbols::DumperRangesHandler:
+      public DwarfCUToModule::RangesHandler {
+ public:
+  DumperRangesHandler(const uint8_t *buffer, uint64 size,
+                      dwarf2reader::ByteReader* reader)
+      : buffer_(buffer), size_(size), reader_(reader) { }
+
+  bool ReadRanges(uint64 offset, Module::Address base_address,
+                  vector<Module::Range>* ranges) {
+    DwarfRangeListHandler handler(base_address, ranges);
+    dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_,
+                                                   &handler);
+
+    return rangelist_reader.ReadRangeList(offset);
+  }
+
+ private:
+  const uint8_t *buffer_;
+  uint64 size_;
+  dwarf2reader::ByteReader* reader_;
+};
+
 // A line-to-module loader that accepts line number info parsed by
 // dwarf2reader::LineInfo and populates a Module and a line vector
 // with the results.
@@ -425,6 +452,18 @@
   // Build a line-to-module loader for the root handler to use.
   DumperLineToModule line_to_module(&byte_reader);
 
+  // Optional .debug_ranges reader
+  scoped_ptr<DumperRangesHandler> ranges_handler;
+  dwarf2reader::SectionMap::const_iterator ranges_entry =
+      file_context.section_map().find("__debug_ranges");
+  if (ranges_entry != file_context.section_map().end()) {
+    const std::pair<const uint8_t *, uint64>& ranges_section =
+      ranges_entry->second;
+    ranges_handler.reset(
+      new DumperRangesHandler(ranges_section.first, ranges_section.second,
+                              &byte_reader));
+  }
+
   // Walk the __debug_info section, one compilation unit at a time.
   uint64 debug_info_length = debug_info_section.second;
   for (uint64 offset = 0; offset < debug_info_length;) {
@@ -432,7 +471,8 @@
     // debug info.
     DwarfCUToModule::WarningReporter reporter(selected_object_name_,
                                               offset);
-    DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter);
+    DwarfCUToModule root_handler(&file_context, &line_to_module,
+                                 ranges_handler.get(), &reporter);
     // Make a Dwarf2Handler that drives our DIEHandler.
     dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
     // Make a DWARF parser for the compilation unit at OFFSET.
diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h
index 9463f7d..ab8a99d 100644
--- a/src/common/mac/dump_syms.h
+++ b/src/common/mac/dump_syms.h
@@ -125,6 +125,7 @@
  private:
   // Used internally.
   class DumperLineToModule;
+  class DumperRangesHandler;
   class LoadCommandDumper;
 
   // This method behaves similarly to NXFindBestFatArch, but it supports
diff --git a/src/common/module.cc b/src/common/module.cc
index 13c4647..11bfc44 100644
--- a/src/common/module.cc
+++ b/src/common/module.cc
@@ -258,24 +258,33 @@
     for (FunctionSet::const_iterator func_it = functions_.begin();
          func_it != functions_.end(); ++func_it) {
       Function *func = *func_it;
-      stream << "FUNC " << hex
-             << (func->address - load_address_) << " "
-             << func->size << " "
-             << func->parameter_size << " "
-             << func->name << dec << "\n";
-      if (!stream.good())
-        return ReportError();
+      vector<Line>::iterator line_it = func->lines.begin();
+      for (auto range_it = func->ranges.cbegin();
+           range_it != func->ranges.cend(); ++range_it) {
+        stream << "FUNC " << hex
+               << (range_it->address - load_address_) << " "
+               << range_it->size << " "
+               << func->parameter_size << " "
+               << func->name << dec << "\n";
 
-      for (vector<Line>::iterator line_it = func->lines.begin();
-           line_it != func->lines.end(); ++line_it) {
-        stream << hex
-               << (line_it->address - load_address_) << " "
-               << line_it->size << " "
-               << dec
-               << line_it->number << " "
-               << line_it->file->source_id << "\n";
         if (!stream.good())
           return ReportError();
+
+        while ((line_it != func->lines.end()) &&
+               (line_it->address >= range_it->address) &&
+               (line_it->address < (range_it->address + range_it->size))) {
+          stream << hex
+                 << (line_it->address - load_address_) << " "
+                 << line_it->size << " "
+                 << dec
+                 << line_it->number << " "
+                 << line_it->file->source_id << "\n";
+
+          if (!stream.good())
+            return ReportError();
+
+          ++line_it;
+        }
       }
     }
 
diff --git a/src/common/module.h b/src/common/module.h
index 6c2bb27..7b1a0db 100644
--- a/src/common/module.h
+++ b/src/common/module.h
@@ -85,10 +85,19 @@
     int source_id;
   };
 
+  // An address range.
+  struct Range {
+    Range(const Address address_input, const Address size_input) :
+        address(address_input), size(size_input) { }
+
+    Address address;
+    Address size;
+  };
+
   // A function.
   struct Function {
     Function(const string &name_input, const Address &address_input) :
-        name(name_input), address(address_input), size(0), parameter_size(0) {}
+        name(name_input), address(address_input), parameter_size(0) {}
 
     // For sorting by address.  (Not style-guide compliant, but it's
     // stupid not to put this in the struct.)
@@ -99,9 +108,9 @@
     // The function's name.
     const string name;
 
-    // The start address and length of the function's code.
+    // The start address and the address ranges covered by the function.
     const Address address;
-    Address size;
+    vector<Range> ranges;
 
     // The function's parameter size.
     Address parameter_size;
diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
index 78406e3..819fa03 100644
--- a/src/common/module_unittest.cc
+++ b/src/common/module_unittest.cc
@@ -55,7 +55,8 @@
   const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99LL;
 
   Module::Function *function = new Module::Function(name, DUP_ADDRESS);
-  function->size = DUP_SIZE;
+  Module::Range range(DUP_ADDRESS, DUP_SIZE);
+  function->ranges.push_back(range);
   function->parameter_size = DUP_PARAMETER_SIZE;
   return function;
 }
@@ -92,7 +93,8 @@
   Module::File *file = m.FindFile("file_name.cc");
   Module::Function *function = new Module::Function(
       "function_name", 0xe165bf8023b9d9abLL);
-  function->size = 0x1e4bb0eb1cbf5b09LL;
+  Module::Range range(0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL);
+  function->ranges.push_back(range);
   function->parameter_size = 0x772beee89114358aLL;
   Module::Line line = { 0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL,
                         file, 67519080 };
@@ -120,7 +122,8 @@
   // A function.
   Module::Function *function = new Module::Function(
       "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3LL);
-  function->size = 0x2922088f98d3f6fcLL;
+  Module::Range range(0xbec774ea5dd935f3LL, 0x2922088f98d3f6fcLL);
+  function->ranges.push_back(range);
   function->parameter_size = 0xe5e9aa008bd5f0d0LL;
 
   // Some source lines.  The module should not sort these.
@@ -177,13 +180,14 @@
   // Create a function.
   Module::Function *function = new Module::Function(
       "function_name", 0x9b926d464f0b9384LL);
-  function->size = 0x4f524a4ba795e6a6LL;
+  Module::Range range(0x9b926d464f0b9384LL, 0x4f524a4ba795e6a6LL);
+  function->ranges.push_back(range);
   function->parameter_size = 0xbbe8133a6641c9b7LL;
 
   // Source files that refer to some files, but not others.
-  Module::Line line1 = { 0x595fa44ebacc1086LL, 0x1e1e0191b066c5b3LL,
+  Module::Line line1 = { 0xab415089485e1a20LL, 0x126e3124979291f2LL,
                          file1, 137850127 };
-  Module::Line line2 = { 0x401ce8c8a12d25e3LL, 0x895751c41b8d2ce2LL,
+  Module::Line line2 = { 0xb2675b5c3c2ed33fLL, 0x1df77f5551dbd68cLL,
                          file3, 28113549 };
   function->lines.push_back(line1);
   function->lines.push_back(line2);
@@ -210,8 +214,8 @@
                "FILE 1 filename3\n"
                "FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7"
                " function_name\n"
-               "595fa44ebacc1086 1e1e0191b066c5b3 137850127 0\n"
-               "401ce8c8a12d25e3 895751c41b8d2ce2 28113549 1\n",
+               "ab415089485e1a20 126e3124979291f2 137850127 0\n"
+               "b2675b5c3c2ed33f 1df77f5551dbd68c 28113549 1\n",
                contents.c_str());
 }
 
@@ -225,7 +229,8 @@
   // A function.
   Module::Function *function = new Module::Function(
       "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3LL);
-  function->size = 0x2922088f98d3f6fcLL;
+  Module::Range range(0xbec774ea5dd935f3LL, 0x2922088f98d3f6fcLL);
+  function->ranges.push_back(range);
   function->parameter_size = 0xe5e9aa008bd5f0d0LL;
 
   // Some source lines.  The module should not sort these.
@@ -267,12 +272,14 @@
   // Two functions.
   Module::Function *function1 = new Module::Function(
       "_without_form", 0xd35024aa7ca7da5cLL);
-  function1->size = 0x200b26e605f99071LL;
+  Module::Range r1(0xd35024aa7ca7da5cLL, 0x200b26e605f99071LL);
+  function1->ranges.push_back(r1);
   function1->parameter_size = 0xf14ac4fed48c4a99LL;
 
   Module::Function *function2 = new Module::Function(
       "_and_void", 0x2987743d0b35b13fLL);
-  function2->size = 0xb369db048deb3010LL;
+  Module::Range r2(0x2987743d0b35b13fLL, 0xb369db048deb3010LL);
+  function2->ranges.push_back(r2);
   function2->parameter_size = 0x938e556cb5a79988LL;
 
   // Put them in a vector.
@@ -504,7 +511,8 @@
   m.AddExtern(extern2);
 
   Module::Function* function = new Module::Function("_xyz", 0xfff0);
-  function->size = 0x10;
+  Module::Range range(0xfff0, 0x10);
+  function->ranges.push_back(range);
   function->parameter_size = 0;
   m.AddFunction(function);
 
@@ -541,7 +549,8 @@
   // The corresponding function from the DWARF debug data have the actual
   // address.
   Module::Function* function = new Module::Function("_thumb_xyz", 0xfff0);
-  function->size = 0x10;
+  Module::Range range(0xfff0, 0x10);
+  function->ranges.push_back(range);
   function->parameter_size = 0;
   m.AddFunction(function);
 
diff --git a/src/common/stabs_to_module.cc b/src/common/stabs_to_module.cc
index 0a83cf2..049a6cc 100644
--- a/src/common/stabs_to_module.cc
+++ b/src/common/stabs_to_module.cc
@@ -91,7 +91,8 @@
                                   uint64_t address) {
   assert(!current_function_);
   Module::Function *f = new Module::Function(Demangle(name), address);
-  f->size = 0;           // We compute this in StabsToModule::Finalize().
+  Module::Range r(address, 0); // We compute this in StabsToModule::Finalize().
+  f->ranges.push_back(r);
   f->parameter_size = 0; // We don't provide this information.
   current_function_ = f;
   boundaries_.push_back(static_cast<Module::Address>(address));
@@ -167,14 +168,14 @@
     vector<Module::Address>::const_iterator boundary
         = std::upper_bound(boundaries_.begin(), boundaries_.end(), f->address);
     if (boundary != boundaries_.end())
-      f->size = *boundary - f->address;
+      f->ranges[0].size = *boundary - f->address;
     else
       // If this is the last function in the module, and the STABS
       // reader was unable to give us its ending address, then assign
       // it a bogus, very large value.  This will happen at most once
       // per module: since we've added all functions' addresses to the
       // boundary table, only one can be the last.
-      f->size = kFallbackSize;
+      f->ranges[0].size = kFallbackSize;
 
     // Compute sizes for each of the function f's lines --- if it has any.
     if (!f->lines.empty()) {
@@ -185,7 +186,8 @@
            line_it != last_line; line_it++)
         line_it[0].size = line_it[1].address - line_it[0].address;
       // Compute the size of the last line from f's end address.
-      last_line->size = (f->address + f->size) - last_line->address;
+      last_line->size =
+        (f->ranges[0].address + f->ranges[0].size) - last_line->address;
     }
   }
   // Now that everything has a size, add our functions to the module, and
diff --git a/src/common/stabs_to_module_unittest.cc b/src/common/stabs_to_module_unittest.cc
index d445d1d..aae0047 100644
--- a/src/common/stabs_to_module_unittest.cc
+++ b/src/common/stabs_to_module_unittest.cc
@@ -64,7 +64,7 @@
   Module::Function *function = functions[0];
   EXPECT_STREQ("function", function->name.c_str());
   EXPECT_EQ(0xfde4abbed390c394LL, function->address);
-  EXPECT_EQ(0x10U, function->size);
+  EXPECT_EQ(0x10U, function->ranges[0].size);
   EXPECT_EQ(0U, function->parameter_size);
   ASSERT_EQ((size_t) 1, function->lines.size());
   Module::Line *line = &function->lines[0];
@@ -130,7 +130,7 @@
 
   Module::Function *function = functions[0];
   EXPECT_EQ(0xf2cfda36ecf7f46dLL, function->address);
-  EXPECT_LT(0U, function->size);  // should have used dummy size
+  EXPECT_LT(0U, function->ranges[0].size); // should have used dummy size
   EXPECT_EQ(0U, function->parameter_size);
   ASSERT_EQ(0U, function->lines.size());
 }
@@ -166,7 +166,7 @@
   Module::Function *function = functions[0];
   EXPECT_STREQ("function", function->name.c_str());
   EXPECT_EQ(0xb4513962eff94e92LL, function->address);
-  EXPECT_EQ(0x1000100000000ULL, function->size); // inferred from CU end
+  EXPECT_EQ(0x1000100000000ULL, function->ranges[0].size); // inferred from CU end
   EXPECT_EQ(0U, function->parameter_size);
   ASSERT_EQ((size_t) 2, function->lines.size());
 
@@ -216,7 +216,7 @@
                "push_back(unsigned long long const&)",
                function->name.c_str());
   EXPECT_EQ(0xf2cfda63cef7f46dLL, function->address);
-  EXPECT_LT(0U, function->size); // should have used dummy size
+  EXPECT_LT(0U, function->ranges[0].size); // should have used dummy size
   EXPECT_EQ(0U, function->parameter_size);
   ASSERT_EQ(0U, function->lines.size());
 }