Detecting if iOS app is run in debugger - iphone

I set up my application to either send debugging output to console or a log file. Now, I'd like to decide with in the code whether
it is run in the debugger (or simulator) and have thus a console window where I would like to read the output directly or if
there is no console window and thus, the output should be redirected to a file.
Is there a way to determine if the app runs in the debugger?

There's a function from Apple to detect whether a program is being debugged in the Technical Q&A 1361 (entry in Mac library and entry in iOS library; they are identical).
Code from the Technical Q&A:
#include <assert.h>
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sysctl.h>
static bool AmIBeingDebugged(void)
// Returns true if the current process is being debugged (either
// running under the debugger or has a debugger attached post facto).
{
int junk;
int mib[4];
struct kinfo_proc info;
size_t size;
// Initialize the flags so that, if sysctl fails for some bizarre
// reason, we get a predictable result.
info.kp_proc.p_flag = 0;
// Initialize mib, which tells sysctl the info we want, in this case
// we're looking for information about a specific process ID.
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
// Call sysctl.
size = sizeof(info);
junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
assert(junk == 0);
// We're being debugged if the P_TRACED flag is set.
return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
}
Also pay attention to this note at the end of the Q&A:
Important: Because the definition of the kinfo_proc structure (in <sys/sysctl.h>) is conditionalized by __APPLE_API_UNSTABLE, you should restrict use of the above code to the debug build of your program.

