1 //===-- DWARFFormValue.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 <assert.h>
11 
12 #include "lldb/Core/dwarf.h"
13 #include "lldb/Core/Stream.h"
14 
15 #include "DWARFFormValue.h"
16 #include "DWARFCompileUnit.h"
17 
18 class DWARFCompileUnit;
19 
20 using namespace lldb_private;
21 
22 
23 static uint8_t g_form_sizes_addr4[] =
24 {
25     0, // 0x00 unused
26     4, // 0x01 DW_FORM_addr
27     0, // 0x02 unused
28     0, // 0x03 DW_FORM_block2
29     0, // 0x04 DW_FORM_block4
30     2, // 0x05 DW_FORM_data2
31     4, // 0x06 DW_FORM_data4
32     8, // 0x07 DW_FORM_data8
33     0, // 0x08 DW_FORM_string
34     0, // 0x09 DW_FORM_block
35     0, // 0x0a DW_FORM_block1
36     1, // 0x0b DW_FORM_data1
37     1, // 0x0c DW_FORM_flag
38     0, // 0x0d DW_FORM_sdata
39     4, // 0x0e DW_FORM_strp
40     0, // 0x0f DW_FORM_udata
41     4, // 0x10 DW_FORM_ref_addr
42     1, // 0x11 DW_FORM_ref1
43     2, // 0x12 DW_FORM_ref2
44     4, // 0x13 DW_FORM_ref4
45     8, // 0x14 DW_FORM_ref8
46     0, // 0x15 DW_FORM_ref_udata
47     0, // 0x16 DW_FORM_indirect
48 };
49 
50 static uint8_t
51 g_form_sizes_addr8[] =
52 {
53     0, // 0x00 unused
54     8, // 0x01 DW_FORM_addr
55     0, // 0x02 unused
56     0, // 0x03 DW_FORM_block2
57     0, // 0x04 DW_FORM_block4
58     2, // 0x05 DW_FORM_data2
59     4, // 0x06 DW_FORM_data4
60     8, // 0x07 DW_FORM_data8
61     0, // 0x08 DW_FORM_string
62     0, // 0x09 DW_FORM_block
63     0, // 0x0a DW_FORM_block1
64     1, // 0x0b DW_FORM_data1
65     1, // 0x0c DW_FORM_flag
66     0, // 0x0d DW_FORM_sdata
67     4, // 0x0e DW_FORM_strp
68     0, // 0x0f DW_FORM_udata
69     8, // 0x10 DW_FORM_ref_addr
70     1, // 0x11 DW_FORM_ref1
71     2, // 0x12 DW_FORM_ref2
72     4, // 0x13 DW_FORM_ref4
73     8, // 0x14 DW_FORM_ref8
74     0, // 0x15 DW_FORM_ref_udata
75     0, // 0x16 DW_FORM_indirect
76 };
77 
78 const uint8_t *
79 DWARFFormValue::GetFixedFormSizesForAddressSize (uint8_t addr_size)
80 {
81     switch (addr_size)
82     {
83     case 4: return g_form_sizes_addr4;
84     case 8: return g_form_sizes_addr8;
85     }
86     return NULL;
87 }
88 
89 DWARFFormValue::DWARFFormValue(dw_form_t form) :
90     m_form(form),
91     m_value()
92 {
93 }
94 
95 bool
96 DWARFFormValue::ExtractValue(const DataExtractor& data, uint32_t* offset_ptr, const DWARFCompileUnit* cu)
97 {
98     bool indirect = false;
99     bool is_block = false;
100     m_value.data = NULL;
101     // Read the value for the form into value and follow and DW_FORM_indirect instances we run into
102     do
103     {
104         indirect = false;
105         switch (m_form)
106         {
107         case DW_FORM_addr:      m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(cu));  break;
108         case DW_FORM_block2:    m_value.value.uval = data.GetU16(offset_ptr); is_block = true;          break;
109         case DW_FORM_block4:    m_value.value.uval = data.GetU32(offset_ptr); is_block = true;          break;
110         case DW_FORM_data2:     m_value.value.uval = data.GetU16(offset_ptr);                           break;
111         case DW_FORM_data4:     m_value.value.uval = data.GetU32(offset_ptr);                           break;
112         case DW_FORM_data8:     m_value.value.uval = data.GetU64(offset_ptr);                           break;
113         case DW_FORM_string:    m_value.value.cstr = data.GetCStr(offset_ptr);
114                                 // Set the string value to also be the data for inlined cstr form values only
115                                 // so we can tell the differnence between DW_FORM_string and DW_FORM_strp form
116                                 // values;
117                                 m_value.data = (uint8_t*)m_value.value.cstr;                            break;
118         case DW_FORM_block:     m_value.value.uval = data.GetULEB128(offset_ptr); is_block = true;      break;
119         case DW_FORM_block1:    m_value.value.uval = data.GetU8(offset_ptr); is_block = true;           break;
120         case DW_FORM_data1:     m_value.value.uval = data.GetU8(offset_ptr);                            break;
121         case DW_FORM_flag:      m_value.value.uval = data.GetU8(offset_ptr);                            break;
122         case DW_FORM_sdata:     m_value.value.sval = data.GetSLEB128(offset_ptr);                       break;
123         case DW_FORM_strp:      m_value.value.uval = data.GetU32(offset_ptr);                           break;
124     //  case DW_FORM_APPLE_db_str:
125         case DW_FORM_udata:     m_value.value.uval = data.GetULEB128(offset_ptr);                       break;
126         case DW_FORM_ref_addr:  m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(cu));  break;
127         case DW_FORM_ref1:      m_value.value.uval = data.GetU8(offset_ptr);                            break;
128         case DW_FORM_ref2:      m_value.value.uval = data.GetU16(offset_ptr);                           break;
129         case DW_FORM_ref4:      m_value.value.uval = data.GetU32(offset_ptr);                           break;
130         case DW_FORM_ref8:      m_value.value.uval = data.GetU64(offset_ptr);                           break;
131         case DW_FORM_ref_udata: m_value.value.uval = data.GetULEB128(offset_ptr);                       break;
132         case DW_FORM_indirect:
133             m_form = data.GetULEB128(offset_ptr);
134             indirect = true;
135             break;
136 
137         default:
138             return false;
139             break;
140         }
141     } while (indirect);
142 
143     if (is_block)
144     {
145         m_value.data = data.PeekData(*offset_ptr, m_value.value.uval);
146         if (m_value.data != NULL)
147         {
148             *offset_ptr += m_value.value.uval;
149         }
150     }
151 
152     return true;
153 }
154 
155 bool
156 DWARFFormValue::SkipValue(const DataExtractor& debug_info_data, uint32_t* offset_ptr, const DWARFCompileUnit* cu) const
157 {
158     return DWARFFormValue::SkipValue(m_form, debug_info_data, offset_ptr, cu);
159 }
160 
161 bool
162 DWARFFormValue::SkipValue(dw_form_t form, const DataExtractor& debug_info_data, uint32_t* offset_ptr, const DWARFCompileUnit* cu)
163 {
164     bool indirect = false;
165     do
166     {
167         indirect = false;
168         switch (form)
169         {
170         // Blocks if inlined data that have a length field and the data bytes
171         // inlined in the .debug_info
172         case DW_FORM_block      : { dw_uleb128_t size = debug_info_data.GetULEB128(offset_ptr); *offset_ptr += size; } return true;
173         case DW_FORM_block1     : { dw_uleb128_t size = debug_info_data.GetU8(offset_ptr);          *offset_ptr += size; } return true;
174         case DW_FORM_block2     : { dw_uleb128_t size = debug_info_data.GetU16(offset_ptr);         *offset_ptr += size; } return true;
175         case DW_FORM_block4     : { dw_uleb128_t size = debug_info_data.GetU32(offset_ptr);         *offset_ptr += size; } return true;
176 
177         // Inlined NULL terminated C-strings
178         case DW_FORM_string     :
179             debug_info_data.GetCStr(offset_ptr);
180             return true;
181 
182         // Compile unit address sized values
183         case DW_FORM_addr       :
184         case DW_FORM_ref_addr   :
185             *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu);
186             return true;
187 
188         // 1 byte values
189         case DW_FORM_data1      :
190         case DW_FORM_flag       :
191         case DW_FORM_ref1       :
192             *offset_ptr += 1;
193             return true;
194 
195         // 2 byte values
196         case DW_FORM_data2      :
197         case DW_FORM_ref2       :
198             *offset_ptr += 2;
199             return true;
200 
201         // 4 byte values
202         case DW_FORM_strp       :
203         case DW_FORM_data4      :
204         case DW_FORM_ref4       :
205             *offset_ptr += 4;
206             return true;
207 
208         // 8 byte values
209         case DW_FORM_data8      :
210         case DW_FORM_ref8       :
211             *offset_ptr += 8;
212             return true;
213 
214         // signed or unsigned LEB 128 values
215     //  case DW_FORM_APPLE_db_str:
216         case DW_FORM_sdata      :
217         case DW_FORM_udata      :
218         case DW_FORM_ref_udata  :
219             debug_info_data.Skip_LEB128(offset_ptr);
220             return true;
221 
222         case DW_FORM_indirect   :
223             indirect = true;
224             form = debug_info_data.GetULEB128(offset_ptr);
225             break;
226         default:
227             return false;
228         }
229     } while (indirect);
230     return true;
231 }
232 
233 //bool
234 //DWARFFormValue::PutUnsigned(dw_form_t form, dw_offset_t offset, uint64_t value, BinaryStreamBuf& out_buff, const DWARFCompileUnit* cu, bool fixup_cu_relative_refs)
235 //{
236 //  assert(offset != DW_INVALID_OFFSET);
237 ////    printf("PutUnsigned(%s, 0x%8.8x, 0x%16.16llx, %d)\n", DW_FORM_value_to_name(form), offset, value, fixup_cu_relative_refs);
238 //  // Read the value for the form into value and follow and DW_FORM_indirect instances we run into
239 //  switch (form)
240 //  {
241 //  case DW_FORM_addr:      offset = out_buff.PutMax64(offset, value, DWARFCompileUnit::GetAddressByteSize(cu));    break;
242 //
243 //  case DW_FORM_flag:
244 //  case DW_FORM_data1:     offset = out_buff.Put8(offset, value);                  break;
245 //  case DW_FORM_data2:     offset = out_buff.Put16(offset, value);                 break;
246 //  case DW_FORM_data4:     offset = out_buff.Put32(offset, value);                 break;
247 //  case DW_FORM_data8:     offset = out_buff.Put64(offset, value);                 break;
248 ////    case DW_FORM_udata:     offset = out_buff.Put32_as_ULEB128(offset, value);      break;
249 ////    case DW_FORM_sdata:     offset = out_buff.Put32_as_SLEB128(offset, value);      break;
250 //  case DW_FORM_strp:      offset = out_buff.Put32(offset, value);                 break;
251 ////    case DW_FORM_APPLE_db_str:
252 ////                            offset = out_buff.Put32_as_ULEB128(offset, value);      break;
253 //
254 //  case DW_FORM_ref1:
255 //      if (fixup_cu_relative_refs) value -= cu->GetOffset();
256 //      offset = out_buff.Put8(offset, value);
257 //      break;
258 //  case DW_FORM_ref2:
259 //      if (fixup_cu_relative_refs) value -= cu->GetOffset();
260 //      offset = out_buff.Put16(offset, value);
261 //      break;
262 //  case DW_FORM_ref4:
263 //      if (fixup_cu_relative_refs) value -= cu->GetOffset();
264 //      offset = out_buff.Put32(offset, value);
265 //      break;
266 //  case DW_FORM_ref8:
267 //      if (fixup_cu_relative_refs) value -= cu->GetOffset();
268 //      offset = out_buff.Put64(offset, value);
269 //      break;
270 ////    case DW_FORM_ref_udata:
271 ////        if (fixup_cu_relative_refs) value -= cu->GetOffset();
272 ////        offset = out_buff.Put32_as_ULEB128(offset, value);
273 ////        break;
274 //  case DW_FORM_ref_addr:
275 //      // TODO: Add support for DWARF3 if we ever start emitting DWARF3. The DW_FORM_ref_addr
276 //      // is always the same size as an address prior to DWARF3, and with DWARF3 or later it
277 //      // is 4 hard coded to bytes.
278 //      offset = out_buff.PutMax64(offset, value, DWARFCompileUnit::GetAddressByteSize(cu));
279 //      break;
280 //
281 //  default:
282 //      return false;
283 //  }
284 //
285 //  return true;
286 //}
287 
288 //bool
289 //DWARFFormValue::TransferValue(dw_form_t form, const DataExtractor& data, uint32_t* offset_ptr, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff)
290 //{
291 //  DWARFFormValue formValue(form);
292 //  if (formValue.ExtractValue(data, offset_ptr,cu))
293 //      return TransferValue(formValue, cu, out_buff);
294 //  return false;
295 //}
296 
297 //bool
298 //DWARFFormValue::TransferValue(const DWARFFormValue& formValue, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff)
299 //{
300 //  // Read the value for the form into value and follow and DW_FORM_indirect instances we run into
301 //  dw_form_t form = formValue.Form();
302 //  switch (form)
303 //  {
304 //  case DW_FORM_addr:
305 //  case DW_FORM_ref_addr:
306 //      {
307 //          uint8_t addr_size = DWARFCompileUnit::GetAddressByteSize(cu);
308 //          out_buff.AppendMax64(formValue.Unsigned(), addr_size);
309 //      }
310 //      break;
311 //
312 //  case DW_FORM_block:     out_buff.Append32_as_ULEB128(formValue.Unsigned()); break;
313 //  case DW_FORM_block1:    out_buff.Append8(formValue.Unsigned());             break;
314 //  case DW_FORM_block2:    out_buff.Append16(formValue.Unsigned());            break;
315 //  case DW_FORM_block4:    out_buff.Append32(formValue.Unsigned());            break;
316 //
317 //  case DW_FORM_flag:
318 //  case DW_FORM_data1:     out_buff.Append8(formValue.Unsigned());             break;
319 //  case DW_FORM_data2:     out_buff.Append16(formValue.Unsigned());            break;
320 //  case DW_FORM_data4:     out_buff.Append32(formValue.Unsigned());            break;
321 //  case DW_FORM_data8:     out_buff.Append64(formValue.Unsigned());            break;
322 //  case DW_FORM_udata:     out_buff.Append32_as_ULEB128(formValue.Unsigned()); break;
323 //  case DW_FORM_sdata:     out_buff.Append32_as_SLEB128(formValue.Signed());   break;
324 //
325 //  case DW_FORM_string:    out_buff.AppendCStr(formValue.m_value.value.cstr);      break;
326 //  case DW_FORM_strp:      out_buff.Append32(formValue.Unsigned());            break;
327 ////    case DW_FORM_APPLE_db_str:
328 ////                            out_buff.Append32_as_ULEB128(formValue.Unsigned()); break;
329 //
330 //  case DW_FORM_ref1:      out_buff.Append8(formValue.Unsigned());             break;
331 //  case DW_FORM_ref2:      out_buff.Append16(formValue.Unsigned());            break;
332 //  case DW_FORM_ref4:      out_buff.Append32(formValue.Unsigned());            break;
333 //  case DW_FORM_ref8:      out_buff.Append64(formValue.Unsigned());            break;
334 //  case DW_FORM_ref_udata: out_buff.Append32_as_ULEB128(formValue.Unsigned()); break;
335 //
336 //  case DW_FORM_indirect:
337 //      assert(!"DW_FORM_indirect found in DWARFFormValue::TransferValue() for an extracted form...");
338 //      break;
339 //
340 //  default:
341 //      Log::Error("DWARFFormValue::TransferValue() Unrecognized form: 0x%4.4x", form);
342 //      return false;
343 //      break;
344 //  }
345 //
346 //  const uint8_t* block_data = formValue.BlockData();
347 //  if (block_data)
348 //      out_buff.AppendData(block_data, formValue.Unsigned());
349 //  return true;
350 //}
351 
352 void
353 DWARFFormValue::Dump(Stream *s, const DataExtractor* debug_str_data, const DWARFCompileUnit* cu) const
354 {
355     uint64_t uvalue = Unsigned();
356     bool cu_relative_offset = false;
357 
358     bool verbose = s->GetVerbose();
359 
360     switch (m_form)
361     {
362     case DW_FORM_addr:      s->Address(uvalue, sizeof (uint64_t)); break;
363     case DW_FORM_flag:
364     case DW_FORM_data1:     s->PutHex8(uvalue);     break;
365     case DW_FORM_data2:     s->PutHex16(uvalue);        break;
366     case DW_FORM_data4:     s->PutHex32(uvalue);        break;
367     case DW_FORM_data8:     s->PutHex64(uvalue);        break;
368     case DW_FORM_string:    s->QuotedCString(AsCString(NULL));          break;
369     case DW_FORM_block:
370     case DW_FORM_block1:
371     case DW_FORM_block2:
372     case DW_FORM_block4:
373         if (uvalue > 0)
374         {
375             switch (m_form)
376             {
377             case DW_FORM_block:  s->Printf("<0x%llx> ", uvalue);                break;
378             case DW_FORM_block1: s->Printf("<0x%2.2x> ", (uint8_t)uvalue);      break;
379             case DW_FORM_block2: s->Printf("<0x%4.4x> ", (uint16_t)uvalue);     break;
380             case DW_FORM_block4: s->Printf("<0x%8.8x> ", (uint32_t)uvalue);     break;
381             default:                                                            break;
382             }
383 
384             const uint8_t* data_ptr = m_value.data;
385             if (data_ptr)
386             {
387                 const uint8_t* end_data_ptr = data_ptr + uvalue;    // uvalue contains size of block
388                 while (data_ptr < end_data_ptr)
389                 {
390                     s->Printf("%2.2x ", *data_ptr);
391                     ++data_ptr;
392                 }
393             }
394             else
395                 s->PutCString("NULL");
396         }
397         break;
398 
399     case DW_FORM_sdata:     s->PutSLEB128(uvalue); break;
400     case DW_FORM_udata:     s->PutULEB128(uvalue); break;
401     case DW_FORM_strp:
402         if (debug_str_data)
403         {
404             if (verbose)
405                 s->Printf(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue);
406 
407             const char* dbg_str = AsCString(debug_str_data);
408             if (dbg_str)
409                 s->QuotedCString(dbg_str);
410         }
411         else
412         {
413             s->PutHex32(uvalue);
414         }
415         break;
416 
417     case DW_FORM_ref_addr:
418     {
419         s->Address(uvalue, sizeof (uint64_t) * 2);
420         break;
421     }
422     case DW_FORM_ref1:      cu_relative_offset = true;  if (verbose) s->Printf("cu + 0x%2.2x", (uint8_t)uvalue); break;
423     case DW_FORM_ref2:      cu_relative_offset = true;  if (verbose) s->Printf("cu + 0x%4.4x", (uint16_t)uvalue); break;
424     case DW_FORM_ref4:      cu_relative_offset = true;  if (verbose) s->Printf("cu + 0x%4.4x", (uint32_t)uvalue); break;
425     case DW_FORM_ref8:      cu_relative_offset = true;  if (verbose) s->Printf("cu + 0x%8.8llx", uvalue); break;
426     case DW_FORM_ref_udata: cu_relative_offset = true;  if (verbose) s->Printf("cu + 0x%llx", uvalue); break;
427 
428     // All DW_FORM_indirect attributes should be resolved prior to calling this function
429     case DW_FORM_indirect:  s->PutCString("DW_FORM_indirect"); break;
430     default:
431         s->Printf("DW_FORM(0x%4.4x)", m_form);
432         break;
433     }
434 
435     if (cu_relative_offset)
436     {
437         if (verbose)
438             s->PutCString(" => ");
439 
440         s->Printf("{0x%8.8x}", (uvalue + (cu ? cu->GetOffset() : 0)));
441     }
442 }
443 
444 const char*
445 DWARFFormValue::AsCString(const DataExtractor* debug_str_data_ptr) const
446 {
447     if (IsInlinedCStr())
448         return m_value.value.cstr;
449     else if (debug_str_data_ptr)
450         return debug_str_data_ptr->PeekCStr(m_value.value.uval);
451     return NULL;
452 }
453 
454 uint64_t
455 DWARFFormValue::Reference(const DWARFCompileUnit* cu) const
456 {
457     uint64_t die_offset = m_value.value.uval;
458     switch (m_form)
459     {
460     case DW_FORM_ref1:
461     case DW_FORM_ref2:
462     case DW_FORM_ref4:
463     case DW_FORM_ref8:
464     case DW_FORM_ref_udata:
465         die_offset += (cu ? cu->GetOffset() : 0);
466         break;
467 
468     default:
469         break;
470     }
471 
472     return die_offset;
473 }
474 
475 //----------------------------------------------------------------------
476 // Resolve any compile unit specific references so that we don't need
477 // the compile unit at a later time in order to work with the form
478 // value.
479 //----------------------------------------------------------------------
480 bool
481 DWARFFormValue::ResolveCompileUnitReferences(const DWARFCompileUnit* cu)
482 {
483     switch (m_form)
484     {
485     case DW_FORM_ref1:
486     case DW_FORM_ref2:
487     case DW_FORM_ref4:
488     case DW_FORM_ref8:
489     case DW_FORM_ref_udata:
490         m_value.value.uval += cu->GetOffset();
491         m_form = DW_FORM_ref_addr;
492         return true;
493         break;
494 
495     default:
496         break;
497     }
498 
499     return false;
500 }
501 
502 const uint8_t*
503 DWARFFormValue::BlockData() const
504 {
505     if (!IsInlinedCStr())
506         return m_value.data;
507     return NULL;
508 }
509 
510 
511 bool
512 DWARFFormValue::IsBlockForm(const dw_form_t form)
513 {
514     switch (form)
515     {
516     case DW_FORM_block:
517     case DW_FORM_block1:
518     case DW_FORM_block2:
519     case DW_FORM_block4:
520         return true;
521     }
522     return false;
523 }
524 
525 bool
526 DWARFFormValue::IsDataForm(const dw_form_t form)
527 {
528     switch (form)
529     {
530     case DW_FORM_sdata:
531     case DW_FORM_udata:
532     case DW_FORM_data1:
533     case DW_FORM_data2:
534     case DW_FORM_data4:
535     case DW_FORM_data8:
536         return true;
537     }
538     return false;
539 }
540 
541 int
542 DWARFFormValue::Compare (const DWARFFormValue& a_value, const DWARFFormValue& b_value, const DWARFCompileUnit* a_cu, const DWARFCompileUnit* b_cu, const DataExtractor* debug_str_data_ptr)
543 {
544     dw_form_t a_form = a_value.Form();
545     dw_form_t b_form = b_value.Form();
546     if (a_form < b_form)
547         return -1;
548     if (a_form > b_form)
549         return 1;
550     switch (a_form)
551     {
552     case DW_FORM_addr:
553     case DW_FORM_flag:
554     case DW_FORM_data1:
555     case DW_FORM_data2:
556     case DW_FORM_data4:
557     case DW_FORM_data8:
558     case DW_FORM_udata:
559     case DW_FORM_ref_addr:
560         {
561             uint64_t a = a_value.Unsigned();
562             uint64_t b = b_value.Unsigned();
563             if (a < b)
564                 return -1;
565             if (a > b)
566                 return 1;
567             return 0;
568         }
569 
570     case DW_FORM_sdata:
571         {
572             int64_t a = a_value.Signed();
573             int64_t b = b_value.Signed();
574             if (a < b)
575                 return -1;
576             if (a > b)
577                 return 1;
578             return 0;
579         }
580 
581     case DW_FORM_string:
582     case DW_FORM_strp:
583         {
584             const char *a_string = a_value.AsCString(debug_str_data_ptr);
585             const char *b_string = b_value.AsCString(debug_str_data_ptr);
586             if (a_string == b_string)
587                 return 0;
588             else if (a_string && b_string)
589                 return strcmp(a_string, b_string);
590             else if (a_string == NULL)
591                 return -1;  // A string is NULL, and B is valid
592             else
593                 return 1;   // A string valid, and B is NULL
594         }
595 
596 
597     case DW_FORM_block:
598     case DW_FORM_block1:
599     case DW_FORM_block2:
600     case DW_FORM_block4:
601         {
602             uint64_t a_len = a_value.Unsigned();
603             uint64_t b_len = b_value.Unsigned();
604             if (a_len < b_len)
605                 return -1;
606             if (a_len > b_len)
607                 return 1;
608             // The block lengths are the same
609             return memcmp(a_value.BlockData(), b_value.BlockData(), a_value.Unsigned());
610         }
611         break;
612 
613     case DW_FORM_ref1:
614     case DW_FORM_ref2:
615     case DW_FORM_ref4:
616     case DW_FORM_ref8:
617     case DW_FORM_ref_udata:
618         {
619             uint64_t a = a_value.Reference(a_cu);
620             uint64_t b = b_value.Reference(b_cu);
621             if (a < b)
622                 return -1;
623             if (a > b)
624                 return 1;
625             return 0;
626         }
627 
628     case DW_FORM_indirect:
629         assert(!"This shouldn't happen after the form has been extracted...");
630         break;
631 
632     default:
633         assert(!"Unhandled DW_FORM");
634         break;
635     }
636     return -1;
637 }
638 
639