- add sources.
[platform/framework/web/crosswalk.git] / src / courgette / disassembler_win32_x64.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "courgette/disassembler_win32_x64.h"
6
7 #include <algorithm>
8 #include <string>
9 #include <vector>
10
11 #include "base/basictypes.h"
12 #include "base/logging.h"
13
14 #include "courgette/assembly_program.h"
15 #include "courgette/courgette.h"
16 #include "courgette/encoded_program.h"
17
18 namespace courgette {
19
20 DisassemblerWin32X64::DisassemblerWin32X64(const void* start, size_t length)
21   : Disassembler(start, length),
22     incomplete_disassembly_(false),
23     is_PE32_plus_(false),
24     optional_header_(NULL),
25     size_of_optional_header_(0),
26     offset_of_data_directories_(0),
27     machine_type_(0),
28     number_of_sections_(0),
29     sections_(NULL),
30     has_text_section_(false),
31     size_of_code_(0),
32     size_of_initialized_data_(0),
33     size_of_uninitialized_data_(0),
34     base_of_code_(0),
35     base_of_data_(0),
36     image_base_(0),
37     size_of_image_(0),
38     number_of_data_directories_(0) {
39 }
40
41 // ParseHeader attempts to match up the buffer with the Windows data
42 // structures that exist within a Windows 'Portable Executable' format file.
43 // Returns 'true' if the buffer matches, and 'false' if the data looks
44 // suspicious.  Rather than try to 'map' the buffer to the numerous windows
45 // structures, we extract the information we need into the courgette::PEInfo
46 // structure.
47 //
48 bool DisassemblerWin32X64::ParseHeader() {
49   if (length() < kOffsetOfFileAddressOfNewExeHeader + 4 /*size*/)
50     return Bad("Too small");
51
52   // Have 'MZ' magic for a DOS header?
53   if (start()[0] != 'M' || start()[1] != 'Z')
54     return Bad("Not MZ");
55
56   // offset from DOS header to PE header is stored in DOS header.
57   uint32 offset = ReadU32(start(),
58                           kOffsetOfFileAddressOfNewExeHeader);
59
60   if (offset >= length())
61     return Bad("Bad offset to PE header");
62
63   const uint8* const pe_header = OffsetToPointer(offset);
64   const size_t kMinPEHeaderSize = 4 /*signature*/ + kSizeOfCoffHeader;
65   if (pe_header <= start() ||
66       pe_header >= end() - kMinPEHeaderSize)
67     return Bad("Bad offset to PE header");
68
69   if (offset % 8 != 0)
70     return Bad("Misaligned PE header");
71
72   // The 'PE' header is an IMAGE_NT_HEADERS structure as defined in WINNT.H.
73   // See http://msdn.microsoft.com/en-us/library/ms680336(VS.85).aspx
74   //
75   // The first field of the IMAGE_NT_HEADERS is the signature.
76   if (!(pe_header[0] == 'P' &&
77         pe_header[1] == 'E' &&
78         pe_header[2] == 0 &&
79         pe_header[3] == 0))
80     return Bad("no PE signature");
81
82   // The second field of the IMAGE_NT_HEADERS is the COFF header.
83   // The COFF header is also called an IMAGE_FILE_HEADER
84   //   http://msdn.microsoft.com/en-us/library/ms680313(VS.85).aspx
85   const uint8* const coff_header = pe_header + 4;
86   machine_type_       = ReadU16(coff_header, 0);
87   number_of_sections_ = ReadU16(coff_header, 2);
88   size_of_optional_header_ = ReadU16(coff_header, 16);
89
90   // The rest of the IMAGE_NT_HEADERS is the IMAGE_OPTIONAL_HEADER(32|64)
91   const uint8* const optional_header = coff_header + kSizeOfCoffHeader;
92   optional_header_ = optional_header;
93
94   if (optional_header + size_of_optional_header_ >= end())
95     return Bad("optional header past end of file");
96
97   // Check we can read the magic.
98   if (size_of_optional_header_ < 2)
99     return Bad("optional header no magic");
100
101   uint16 magic = ReadU16(optional_header, 0);
102
103   if (magic == kImageNtOptionalHdr32Magic) {
104     is_PE32_plus_ = false;
105     offset_of_data_directories_ =
106       kOffsetOfDataDirectoryFromImageOptionalHeader32;
107   } else if (magic == kImageNtOptionalHdr64Magic) {
108     is_PE32_plus_ = true;
109     offset_of_data_directories_ =
110       kOffsetOfDataDirectoryFromImageOptionalHeader64;
111   } else {
112     return Bad("unrecognized magic");
113   }
114
115   // Check that we can read the rest of the the fixed fields.  Data directories
116   // directly follow the fixed fields of the IMAGE_OPTIONAL_HEADER.
117   if (size_of_optional_header_ < offset_of_data_directories_)
118     return Bad("optional header too short");
119
120   // The optional header is either an IMAGE_OPTIONAL_HEADER32 or
121   // IMAGE_OPTIONAL_HEADER64
122   // http://msdn.microsoft.com/en-us/library/ms680339(VS.85).aspx
123   //
124   // Copy the fields we care about.
125   size_of_code_               = ReadU32(optional_header, 4);
126   size_of_initialized_data_   = ReadU32(optional_header, 8);
127   size_of_uninitialized_data_ = ReadU32(optional_header, 12);
128   base_of_code_               = ReadU32(optional_header, 20);
129   if (is_PE32_plus_) {
130     base_of_data_ = 0;
131     image_base_  = ReadU64(optional_header, 24);
132   } else {
133     base_of_data_ = ReadU32(optional_header, 24);
134     image_base_   = ReadU32(optional_header, 28);
135   }
136   size_of_image_ = ReadU32(optional_header, 56);
137   number_of_data_directories_ =
138     ReadU32(optional_header, (is_PE32_plus_ ? 108 : 92));
139
140   if (size_of_code_ >= length() ||
141       size_of_initialized_data_ >= length() ||
142       size_of_code_ + size_of_initialized_data_ >= length()) {
143     // This validation fires on some perfectly fine executables.
144     //  return Bad("code or initialized data too big");
145   }
146
147   // TODO(sra): we can probably get rid of most of the data directories.
148   bool b = true;
149   // 'b &= ...' could be short circuit 'b = b && ...' but it is not necessary
150   // for correctness and it compiles smaller this way.
151   b &= ReadDataDirectory(0, &export_table_);
152   b &= ReadDataDirectory(1, &import_table_);
153   b &= ReadDataDirectory(2, &resource_table_);
154   b &= ReadDataDirectory(3, &exception_table_);
155   b &= ReadDataDirectory(5, &base_relocation_table_);
156   b &= ReadDataDirectory(11, &bound_import_table_);
157   b &= ReadDataDirectory(12, &import_address_table_);
158   b &= ReadDataDirectory(13, &delay_import_descriptor_);
159   b &= ReadDataDirectory(14, &clr_runtime_header_);
160   if (!b) {
161     return Bad("malformed data directory");
162   }
163
164   // Sections follow the optional header.
165   sections_ =
166       reinterpret_cast<const Section*>(optional_header +
167                                        size_of_optional_header_);
168   size_t detected_length = 0;
169
170   for (int i = 0;  i < number_of_sections_;  ++i) {
171     const Section* section = &sections_[i];
172
173     // TODO(sra): consider using the 'characteristics' field of the section
174     // header to see if the section contains instructions.
175     if (memcmp(section->name, ".text", 6) == 0)
176       has_text_section_ = true;
177
178     uint32 section_end =
179         section->file_offset_of_raw_data + section->size_of_raw_data;
180     if (section_end > detected_length)
181       detected_length = section_end;
182   }
183
184   // Pretend our in-memory copy is only as long as our detected length.
185   ReduceLength(detected_length);
186
187   if (is_32bit()) {
188     return Bad("32 bit executables are not supported by this disassembler");
189   }
190
191   if (!has_text_section()) {
192     return Bad("Resource-only executables are not yet supported");
193   }
194
195   return Good();
196 }
197
198 bool DisassemblerWin32X64::Disassemble(AssemblyProgram* target) {
199   if (!ok())
200     return false;
201
202   target->set_image_base(image_base());
203
204   if (!ParseAbs32Relocs())
205     return false;
206
207   ParseRel32RelocsFromSections();
208
209   if (!ParseFile(target))
210     return false;
211
212   target->DefaultAssignIndexes();
213
214   return true;
215 }
216
217 ////////////////////////////////////////////////////////////////////////////////
218
219 bool DisassemblerWin32X64::ParseRelocs(std::vector<RVA> *relocs) {
220   relocs->clear();
221
222   size_t relocs_size = base_relocation_table_.size_;
223   if (relocs_size == 0)
224     return true;
225
226   // The format of the base relocation table is a sequence of variable sized
227   // IMAGE_BASE_RELOCATION blocks.  Search for
228   //   "The format of the base relocation data is somewhat quirky"
229   // at http://msdn.microsoft.com/en-us/library/ms809762.aspx
230
231   const uint8* relocs_start = RVAToPointer(base_relocation_table_.address_);
232   const uint8* relocs_end = relocs_start + relocs_size;
233
234   // Make sure entire base relocation table is within the buffer.
235   if (relocs_start < start() ||
236       relocs_start >= end() ||
237       relocs_end <= start() ||
238       relocs_end > end()) {
239     return Bad(".relocs outside image");
240   }
241
242   const uint8* block = relocs_start;
243
244   // Walk the variable sized blocks.
245   while (block + 8 < relocs_end) {
246     RVA page_rva = ReadU32(block, 0);
247     uint32 size = ReadU32(block, 4);
248     if (size < 8 ||        // Size includes header ...
249         size % 4  !=  0)   // ... and is word aligned.
250       return Bad("unreasonable relocs block");
251
252     const uint8* end_entries = block + size;
253
254     if (end_entries <= block ||
255         end_entries <= start() ||
256         end_entries > end())
257       return Bad(".relocs block outside image");
258
259     // Walk through the two-byte entries.
260     for (const uint8* p = block + 8;  p < end_entries;  p += 2) {
261       uint16 entry = ReadU16(p, 0);
262       int type = entry >> 12;
263       int offset = entry & 0xFFF;
264
265       RVA rva = page_rva + offset;
266       if (type == 10) {         // IMAGE_REL_BASED_DIR64
267         relocs->push_back(rva);
268       } else if (type == 0) {  // IMAGE_REL_BASED_ABSOLUTE
269         // Ignore, used as padding.
270       } else {
271         // Does not occur in Windows x64 executables.
272         return Bad("unknown type of reloc");
273       }
274     }
275
276     block += size;
277   }
278
279   std::sort(relocs->begin(), relocs->end());
280
281   return true;
282 }
283
284 const Section* DisassemblerWin32X64::RVAToSection(RVA rva) const {
285   for (int i = 0; i < number_of_sections_; i++) {
286     const Section* section = &sections_[i];
287     uint32 offset = rva - section->virtual_address;
288     if (offset < section->virtual_size) {
289       return section;
290     }
291   }
292   return NULL;
293 }
294
295 int DisassemblerWin32X64::RVAToFileOffset(RVA rva) const {
296   const Section* section = RVAToSection(rva);
297   if (section) {
298     uint32 offset = rva - section->virtual_address;
299     if (offset < section->size_of_raw_data) {
300       return section->file_offset_of_raw_data + offset;
301     } else {
302       return kNoOffset;  // In section but not in file (e.g. uninit data).
303     }
304   }
305
306   // Small RVA values point into the file header in the loaded image.
307   // RVA 0 is the module load address which Windows uses as the module handle.
308   // RVA 2 sometimes occurs, I'm not sure what it is, but it would map into the
309   // DOS header.
310   if (rva == 0 || rva == 2)
311     return rva;
312
313   NOTREACHED();
314   return kNoOffset;
315 }
316
317 const uint8* DisassemblerWin32X64::RVAToPointer(RVA rva) const {
318   int file_offset = RVAToFileOffset(rva);
319   if (file_offset == kNoOffset)
320     return NULL;
321   else
322     return OffsetToPointer(file_offset);
323 }
324
325 std::string DisassemblerWin32X64::SectionName(const Section* section) {
326   if (section == NULL)
327     return "<none>";
328   char name[9];
329   memcpy(name, section->name, 8);
330   name[8] = '\0';  // Ensure termination.
331   return name;
332 }
333
334 CheckBool DisassemblerWin32X64::ParseFile(AssemblyProgram* program) {
335   // Walk all the bytes in the file, whether or not in a section.
336   uint32 file_offset = 0;
337   while (file_offset < length()) {
338     const Section* section = FindNextSection(file_offset);
339     if (section == NULL) {
340       // No more sections.  There should not be extra stuff following last
341       // section.
342       //   ParseNonSectionFileRegion(file_offset, pe_info().length(), program);
343       break;
344     }
345     if (file_offset < section->file_offset_of_raw_data) {
346       uint32 section_start_offset = section->file_offset_of_raw_data;
347       if(!ParseNonSectionFileRegion(file_offset, section_start_offset,
348                                     program))
349         return false;
350
351       file_offset = section_start_offset;
352     }
353     uint32 end = file_offset + section->size_of_raw_data;
354     if (!ParseFileRegion(section, file_offset, end, program))
355       return false;
356     file_offset = end;
357   }
358
359 #if COURGETTE_HISTOGRAM_TARGETS
360   HistogramTargets("abs32 relocs", abs32_target_rvas_);
361   HistogramTargets("rel32 relocs", rel32_target_rvas_);
362 #endif
363
364   return true;
365 }
366
367 bool DisassemblerWin32X64::ParseAbs32Relocs() {
368   abs32_locations_.clear();
369   if (!ParseRelocs(&abs32_locations_))
370     return false;
371
372   std::sort(abs32_locations_.begin(), abs32_locations_.end());
373
374 #if COURGETTE_HISTOGRAM_TARGETS
375   for (size_t i = 0;  i < abs32_locations_.size(); ++i) {
376     RVA rva = abs32_locations_[i];
377     // The 4 bytes at the relocation are a reference to some address.
378     uint32 target_address = Read32LittleEndian(RVAToPointer(rva));
379     ++abs32_target_rvas_[target_address - image_base()];
380   }
381 #endif
382   return true;
383 }
384
385 void DisassemblerWin32X64::ParseRel32RelocsFromSections() {
386   uint32 file_offset = 0;
387   while (file_offset < length()) {
388     const Section* section = FindNextSection(file_offset);
389     if (section == NULL)
390       break;
391     if (file_offset < section->file_offset_of_raw_data)
392       file_offset = section->file_offset_of_raw_data;
393     ParseRel32RelocsFromSection(section);
394     file_offset += section->size_of_raw_data;
395   }
396   std::sort(rel32_locations_.begin(), rel32_locations_.end());
397
398 #if COURGETTE_HISTOGRAM_TARGETS
399   VLOG(1) << "abs32_locations_ " << abs32_locations_.size()
400           << "\nrel32_locations_ " << rel32_locations_.size()
401           << "\nabs32_target_rvas_ " << abs32_target_rvas_.size()
402           << "\nrel32_target_rvas_ " << rel32_target_rvas_.size();
403
404   int common = 0;
405   std::map<RVA, int>::iterator abs32_iter = abs32_target_rvas_.begin();
406   std::map<RVA, int>::iterator rel32_iter = rel32_target_rvas_.begin();
407   while (abs32_iter != abs32_target_rvas_.end() &&
408          rel32_iter != rel32_target_rvas_.end()) {
409     if (abs32_iter->first < rel32_iter->first)
410       ++abs32_iter;
411     else if (rel32_iter->first < abs32_iter->first)
412       ++rel32_iter;
413     else {
414       ++common;
415       ++abs32_iter;
416       ++rel32_iter;
417     }
418   }
419   VLOG(1) << "common " << common;
420 #endif
421 }
422
423 void DisassemblerWin32X64::ParseRel32RelocsFromSection(const Section* section) {
424   // TODO(sra): use characteristic.
425   bool isCode = strcmp(section->name, ".text") == 0;
426   if (!isCode)
427     return;
428
429   uint32 start_file_offset = section->file_offset_of_raw_data;
430   uint32 end_file_offset = start_file_offset + section->size_of_raw_data;
431   RVA relocs_start_rva = base_relocation_table().address_;
432
433   const uint8* start_pointer = OffsetToPointer(start_file_offset);
434   const uint8* end_pointer = OffsetToPointer(end_file_offset);
435
436   RVA start_rva = FileOffsetToRVA(start_file_offset);
437   RVA end_rva = start_rva + section->virtual_size;
438
439   // Quick way to convert from Pointer to RVA within a single Section is to
440   // subtract 'pointer_to_rva'.
441   const uint8* const adjust_pointer_to_rva = start_pointer - start_rva;
442
443   std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin();
444
445   // Find the rel32 relocations.
446   const uint8* p = start_pointer;
447   while (p < end_pointer) {
448     RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva);
449     if (current_rva == relocs_start_rva) {
450       uint32 relocs_size = base_relocation_table().size_;
451       if (relocs_size) {
452         p += relocs_size;
453         continue;
454       }
455     }
456
457     //while (abs32_pos != abs32_locations_.end() && *abs32_pos < current_rva)
458     //  ++abs32_pos;
459
460     // Heuristic discovery of rel32 locations in instruction stream: are the
461     // next few bytes the start of an instruction containing a rel32
462     // addressing mode?
463     const uint8* rel32 = NULL;
464
465     if (p + 5 <= end_pointer) {
466       if (*p == 0xE8 || *p == 0xE9) {  // jmp rel32 and call rel32
467         rel32 = p + 1;
468       }
469     }
470     if (p + 6 <= end_pointer) {
471       if (*p == 0x0F  &&  (*(p+1) & 0xF0) == 0x80) {  // Jcc long form
472         if (p[1] != 0x8A && p[1] != 0x8B)  // JPE/JPO unlikely
473           rel32 = p + 2;
474       }
475     }
476     if (rel32) {
477       RVA rel32_rva = static_cast<RVA>(rel32 - adjust_pointer_to_rva);
478
479       // Is there an abs32 reloc overlapping the candidate?
480       while (abs32_pos != abs32_locations_.end() && *abs32_pos < rel32_rva - 3)
481         ++abs32_pos;
482       // Now: (*abs32_pos > rel32_rva - 4) i.e. the lowest addressed 4-byte
483       // region that could overlap rel32_rva.
484       if (abs32_pos != abs32_locations_.end()) {
485         if (*abs32_pos < rel32_rva + 4) {
486           // Beginning of abs32 reloc is before end of rel32 reloc so they
487           // overlap.  Skip four bytes past the abs32 reloc.
488           p += (*abs32_pos + 4) - current_rva;
489           continue;
490         }
491       }
492
493       RVA target_rva = rel32_rva + 4 + Read32LittleEndian(rel32);
494       // To be valid, rel32 target must be within image, and within this
495       // section.
496       if (IsValidRVA(target_rva) &&
497           start_rva <= target_rva && target_rva < end_rva) {
498         rel32_locations_.push_back(rel32_rva);
499 #if COURGETTE_HISTOGRAM_TARGETS
500         ++rel32_target_rvas_[target_rva];
501 #endif
502         p = rel32 + 4;
503         continue;
504       }
505     }
506     p += 1;
507   }
508 }
509
510 CheckBool DisassemblerWin32X64::ParseNonSectionFileRegion(
511     uint32 start_file_offset,
512     uint32 end_file_offset,
513     AssemblyProgram* program) {
514   if (incomplete_disassembly_)
515     return true;
516
517   const uint8* start = OffsetToPointer(start_file_offset);
518   const uint8* end = OffsetToPointer(end_file_offset);
519
520   const uint8* p = start;
521
522   while (p < end) {
523     if (!program->EmitByteInstruction(*p))
524       return false;
525     ++p;
526   }
527
528   return true;
529 }
530
531 CheckBool DisassemblerWin32X64::ParseFileRegion(
532     const Section* section,
533     uint32 start_file_offset, uint32 end_file_offset,
534     AssemblyProgram* program) {
535   RVA relocs_start_rva = base_relocation_table().address_;
536
537   const uint8* start_pointer = OffsetToPointer(start_file_offset);
538   const uint8* end_pointer = OffsetToPointer(end_file_offset);
539
540   RVA start_rva = FileOffsetToRVA(start_file_offset);
541   RVA end_rva = start_rva + section->virtual_size;
542
543   // Quick way to convert from Pointer to RVA within a single Section is to
544   // subtract 'pointer_to_rva'.
545   const uint8* const adjust_pointer_to_rva = start_pointer - start_rva;
546
547   std::vector<RVA>::iterator rel32_pos = rel32_locations_.begin();
548   std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin();
549
550   if (!program->EmitOriginInstruction(start_rva))
551     return false;
552
553   const uint8* p = start_pointer;
554
555   while (p < end_pointer) {
556     RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva);
557
558     // The base relocation table is usually in the .relocs section, but it could
559     // actually be anywhere.  Make sure we skip it because we will regenerate it
560     // during assembly.
561     if (current_rva == relocs_start_rva) {
562       if (!program->EmitPeRelocsInstruction())
563         return false;
564       uint32 relocs_size = base_relocation_table().size_;
565       if (relocs_size) {
566         p += relocs_size;
567         continue;
568       }
569     }
570
571     while (abs32_pos != abs32_locations_.end() && *abs32_pos < current_rva)
572       ++abs32_pos;
573
574     if (abs32_pos != abs32_locations_.end() && *abs32_pos == current_rva) {
575       uint32 target_address = Read32LittleEndian(p);
576       RVA target_rva = target_address - image_base();
577       // TODO(sra): target could be Label+offset.  It is not clear how to guess
578       // which it might be.  We assume offset==0.
579       if (!program->EmitAbs32(program->FindOrMakeAbs32Label(target_rva)))
580         return false;
581       p += 4;
582       continue;
583     }
584
585     while (rel32_pos != rel32_locations_.end() && *rel32_pos < current_rva)
586       ++rel32_pos;
587
588     if (rel32_pos != rel32_locations_.end() && *rel32_pos == current_rva) {
589       RVA target_rva = current_rva + 4 + Read32LittleEndian(p);
590       if (!program->EmitRel32(program->FindOrMakeRel32Label(target_rva)))
591         return false;
592       p += 4;
593       continue;
594     }
595
596     if (incomplete_disassembly_) {
597       if ((abs32_pos == abs32_locations_.end() || end_rva <= *abs32_pos) &&
598           (rel32_pos == rel32_locations_.end() || end_rva <= *rel32_pos) &&
599           (end_rva <= relocs_start_rva || current_rva >= relocs_start_rva)) {
600         // No more relocs in this section, don't bother encoding bytes.
601         break;
602       }
603     }
604
605     if (!program->EmitByteInstruction(*p))
606       return false;
607     p += 1;
608   }
609
610   return true;
611 }
612
613 #if COURGETTE_HISTOGRAM_TARGETS
614 // Histogram is printed to std::cout.  It is purely for debugging the algorithm
615 // and is only enabled manually in 'exploration' builds.  I don't want to add
616 // command-line configuration for this feature because this code has to be
617 // small, which means compiled-out.
618 void DisassemblerWin32X64::HistogramTargets(const char* kind,
619                                             const std::map<RVA, int>& map) {
620   int total = 0;
621   std::map<int, std::vector<RVA> > h;
622   for (std::map<RVA, int>::const_iterator p = map.begin();
623        p != map.end();
624        ++p) {
625     h[p->second].push_back(p->first);
626     total += p->second;
627   }
628
629   std::cout << total << " " << kind << " to "
630             << map.size() << " unique targets" << std::endl;
631
632   std::cout << "indegree: #targets-with-indegree (example)" << std::endl;
633   const int kFirstN = 15;
634   bool someSkipped = false;
635   int index = 0;
636   for (std::map<int, std::vector<RVA> >::reverse_iterator p = h.rbegin();
637        p != h.rend();
638        ++p) {
639     ++index;
640     if (index <= kFirstN || p->first <= 3) {
641       if (someSkipped) {
642         std::cout << "..." << std::endl;
643       }
644       size_t count = p->second.size();
645       std::cout << std::dec << p->first << ": " << count;
646       if (count <= 2) {
647         for (size_t i = 0;  i < count;  ++i)
648           std::cout << "  " << DescribeRVA(p->second[i]);
649       }
650       std::cout << std::endl;
651       someSkipped = false;
652     } else {
653       someSkipped = true;
654     }
655   }
656 }
657 #endif  // COURGETTE_HISTOGRAM_TARGETS
658
659
660 // DescribeRVA is for debugging only.  I would put it under #ifdef DEBUG except
661 // that during development I'm finding I need to call it when compiled in
662 // Release mode.  Hence:
663 // TODO(sra): make this compile only for debug mode.
664 std::string DisassemblerWin32X64::DescribeRVA(RVA rva) const {
665   const Section* section = RVAToSection(rva);
666   std::ostringstream s;
667   s << std::hex << rva;
668   if (section) {
669     s << " (";
670     s << SectionName(section) << "+"
671       << std::hex << (rva - section->virtual_address)
672       << ")";
673   }
674   return s.str();
675 }
676
677 const Section* DisassemblerWin32X64::FindNextSection(uint32 fileOffset) const {
678   const Section* best = 0;
679   for (int i = 0; i < number_of_sections_; i++) {
680     const Section* section = &sections_[i];
681     if (section->size_of_raw_data > 0) {  // i.e. has data in file.
682       if (fileOffset <= section->file_offset_of_raw_data) {
683         if (best == 0 ||
684             section->file_offset_of_raw_data < best->file_offset_of_raw_data) {
685           best = section;
686         }
687       }
688     }
689   }
690   return best;
691 }
692
693 RVA DisassemblerWin32X64::FileOffsetToRVA(uint32 file_offset) const {
694   for (int i = 0; i < number_of_sections_; i++) {
695     const Section* section = &sections_[i];
696     uint32 offset = file_offset - section->file_offset_of_raw_data;
697     if (offset < section->size_of_raw_data) {
698       return section->virtual_address + offset;
699     }
700   }
701   return 0;
702 }
703
704 bool DisassemblerWin32X64::ReadDataDirectory(
705     int index,
706     ImageDataDirectory* directory) {
707
708   if (index < number_of_data_directories_) {
709     size_t offset = index * 8 + offset_of_data_directories_;
710     if (offset >= size_of_optional_header_)
711       return Bad("number of data directories inconsistent");
712     const uint8* data_directory = optional_header_ + offset;
713     if (data_directory < start() ||
714         data_directory + 8 >= end())
715       return Bad("data directory outside image");
716     RVA rva = ReadU32(data_directory, 0);
717     size_t size  = ReadU32(data_directory, 4);
718     if (size > size_of_image_)
719       return Bad("data directory size too big");
720
721     // TODO(sra): validate RVA.
722     directory->address_ = rva;
723     directory->size_ = static_cast<uint32>(size);
724     return true;
725   } else {
726     directory->address_ = 0;
727     directory->size_ = 0;
728     return true;
729   }
730 }
731
732 }  // namespace courgette