崩溃日志包含“二进制图像”部分,其中包含有关架构(armv6/armv7)和所有加载模块的标识符的信息。如何在运行时确定这些信息?(至少,仅适用于应用程序可执行文件)
NSBundle 具有方法 executableArchitectures,但如何确定正在运行哪个架构?
问问题
4875 次
3 回答
19
是时候回答长篇大论了。应用程序中 dyld 图像的 mach 标头包含您要查找的信息。我添加了一个示例,我只测试过它可以工作,所以我不建议将它直接粘贴到生产代码中。它的作用是获取所有当前加载的 dyld 图像的所有 mach 标头,并打印与崩溃日志的二进制图像部分非常相似的输出。我调用的方法不是线程安全的。我缺少的一件事是二进制图像的结束地址,因为我没有费心查找如何找到它。
主程序
#import <UIKit/UIKit.h>
#include <string.h>
#import <mach-o/loader.h>
#import <mach-o/dyld.h>
#import <mach-o/arch.h>
void printImage(const struct mach_header *header)
{
uint8_t *header_ptr = (uint8_t*)header;
typedef struct load_command load_command;
const NXArchInfo *info = NXGetArchInfoFromCpuType(header->cputype, header->cpusubtype);
//Print the architecture ex. armv7
printf("%s ", info->name);
header_ptr += sizeof(struct mach_header);
load_command *command = (load_command*)header_ptr;
for(int i = 0; i < header->ncmds > 0; ++i)
{
if(command->cmd == LC_UUID)
{
struct uuid_command ucmd = *(struct uuid_command*)header_ptr;
CFUUIDRef cuuid = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, *((CFUUIDBytes*)ucmd.uuid));
CFStringRef suuid = CFUUIDCreateString(kCFAllocatorDefault, cuuid);
CFStringEncoding encoding = CFStringGetFastestEncoding(suuid);
//Print UUID
printf("<%s> ", CFStringGetCStringPtr(suuid, encoding));
CFRelease(cuuid);
CFRelease(suuid);
break;
}
header_ptr += command->cmdsize;
command = (load_command*)header_ptr;
}
}
void printBinaryImages()
{
printf("Binary Images:\n");
//Get count of all currently loaded DYLD
uint32_t count = _dyld_image_count();
for(uint32_t i = 0; i < count; i++)
{
//Name of image (includes full path)
const char *dyld = _dyld_get_image_name(i);
//Get name of file
int slength = strlen(dyld);
int j;
for(j = slength - 1; j>= 0; --j)
if(dyld[j] == '/') break;
//strndup only available in iOS 4.3
char *name = strndup(dyld + ++j, slength - j);
printf("%s ", name);
free(name);
const struct mach_header *header = _dyld_get_image_header(i);
//print address range
printf("0x%X - ??? ", (uint32_t)header);
printImage(header);
//print file path
printf("%s\n", dyld);
}
printf("\n");
}
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
printBinaryImages();
[pool release];
return retVal;
}
示例输出:
Binary Images:
TestBed 0x1000 - ??? i386 <E96D079C-E035-389D-AA12-71E968C76BFE> /Users/username/Library/Application Support/iPhone Simulator/4.3/Applications/6F64D9F8-9179-4E21-AE32-4D4604BE77E5/TestBed.app/TestBed
UIKit 0x8000 - ??? i386 <72030911-362F-3E47-BAF3-ACD2CB6F88C0> /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk/System/Library/Frameworks/UIKit.framework/UIKit
Foundation 0x772000 - ??? i386 <EB718CBD-1D57-3D31-898D-7CFA9C172A46> /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk/System/Library/Frameworks/Foundation.framework/Foundation
CoreGraphics 0xA10000 - ??? i386 <D168A716-71F2-337A-AE0B-9DCF51AE9181> /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics
libSystem.dylib 0xCAA000 - ??? i386 <8DF0AFCD-FFA5-3049-88E2-7410F8398749> /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk/usr/lib/libSystem.dylib
...
于 2011-04-08T13:02:14.453 回答
2
由于您正在构建应用程序,因此对于仅关于架构的快速回答,您可以检查一些预处理器定义以确定构建应用程序的当前架构。确保首先检查可用的最高版本的 arm,因为每个新版本都定义了所有旧版本。
#if __arm__
#import <arm/arch.h>
#ifdef __ARM_ARCH_6K__
//This is armv6
#endif //__ARM_ARCH_6K__
#endif //__arm__
于 2011-04-07T14:08:58.303 回答
0
我们可以使用 sysctl、sysctlbyname 系统调用来获取或设置系统信息。
示例代码:
#import <sys/sysctl.h>
#import <mach/machine.h>
int32_t value = 0;
size_t length = sizeof(value);
sysctlbyname("hw.cputype", &value, &length, NULL, 0);
if (value == CPU_TYPE_ARM64) {
// arm64
}
else if (value == CPU_TYPE_ARM) {
// armv7/armv7s
}
else if (value == CPU_TYPE_X86) {
// simulator
}
我只是列出了 2016 年最常见的拱门。寻找“hw.cpusubtype”以获得更多细节,比如CPU_SUBTYPE_ARM_V6
CPU_SUBTYPE_ARM_V7
CPU_SUBTYPE_ARM_V7S
于 2016-04-20T03:45:24.763 回答