diff options
author | Enrico Granata <granata.enrico@gmail.com> | 2011-07-29 21:31:46 +0000 |
---|---|---|
committer | Enrico Granata <granata.enrico@gmail.com> | 2011-07-29 21:31:46 +0000 |
commit | ebbe5643b245d375131fe7c0963d7ce5d4168e37 (patch) | |
tree | 96b126e1d302ab3cc07515f82c73bb4835ccce63 | |
parent | b081ba651cd0f5048e30ad4e938d9e402abfc142 (diff) | |
download | bcm5719-llvm-ebbe5643b245d375131fe7c0963d7ce5d4168e37.tar.gz bcm5719-llvm-ebbe5643b245d375131fe7c0963d7ce5d4168e37.zip |
new synthetic children provider for CFString and related classes ; test case for it
llvm-svn: 136525
4 files changed, 577 insertions, 3 deletions
diff --git a/lldb/examples/synthetic/CFString.py b/lldb/examples/synthetic/CFString.py new file mode 100644 index 00000000000..bf82c1ddde3 --- /dev/null +++ b/lldb/examples/synthetic/CFString.py @@ -0,0 +1,206 @@ +# synthetic children provider for CFString +# (and related NSString class) +import lldb +class CFStringSynthProvider: + def __init__(self,valobj,dict): + self.valobj = valobj; + self.update() + # children other than "content" are for debugging only and must not be used in production code + def num_children(self): + return 6; + def read_unicode(self, pointer): + process = self.valobj.GetTarget().GetProcess() + error = lldb.SBError() + pystr = u'' + # cannot do the read at once because the length value has + # a weird encoding. better play it safe here + while True: + content = process.ReadMemory(pointer, 2, error) + new_bytes = bytearray(content) + b0 = new_bytes[0] + b1 = new_bytes[1] + pointer = pointer + 2 + if b0 == 0 and b1 == 0: + break + # rearrange bytes depending on endianness + # (do we really need this or is Cocoa going to + # use Windows-compatible little-endian even + # if the target is big endian?) + if self.is_little: + value = b1 * 256 + b0 + else: + value = b0 * 256 + b1 + pystr = pystr + unichr(value) + return pystr + # handle the special case strings + # only use the custom code for the tested LP64 case + def handle_special(self): + if self.lp64 == False: + # for 32bit targets, use safe ObjC code + return self.handle_unicode_string_safe() + offset = 12 + pointer = int(self.valobj.GetValue(), 0) + offset + pystr = self.read_unicode(pointer) + return self.valobj.CreateValueFromExpression("content", + "(char*)\"" + pystr.encode('utf-8') + "\"") + # last resort call, use ObjC code to read; the final aim is to + # be able to strip this call away entirely and only do the read + # ourselves + def handle_unicode_string_safe(self): + return self.valobj.CreateValueFromExpression("content", + "(char*)\"" + self.valobj.GetObjectDescription() + "\""); + def handle_unicode_string(self): + # step 1: find offset + if self.inline: + pointer = int(self.valobj.GetValue(), 0) + self.size_of_cfruntime_base(); + if self.explicit == False: + # untested, use the safe code path + return self.handle_unicode_string_safe(); + else: + # not sure why 8 bytes are skipped here + # (lldb) mem read -c 50 0x00000001001154f0 + # 0x1001154f0: 98 1a 85 71 ff 7f 00 00 90 07 00 00 01 00 00 00 ...q?........... + # 0x100115500: 03 00 00 00 00 00 00 00 *c3 03 78 00 78 00 00 00 ........?.x.x... + # 0x100115510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + # 0x100115520: 00 00 .. + # content begins at * (i.e. 8 bytes into variants, skipping void* buffer in + # __notInlineImmutable1 entirely, while the length byte is correctly located + # for an inline string) + pointer = pointer + 8; + else: + pointer = int(self.valobj.GetValue(), 0) + self.size_of_cfruntime_base(); + # read 8 bytes here and make an address out of them + vopointer = self.valobj.CreateChildAtOffset("dummy", + pointer,self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar).GetPointerType()); + pointer = int(vopointer.GetValue(), 0) + # step 2: read Unicode data at pointer + pystr = self.read_unicode(pointer) + # step 3: return it + return self.valobj.CreateValueFromExpression("content", + "(char*)\"" + pystr.encode('utf-8') + "\"") + # we read at "the right place" into the __CFString object instead of running code + # we are replicating the functionality of __CFStrContents in CFString.c here + def handle_UTF8_inline(self): + offset = int(self.valobj.GetValue(), 0) + self.size_of_cfruntime_base(); + if self.explicit == False: + offset = offset + 1; + return self.valobj.CreateValueFromAddress("content", + offset, self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar)); + def handle_UTF8_not_inline(self): + offset = self.size_of_cfruntime_base(); + return self.valobj.CreateChildAtOffset("content", + offset,self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar).GetPointerType()); + def get_child_at_index(self,index): + if index == 0: + return self.valobj.CreateValueFromExpression("mutable", + str(int(self.mutable))); + if index == 1: + return self.valobj.CreateValueFromExpression("inline", + str(int(self.inline))); + if index == 2: + return self.valobj.CreateValueFromExpression("explicit", + str(int(self.explicit))); + if index == 3: + return self.valobj.CreateValueFromExpression("unicode", + str(int(self.unicode))); + if index == 4: + return self.valobj.CreateValueFromExpression("special", + str(int(self.special))); + if index == 5: + if self.unicode == True: + return self.handle_unicode_string(); + elif self.special == True: + return self.handle_special(); + elif self.inline == True: + return self.handle_UTF8_inline(); + else: + return self.handle_UTF8_not_inline(); + def get_child_index(self,name): + if name == "content": + return self.num_children() - 1; + if name == "mutable": + return 0; + if name == "inline": + return 1; + if name == "explicit": + return 2; + if name == "unicode": + return 3; + if name == "special": + return 4; + def is_64bit(self): + if self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8: + return True; + else: + return False; + def is_little_endian(self): + # 4 is eByteOrderLittle + if self.valobj.GetTarget().GetProcess().GetByteOrder() == 4: + return True; + else: + return False; + # CFRuntimeBase is defined as having an additional + # 4 bytes (padding?) on LP64 architectures + # to get its size we add up sizeof(pointer)+4 + # and then add 4 more bytes if we are on a 64bit system + def size_of_cfruntime_base(self): + if self.lp64 == True: + return 8+4+4; + else: + return 4+4; + # the info bits are part of the CFRuntimeBase structure + # to get at them we have to skip a uintptr_t and then get + # at the least-significant byte of a 4 byte array. If we are + # on big-endian this means going to byte 3, if we are on + # little endian (OSX & iOS), this means reading byte 0 + def offset_of_info_bits(self): + if self.lp64 == True: + offset = 8; + else: + offset = 4; + if self.is_little == False: + offset = offset + 3; + return offset; + def read_info_bits(self): + cfinfo = self.valobj.CreateChildAtOffset("cfinfo", + self.offset_of_info_bits(), + self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar)); + cfinfo.SetFormat(11) + info = cfinfo.GetValue(); + return int(info,0); + # calculating internal flag bits of the CFString object + # this stuff is defined and discussed in CFString.c + def is_mutable(self): + return (self.info_bits & 1) == 1; + def is_inline(self): + return (self.info_bits & 0x60) == 0; + # this flag's name is ambiguous, it turns out + # we must skip a length byte to get at the data + # when this flag is False + def has_explicit_length(self): + return (self.info_bits & (1 | 4)) != 4; + # probably a subclass of NSString. obtained this from [str pathExtension] + # here info_bits = 0 and Unicode data at the start of the padding word + # in the long run using the isa value might be safer as a way to identify this + # instead of reading the info_bits + def is_special_case(self): + return self.info_bits == 0; + def is_unicode(self): + return (self.info_bits & 0x10) == 0x10; + # preparing ourselves to read into memory + # by adjusting architecture-specific info + def adjust_for_architecture(self): + self.lp64 = self.is_64bit(); + self.is_little = self.is_little_endian(); + # reading info bits out of the CFString and computing + # useful values to get at the real data + def compute_flags(self): + self.info_bits = self.read_info_bits(); + self.mutable = self.is_mutable(); + self.inline = self.is_inline(); + self.explicit = self.has_explicit_length(); + self.unicode = self.is_unicode(); + self.special = self.is_special_case(); + def update(self): + self.adjust_for_architecture(); + self.compute_flags(); diff --git a/lldb/test/functionalities/data-formatter/data-formatter-objc/CFString.py b/lldb/test/functionalities/data-formatter/data-formatter-objc/CFString.py new file mode 100644 index 00000000000..bf82c1ddde3 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/data-formatter-objc/CFString.py @@ -0,0 +1,206 @@ +# synthetic children provider for CFString +# (and related NSString class) +import lldb +class CFStringSynthProvider: + def __init__(self,valobj,dict): + self.valobj = valobj; + self.update() + # children other than "content" are for debugging only and must not be used in production code + def num_children(self): + return 6; + def read_unicode(self, pointer): + process = self.valobj.GetTarget().GetProcess() + error = lldb.SBError() + pystr = u'' + # cannot do the read at once because the length value has + # a weird encoding. better play it safe here + while True: + content = process.ReadMemory(pointer, 2, error) + new_bytes = bytearray(content) + b0 = new_bytes[0] + b1 = new_bytes[1] + pointer = pointer + 2 + if b0 == 0 and b1 == 0: + break + # rearrange bytes depending on endianness + # (do we really need this or is Cocoa going to + # use Windows-compatible little-endian even + # if the target is big endian?) + if self.is_little: + value = b1 * 256 + b0 + else: + value = b0 * 256 + b1 + pystr = pystr + unichr(value) + return pystr + # handle the special case strings + # only use the custom code for the tested LP64 case + def handle_special(self): + if self.lp64 == False: + # for 32bit targets, use safe ObjC code + return self.handle_unicode_string_safe() + offset = 12 + pointer = int(self.valobj.GetValue(), 0) + offset + pystr = self.read_unicode(pointer) + return self.valobj.CreateValueFromExpression("content", + "(char*)\"" + pystr.encode('utf-8') + "\"") + # last resort call, use ObjC code to read; the final aim is to + # be able to strip this call away entirely and only do the read + # ourselves + def handle_unicode_string_safe(self): + return self.valobj.CreateValueFromExpression("content", + "(char*)\"" + self.valobj.GetObjectDescription() + "\""); + def handle_unicode_string(self): + # step 1: find offset + if self.inline: + pointer = int(self.valobj.GetValue(), 0) + self.size_of_cfruntime_base(); + if self.explicit == False: + # untested, use the safe code path + return self.handle_unicode_string_safe(); + else: + # not sure why 8 bytes are skipped here + # (lldb) mem read -c 50 0x00000001001154f0 + # 0x1001154f0: 98 1a 85 71 ff 7f 00 00 90 07 00 00 01 00 00 00 ...q?........... + # 0x100115500: 03 00 00 00 00 00 00 00 *c3 03 78 00 78 00 00 00 ........?.x.x... + # 0x100115510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + # 0x100115520: 00 00 .. + # content begins at * (i.e. 8 bytes into variants, skipping void* buffer in + # __notInlineImmutable1 entirely, while the length byte is correctly located + # for an inline string) + pointer = pointer + 8; + else: + pointer = int(self.valobj.GetValue(), 0) + self.size_of_cfruntime_base(); + # read 8 bytes here and make an address out of them + vopointer = self.valobj.CreateChildAtOffset("dummy", + pointer,self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar).GetPointerType()); + pointer = int(vopointer.GetValue(), 0) + # step 2: read Unicode data at pointer + pystr = self.read_unicode(pointer) + # step 3: return it + return self.valobj.CreateValueFromExpression("content", + "(char*)\"" + pystr.encode('utf-8') + "\"") + # we read at "the right place" into the __CFString object instead of running code + # we are replicating the functionality of __CFStrContents in CFString.c here + def handle_UTF8_inline(self): + offset = int(self.valobj.GetValue(), 0) + self.size_of_cfruntime_base(); + if self.explicit == False: + offset = offset + 1; + return self.valobj.CreateValueFromAddress("content", + offset, self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar)); + def handle_UTF8_not_inline(self): + offset = self.size_of_cfruntime_base(); + return self.valobj.CreateChildAtOffset("content", + offset,self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar).GetPointerType()); + def get_child_at_index(self,index): + if index == 0: + return self.valobj.CreateValueFromExpression("mutable", + str(int(self.mutable))); + if index == 1: + return self.valobj.CreateValueFromExpression("inline", + str(int(self.inline))); + if index == 2: + return self.valobj.CreateValueFromExpression("explicit", + str(int(self.explicit))); + if index == 3: + return self.valobj.CreateValueFromExpression("unicode", + str(int(self.unicode))); + if index == 4: + return self.valobj.CreateValueFromExpression("special", + str(int(self.special))); + if index == 5: + if self.unicode == True: + return self.handle_unicode_string(); + elif self.special == True: + return self.handle_special(); + elif self.inline == True: + return self.handle_UTF8_inline(); + else: + return self.handle_UTF8_not_inline(); + def get_child_index(self,name): + if name == "content": + return self.num_children() - 1; + if name == "mutable": + return 0; + if name == "inline": + return 1; + if name == "explicit": + return 2; + if name == "unicode": + return 3; + if name == "special": + return 4; + def is_64bit(self): + if self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8: + return True; + else: + return False; + def is_little_endian(self): + # 4 is eByteOrderLittle + if self.valobj.GetTarget().GetProcess().GetByteOrder() == 4: + return True; + else: + return False; + # CFRuntimeBase is defined as having an additional + # 4 bytes (padding?) on LP64 architectures + # to get its size we add up sizeof(pointer)+4 + # and then add 4 more bytes if we are on a 64bit system + def size_of_cfruntime_base(self): + if self.lp64 == True: + return 8+4+4; + else: + return 4+4; + # the info bits are part of the CFRuntimeBase structure + # to get at them we have to skip a uintptr_t and then get + # at the least-significant byte of a 4 byte array. If we are + # on big-endian this means going to byte 3, if we are on + # little endian (OSX & iOS), this means reading byte 0 + def offset_of_info_bits(self): + if self.lp64 == True: + offset = 8; + else: + offset = 4; + if self.is_little == False: + offset = offset + 3; + return offset; + def read_info_bits(self): + cfinfo = self.valobj.CreateChildAtOffset("cfinfo", + self.offset_of_info_bits(), + self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar)); + cfinfo.SetFormat(11) + info = cfinfo.GetValue(); + return int(info,0); + # calculating internal flag bits of the CFString object + # this stuff is defined and discussed in CFString.c + def is_mutable(self): + return (self.info_bits & 1) == 1; + def is_inline(self): + return (self.info_bits & 0x60) == 0; + # this flag's name is ambiguous, it turns out + # we must skip a length byte to get at the data + # when this flag is False + def has_explicit_length(self): + return (self.info_bits & (1 | 4)) != 4; + # probably a subclass of NSString. obtained this from [str pathExtension] + # here info_bits = 0 and Unicode data at the start of the padding word + # in the long run using the isa value might be safer as a way to identify this + # instead of reading the info_bits + def is_special_case(self): + return self.info_bits == 0; + def is_unicode(self): + return (self.info_bits & 0x10) == 0x10; + # preparing ourselves to read into memory + # by adjusting architecture-specific info + def adjust_for_architecture(self): + self.lp64 = self.is_64bit(); + self.is_little = self.is_little_endian(); + # reading info bits out of the CFString and computing + # useful values to get at the real data + def compute_flags(self): + self.info_bits = self.read_info_bits(); + self.mutable = self.is_mutable(); + self.inline = self.is_inline(); + self.explicit = self.has_explicit_length(); + self.unicode = self.is_unicode(); + self.special = self.is_special_case(); + def update(self): + self.adjust_for_architecture(); + self.compute_flags(); diff --git a/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py b/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py index d6d32c20717..a180c33e6fe 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py @@ -49,6 +49,7 @@ class DataFormatterTestCase(TestBase): def cleanup(): self.runCmd('type format clear', check=False) self.runCmd('type summary clear', check=False) + self.runCmd('type synth clear', check=False) # Execute the cleanup function during test case tear down. self.addTearDownHook(cleanup) @@ -98,6 +99,130 @@ class DataFormatterTestCase(TestBase): self.expect("frame variable *object", substrs = ['a test']); + # Now check that the synth for CFString works + self.runCmd("script from CFString import *") + self.runCmd("type synth add -l CFStringSynthProvider NSString") + + self.expect('frame variable str -P 1', + substrs = ['mutable =', + 'inline = ', + 'explicit = ', + 'content = ', + 'A rather short ASCII NSString object is here']) + + self.expect('frame variable str2 -P 1', + substrs = ['mutable =', + 'inline = ', + 'explicit = ', + 'content = ', + 'A rather short UTF8 NSString object is here']) + + self.expect('frame variable str3 -P 1', + substrs = ['mutable =', + 'inline = ', + 'explicit = ', + 'content = ', + 'A string made with the at sign is here']) + + self.expect('frame variable str4 -P 1', + substrs = ['mutable =', + 'inline = ', + 'explicit = ', + 'content = ', + 'This is string number 4 right here']) + + self.expect('frame variable str5 -P 1', + substrs = ['mutable =', + 'inline = ', + 'explicit = ', + 'content = ', + '{{1, 1}, {5, 5}}']) + + self.expect('frame variable str6 -P 1', + substrs = ['mutable =', + 'inline = ', + 'explicit = ', + 'content = ', + '1ST']) + + self.expect('frame variable str7 -P 1', + substrs = ['mutable =', + 'inline = ', + 'explicit = ', + 'content = ', + '\\xcf\\x83xx']) + + self.expect('frame variable str8 -P 1', + substrs = ['mutable =', + 'inline = ', + 'explicit = ', + 'content = ', + 'hasVeryLongExtensionThisTime']) + + self.expect('frame variable str9 -P 1', + substrs = ['mutable =', + 'inline = ', + 'explicit = ', + 'content = ', + 'a very much boring task to write a string this way!!\\xe4\\x8c\\xb3']) + + self.expect('frame variable str10 -P 1', + substrs = ['mutable =', + 'inline = ', + 'explicit = ', + 'content = ', + 'This is a Unicode string \\xcf\\x83 number 4 right here']) + + self.expect('frame variable str11 -P 1', + substrs = ['mutable =', + 'inline = ', + 'explicit = ', + 'content = ', + '__NSCFString']) + + self.expect('frame variable processName -P 1', + substrs = ['mutable =', + 'inline = ', + 'explicit = ', + 'content = ', + 'a.out']) + + self.expect('frame variable str12 -P 1', + substrs = ['mutable =', + 'inline = ', + 'explicit = ', + 'content = ', + 'Process Name: a.out Process Id:']) + + # make it a summary + self.runCmd("type summary add -f \"${svar.content}\" NSString") + + self.expect('frame variable str', + substrs = ['A rather short ASCII NSString object is here']) + self.expect('frame variable str2', + substrs = ['A rather short UTF8 NSString object is here']) + self.expect('frame variable str3', + substrs = ['A string made with the at sign is here']) + self.expect('frame variable str4', + substrs = ['This is string number 4 right here']) + self.expect('frame variable str5', + substrs = ['{{1, 1}, {5, 5}}']) + self.expect('frame variable str6', + substrs = ['1ST']) + self.expect('frame variable str7', + substrs = ['\\xcf\\x83xx']) + self.expect('frame variable str8', + substrs = ['hasVeryLongExtensionThisTime']) + self.expect('frame variable str9', + substrs = ['a very much boring task to write a string this way!!\\xe4\\x8c\\xb3']) + self.expect('frame variable str10', + substrs = ['This is a Unicode string \\xcf\\x83 number 4 right here']) + self.expect('frame variable str11', + substrs = ['__NSCFString']) + self.expect('frame variable processName', + substrs = ['a.out']) + self.expect('frame variable str12', + substrs = ['Process Name: a.out Process Id:']) if __name__ == '__main__': import atexit diff --git a/lldb/test/functionalities/data-formatter/data-formatter-objc/main.m b/lldb/test/functionalities/data-formatter/data-formatter-objc/main.m index 4a7fe97ed6d..4749749b953 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-objc/main.m +++ b/lldb/test/functionalities/data-formatter/data-formatter-objc/main.m @@ -70,9 +70,6 @@ int main (int argc, const char * argv[]) NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - // insert code here... - NSLog(@"Hello, World!"); - MyClass *object = [[MyClass alloc] initWithInt:1 andFloat:3.14 andChar: 'E']; [object doIncrementByInt:3]; @@ -80,6 +77,46 @@ int main (int argc, const char * argv[]) MyOtherClass *object2 = [[MyOtherClass alloc] initWithInt:2 andFloat:6.28 andChar: 'G' andOtherInt:-1]; [object2 doIncrementByInt:3]; + + NSString *str = [NSString stringWithCString:"A rather short ASCII NSString object is here" encoding:NSASCIIStringEncoding]; + + NSString *str2 = [NSString stringWithUTF8String:"A rather short UTF8 NSString object is here"]; + + NSString *str3 = @"A string made with the at sign is here"; + + NSString *str4 = [NSString stringWithFormat:@"This is string number %ld right here", (long)4]; + + NSRect rect = NSMakeRect(1,1,5,5); + + NSString* str5 = NSStringFromRect(rect); + + NSString* str6 = [@"/usr/doc/README.1ST" pathExtension]; + + const unichar myCharacters[] = {0x03C3,'x','x'}; + NSString *str7 = [NSString stringWithCharacters: myCharacters + length: sizeof myCharacters / sizeof *myCharacters]; + + NSString* str8 = [@"/usr/doc/file.hasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTimehasVeryLongExtensionThisTime" pathExtension]; + + const unichar myOtherCharacters[] = {'a',' ', 'v','e','r','y',' ', + 'm','u','c','h',' ','b','o','r','i','n','g',' ','t','a','s','k', + ' ','t','o',' ','w','r','i','t','e', ' ', 'a', ' ', 's', 't', 'r', 'i', 'n', 'g', ' ', + 't','h','i','s',' ','w','a','y','!','!','0x03C3'}; + NSString *str9 = [NSString stringWithCharacters: myOtherCharacters + length: sizeof myOtherCharacters / sizeof *myOtherCharacters]; + + const unichar myNextCharacters[] = {0x03C3, 0x0000}; + + NSString *str10 = [NSString stringWithFormat:@"This is a Unicode string %S number %ld right here", myNextCharacters, (long)4]; + + NSString *str11 = [str10 className]; + + NSString *label1 = @"Process Name: "; + NSString *label2 = @"Process Id: "; + NSString *processName = [[NSProcessInfo processInfo] processName]; + NSString *processID = [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]]; + NSString *str12 = [NSString stringWithFormat:@"%@ %@ %@ %@", label1, processName, label2, processID]; + // Set break point at this line. [pool drain]; return 0; |