Support object files larger than 2**32.
Reviewed at https://breakpad.appspot.com/7834002/#ps340001 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1453 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
0f27af628f
commit
aa75fa5d4e
7 changed files with 189 additions and 40 deletions
|
@ -141,6 +141,7 @@
|
||||||
'mac/scoped_task_suspend-inl.h',
|
'mac/scoped_task_suspend-inl.h',
|
||||||
'mac/string_utilities.cc',
|
'mac/string_utilities.cc',
|
||||||
'mac/string_utilities.h',
|
'mac/string_utilities.h',
|
||||||
|
'mac/super_fat_arch.h',
|
||||||
'md5.cc',
|
'md5.cc',
|
||||||
'md5.h',
|
'md5.h',
|
||||||
'memory.h',
|
'memory.h',
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
|
|
||||||
#include "common/byte_cursor.h"
|
#include "common/byte_cursor.h"
|
||||||
#include "common/mac/macho_reader.h"
|
#include "common/mac/macho_reader.h"
|
||||||
|
#include "common/mac/super_fat_arch.h"
|
||||||
#include "common/module.h"
|
#include "common/module.h"
|
||||||
#include "common/symbol_data.h"
|
#include "common/symbol_data.h"
|
||||||
|
|
||||||
|
@ -59,6 +60,7 @@ class DumpSymbols {
|
||||||
input_pathname_(),
|
input_pathname_(),
|
||||||
object_filename_(),
|
object_filename_(),
|
||||||
contents_(),
|
contents_(),
|
||||||
|
object_files_(),
|
||||||
selected_object_file_(),
|
selected_object_file_(),
|
||||||
selected_object_name_() { }
|
selected_object_name_() { }
|
||||||
~DumpSymbols() {
|
~DumpSymbols() {
|
||||||
|
@ -98,14 +100,14 @@ class DumpSymbols {
|
||||||
// architecture matches that of this dumper program.
|
// architecture matches that of this dumper program.
|
||||||
bool SetArchitecture(const std::string &arch_name);
|
bool SetArchitecture(const std::string &arch_name);
|
||||||
|
|
||||||
// Return a pointer to an array of 'struct fat_arch' structures,
|
// Return a pointer to an array of SuperFatArch structures describing the
|
||||||
// describing the object files contained in this dumper's file. Set
|
// object files contained in this dumper's file. Set *|count| to the number
|
||||||
// *|count| to the number of elements in the array. The returned array is
|
// of elements in the array. The returned array is owned by this DumpSymbols
|
||||||
// owned by this DumpSymbols instance.
|
// instance.
|
||||||
//
|
//
|
||||||
// If there are no available architectures, this function
|
// If there are no available architectures, this function
|
||||||
// may return NULL.
|
// may return NULL.
|
||||||
const struct fat_arch *AvailableArchitectures(size_t *count) {
|
const SuperFatArch* AvailableArchitectures(size_t *count) {
|
||||||
*count = object_files_.size();
|
*count = object_files_.size();
|
||||||
if (object_files_.size() > 0)
|
if (object_files_.size() > 0)
|
||||||
return &object_files_[0];
|
return &object_files_[0];
|
||||||
|
@ -127,6 +129,11 @@ class DumpSymbols {
|
||||||
class DumperLineToModule;
|
class DumperLineToModule;
|
||||||
class LoadCommandDumper;
|
class LoadCommandDumper;
|
||||||
|
|
||||||
|
// This method behaves similarly to NXFindBestFatArch, but it supports
|
||||||
|
// SuperFatArch.
|
||||||
|
SuperFatArch* FindBestMatchForArchitecture(
|
||||||
|
cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
|
||||||
|
|
||||||
// Return an identifier string for the file this DumpSymbols is dumping.
|
// Return an identifier string for the file this DumpSymbols is dumping.
|
||||||
std::string Identifier();
|
std::string Identifier();
|
||||||
|
|
||||||
|
@ -167,15 +174,15 @@ class DumpSymbols {
|
||||||
// The complete contents of object_filename_, mapped into memory.
|
// The complete contents of object_filename_, mapped into memory.
|
||||||
NSData *contents_;
|
NSData *contents_;
|
||||||
|
|
||||||
// A vector of fat_arch structures describing the object files
|
// A vector of SuperFatArch structures describing the object files
|
||||||
// object_filename_ contains. If object_filename_ refers to a fat binary,
|
// object_filename_ contains. If object_filename_ refers to a fat binary,
|
||||||
// this may have more than one element; if it refers to a Mach-O file, this
|
// this may have more than one element; if it refers to a Mach-O file, this
|
||||||
// has exactly one element.
|
// has exactly one element.
|
||||||
vector<struct fat_arch> object_files_;
|
vector<SuperFatArch> object_files_;
|
||||||
|
|
||||||
// The object file in object_files_ selected to dump, or NULL if
|
// The object file in object_files_ selected to dump, or NULL if
|
||||||
// SetArchitecture hasn't been called yet.
|
// SetArchitecture hasn't been called yet.
|
||||||
const struct fat_arch *selected_object_file_;
|
const SuperFatArch *selected_object_file_;
|
||||||
|
|
||||||
// A string that identifies the selected object file, for use in error
|
// A string that identifies the selected object file, for use in error
|
||||||
// messages. This is usually object_filename_, but if that refers to a
|
// messages. This is usually object_filename_, but if that refers to a
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
|
|
||||||
#include "common/mac/dump_syms.h"
|
#include "common/mac/dump_syms.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <Foundation/Foundation.h>
|
#include <Foundation/Foundation.h>
|
||||||
#include <mach-o/arch.h>
|
#include <mach-o/arch.h>
|
||||||
#include <mach-o/fat.h>
|
#include <mach-o/fat.h>
|
||||||
|
@ -170,7 +171,7 @@ bool DumpSymbols::Read(NSString *filename) {
|
||||||
|
|
||||||
// Get our own copy of fat_reader's object file list.
|
// Get our own copy of fat_reader's object file list.
|
||||||
size_t object_files_count;
|
size_t object_files_count;
|
||||||
const struct fat_arch *object_files =
|
const SuperFatArch *object_files =
|
||||||
fat_reader.object_files(&object_files_count);
|
fat_reader.object_files(&object_files_count);
|
||||||
if (object_files_count == 0) {
|
if (object_files_count == 0) {
|
||||||
fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
|
fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
|
||||||
|
@ -179,7 +180,7 @@ bool DumpSymbols::Read(NSString *filename) {
|
||||||
}
|
}
|
||||||
object_files_.resize(object_files_count);
|
object_files_.resize(object_files_count);
|
||||||
memcpy(&object_files_[0], object_files,
|
memcpy(&object_files_[0], object_files,
|
||||||
sizeof(struct fat_arch) * object_files_count);
|
sizeof(SuperFatArch) * object_files_count);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -187,9 +188,8 @@ bool DumpSymbols::Read(NSString *filename) {
|
||||||
bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
|
bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
|
||||||
cpu_subtype_t cpu_subtype) {
|
cpu_subtype_t cpu_subtype) {
|
||||||
// Find the best match for the architecture the user requested.
|
// Find the best match for the architecture the user requested.
|
||||||
const struct fat_arch *best_match
|
const SuperFatArch *best_match = FindBestMatchForArchitecture(
|
||||||
= NXFindBestFatArch(cpu_type, cpu_subtype, &object_files_[0],
|
cpu_type, cpu_subtype);
|
||||||
static_cast<uint32_t>(object_files_.size()));
|
|
||||||
if (!best_match) return false;
|
if (!best_match) return false;
|
||||||
|
|
||||||
// Record the selected object file.
|
// Record the selected object file.
|
||||||
|
@ -207,6 +207,56 @@ bool DumpSymbols::SetArchitecture(const std::string &arch_name) {
|
||||||
return arch_set;
|
return arch_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SuperFatArch* DumpSymbols::FindBestMatchForArchitecture(
|
||||||
|
cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
|
||||||
|
// Check if all the object files can be converted to struct fat_arch.
|
||||||
|
bool can_convert_to_fat_arch = true;
|
||||||
|
vector<struct fat_arch> fat_arch_vector;
|
||||||
|
for (vector<SuperFatArch>::const_iterator it = object_files_.begin();
|
||||||
|
it != object_files_.end();
|
||||||
|
++it) {
|
||||||
|
struct fat_arch arch;
|
||||||
|
bool success = it->ConvertToFatArch(&arch);
|
||||||
|
if (!success) {
|
||||||
|
can_convert_to_fat_arch = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fat_arch_vector.push_back(arch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all the object files can be converted to struct fat_arch, use
|
||||||
|
// NXFindBestFatArch.
|
||||||
|
if (can_convert_to_fat_arch) {
|
||||||
|
const struct fat_arch *best_match
|
||||||
|
= NXFindBestFatArch(cpu_type, cpu_subtype, &fat_arch_vector[0],
|
||||||
|
static_cast<uint32_t>(fat_arch_vector.size()));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fat_arch_vector.size(); ++i) {
|
||||||
|
if (best_match == &fat_arch_vector[i])
|
||||||
|
return &object_files_[i];
|
||||||
|
}
|
||||||
|
assert(best_match == NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for an exact match with cpu_type and cpu_subtype.
|
||||||
|
for (vector<SuperFatArch>::iterator it = object_files_.begin();
|
||||||
|
it != object_files_.end();
|
||||||
|
++it) {
|
||||||
|
if (it->cputype == cpu_type && it->cpusubtype == cpu_subtype)
|
||||||
|
return &*it;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No exact match found.
|
||||||
|
// TODO(erikchen): If it becomes necessary, we can copy the implementation of
|
||||||
|
// NXFindBestFatArch, located at
|
||||||
|
// http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c.
|
||||||
|
fprintf(stderr, "Failed to find an exact match for an object file with cpu "
|
||||||
|
"type: %d and cpu subtype: %d. Furthermore, at least one object file is "
|
||||||
|
"larger than 2**32.\n", cpu_type, cpu_subtype);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
string DumpSymbols::Identifier() {
|
string DumpSymbols::Identifier() {
|
||||||
FileID file_id([object_filename_ fileSystemRepresentation]);
|
FileID file_id([object_filename_ fileSystemRepresentation]);
|
||||||
unsigned char identifier_bytes[16];
|
unsigned char identifier_bytes[16];
|
||||||
|
|
|
@ -101,22 +101,26 @@ bool FatReader::Read(const uint8_t *buffer, size_t size) {
|
||||||
// Read the list of object files.
|
// Read the list of object files.
|
||||||
object_files_.resize(object_files_count);
|
object_files_.resize(object_files_count);
|
||||||
for (size_t i = 0; i < object_files_count; i++) {
|
for (size_t i = 0; i < object_files_count; i++) {
|
||||||
struct fat_arch *objfile = &object_files_[i];
|
struct fat_arch objfile;
|
||||||
|
|
||||||
// Read this object file entry, byte-swapping as appropriate.
|
// Read this object file entry, byte-swapping as appropriate.
|
||||||
cursor >> objfile->cputype
|
cursor >> objfile.cputype
|
||||||
>> objfile->cpusubtype
|
>> objfile.cpusubtype
|
||||||
>> objfile->offset
|
>> objfile.offset
|
||||||
>> objfile->size
|
>> objfile.size
|
||||||
>> objfile->align;
|
>> objfile.align;
|
||||||
|
|
||||||
|
SuperFatArch super_fat_arch(objfile);
|
||||||
|
object_files_[i] = super_fat_arch;
|
||||||
|
|
||||||
if (!cursor) {
|
if (!cursor) {
|
||||||
reporter_->TooShort();
|
reporter_->TooShort();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Does the file actually have the bytes this entry refers to?
|
// Does the file actually have the bytes this entry refers to?
|
||||||
size_t fat_size = buffer_.Size();
|
size_t fat_size = buffer_.Size();
|
||||||
if (objfile->offset > fat_size ||
|
if (objfile.offset > fat_size ||
|
||||||
objfile->size > fat_size - objfile->offset) {
|
objfile.size > fat_size - objfile.offset) {
|
||||||
reporter_->MisplacedObjectFile();
|
reporter_->MisplacedObjectFile();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -139,16 +143,14 @@ bool FatReader::Read(const uint8_t *buffer, size_t size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
object_files_[0].offset = 0;
|
object_files_[0].offset = 0;
|
||||||
object_files_[0].size = static_cast<uint32_t>(buffer_.Size());
|
object_files_[0].size = static_cast<uint64_t>(buffer_.Size());
|
||||||
// This alignment is correct for 32 and 64-bit x86 and ppc.
|
// This alignment is correct for 32 and 64-bit x86 and ppc.
|
||||||
// See get_align in the lipo source for other architectures:
|
// See get_align in the lipo source for other architectures:
|
||||||
// http://www.opensource.apple.com/source/cctools/cctools-773/misc/lipo.c
|
// http://www.opensource.apple.com/source/cctools/cctools-773/misc/lipo.c
|
||||||
object_files_[0].align = 12; // 2^12 == 4096
|
object_files_[0].align = 12; // 2^12 == 4096
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reporter_->BadHeader();
|
reporter_->BadHeader();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/byte_cursor.h"
|
#include "common/byte_cursor.h"
|
||||||
|
#include "common/mac/super_fat_arch.h"
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
namespace mach_o {
|
namespace mach_o {
|
||||||
|
@ -111,13 +112,13 @@ class FatReader {
|
||||||
// single object file is the Mach-O file.
|
// single object file is the Mach-O file.
|
||||||
bool Read(const uint8_t *buffer, size_t size);
|
bool Read(const uint8_t *buffer, size_t size);
|
||||||
|
|
||||||
// Return an array of 'struct fat_arch' structures describing the
|
// Return an array of 'SuperFatArch' structures describing the
|
||||||
// object files present in this fat binary file. Set |size| to the
|
// object files present in this fat binary file. Set |size| to the
|
||||||
// number of elements in the array.
|
// number of elements in the array.
|
||||||
//
|
//
|
||||||
// Assuming Read returned true, the entries are validated: it is
|
// Assuming Read returned true, the entries are validated: it is safe to
|
||||||
// safe to assume that the offsets and sizes in each 'struct
|
// assume that the offsets and sizes in each SuperFatArch refer to subranges
|
||||||
// fat_arch' refer to subranges of the bytes passed to Read.
|
// of the bytes passed to Read.
|
||||||
//
|
//
|
||||||
// If there are no object files in this fat binary, then this
|
// If there are no object files in this fat binary, then this
|
||||||
// function can return NULL.
|
// function can return NULL.
|
||||||
|
@ -129,7 +130,7 @@ class FatReader {
|
||||||
// possible to use the result with OS X functions like NXFindBestFatArch,
|
// possible to use the result with OS X functions like NXFindBestFatArch,
|
||||||
// so that the symbol dumper will behave consistently with other OS X
|
// so that the symbol dumper will behave consistently with other OS X
|
||||||
// utilities that work with fat binaries.
|
// utilities that work with fat binaries.
|
||||||
const struct fat_arch *object_files(size_t *count) const {
|
const SuperFatArch* object_files(size_t *count) const {
|
||||||
*count = object_files_.size();
|
*count = object_files_.size();
|
||||||
if (object_files_.size() > 0)
|
if (object_files_.size() > 0)
|
||||||
return &object_files_[0];
|
return &object_files_[0];
|
||||||
|
@ -149,7 +150,7 @@ class FatReader {
|
||||||
|
|
||||||
// The list of object files in this binary.
|
// The list of object files in this binary.
|
||||||
// object_files_.size() == fat_header.nfat_arch
|
// object_files_.size() == fat_header.nfat_arch
|
||||||
vector<struct fat_arch> object_files_;
|
vector<SuperFatArch> object_files_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A segment in a Mach-O file. All these fields have been byte-swapped as
|
// A segment in a Mach-O file. All these fields have been byte-swapped as
|
||||||
|
|
88
src/common/mac/super_fat_arch.h
Normal file
88
src/common/mac/super_fat_arch.h
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
// Copyright (c) 2015, Google Inc.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// Original author: Erik Chen <erikchen@chromium.org>
|
||||||
|
|
||||||
|
// super_fat_arch.h: A class to handle 64-bit object files. Has conversions to
|
||||||
|
// and from struct fat_arch.
|
||||||
|
|
||||||
|
#ifndef BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_
|
||||||
|
#define BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <mach-o/fat.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// Similar to struct fat_arch, except size-related parameters support
|
||||||
|
// 64-bits.
|
||||||
|
class SuperFatArch {
|
||||||
|
public:
|
||||||
|
uint32_t cputype;
|
||||||
|
uint32_t cpusubtype;
|
||||||
|
uint64_t offset;
|
||||||
|
uint64_t size;
|
||||||
|
uint64_t align;
|
||||||
|
|
||||||
|
SuperFatArch() :
|
||||||
|
cputype(0),
|
||||||
|
cpusubtype(0),
|
||||||
|
offset(0),
|
||||||
|
size(0),
|
||||||
|
align(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit SuperFatArch(const struct fat_arch &arch) :
|
||||||
|
cputype(arch.cputype),
|
||||||
|
cpusubtype(arch.cpusubtype),
|
||||||
|
offset(arch.offset),
|
||||||
|
size(arch.size),
|
||||||
|
align(arch.align) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns false if the conversion cannot be made.
|
||||||
|
// If the conversion succeeds, the result is placed in |output_arch|.
|
||||||
|
bool ConvertToFatArch(struct fat_arch* output_arch) const {
|
||||||
|
if (offset > std::numeric_limits<uint32_t>::max())
|
||||||
|
return false;
|
||||||
|
if (size > std::numeric_limits<uint32_t>::max())
|
||||||
|
return false;
|
||||||
|
if (align > std::numeric_limits<uint32_t>::max())
|
||||||
|
return false;
|
||||||
|
struct fat_arch arch;
|
||||||
|
arch.cputype = cputype;
|
||||||
|
arch.cpusubtype = cpusubtype;
|
||||||
|
arch.offset = offset;
|
||||||
|
arch.size = size;
|
||||||
|
arch.align = align;
|
||||||
|
*output_arch = arch;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_
|
|
@ -126,14 +126,14 @@ static bool Start(const Options &options) {
|
||||||
fprintf(stderr, "%s: no architecture '%s' is present in file.\n",
|
fprintf(stderr, "%s: no architecture '%s' is present in file.\n",
|
||||||
[primary_file fileSystemRepresentation], options.arch->name);
|
[primary_file fileSystemRepresentation], options.arch->name);
|
||||||
size_t available_size;
|
size_t available_size;
|
||||||
const struct fat_arch *available =
|
const SuperFatArch *available =
|
||||||
dump_symbols.AvailableArchitectures(&available_size);
|
dump_symbols.AvailableArchitectures(&available_size);
|
||||||
if (available_size == 1)
|
if (available_size == 1)
|
||||||
fprintf(stderr, "the file's architecture is: ");
|
fprintf(stderr, "the file's architecture is: ");
|
||||||
else
|
else
|
||||||
fprintf(stderr, "architectures present in the file are:\n");
|
fprintf(stderr, "architectures present in the file are:\n");
|
||||||
for (size_t i = 0; i < available_size; i++) {
|
for (size_t i = 0; i < available_size; i++) {
|
||||||
const struct fat_arch *arch = &available[i];
|
const SuperFatArch *arch = &available[i];
|
||||||
const NXArchInfo *arch_info =
|
const NXArchInfo *arch_info =
|
||||||
google_breakpad::BreakpadGetArchInfoFromCpuType(
|
google_breakpad::BreakpadGetArchInfoFromCpuType(
|
||||||
arch->cputype, arch->cpusubtype);
|
arch->cputype, arch->cpusubtype);
|
||||||
|
|
Loading…
Reference in a new issue