/thirdparty/breakpad/common/mac/macho_walker.cc

http://github.com/tomahawk-player/tomahawk · C++ · 267 lines · 182 code · 42 blank · 43 comment · 55 complexity · f725888230b609aeb70cb6fa5fd31836 MD5 · raw file

  1. // Copyright (c) 2006, Google Inc.
  2. // All rights reserved.
  3. //
  4. // Redistribution and use in source and binary forms, with or without
  5. // modification, are permitted provided that the following conditions are
  6. // met:
  7. //
  8. // * Redistributions of source code must retain the above copyright
  9. // notice, this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above
  11. // copyright notice, this list of conditions and the following disclaimer
  12. // in the documentation and/or other materials provided with the
  13. // distribution.
  14. // * Neither the name of Google Inc. nor the names of its
  15. // contributors may be used to endorse or promote products derived from
  16. // this software without specific prior written permission.
  17. //
  18. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. // macho_walker.cc: Iterate over the load commands in a mach-o file
  30. //
  31. // See macho_walker.h for documentation
  32. //
  33. // Author: Dan Waylonis
  34. extern "C" { // necessary for Leopard
  35. #include <assert.h>
  36. #include <fcntl.h>
  37. #include <mach-o/arch.h>
  38. #include <mach-o/loader.h>
  39. #include <mach-o/swap.h>
  40. #include <string.h>
  41. #include <unistd.h>
  42. }
  43. #include "common/mac/byteswap.h"
  44. #include "common/mac/macho_walker.h"
  45. #include "common/mac/macho_utilities.h"
  46. namespace MacFileUtilities {
  47. MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
  48. void *context)
  49. : file_(0),
  50. memory_(NULL),
  51. memory_size_(0),
  52. callback_(callback),
  53. callback_context_(context),
  54. current_header_(NULL),
  55. current_header_size_(0),
  56. current_header_offset_(0) {
  57. file_ = open(path, O_RDONLY);
  58. }
  59. MachoWalker::MachoWalker(void *memory, size_t size,
  60. LoadCommandCallback callback, void *context)
  61. : file_(0),
  62. memory_(memory),
  63. memory_size_(size),
  64. callback_(callback),
  65. callback_context_(context),
  66. current_header_(NULL),
  67. current_header_size_(0),
  68. current_header_offset_(0) {
  69. }
  70. MachoWalker::~MachoWalker() {
  71. if (file_ != -1)
  72. close(file_);
  73. }
  74. int MachoWalker::ValidateCPUType(int cpu_type) {
  75. // If the user didn't specify, use the local architecture.
  76. if (cpu_type == 0) {
  77. const NXArchInfo *arch = NXGetLocalArchInfo();
  78. assert(arch);
  79. cpu_type = arch->cputype;
  80. }
  81. return cpu_type;
  82. }
  83. bool MachoWalker::WalkHeader(int cpu_type) {
  84. int valid_cpu_type = ValidateCPUType(cpu_type);
  85. off_t offset;
  86. if (FindHeader(valid_cpu_type, offset)) {
  87. if (cpu_type & CPU_ARCH_ABI64)
  88. return WalkHeader64AtOffset(offset);
  89. return WalkHeaderAtOffset(offset);
  90. }
  91. return false;
  92. }
  93. bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
  94. if (memory_) {
  95. if (offset < 0)
  96. return false;
  97. bool result = true;
  98. if (offset + size > memory_size_) {
  99. if (static_cast<size_t>(offset) >= memory_size_)
  100. return false;
  101. size = memory_size_ - offset;
  102. result = false;
  103. }
  104. memcpy(buffer, static_cast<char *>(memory_) + offset, size);
  105. return result;
  106. } else {
  107. return pread(file_, buffer, size, offset) == (ssize_t)size;
  108. }
  109. }
  110. bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
  111. if (current_header_) {
  112. memcpy(header, current_header_, sizeof(mach_header_64));
  113. *offset = current_header_offset_;
  114. return true;
  115. }
  116. return false;
  117. }
  118. bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
  119. int valid_cpu_type = ValidateCPUType(cpu_type);
  120. // Read the magic bytes that's common amongst all mach-o files
  121. uint32_t magic;
  122. if (!ReadBytes(&magic, sizeof(magic), 0))
  123. return false;
  124. offset = sizeof(magic);
  125. // Figure out what type of file we've got
  126. bool is_fat = false;
  127. if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
  128. is_fat = true;
  129. }
  130. else if (magic != MH_MAGIC && magic != MH_CIGAM && magic != MH_MAGIC_64 &&
  131. magic != MH_CIGAM_64) {
  132. return false;
  133. }
  134. if (!is_fat) {
  135. // If we don't have a fat header, check if the cpu type matches the single
  136. // header
  137. cpu_type_t header_cpu_type;
  138. if (!ReadBytes(&header_cpu_type, sizeof(header_cpu_type), offset))
  139. return false;
  140. if (magic == MH_CIGAM || magic == MH_CIGAM_64)
  141. header_cpu_type = ByteSwap(header_cpu_type);
  142. if (valid_cpu_type != header_cpu_type)
  143. return false;
  144. offset = 0;
  145. return true;
  146. } else {
  147. // Read the fat header and find an appropriate architecture
  148. offset = 0;
  149. struct fat_header fat;
  150. if (!ReadBytes(&fat, sizeof(fat), offset))
  151. return false;
  152. if (NXHostByteOrder() != NX_BigEndian)
  153. swap_fat_header(&fat, NXHostByteOrder());
  154. offset += sizeof(fat);
  155. // Search each architecture for the desired one
  156. struct fat_arch arch;
  157. for (uint32_t i = 0; i < fat.nfat_arch; ++i) {
  158. if (!ReadBytes(&arch, sizeof(arch), offset))
  159. return false;
  160. if (NXHostByteOrder() != NX_BigEndian)
  161. swap_fat_arch(&arch, 1, NXHostByteOrder());
  162. if (arch.cputype == valid_cpu_type) {
  163. offset = arch.offset;
  164. return true;
  165. }
  166. offset += sizeof(arch);
  167. }
  168. }
  169. return false;
  170. }
  171. bool MachoWalker::WalkHeaderAtOffset(off_t offset) {
  172. struct mach_header header;
  173. if (!ReadBytes(&header, sizeof(header), offset))
  174. return false;
  175. bool swap = (header.magic == MH_CIGAM);
  176. if (swap)
  177. swap_mach_header(&header, NXHostByteOrder());
  178. // Copy the data into the mach_header_64 structure. Since the 32-bit and
  179. // 64-bit only differ in the last field (reserved), this is safe to do.
  180. struct mach_header_64 header64;
  181. memcpy((void *)&header64, (const void *)&header, sizeof(header));
  182. header64.reserved = 0;
  183. current_header_ = &header64;
  184. current_header_size_ = sizeof(header); // 32-bit, not 64-bit
  185. current_header_offset_ = offset;
  186. offset += current_header_size_;
  187. bool result = WalkHeaderCore(offset, header.ncmds, swap);
  188. current_header_ = NULL;
  189. current_header_size_ = 0;
  190. current_header_offset_ = 0;
  191. return result;
  192. }
  193. bool MachoWalker::WalkHeader64AtOffset(off_t offset) {
  194. struct mach_header_64 header;
  195. if (!ReadBytes(&header, sizeof(header), offset))
  196. return false;
  197. bool swap = (header.magic == MH_CIGAM_64);
  198. if (swap)
  199. breakpad_swap_mach_header_64(&header, NXHostByteOrder());
  200. current_header_ = &header;
  201. current_header_size_ = sizeof(header);
  202. current_header_offset_ = offset;
  203. offset += current_header_size_;
  204. bool result = WalkHeaderCore(offset, header.ncmds, swap);
  205. current_header_ = NULL;
  206. current_header_size_ = 0;
  207. current_header_offset_ = 0;
  208. return result;
  209. }
  210. bool MachoWalker::WalkHeaderCore(off_t offset, uint32_t number_of_commands,
  211. bool swap) {
  212. for (uint32_t i = 0; i < number_of_commands; ++i) {
  213. struct load_command cmd;
  214. if (!ReadBytes(&cmd, sizeof(cmd), offset))
  215. return false;
  216. if (swap)
  217. swap_load_command(&cmd, NXHostByteOrder());
  218. // Call the user callback
  219. if (callback_ && !callback_(this, &cmd, offset, swap, callback_context_))
  220. break;
  221. offset += cmd.cmdsize;
  222. }
  223. return true;
  224. }
  225. } // namespace MacFileUtilities