some API cleanups + added lineprogram
diff --git a/elftools/dwarf/descriptions.py b/elftools/dwarf/descriptions.py
index ddb8f6b..57df8a4 100644
--- a/elftools/dwarf/descriptions.py
+++ b/elftools/dwarf/descriptions.py
@@ -247,7 +247,6 @@
     else:
         # Relative offset to the current DIE's CU
         ref_die_offset = attr.value + die.cu.cu_offset
-    #print '&&&', attr.form, attr.value, ref_die_offset, ref_die_offset - section_offset
 
     # Now find the CU this DIE belongs to (since we have to find its abbrev
     # table). This is done by linearly scanning through all CUs, looking for
diff --git a/elftools/dwarf/dwarfinfo.py b/elftools/dwarf/dwarfinfo.py
index db42017..8bda113 100644
--- a/elftools/dwarf/dwarfinfo.py
+++ b/elftools/dwarf/dwarfinfo.py
@@ -8,13 +8,13 @@
 #-------------------------------------------------------------------------------
 from collections import namedtuple
 
-from ..construct import CString
 from ..common.exceptions import DWARFError
 from ..common.utils import (struct_parse, dwarf_assert,
                             parse_cstring_from_stream)
 from .structs import DWARFStructs
 from .compileunit import CompileUnit
 from .abbrevtable import AbbrevTable
+from .lineprogram import LineProgram
 
 
 # Describes a debug section
@@ -74,21 +74,10 @@
         # Cache for abbrev tables: a dict keyed by offset
         self._abbrevtable_cache = {}
     
-    def num_CUs(self):
-        """ Number of compile units in the debug info
-        """
-        return len(self._CU)
-    
-    def get_CU(self, n):
-        """ Get the compile unit (CompileUnit object) at index #n
-        """
-        return self._CU[n]
-    
     def iter_CUs(self):
         """ Yield all the compile units (CompileUnit objects) in the debug info
         """
-        for i in range(self.num_CUs()):
-            yield self.get_CU(i)
+        return iter(self._CU)
     
     def get_abbrev_table(self, offset):
         """ Get an AbbrevTable from the given offset in the debug_abbrev
@@ -124,9 +113,8 @@
         """ Parse CU entries from debug_info.
         """
         offset = 0
-        section_boundary = self.debug_info_sec.size
         CUlist = []
-        while offset < section_boundary:
+        while offset < self.debug_info_sec.size:
             # Section 7.4 (32-bit and 64-bit DWARF Formats) of the DWARF spec v3
             # states that the first 32-bit word of the CU header determines 
             # whether the CU is represented with 32-bit or 64-bit DWARF format.
@@ -181,3 +169,38 @@
         """
         return 2 <= version <= 3
 
+    def _parse_line_programs(self):
+        """ Parse line programs from debug_line
+        """
+        offset = 0
+        lineprograms = []
+        while offset < self.debug_line_sec.size:
+            # Similarly to CU parsing, peek at the initial_length field of the
+            # header to figure out the DWARF format for it.
+            initial_length = struct_parse(
+                self.structs.Dwarf_uint32(''), self.debug_line_sec, offset)
+            dwarf_format = 64 if initial_length == 0xFFFFFFFF else 32
+
+            # Prepare the structs for this line program, based on its format
+            # and the default endianness. The address_size plays no role for
+            # line programs so we just give it a default value.
+            lineprog_structs = DWARFStructs(
+                little_endian=self.little_endian,
+                dwarf_format=dwarf_format,
+                address_size=4)
+
+            lineprog_header = struct_parse(
+                lineprog_structs.Dwarf_lineprog_header,
+                self.debug_line_sec.stream,
+                offset)
+
+            lineprograms.append(LineProgram(
+                header=lineprog_header,
+                dwarfinfo=self,
+                structs=lineprog_structs))
+
+            # Calculate the offset to the next line program (see DWARF 6.2.4)
+            offset += ( lineprog_header['unit_length'] +
+                        lineprog_structs.initial_length_field_size())
+        return lineprograms
+
diff --git a/elftools/dwarf/lineprogram.py b/elftools/dwarf/lineprogram.py
new file mode 100644
index 0000000..d865141
--- /dev/null
+++ b/elftools/dwarf/lineprogram.py
@@ -0,0 +1,23 @@
+#-------------------------------------------------------------------------------
+# elftools: dwarf/lineprogram.py
+#
+# DWARF line number program
+#
+# Eli Bendersky (eliben@gmail.com)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+
+
+class LineProgram(object):
+    def __init__(self, header, dwarfinfo, structs):
+        self.dwarfinfo = dwarfinfo
+        self.header = header
+        pass
+
+    #------ PRIVATE ------#
+    
+    def __getitem__(self, name):
+        """ Implement dict-like access to header entries
+        """
+        return self.header[name]
+
diff --git a/elftools/elf/elffile.py b/elftools/elf/elffile.py
index a9ca631..065c06d 100644
--- a/elftools/elf/elffile.py
+++ b/elftools/elf/elffile.py
@@ -105,6 +105,8 @@
     
     def has_dwarf_info(self):
         """ Check whether this file appears to have debugging information. 
+            We assume that if it has the debug_info section, it has all theother
+            required sections as well.
         """
         return bool(self.get_section_by_name('.debug_info'))