It is possible to instruct the debugger to set environment variables when it launches a process it is about to debug. This can be done in Xcode by going to the menu item Product->Edit Scheme. Then under the Debug scheme's Arguments tab add a new environment variable. The variable should be named "debugger" with the value "true". Then the following code snippet can be used to determine if the debugger launched your process:
NSDictionary* env = [NSProcessInfo processInfo].environment;
if ([env[#"debugger"] isEqual:#"true"]) {
NSLog(#"debugger yes");
}
else {
NSLog(#"debugger no");
}

For those who are looking for a simpler solution - this works perfectly:
func isDebuggerAttached() -> Bool {
return getppid() != 1
}

The simplest solution actually is
_isDebugging = isatty(STDERR_FILENO);
It isn't exactly the same as telling whether the app is running under debugger, but good enough (even better?) to determine whether the log should be written to disk.

Based off an answer in a duplicate thread that was for Objective-C as well and showed how HockeyApp-iOS does it, here's a Swift 5 version:
let isDebuggerAttached: Bool = {
var debuggerIsAttached = false
var name: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()]
var info: kinfo_proc = kinfo_proc()
var info_size = MemoryLayout<kinfo_proc>.size
let success = name.withUnsafeMutableBytes { (nameBytePtr: UnsafeMutableRawBufferPointer) -> Bool in
guard let nameBytesBlindMemory = nameBytePtr.bindMemory(to: Int32.self).baseAddress else { return false }
return -1 != sysctl(nameBytesBlindMemory, 4, &info/*UnsafeMutableRawPointer!*/, &info_size/*UnsafeMutablePointer<Int>!*/, nil, 0)
}
// The original HockeyApp code checks for this; you could just as well remove these lines:
if !success {
debuggerIsAttached = false
}
if !debuggerIsAttached && (info.kp_proc.p_flag & P_TRACED) != 0 {
debuggerIsAttached = true
}
return debuggerIsAttached
}()

Always good to have different solutions, so here are my two cents:
The idea is to check the stderr filehandle (this is where NSLog prints to). This solution has reliably been working since at least iOS 4 and keeps doing so in iOS 9, both on the simulator and device.
#import <sys/ioctl.h>
#import <sys/param.h>
#if TARGET_IPHONE_SIMULATOR
#import <sys/conf.h>
#else
// Not sure why <sys/conf.h> is missing on the iPhoneOS.platform.
// It's there on iPhoneSimulator.platform, though. We need it for D_DISK, only:
#if ! defined(D_DISK)
#define D_DISK 2
#endif
#endif
BOOL isDebuggerAttatchedToConsole(void)
{
// We use the type of the stderr file descriptor
// to guess if a debugger is attached.
int fd = STDERR_FILENO;
// is the file handle open?
if (fcntl(fd, F_GETFD, 0) < 0) {
return NO;
}
// get the path of stderr's file handle
char buf[MAXPATHLEN + 1];
if (fcntl(fd, F_GETPATH, buf ) >= 0) {
if (strcmp(buf, "/dev/null") == 0)
return NO;
if (strncmp(buf, "/dev/tty", 8) == 0)
return YES;
}
// On the device, without attached Xcode, the type is D_DISK (otherwise it's D_TTY)
int type;
if (ioctl(fd, FIODTYPE, &type) < 0) {
return NO;
}
return type != D_DISK;
}

I usually go for a much more simple solution; is the binary compiled with optimizations?
A debug build is not optimized, and logs are nice. A release build should have optimizations and not as many logs. You can check for this with the __OPTIMIZE__ symbol.
For logging I use this setup for logg-functions:
#ifdef __OPTIMIZE__
#define CWLog(...)
#define CWLogDebug(...)
#define CWLogInfo(...)
#else
#define CWLog(...) NSLog(__VA_ARGS__)
#define CWLogDebug( s, ... ) NSLog( #"DEBUG <%p %#:(%d)> %#", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#ifndef LOG_INFO
#define CWLogInfo(...)
#else
#define CWLogInfo( s, ... ) NSLog( #"INFO <%p %#:(%d)> %#", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#endif
#endif
#define CWLogWarning( s, ... ) NSLog( #"WARNING <%p %#:(%d)> %#", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#define CWLogError( s, ... ) NSLog( #"ERROR <%p %#:(%d)> %#", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )

Why not using conditional compilation block in Swift?
#if DEBUG
// Do something.
#endif
Any objection?
You can define if you want a runtime constant
#if DEBUG
public let IS_RUNNING_IN_DEBUGGER: Bool = true
#else
public let IS_RUNNING_IN_DEBUGGER: Bool = false
#endif
The same approach can be used in Objc & more.

Related

How to reset HIDIdleTime on macOS 10.14

For the past couple of days I've been trying to write an application that would reset the IORegistry > IOHIDSystem > HIDIdleTime entry. The end goal would be to prevent other applications that read this value from marking the user as idle (it's not only about power management or preventing sleep). Assume that sandboxing is disabled and the application has all necessary permissions (such as accessibility access).
Here are my attempts at doing this (unsuccessful so far):
Attempt 1 - move the mouse cursor to simulate activity:
Variant 1:
let mouseCursorPosition = CGPoint(x: Int.random(in: 0...500), y: Int.random(in: 0...500))
CGWarpMouseCursorPosition(mouseCursorPosition)
Variant 2:
CGDisplayMoveCursorToPoint(CGMainDisplayID(), mouseCursorPosition)
Variant 3 (using CGEvent by itself or together with one of the 2 variants above):
let moveEvent = CGEvent(mouseEventSource: nil, mouseType:
CGEventType.mouseMoved, mouseCursorPosition: mouseCursorPosition,
mouseButton: CGMouseButton.left)
moveEvent?.post(tap: CGEventTapLocation.cghidEventTap)
Variant 4 (using IOHIDSetMouseLocation / IOHIDPostEvent):
func moveCursor() {
let service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOHIDSystem"))
if (service == 0) { return }
var connect:io_connect_t = 0
let result = IOServiceOpen(service, mach_task_self_, UInt32(kIOHIDParamConnectType), &connect)
IOObjectRelease(service)
if (result == kIOReturnSuccess) {
let cursorX = Int16.random(in: 0...100)
let cursorY = Int16.random(in: 0...100)
IOHIDSetMouseLocation(connect, Int32(cursorX), Int32(cursorY))
let cursorLocation:IOGPoint = IOGPoint(x: cursorX, y: cursorY)
var event:NXEventData = NXEventData()
IOHIDPostEvent(connect, UInt32(NX_MOUSEMOVED), cursorLocation, &event, 0, 0, 0)
}
}
NOTE: I've later learned that starting with macOS 10.12, IOHIDPostEvent doesn't reset HIDIdleTime (source: https://github.com/tekezo/Karabiner-Elements/issues/385). Also tried simulating keypresses without success.
Attempt 2 - overwrite the value directly in the IORegistry
func overwriteValue() -> Bool {
var iterator: io_iterator_t = 0
defer { IOObjectRelease(iterator) }
guard IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOHIDSystem"), &iterator) == kIOReturnSuccess else { return false }
let entry: io_registry_entry_t = IOIteratorNext(iterator)
defer { IOObjectRelease(entry) }
guard entry != 0 else { return false }
var value:NSInteger = 0;
var convertedValue:CFNumber = CFNumberCreate(kCFAllocatorDefault, CFNumberType.nsIntegerType, &value);
let result = IORegistryEntrySetCFProperty(entry, "HIDIdleTime" as CFString, convertedValue)
if (result != kIOReturnSuccess) { return false }
return true
}
While this seems to work (the function above returns true), the value is then overwritten by the system, which keeps track of the actual idle time in memory. Got a bit of insight into this from the source code release by Apple for IOHIDSystem here. Currently using this script to easily monitor system idle time and test solutions.
Any suggestions are greatly appreciated. If at all possible, I'm trying to avoid writing my own virtual driver (although I'm open to hooking into an existing one and simulating events if at all possible).
The thing is that the registry property isn't a normal property, but is generated on the fly every time properties are queried (see _idleTimeSerializerCallback in the source).
Long story short, you need to force lastUndimEvent to be reset, which you can do with external method 6 of an IOHIDParamUserClient.
I don't speak Swift, but here is some C code that does precisely that:
// clang -o t t.c -Wall -O3 -framework CoreFoundation -framework IOKit
#include <stdio.h>
#include <stdint.h>
#include <mach/mach.h>
#include <CoreFoundation/CoreFoundation.h>
extern const mach_port_t kIOMasterPortDefault;
typedef mach_port_t io_object_t;
typedef io_object_t io_service_t;
typedef io_object_t io_connect_t;
kern_return_t IOObjectRelease(io_object_t object);
CFMutableDictionaryRef IOServiceMatching(const char *name) CF_RETURNS_RETAINED;
io_service_t IOServiceGetMatchingService(mach_port_t master, CFDictionaryRef matching CF_RELEASES_ARGUMENT);
kern_return_t IOServiceOpen(io_service_t service, task_t task, uint32_t type, io_connect_t *client);
kern_return_t IOServiceClose(io_connect_t client);
kern_return_t IOConnectCallScalarMethod(io_connect_t client, uint32_t selector, const uint64_t *in, uint32_t inCnt, uint64_t *out, uint32_t *outCnt);
const uint32_t kIOHIDParamConnectType = 1;
const uint32_t kIOHIDActivityUserIdle = 3;
const uint32_t kIOHIDActivityReport = 0;
const uint32_t kIOHIDParam_extSetStateForSelector = 6;
#define LOG(str, args...) do { fprintf(stderr, str "\n", ##args); } while(0)
int hid_reset(void)
{
int retval = -1;
kern_return_t ret = 0;
io_service_t service = MACH_PORT_NULL;
io_connect_t client = MACH_PORT_NULL;
service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOHIDSystem"));
LOG("service: %x", service);
if(!MACH_PORT_VALID(service)) goto out;
ret = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &client);
LOG("client: %x, %s", client, mach_error_string(ret));
if(ret != KERN_SUCCESS || !MACH_PORT_VALID(client)) goto out;
uint64_t in[] = { kIOHIDActivityUserIdle, kIOHIDActivityReport };
ret = IOConnectCallScalarMethod(client, kIOHIDParam_extSetStateForSelector, in, 2, NULL, NULL);
LOG("extSetStateForSelector: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS) goto out;
retval = 0;
out:;
if(MACH_PORT_VALID(client)) IOServiceClose(client);
if(MACH_PORT_VALID(service)) IOObjectRelease(service);
return retval;
}
int main(void)
{
return hid_reset();
}
It works for me on High Sierra as non-root, haven't tested it elsewhere. I do run a non-standard system configuration though, so if you get an error saying (iokit/common) not permitted on the external method, it's likely you're hitting mac_iokit_check_hid_control and might need additional entitlements, accessibility clearance, or something like that.
For Wine, we've discovered that we needed to use two different functions to get the full effects we were looking for. One is deprecated, but I could find no non-deprecated replacement. Maybe one of them will be enough for your purposes:
/* This wakes from display sleep, but doesn't affect the screen saver. */
static IOPMAssertionID assertion;
IOPMAssertionDeclareUserActivity(CFSTR("Wine user input"), kIOPMUserActiveLocal, &assertion);
/* This prevents the screen saver, but doesn't wake from display sleep. */
/* It's deprecated, but there's no better alternative. */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
UpdateSystemActivity(UsrActivity);
#pragma clang diagnostic pop

General param error retrieving record format with AudioQueueGetProperty

I am getting a -50 (general param error) from a call to AudioQueueGetProperty. Please help me as it has been several months since I've touched XCode and any iPhone work. This is likely a simple goof on my behalf but I cannot resolve it. My code leading to the -50:
//Setup format
AudioStreamBasicDescription recordFormat;
memset(&recordFormat, 0, sizeof(recordFormat));
recordFormat.mFormatID = kAudioFormatMPEG4AAC;
recordFormat.mChannelsPerFrame = 2;
CCGetDefaultInputDeviceSampleRate(&recordFormat.mSampleRate);
UInt32 propSize = sizeof(recordFormat);
AQ(AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL,
&propSize, &recordFormat),
"AudioFormatGetProperty throws unexpected errors.");
//Setup Queue
//listing 4.8-4.9
AudioQueueRef theQueue = {0};
self->queue = theQueue;
AQ(AudioQueueNewInput(&recordFormat, CCAudioRecordingCallback,
self, NULL, NULL, 0, &self->queue),
"AudioQueueNewInput throws unexpected errors.");
UInt32 size = sizeof(recordFormat);
AQ(AudioQueueGetProperty(self->queue,
kAudioConverterCurrentOutputStreamDescription,
&recordFormat,
&size),
"Getting audio property kAudioConverterCurrentOutputStreamDescription throws unexpected errors.");
I have verified that I have a valid queue just as I make the call to AudioQueueGetProperty. I've tried both ways of passing the queue "self->queue", and "self.queue" and they both result in the same error. The queue is defined as follows:
#interface CCAudioRecorder()
//...
#property (nonatomic, assign) AudioQueueRef queue;
//...
#end
#implementation CCAudioRecorder
#synthesize queue;
AQ is a #def:
#define AQ(expr, msg) if(nil!=CheckError((expr), msg)) [NSException raise:#"AudioException" format:#"Unexpected exception occured."];
Which resolves to the following error checking function:
static NSString* CheckError(OSStatus error, const char* operation)
{
if (noErr == error) return nil;
NSString *errorMessage = nil;
char errorString[20];
//See if it appears to be a 4-char code
*(UInt32 *)(errorString+1) = CFSwapInt32HostToBig(error);
if ( isprint(errorString[1]) && isprint(errorString[2])
&& isprint(errorString[3]) && isprint(errorString[4]) )
{
errorString[0] = errorString[5] = '\'';
errorString[6] = '\0';
} else {
sprintf(errorString, "%d", (int)error);
}
errorMessage = [NSString stringWithFormat:
#"Audio Error: %# (%#)\n",
[NSString stringWithUTF8String:operation],
[NSString stringWithUTF8String:errorString]];
NSLog(#"%#", errorMessage);
return errorMessage;
}
I've also tried calling AudioFormatGetProperty on a queue created with a local variable, avoiding the class instance level iVar and still get the same error:
AudioQueueRef theQueue = {0};
AQ(AudioQueueNewInput(&recordFormat, CCAudioRecordingCallback,
self, NULL, NULL, 0, &theQueue),
"AudioQueueNewInput throws unexpected errors.");
UInt32 size = sizeof(recordFormat);
AQ(AudioQueueGetProperty(theQueue,
kAudioConverterCurrentOutputStreamDescription,
&recordFormat,
&size),
"Getting audio property kAudioConverterCurrentOutputStreamDescription throws unexpected errors.");
** Update **
I have the following code which works on the simulator and not on the device. (I have not cross referenced it with what I posted earlier but I believe it's either similar or the exact.)
AudioQueueRef theQueue = {0};
self->queue = theQueue;
AQ(AudioQueueNewInput(&recordFormat, CCAudioRecordingCallback,
self, NULL, NULL, 0, &self->queue),
"AudioQueueNewInput throws unexpected errors.");
UInt32 size = sizeof(recordFormat);
AQ(AudioQueueGetProperty(self->queue,
kAudioConverterCurrentOutputStreamDescription,
&recordFormat,
&size),
"Getting audio property kAudioConverterCurrentOutputStreamDescription throws unexpected errors.");
Running it on device I get a crash in the same spot with error -50 general param error. My device is an iPhone 4S running iOS6 I'm working with XCode 4.5.
You are following the code from the learning core audio book right? Chapter 4 about implementing a recorder? I noticed a difference between your code and the book's code, in the book they simply initialize the Queue and use it as is:
AudioQueueRef queue = {0};
UInt32 size = sizeof(recordFormat);
CheckError(AudioQueueGetProperty(queue, kAudioConverterCurrentOutputStreamDescription,
&recordFormat, &size), "couldn't get queue's format");
I'm not sure why you're throwing self in the mix. But that's definitely what's causing your bug. If all fails simply download the complete code for that chapter here and see where you can identify your mistake.

How to create UUID type 1 in objective C (iOS)

I created UUID (don't know which type) with the following code:
// Create universally unique identifier (object)
CFUUIDRef uuidObject = CFUUIDCreate(kCFAllocatorDefault);
// Get the string representation of CFUUID object.
NSString *uuidStr = (__bridge NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuidObject);
CFRelease(uuidObject);
But my API that is send data to says that is not type 1 that it needs http://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_.28MAC_address.29.
How to create this type1 UUID in objC (iphone)?
I have problems making this in obj C, is it an option to use C code to generate this?
I've been searching for the same thing. Here it is:
uuid_generate_time
https://developer.apple.com/library/ios/documentation/System/Conceptual/ManPages_iPhoneOS/man3/uuid_generate_time.3.html
Also there's Apple source code for this function:
http://www.opensource.apple.com/source/xnu/xnu-792.13.8/libkern/uuid/uuid.c
NSString* uuidString = nil;
// Get UUID type 1
uuid_t dateUUID;
uuid_generate_time(dateUUID);
// Convert it to string
uuid_string_t unparsedUUID;
uuid_unparse_lower(dateUUID, unparsedUUID);
uuidString = [[NSString alloc] initWithUTF8String:unparsedUUID];
Get the MAC address first: (from developertips)
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
...
- (NSString *)getMacAddress
{
int mgmtInfoBase[6];
char *msgBuffer = NULL;
size_t length;
unsigned char macAddress[6];
struct if_msghdr *interfaceMsgStruct;
struct sockaddr_dl *socketStruct;
NSString *errorFlag = NULL;
// Setup the management Information Base (mib)
mgmtInfoBase[0] = CTL_NET; // Request network subsystem
mgmtInfoBase[1] = AF_ROUTE; // Routing table info
mgmtInfoBase[2] = 0;
mgmtInfoBase[3] = AF_LINK; // Request link layer information
mgmtInfoBase[4] = NET_RT_IFLIST; // Request all configured interfaces
// With all configured interfaces requested, get handle index
if ((mgmtInfoBase[5] = if_nametoindex("en0")) == 0)
errorFlag = #"if_nametoindex failure";
else
{
// Get the size of the data available (store in len)
if (sysctl(mgmtInfoBase, 6, NULL, &length, NULL, 0) < 0)
errorFlag = #"sysctl mgmtInfoBase failure";
else
{
// Alloc memory based on above call
if ((msgBuffer = malloc(length)) == NULL)
errorFlag = #"buffer allocation failure";
else
{
// Get system information, store in buffer
if (sysctl(mgmtInfoBase, 6, msgBuffer, &length, NULL, 0) < 0)
errorFlag = #"sysctl msgBuffer failure";
}
}
}
// Befor going any further...
if (errorFlag != NULL)
{
NSLog(#"Error: %#", errorFlag);
return errorFlag;
}
// Map msgbuffer to interface message structure
interfaceMsgStruct = (struct if_msghdr *) msgBuffer;
// Map to link-level socket structure
socketStruct = (struct sockaddr_dl *) (interfaceMsgStruct + 1);
// Copy link layer address data in socket structure to an array
memcpy(&macAddress, socketStruct->sdl_data + socketStruct->sdl_nlen, 6);
// Read from char array into a string object, into traditional Mac address format
NSString *macAddressString = [NSString stringWithFormat:#"%02X:%02X:%02X:%02X:%02X:%02X",
macAddress[0], macAddress[1], macAddress[2],
macAddress[3], macAddress[4], macAddress[5]];
NSLog(#"Mac Address: %#", macAddressString);
// Release the buffer memory
free(msgBuffer);
return macAddressString;
}
Then generate the UUIDv1 with the rfc4122 spec, if the spec is too long to read, you may port the code from other language, here's one that I found: https://github.com/fredriklindberg/class.uuid.php/blob/master/class.uuid.php
Using following function you can create dynamic UUID.
-(NSString*)getDynamicUUID
{
CFUUIDRef uuidObj = CFUUIDCreate(nil);//create a new UUID
NSString *uuidString = (NSString*)CFUUIDCreateString(nil, uuidObj);
CFRelease(uuidObj);
return uuidString;
}
Hope this helps..

How to determine binary image architecture at runtime?

Crash log contains "Binary Images" section with information about architecture (armv6/armv7) and identifier of all loaded modules. How to determine this information at runtime? (at least, just for application executable)
NSBundle has method executableArchitectures, but how to determine which architecture is running?
Alright time for the long answer. The mach headers of the dyld images in the application contain the information you are looking for. I have added an example that I only tested to work and nothing else so I would not recommend pasting it directly into production code. What it does it get all of the mach headers for all of the currently loaded dyld images and prints an output very similar to the Binary Images section of the crash log. The methods I call are not thread safe. The one thing I am missing is the end address to the binary image because I did not bother looking up how to find that.
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;
}
Example output:
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
...
For a quick answer about architecture alone since you are building your application you can check some preprocessor defines to determine the current architecture that your application is built for. Make sure you check for the highest version of arm available first because each newer version defines all older versions.
#if __arm__
#import <arm/arch.h>
#ifdef __ARM_ARCH_6K__
//This is armv6
#endif //__ARM_ARCH_6K__
#endif //__arm__
We can use sysctl, sysctlbyname system call to get or set system information.
Sample code:
#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
}
I just list most common arch at 2016. Look for "hw.cpusubtype" to get more detial, like CPU_SUBTYPE_ARM_V6 CPU_SUBTYPE_ARM_V7 CPU_SUBTYPE_ARM_V7S

Unit test in xcode : inconsistent build result

Test Case '-[TestParse testParsing]' started.
/Developer/Tools/RunPlatformUnitTests.include: line 415: 3256 Segmentation fault "${THIN_TEST_RIG}" "${OTHER_TEST_FLAGS}" "${TEST_BUNDLE_PATH}"
/Developer/Tools/RunPlatformUnitTests.include:451: error: Test rig '/Developer/Platforms /iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.2.sdk/Developer/usr/bin/otest'
exited abnormally with code 139 (it may have crashed).
I got this seg fault message while I built test case randomly (sometime it built successfully, sometimes it throws seg fault). I'm not sure how I could fix this error.
Only thing I test here is I wrote one class name Parse with class level method. And in test case I just call it like
var = [Parse methodName:filepath];
method is like this
NSMutableDictionary *tempBox = [[NSMutableDictionary alloc] init];
FILE *fd = fopen([filePath UTF8String], "r");
if(!fd){
NSLog(#"fail to open file\n");
}
char buf[4096], *ptr;
char name[512], description[4096];
int isNewInfo = 2, description_continue = 0;
// for (line = 0; line < [args objectAtIndex:1]; line++) {
// fgets(buf, 4096, fd);
// }
while(fgets(buf, sizeof(buf), fd) != NULL){
if(strcmp(buf, "\n") == 0){
isNewInfo -= 1;
if(isNewInfo == 0){
isNewInfo = 2;
description_continue = 0;
description[strlen(description)-1] = '\0';
[self saveDrinkandResetBuf:name
detail:description box:tempBox];
if(name[0] != 0 || description[0] != 0){
NSLog(#"fail to reset...");
}
}
}
if(description_continue){
strcat(description, buf);
continue;
}
if((ptr = strstr(buf, "Drink Name: "))){
memcpy(name, buf+12, strlen(buf));
name[strlen(name)] = '\0';
continue;
}
if((ptr = strstr(buf, "Description: "))){
memcpy(description, buf+13, strlen(buf));
description_continue = 1;
continue;
}
}
fclose(fd);
NSLog(#"finish parsing section\n");
//[tempBox release];
return tempBox;
Not sure what is going on here..
I suppose, the problem is in array management.
In C if the array is declared in a function (and is not declared as a global or static one), then value of its elements is undefined. So your char description[4096] is filled with any values. And nobody said that '\0' will be there.
And the result of strlen(...) for non-null-terminated char string is not defined. It may result in a memory access violation, as it will keep counting until it reaches the first memory byte whose value is 0.
Moreover, when you call description[strlen(description)-1], strlen can return 0 (imagine that the first value, stored there initially was '\0' and your file was started with two empty lines [to reach this line of code]) - so array index will be -1...