क्रैश लॉग में आर्किटेक्चर (armv6/armv7) और सभी लोड मॉड्यूल के पहचानकर्ता के बारे में जानकारी के साथ "बाइनरी छवियां" अनुभाग शामिल है। रनटाइम पर इस जानकारी को कैसे निर्धारित करें? (कम से कम, केवल आवेदन निष्पादन योग्य के लिए)
एनएसबंडल में विधि निष्पादन योग्य आर्किटेक्चर हैं, लेकिन यह निर्धारित करने के लिए कि कौन सा आर्किटेक्चर चल रहा है?रनटाइम पर बाइनरी छवि आर्किटेक्चर कैसे निर्धारित करें?
उत्तर
लंबे उत्तर के लिए ठीक समय। एप्लिकेशन में डाइल्ड छवियों के मच हेडर में वह जानकारी होती है जिसे आप ढूंढ रहे हैं। मैंने एक उदाहरण जोड़ा है कि मैंने केवल काम करने के लिए परीक्षण किया है और कुछ भी नहीं तो मैं इसे सीधे उत्पादन कोड में पेस्ट करने की अनुशंसा नहीं करता। वर्तमान में लोड की गई सभी छवियों के लिए यह सभी मच हेडर प्राप्त करता है और क्रैश लॉग के बाइनरी छवियों अनुभाग के समान ही आउटपुट प्रिंट करता है। जिन तरीकों को मैं कॉल करता हूं वे थ्रेड सुरक्षित नहीं होते हैं। एक चीज जो मुझे याद आ रही है वह बाइनरी छवि का अंतिम पता है क्योंकि मुझे यह देखने के लिए परेशान नहीं था कि उसे कैसे ढूंढें।
main.m
#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
...
अकेले आर्किटेक्चर के बारे में त्वरित उत्तर के लिए जब आप अपना आवेदन बना रहे हैं तो आप कुछ प्रीप्रोसेसर परिभाषित कर सकते हैं कि वर्तमान एप्लिकेशन को निर्धारित करने के लिए आपका एप्लिकेशन बनाया गया है। सुनिश्चित करें कि आप पहले उपलब्ध शीर्ष के उच्चतम संस्करण की जांच करें क्योंकि प्रत्येक नया संस्करण सभी पुराने संस्करणों को परिभाषित करता है।
#if __arm__
#import <arm/arch.h>
#ifdef __ARM_ARCH_6K__
//This is armv6
#endif //__ARM_ARCH_6K__
#endif //__arm__
हम 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
}
मैं सिर्फ "hw.cpusubtype" के लिए 2016 देखो पर सबसे आम मेहराब सूची अधिक detial प्राप्त करने के लिए, CPU_SUBTYPE_ARM_V6
तरह CPU_SUBTYPE_ARM_V7
CPU_SUBTYPE_ARM_V7S
यह डिवाइस के सीपीयू प्रकार को वापस कर देगा, जब सवाल वास्तुकला के बारे में है, बाइनरी मॉड्यूल के लिए संकलित किया गया था। तो, @ जो का जवाब सही था। – michelnok
जवाब के लिए धन्यवाद! चूंकि मुझे केवल एप्लिकेशन निष्पादन योग्य के लिए सीपीयू आर्किटेक्चर की आवश्यकता है, इसलिए मैंने dladdr (this_function) और फिर Dl_info.dli_fbase को mach_header के लिए पॉइंटर के रूप में उपयोग किया था। – michelnok
@ जो, क्या आपको पता है कि _mh_execute_header (लगभग वैसे ही) से बंडल uuid प्राप्त करना ऐपस्टोर बाइनरी में काम करेगा? यह डेवलपर और विज्ञापन-निर्माण दोनों में काम करता है, लेकिन मैं निश्चित रूप से सुनिश्चित करना चाहता हूं। – Tertium
@ टर्टियम मुझे यकीन नहीं है कि वह कार्य कहां स्थित है लेकिन यदि यह एक निजी ढांचे का हिस्सा है तो इसकी अनुमति नहीं दी जाएगी। – Joe