1 //===-- DWARFDebugAranges.cpp -----------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "DWARFDebugAranges.h"
11 
12 #include <assert.h>
13 #include <stdio.h>
14 
15 #include <algorithm>
16 
17 #include "lldb/Core/Log.h"
18 #include "lldb/Core/Stream.h"
19 #include "lldb/Core/Timer.h"
20 
21 #include "LogChannelDWARF.h"
22 #include "SymbolFileDWARF.h"
23 #include "DWARFDebugInfo.h"
24 #include "DWARFCompileUnit.h"
25 
26 using namespace lldb_private;
27 
28 //----------------------------------------------------------------------
29 // Constructor
30 //----------------------------------------------------------------------
31 DWARFDebugAranges::DWARFDebugAranges() :
32     m_aranges()
33 {
34 }
35 
36 
37 //----------------------------------------------------------------------
38 // Compare function DWARFDebugAranges::Range structures
39 //----------------------------------------------------------------------
40 static bool RangeLessThan (const DWARFDebugAranges::Range& range1, const DWARFDebugAranges::Range& range2)
41 {
42     return range1.lo_pc < range2.lo_pc;
43 }
44 
45 //----------------------------------------------------------------------
46 // CountArangeDescriptors
47 //----------------------------------------------------------------------
48 class CountArangeDescriptors
49 {
50 public:
51     CountArangeDescriptors (uint32_t& count_ref) : count(count_ref)
52     {
53 //      printf("constructor CountArangeDescriptors()\n");
54     }
55     void operator() (const DWARFDebugArangeSet& set)
56     {
57         count += set.NumDescriptors();
58     }
59     uint32_t& count;
60 };
61 
62 //----------------------------------------------------------------------
63 // AddArangeDescriptors
64 //----------------------------------------------------------------------
65 class AddArangeDescriptors
66 {
67 public:
68     AddArangeDescriptors (DWARFDebugAranges::RangeColl& ranges) : range_collection(ranges) {}
69     void operator() (const DWARFDebugArangeSet& set)
70     {
71         const DWARFDebugArangeSet::Descriptor* arange_desc_ptr;
72         DWARFDebugAranges::Range range;
73         range.offset = set.GetCompileUnitDIEOffset();
74 
75         for (uint32_t i=0; (arange_desc_ptr = set.GetDescriptor(i)) != NULL; ++i)
76         {
77             range.lo_pc = arange_desc_ptr->address;
78             range.length = arange_desc_ptr->length;
79 
80             // Insert each item in increasing address order so binary searching
81             // can later be done!
82             DWARFDebugAranges::RangeColl::iterator insert_pos = lower_bound(range_collection.begin(), range_collection.end(), range, RangeLessThan);
83             range_collection.insert(insert_pos, range);
84         }
85     }
86     DWARFDebugAranges::RangeColl& range_collection;
87 };
88 
89 //----------------------------------------------------------------------
90 // PrintRange
91 //----------------------------------------------------------------------
92 static void PrintRange(const DWARFDebugAranges::Range& range)
93 {
94     // Cast the address values in case the address type is compiled as 32 bit
95     printf("0x%8.8x: [0x%8.8llx - 0x%8.8llx)\n", range.offset, (long long)range.lo_pc, (long long)range.hi_pc());
96 }
97 
98 //----------------------------------------------------------------------
99 // Extract
100 //----------------------------------------------------------------------
101 bool
102 DWARFDebugAranges::Extract(const DataExtractor &debug_aranges_data)
103 {
104     if (debug_aranges_data.ValidOffset(0))
105     {
106         uint32_t offset = 0;
107 
108         typedef std::vector<DWARFDebugArangeSet>    SetCollection;
109         typedef SetCollection::const_iterator       SetCollectionIter;
110         SetCollection sets;
111 
112         DWARFDebugArangeSet set;
113         Range range;
114         while (set.Extract(debug_aranges_data, &offset))
115             sets.push_back(set);
116 
117         uint32_t count = 0;
118 
119         for_each(sets.begin(), sets.end(), CountArangeDescriptors(count));
120 
121         if (count > 0)
122         {
123             m_aranges.reserve(count);
124             AddArangeDescriptors range_adder(m_aranges);
125             for_each(sets.begin(), sets.end(), range_adder);
126         }
127 
128     //  puts("\n\nDWARFDebugAranges list is:\n");
129     //  for_each(m_aranges.begin(), m_aranges.end(), PrintRange);
130     }
131     return false;
132 }
133 
134 //----------------------------------------------------------------------
135 // Generate
136 //----------------------------------------------------------------------
137 bool
138 DWARFDebugAranges::Generate(SymbolFileDWARF* dwarf2Data)
139 {
140     Clear();
141     DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
142     if (debug_info)
143     {
144         const bool clear_dies_if_already_not_parsed = true;
145         uint32_t cu_idx = 0;
146         const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
147         for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
148         {
149             DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
150             if (cu)
151                 cu->BuildAddressRangeTable(dwarf2Data, this, clear_dies_if_already_not_parsed);
152         }
153     }
154     return !IsEmpty();
155 }
156 
157 
158 void
159 DWARFDebugAranges::Dump (Log *log) const
160 {
161     if (log == NULL)
162         return;
163     const uint32_t num_ranges = NumRanges();
164     for (uint32_t i = 0; i < num_ranges; ++i)
165     {
166         const Range &range = m_aranges[i];
167         log->Printf ("0x%8.8x: [0x%8.8llx - 0x%8.8llx)", range.offset, (uint64_t)range.lo_pc, (uint64_t)range.hi_pc());
168     }
169 }
170 
171 
172 void
173 DWARFDebugAranges::Range::Dump(Stream *s) const
174 {
175     s->Printf("{0x%8.8x}: [0x%8.8llx - 0x%8.8llx)\n", offset, lo_pc, hi_pc());
176 }
177 
178 //----------------------------------------------------------------------
179 // Dump
180 //----------------------------------------------------------------------
181 //void
182 //DWARFDebugAranges::Dump(SymbolFileDWARF* dwarf2Data, Stream *s)
183 //{
184 //    const DataExtractor &debug_aranges_data = dwarf2Data->get_debug_aranges_data();
185 //    if (debug_aranges_data.ValidOffset(0))
186 //    {
187 //        uint32_t offset = 0;
188 //
189 //        DWARFDebugArangeSet set;
190 //        while (set.Extract(debug_aranges_data, &offset))
191 //            set.Dump(s);
192 //    }
193 //    else
194 //        s->PutCString("< EMPTY >\n");
195 //}
196 //
197 
198 //----------------------------------------------------------------------
199 // AppendDebugRanges
200 //----------------------------------------------------------------------
201 //void
202 //DWARFDebugAranges::AppendDebugRanges(BinaryStreamBuf& debug_ranges, dw_addr_t cu_base_addr, uint32_t addr_size) const
203 //{
204 //  if (!m_aranges.empty())
205 //  {
206 //      RangeCollIterator end = m_aranges.end();
207 //      RangeCollIterator pos;
208 //      RangeCollIterator lo_pos = end;
209 //      for (pos = m_aranges.begin(); pos != end; ++pos)
210 //      {
211 //          if (lo_pos == end)
212 //              lo_pos = pos;
213 //
214 //          RangeCollIterator next = pos + 1;
215 //          if (next != end)
216 //          {
217 //              // Check to see if we can combine two consecutive ranges?
218 //              if (pos->hi_pc == next->lo_pc)
219 //                  continue;   // We can combine them!
220 //          }
221 //
222 //          if (cu_base_addr == 0 || cu_base_addr == DW_INVALID_ADDRESS)
223 //          {
224 //              debug_ranges.AppendMax64(lo_pos->lo_pc, addr_size);
225 //              debug_ranges.AppendMax64(pos->hi_pc, addr_size);
226 //          }
227 //          else
228 //          {
229 //              assert(lo_pos->lo_pc >= cu_base_addr);
230 //              assert(pos->hi_pc >= cu_base_addr);
231 //              debug_ranges.AppendMax64(lo_pos->lo_pc - cu_base_addr, addr_size);
232 //              debug_ranges.AppendMax64(pos->hi_pc - cu_base_addr, addr_size);
233 //          }
234 //
235 //          // Reset the low part of the next address range
236 //          lo_pos = end;
237 //      }
238 //  }
239 //  // Terminate the .debug_ranges with two zero addresses
240 //  debug_ranges.AppendMax64(0, addr_size);
241 //  debug_ranges.AppendMax64(0, addr_size);
242 //
243 //}
244 void
245 DWARFDebugAranges::AppendRange (dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc)
246 {
247     if (!m_aranges.empty())
248     {
249         if (m_aranges.back().offset == offset && m_aranges.back().hi_pc() == low_pc)
250         {
251             m_aranges.back().set_hi_pc(high_pc);
252             return;
253         }
254     }
255     m_aranges.push_back (DWARFDebugAranges::Range(low_pc, high_pc, offset));
256 }
257 
258 void
259 DWARFDebugAranges::Sort (bool minimize, uint32_t n)
260 {
261     Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p",
262                        __PRETTY_FUNCTION__, this);
263 
264     Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES);
265     const size_t orig_arange_size = m_aranges.size();
266     if (log)
267     {
268         log->Printf ("DWARFDebugAranges::Sort(minimize = %u, n = %u) with %zu entries", minimize, n, orig_arange_size);
269         Dump (log);
270     }
271 
272     // Size of one? If so, no sorting is needed
273     if (orig_arange_size <= 1)
274         return;
275     // Sort our address range entries
276     std::stable_sort (m_aranges.begin(), m_aranges.end(), RangeLessThan);
277 
278 
279     if (!minimize)
280         return;
281 
282     // Most address ranges are contiguous from function to function
283     // so our new ranges will likely be smaller. We calculate the size
284     // of the new ranges since although std::vector objects can be resized,
285     // the will never reduce their allocated block size and free any excesss
286     // memory, so we might as well start a brand new collection so it is as
287     // small as possible.
288 
289     // First calculate the size of the new minimal arange vector
290     // so we don't have to do a bunch of re-allocations as we
291     // copy the new minimal stuff over to the new collection
292     size_t minimal_size = 1;
293     size_t i;
294     for (i=1; i<orig_arange_size; ++i)
295     {
296         if (!DWARFDebugAranges::Range::SortedOverlapCheck (m_aranges[i-1], m_aranges[i], n))
297             ++minimal_size;
298     }
299 
300     // If the sizes are the same, then no consecutive aranges can be
301     // combined, we are done
302     if (minimal_size == orig_arange_size)
303         return;
304 
305     // Else, make a new RangeColl that _only_ contains what we need.
306     RangeColl minimal_aranges;
307     minimal_aranges.resize(minimal_size);
308     uint32_t j=0;
309     minimal_aranges[j] = m_aranges[0];
310     for (i=1; i<orig_arange_size; ++i)
311     {
312         if (DWARFDebugAranges::Range::SortedOverlapCheck (minimal_aranges[j], m_aranges[i], n))
313         {
314             minimal_aranges[j].set_hi_pc (m_aranges[i].hi_pc());
315         }
316         else
317         {
318             // Only increment j if we aren't merging
319             minimal_aranges[++j] = m_aranges[i];
320         }
321     }
322     assert (j+1 == minimal_size);
323 
324     // Now swap our new minimal aranges into place. The local
325     // minimal_aranges will then contian the old big collection
326     // which will get freed.
327     minimal_aranges.swap(m_aranges);
328 
329     if (log)
330     {
331         size_t delta = orig_arange_size - m_aranges.size();
332         log->Printf ("DWARFDebugAranges::Sort() %zu entries after minimizing (%zu entries combined for %zu bytes saved)",
333                      m_aranges.size(), delta, delta * sizeof(Range));
334         Dump (log);
335     }
336 }
337 
338 //----------------------------------------------------------------------
339 // FindAddress
340 //----------------------------------------------------------------------
341 dw_offset_t
342 DWARFDebugAranges::FindAddress(dw_addr_t address) const
343 {
344     if ( !m_aranges.empty() )
345     {
346         DWARFDebugAranges::Range range(address);
347         DWARFDebugAranges::RangeCollIterator begin = m_aranges.begin();
348         DWARFDebugAranges::RangeCollIterator end = m_aranges.end();
349         DWARFDebugAranges::RangeCollIterator pos = lower_bound(begin, end, range, RangeLessThan);
350 
351         if ((pos != end) && (pos->lo_pc <= address && address < pos->hi_pc()))
352         {
353         //  printf("FindAddress(1) found 0x%8.8x in compile unit: 0x%8.8x\n", address, pos->offset);
354             return pos->offset;
355         }
356         else if (pos != begin)
357         {
358             --pos;
359             if ((pos->lo_pc <= address) && (address < pos->hi_pc()))
360             {
361             //  printf("FindAddress(2) found 0x%8.8x in compile unit: 0x%8.8x\n", address, pos->offset);
362                 return (*pos).offset;
363             }
364         }
365     }
366     return DW_INVALID_OFFSET;
367 }
368 
369 //----------------------------------------------------------------------
370 // AllRangesAreContiguous
371 //----------------------------------------------------------------------
372 bool
373 DWARFDebugAranges::AllRangesAreContiguous(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const
374 {
375     if (m_aranges.empty())
376         return false;
377 
378     DWARFDebugAranges::RangeCollIterator begin = m_aranges.begin();
379     DWARFDebugAranges::RangeCollIterator end = m_aranges.end();
380     DWARFDebugAranges::RangeCollIterator pos;
381     dw_addr_t next_addr = 0;
382 
383     for (pos = begin; pos != end; ++pos)
384     {
385         if ((pos != begin) && (pos->lo_pc != next_addr))
386             return false;
387         next_addr = pos->hi_pc();
388     }
389     lo_pc = m_aranges.front().lo_pc;    // We checked for empty at the start of function so front() will be valid
390     hi_pc = m_aranges.back().hi_pc();     // We checked for empty at the start of function so back() will be valid
391     return true;
392 }
393 
394 bool
395 DWARFDebugAranges::GetMaxRange(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const
396 {
397     if (m_aranges.empty())
398         return false;
399 
400     lo_pc = m_aranges.front().lo_pc;    // We checked for empty at the start of function so front() will be valid
401     hi_pc = m_aranges.back().hi_pc();   // We checked for empty at the start of function so back() will be valid
402     return true;
403 }
404 
405