Implementing Plausible Crash Recovery

April 2nd, 2014 / Open Source / PLCrashReporter
By: landonf

Yesterday we announced Plausible Crash Recovery, a working crash recovery system built on top of PLCrashReporter. Upon a crash, the recovery implementation steps backwards from the crashing function, restoring non-volatile register state and returning nil to the original caller.

Despite the fact that it was released on April 1st and indeed, was a prank, it does actually work. That doesn’t mean that using it is a good idea, though, and today I figured I’d explain how it works, why you don’t want to use it as-is, and where the underlying technology might actually be applicable.

If you haven’t already checked out the source and played with it yourself, give it a go. You can try plugging in some different crashing bugs of your own, and see how it behaves.

As a fair warning, I’m going to sacrifice some precision in my explanations below for the sake of overall clarity; there are a lot of details and edge cases that must be accounted for when implementing a crash reporter (or in this case, a crash recovery system), and if you’re interested in a digging in further, feel free to stop by and chat with us on the freenode #plcrashreporter IRC channel.

April Fools

I know a number of folks assumed — like many of the other April Fools absurdities — that Plausible Crash Recovery didn’t actually work. Despite the fact that we bolted on a goofy UI, the code works as advertised, as befits a proper hack. The “restoration” UI, despite being totally unnecessary, even shows the actual steps taken to restore thread state; the only exception being the “Reticulating Splines” step – that part I made up.

Disaster Averted

The last time I was privy to a fun April Fools Day prank was back in the 90s, when some co-workers implemented a local man-in-the-middle attack on common stock ticker sites, proxying and adjusting the returned data for our .com to show a precipitious fall (or rise, I don’t recall which). What was fun about the prank wasn’t the actual effect it had on people — as I recall, nobody was seriously fooled, which was probably a good thing for all involved.

Rather, what made my coworker’s prank fun (for me, anyway) was that it was a good hack. It was the kind of wacky technical implementation that you can do when you decide that it’s OK to break the rules and see what neat ideas come of it. It reminded me of the ethos that drove the fabeled MacHack conferences, the source of gems such as Quinn “The Eskimo!”‘s 2002 “Best Hack” winner, Firestarter, which demonstrated that just plugging in a firewire cable was enough to allow DMA writes to the target computer’s video buffer (in this case, displaying flames at the bottom of the screen).

So when it struck me that PLCrashReporter actually had the tooling necessary to implement a bad clone of a bad Visual Basic feature, actually implementing Crash Recovery seemed like a good April 1st hack — in the classic meaning of a hack.

Of course, like most hacks, the fact that it mostly works doesn’t mean you should actually use it.

Rolling Back Time

I often think of PLCrashReporter itself as a “time machine debugger” — it ideally provides a view into the past that can be used to reconstruct the state of the process and debug a long-past failure. Crash Recovery takes this time machine metaphor much further — using PLCrashReporter’s async-safe stack unwinding to step backwards from the crashing function, restoring non-volatile register state and returning nil to the original caller.

To understand how this works, we first need to understand the state that represents a thread of execution, and what parts of it must be rewound to return to the original caller — as well as what can’t be rewound, but really should be.

For a any given process, if you were to pause it at a moment in time — say, when a crash occurs — the crashed function’s execution state would be fully encapsulated in:

  • Global State (including the heap, file descriptors, memory mappings, etc …)
  • Thread Stack
  • CPU Register State

If we want to restart execution in the crashed function’s caller, we need to work backwards from the current process state to restore as much of the caller’s previous state as we can.

Global State

Global state includes (but certainly isn’t limited to) the heap, file descriptors, shared data structures, and even the process’ current working directory. Any part of global state that is changed during execution of the crashing function represents modified state that must be rolled back if we wish to perfectly restore the thread to its pre-crashed state.

Unfortunately, restoring global state is a non-starter — there’s no way for us to know what was changed. For example, if the crashed thread has has corrupted the heap (or it was already corrupt), we can’t restore the heap to a non-corrupted state, and the application will likely just crash again. However, there are plenty of crashes that don’t involve corruption or mutation of global state, in which case we don’t need to restore any global state to allow execution to continue in the caller.

In other words, despite this limitation, we can actually recover from a large number of common crashes despite not having the facility to roll back global state. Of course, the less mutable shared state you use, the more recoverable your crashes are — funny as that might sound in the context of an April Fool’s hack, that’s actually the principal behind “fail fast” semantics often supported in functional programming languages. A failed thread can simply be discarded if there’s no chance it will leave behind partially modfied shared state, and the process state will remain fully consistent.

Thread Stack

The thread’s stack maintains state for each called subroutine via a series of stack frames. At the time of the crash, the current stack frame is represented via the following state:

  • The stack pointer points to the current top of the stack. Any new stack allocations will likewise adjust the stack pointer.
  • The frame pointer usually – depending on the architecture, calling conventions, and emitted code — points to a fixed stack allocation that is at a fixed offset from the caller’s original stack pointer, and is used to store the caller’s return address and original frame pointer.
  • The return address is the address to which the called function should return upon completion. Depending on the architecture and calling conventions, this may be stored in a register (as it is on ARM), or may be stored on the stack via the frame pointer (x86).

To restore the caller’s original stack, as well as to determine the code address at which we should restart execution to simulate a return, we need to derive the caller’s stack pointerframe pointer, and return address from the current thread’s stack state. If we’re able to successfully determine those original values, then we’ll have successfully restored the stack, as well as the execution address.

Of course, if the crashed function smashes any of this data, or the caller’s stack frame, or some other critical data on the stack, we can’t actually recover reliably; should we try, we’ll likely just trigger a secondary crash.

While that’s the basic premise, the actual process of performing the stack unwinding is a bit tricky. On some architectures (including 32-bit iOS and 32-bit Mac OS X), the frame pointer is almost always stored in a fixed register, and can be easily fetched from the crashed thread’s register state. The caller’s original stack state can simply be directly fetched or computed from the frame pointer register.

On other architectures, however, things aren’t so simple. On Mac OS X x86-64, for example, there is no requirement that the frame pointer be saved in a machine register. Instead, additional unwind data is provided by the compiler; this data defines how the caller’s state may be restored from the current thread state: values may be computed from existing registers, existing stack values, as fixed offsets, or through a variety of other mechanisms. This relates to how we restore register state, and we’ll cover how this works in more detail below.

Register State

The crashed thread’s register state represents the processor’s execution state at the time of the crash. During execution, the crashed function may have overwritten some of the caller’s register values; since the crashed function will never have the opportunity to restore those overwritten values, restoring the caller’s state will require that we somehow determine:

  • Which registers are expected by the caller to have been preserved (ie, caller-preserved registers).
  • Which of those registers have been modified and require restoration.
  • How to actually restore the original values for those registers.

To answer the first question, we simply need to look at the platform’s defined calling conventions. For Apple’s platform, these are defined in the iOS ABI Function Call Guide and Mac OS X ABI Function Call Guide. The calling conventions define callee-preserved and caller-preserved registers:

  • Callee-preserved registers (or, non-volatile registers) must be preserved by the called function, if it overwrites the caller’s original register value(s). These are the registers that we must restore, if they’ve been overwritten.
  • Caller-preserved registers (or, volatile registers) must be preserved by the calling function, if it requires later access to those values. These registers may be freely overwritten, and do not need to be restored prior to returning to the caller.

This answers the first question, but we’re left with a connondrum — when execution stops in the middle of a crashing function, how do we know which non-volatile registers have been modified, and how do we know how to restore their original values?

Unfortunately, on Apple’s 32-bit platforms (ARM and i386), the answer is that we don’t. This information is not available, and we simply have to restore the stack state we can and hope that’s enough. Surprisingly, this actually works fairly often. It is, of course, a terrible idea, and one of many good reasons why “crash recovery” ought to be considered a hack, and not an actually useable product.

On Apple’s 64-bit platforms (x86-64 and ARM64), however, this information is provided via the same unwind data that allow us to pop the thread’s stack frame; we can interpret the unwind data at crash time to perform non-volatile register restoration.

Leveraging Unwind Data

Background: Exception Unwinding

We’ve already established that on 32-bit Apple platforms, our ability to unwind the stack is limited due to the lack of unwinding data. The reason for this actually has to do with how exceptions are handled on the platform. On 32-bit Apple systems, when a try/catch/finally block is declared, the current thread’s state is actually saved via setjmp() (or equivalent functionality), and pushed onto a per-thread stack of exception handlers; when it comes time to find an exception handler, the stack is popped until a matching handler is reached, and the equivalent of longjmp() is used to re-load that thread state, resuming execution.

This approach has two downsides; first of all, there’s no way for a debugger or crash reporter to use the exception unwinding information to unwind arbitrary intermediate frames. The only time exception unwinding information is available is when a catch block is executed, and in that case, it’s only possible to restore the specifically saved thread state. Secondly, there is the issue of runtime cost. At each catch or finally statement, the thread state must be saved and pushed onto a stack, even if it’s never used.

The  alternative approach, and what is used on Apple’s 64-bit platforms, is the use of so-called zero-cost exceptions. Rather than recording thread state at runtime, the compiler builds a lookup table that covers all codein an executable. This table defines how to accurately unwind a single frame from any valid instruction address, as well as providing language/runtime-specific definitions of where try/catch/finally blocks are defined, and how to handle them.

As a result, it’s not necessary to do any work at runtime if an exception is not thrown; hence the name “zero-cost exceptions”. If an exception is thrown, the language/exception runtime must consult the lookup table to correctly unwind the stack.

As it turns out, this is exactly the same information that debuggers, crash reporters, and evil crash recovery hacks need to perform their own stack unwinding.

Interpreting the Unwind Data

To correctly unwind a frame in our crash recovery system, we need to actually interpret the unwind data, and extract the rules necessary to calculate, load, or otherwise restore the caller’s original register and stack state.

Conceptually, it helps to think of the unwind data as being stored as two-column table; each row in the table represents an instruction address within the binary (the first column), and (in the second column) are the unwind instructions necessary to restore the caller’s state. To perform the unwind operation, we first need to find the row that represents the instruction at which the crash occured, and then apply any restoration rules defined at that row.

In reality, such a direct encoding of the unwind table would be prohibitively enormous. To solve that, complex encoding schemes are used to minimize duplication and maximize data re-use; on Apple platforms, these are DWARF and Apple’s own Compact Unwind.

DWARF

DWARF is a (mostly) platform architecture-neutral standard for defining debugging information, including unwind data. To add support for a new architecture in PLCrashReporter’s DWARF implementation, it’s generally sufficient to simply add a mapping between DWARF register numbers defined by the platform vendor, and the actual registers they represent; interpreting the format operates entirely in terms of these abstract register numbers.

The encoding is capable of representing almost any possible set of unwind rules; the lookup tables and restoration rules are implemented as an versatile interpreted bytecode, including a turing complete set of DWARF expression opcodes. Amusingly, this aspect of DWARF has been used to implement in-process arbitrary code execution without native code. If you’re curious, you can peruse PLCrashReporter’s DWARF expression interpreter source here.

While enormously useful (and necessary!), the versatility of DWARF comes at the cost of the encoding’s conciseness; this is what Apple set out to address with their non-standard Compact Unwind encoding.

Compact Unwind

Apple’s Compact Unwind encoding is architecture-specific, non-portable, and is unique to Apple. Whereas DWARF can represent almost any set of rules necessary to perform unwinding, Apple took a different approach with the compact unwind encoding — it’s only capable of representing a limited set of unwinding rules, but these rules cover all (or just about all) of the code constructs actually emitted by the compiler. In exchange for these limitations, the compact unwind encoding is, well, compact; it’s much smaller than the corresponding DWARF representation, which means appreciably smaller binaries.

The Compact Unwind encoding can’t represent the full range of unwinding rules that may be required, and as such, it’s used in concert with DWARF. At link time, any DWARF rules that can be represented using the compact unwind encoding will be converted by ld, and the DWARF data will be discarded.

Since the original DWARF data is discarded, this means that correct crash reporting (and, in the case of Crash Recovery, frame unwinding) requires both DWARF and Compact Unwind support. You can find you can find PLCrashReporter’s Compact Unwind implementation (for x86-64 and ARM64) here.

Applying the Unwind Changes

As part of our work to support crash reporting on 64-bit platforms, we already had implemented full DWARF and Compact Unwind support in PLCrashReporter, including the APIs necessary to represent register modifications across stack frames; we implemented this with the eventual goal of including non-volatile register state for all frames in all threads in the crash report.

We had to do very little to implement the Crash Recovery system — it was a simple matter of calling directly into our unwinding APIs from our signal handler, and applying the computed register results to the ucontext_t containing the signal thread state. If you return directly from a signal handler, any changes made to ucontext_t within the signal handler will be applied to the target thread — by modifying the ucontext_t, we’re able to update the stack pointerframe pointer, as well as any non-volatile registers. In addition, by setting the instruction pointer, we actually cause the thread to resume in the crashed function’s caller upon return from the signal handler.

Since it’s just a little bit of glue on top of PLCrashReporter’s existing async-safe APIs, the Crash Recovery code only took about a day to write; if you’d like to take a look, the signal handler additions can be found here.

Returning Nil to the Caller

Having implemented unwinding, the last thing we needed to do was set the return value to nil. I have to admit we cheated a bit here; we ignored floating point and structure return types.

To handle pointer return types (including Objective-C objects), we simply set the return address register to 0x0. This handles most return values, but in the case where structures are returned on the stack, or a special handling is required for floating point, you’ll see unexpected results.

Conclusion

While the Crash Recovery implementation is an interesting technical exploration of what’s possible, it would be a terrible idea to actually use it as a blanket “fix” for crashes, even if it worked absolutely perfectly. The nature of crash is such that the current process state is, by default, undefined; if it was defined, it wouldn’t have crashed. Blindly attempting to proceed can do worse than crash; data corruption and deadlocks are entirely likely.

That doesn’t mean that this avenue of exploration is bereft of value, however. For example, if we extended the PLCrashReporter APIs to directly support the idea of “patch and continue”, we could  support some pretty common operations that currently require custom per-architecture+platform implementations in runtime VMs, such as trapping “optimistic” error handling cases – managed code could use this mechanism to exclude NULL or divide-by-zero checks in generated machine code, instead trapping the signals, verifying that the failure occurs within managed code, and converting the signal into a language-level stack-unwinding NullPointerException or DivideByZero exception.

A more aggressive avenue of exploration is the idea of emergency “hot patches” deployable directly from a crash reporting service. If your shipped application is unexpectedly crashing across your entire user-base with a call to CFRelease(NULL), and you know it’s safe to work around the issue, a crash reporting service could support feeding a PLCrashReporter-based hotpatch to your application, working around the issue until you could actually ship a release.

After all, there’s no upside to having customers being frustrated and continuing to submit crash reports for a known issue.

It’s not clear that we’ll see any of these ideas — or any of the others floating around our heads — in an actual shipping product, but it’s mighty fun to hack something out and see what they might look like.


Introducing Plausible Crash Recovery

April 1st, 2014 / Announcements / Open Source / Plausible Labs
By: landonf

Update: Check out the post-April Fools Follow-up, which delves deeply into the actual implementation of Plausible Crash Recovery, and where this work could actually see practical use.

Sheer performance and deep insight are essential in a crash reporting solution like PLCrashReporter, but our hardcore team is never satisfied by just pushing the envelope — we’re here to destroy it.

Today, I’m extremely pleased to announce the future of iOS and Mac OS crash reporting: Plausible Crash Recovery™.

Plausible Crash Recovery™ works almost by magic, automatically detecting iOS and Mac application crashes, and resuming execution at the next available statement, ensuring that your users never have to deal with a crashed application again. Why just report crashes when you can prevent them?

Crash Recovery is a bit like a time machine, using PLCrashReporter’s best-in-class async-safe stack unwinding to step backwards from the crashing function, restoring non-volatile register state and returning nil to the original caller — think of it like nil messaging on steroids. It truly has to be seen to be believed:

View in HD

Of course, our engineers weren’t satisfied until Plausible Crash Recovery™ handled more fatal signals than any other crash recovery product on the market. NULL dereference? No problem. CFRelease(NULL)? Piece of cake. Sending an Objective-C message to invalid memory? We’ve got you covered.

Developer Preview – Available Today

We could not be happier to get these improvements into the hands of billions of app developers.

If you want to take Plausible Crash Recovery™ for a spin, we’re making it available to early adopters today. Our April 1st preview release contains both the source code to PLCrashReporter with Plausible Crash Recovery™, as well as iOS and Mac OS X demo applications that you can use to test Plausible Crash Recovery™ immediately.

To use PLCrashReporter with Plausible Crash Recovery™ in your own code, simply link against the provided iOS or Mac OS X PLCrashReporter.framework and enable the crash reporter.

Warning: While PLCrashReporter with Plausible Crash Recovery™ does actually work as advertised, it has seen limited testing, and application developers are cautioned to pay close attention to the release date of this announcement prior to shipping PLCrashReporter with Plausible Crash Recovery™ in an actual product.

We also must give credit to Microsoft Visual Basic’s ground-breaking On Error Resume Next, which directly inspired the implementation of PLCrashReporter with Plausible Crash Recovery™.


Crittercism Joins the PLCrashReporter Consortium!

January 22nd, 2014 / Announcements / Open Source
By: landonf

Plausible Labs is extremely pleased to announce that Crittercism has joined the PLCrashReporter Consortium, providing significant support for the ongoing open-source development of PLCrashReporter.

Plausible CrashReporter provides an open source in-process crash reporting framework for use on both the iPhone and Mac OS X, used by first-tier commercial crash reporting services like Crittercism.

Ongoing open source development work is sponsored directly by the members of the PLCrashReporter Consortium, as well as by individual application developers through our application developer support services.

Here at Plausible Labs, we’re big believers in the idea that complex development tools — such as compilers, debuggers, and crash reporters — benefit from being developed openly and under a liberal license, as to allow for wide adoption, peer review, and technical validation of the implementation across the widest possible user base. This development model has made PLCrashReporter one of the most reliable, well-architected, and feature-complete crash reporters available for iOS and Mac OS X.

We’ve laid out an ambitious project roadmap for this new year, starting with a few goals that we believe are imperative to growing PLCrashReporter’s utility and value:

  • Increase the scope and depth of useful data gathered in our crash reports, while maintaining our strict user privacy requirements.
  • Expand the user base of the library to ensure the continued health of the project.
  • Work with implementors of managed runtimes (such as Xamarin, Unity3d, RubyMotion, and RoboVM) to improve compatibility between PLCrashReporter and their managed runtime (some of which already use PLCrashReporter).
  • Maintain our focus on reliability by introducing technical solutions to provide even stronger reliability guarantees as the scope and complexity of the library continues to grow.
  • Improve usage and integration documentation, targeted at both 3rd party integrators, and application developers, to help encourage a healthy development ecosystem.

If your platform or application relies on PLCrashReporter, we’re always interested in hearing about your priorities, and your feedback on our roadmap. The support of existing and new sponsors makes an enormous difference in both the scope and scale of what we can produce, and the sponsorship of companies like Crittercism is imperative to the success of the project.

Tags:


PLCrashReporter 1.2-beta1 (and ARM64 Support!)

September 13th, 2013 / Announcements / Open Source
By: landonf

I’m pleased to announce the first beta release of PLCrashReporter 1.2. Plausible CrashReporter provides an open source in-process crash reporting framework for use on both the iPhone and Mac OS X, and is used by most of the first-tier commercial crash reporting services for Mac OS X and iOS.

This is the first major update to PLCrashReporter’s design since the 1.0 release, and there’s a lot of significant improvements — and we’ve set the stage for some even more significant enhancements for Mac OS X and iOS in the future. The extensive work on this release was funded by Plausible Labs and HockeyApp via the PLCrashReporter Consortium.

New features in this release include:

  • Experimental ARM64 support.
  • Mach-based exception handling on Mac OS X and iOS (configurable).
  • Client-side symbolication using the Mach-O symbol table and Objective-C meta-data (configurable).
  • Enhanced stack unwinding using both DWARF and Apple’s Compact Unwind data when available (i386, and x86-64, ARM64 forthcoming).
  • Support for tracking preserved non-volatile registers across frame walking. Allows for providing non-volatile register state for frames other than the first frame when using compact or DWARF-based unwinding.
  • Back-end support for out-of-process execution.
  • A unique incident identifier is now included in all reports.
  • Reports now include the application’s start time. This can be used to determine (along with the crash report timestamp) if an application is crashing on launch.
  • Build and runtime configuration support for enabling/disabling local symbolication and Mach exception-based reporting.
  • Mac OS X x86-64 is now a fully supported target.

You can download the latest release here, or review the full API Documentation.

More details on a few of the big (and cool) features:

ARM64 Support

We’ve implemented baseline support for ARM64, including all the necessary assembly/architecture code changes. For this initial release — prior to the availability of actual iPhone 5S hardware — we’re providing a separate binary release that includes ARM64 support. This is intended to allow projects that depend on PLCrashReporter to experiment with integrating arm64 into their builds; applications should not be released with PLCrashReporter/ARM64 until the implementation has been validated against actual hardware.

Once we have ARM64 hardware in hand, we’ll validate our implementation via our test suite and fix any issues that likely exist. One of the most exciting changes that we’ll be investigating after the release of the iPhone 5S is support for frame unwinding using the now-available ARM64 compact unwind and DWARF eh_frame data; this will provide the best possible stack traces on iOS, and has not been available for arm32 targets.

Mach Exception Handling

This release supports the use of optional Mach exception handling, rather than a standard POSIX signal handler. The use of Mach exception handling can be configured at runtime, or can easily be excluded/included from the entire build at compile-time.

Mach exceptions differ from POSIX signals in three significant ways:

  • Exception information is delivered as a Mach message via a Mach IPC port, rather than by the kernel calling into a userspace trampoline.
  • Exception handlers may be registered by any process that has the appropriate mach port rights for the target process.
  • Exception handlers may be registered for a specific thread, a specific task (process), or for the entire host. The kernel will search for handlers in that order.

These properties can be useful for a crash reporter; they allow us to operate a reporter entirely out-of-process on platforms where this is supported (eg, Mac OS X), they allow us to create multiple tiers of crash reporting (eg, we can register a per-thread Mach exception handler that detects only crashes that occur in our own crash reporter), and they allow us to catch crashes that leave the currently executing thread in a non-viable state (such as due to a stack overflow, in which case there is no room on the target thread’s stack for the signal handler’s frame).

However, there are also some downsides, which is why Mach exceptions have been such a long time coming to PLCrashReporter, and why they remain optional:

  • On iOS, the APIs required to implement Mach exception handling are not fully public — more details on the implications of this may be found in the API documentation referenced below.
  • A Mach exception handler may conflict with any managed runtime that registers a BSD signal handler that can safely handle otherwise fatal signals, allowing execution to proceed. This includes products such as Xamarin for iOS.
  • Interpretation of particular fault types often requires information that is architecture/kernel specific, and either partially defined or undefined.

In some circles, Mach exception handling has been described as the “holy grail” of crash reporting. I think that’s a bit of a misnomer; I’d be tempted to call them the “holy hand grenade”; they provide some advantages, but can just as easily explode in an implementor’s hand. In the process of implementing this feature, we found (and worked around) two separate kernel bugs that resulted in an in-kernel deadlock caused by in-process use of Mach exceptions. The fact is that Apple treats Mach exceptions as a partially exposed private API, and the only truly supported consumer of Mach exceptions is Apple’s own Crash Reporting implementation.

Our general recommendation is to continue to use POSIX signal handlers on iOS; for further information, refer to PLCrashReporter’s Mach Exceptions on Mac OS X and iOS documentation.
Mach exception handling may be enabled via -[PLCrashReporter initWithConfiguration:].

Client-side Symbolication

While DWARF debugging information is necessary for first-class symbolication, it’s not always available; for example, when running an in-development copy of your code on your phone for which you lost the dSYM by performing a rebuild. Traditionally, the crash report generated by such a case is useless, as you have no reasonable way of matching it up to even symbol names.

To help in these instances, we’ve implemented support for client-side symbolication, which will provide basic symbol information even when the dSYM is long-gone. Our implementation goes quite a bit beyond most other systems, in that in addition to using the Mach-O symbol table (which is often stripped, or in the case of iOS, all symbol names are renamed to <redacted>), Mike Ash implemented async-safe introspection of the runtime Objective-C metadata to fetch class and method names for all symbols implemented in Objective-C. As far as we know, we’re the only crash reporting implementation to do this, and we think it’s pretty neat.

Client-side symbolication may be enabled via -[PLCrashReporter initWithConfiguration:]; since release builds should always have dSYMs, we recommend only enabling client-side symbolication for non-release builds.

Enhanced Stack Unwinding

On x86-64 and i386 (and soon, ARM64!), additional unwinding data is provided in-binary, and may be used to both produce better stack traces, but also to provide the state of non-volatile registers at each stage of the stack frame. To support this, we’ve implemented fully async-safe and portable implementations of DWARF eh_frame stack unwinding, as well as support for Apple’s Compact Frame encoding. This should significantly improve stack traces on Mac OS X, and once we have our hands on the hardware and can add ARM support, ARM64.

In the future, we will also be exposing the enhanced register state for all frames, making it even easier to dig into the state of the process at the time of the crash.


Exploring iOS Crash Reports

April 11th, 2013 / Open Source
By: plausible

Introduction

As developers, when one of our applications crashes, we would like to gather enough information about the crash such that we can reason about its cause and (ideally) fix it. Crash reports generated and provided by tools and services such as iTunes Connect, PLCrashReporter, HockeyApp or others can look a bit daunting at first. We will demystify the important aspects of such reports, so that after reading this article one should be able to use crash report data more effectively.

We are going to be talking mainly about crashes of iOS applications, but some of the concepts can be carried over to crashes on other platforms.

Also, there are some reasons for crashes that are of special interest for iOS developers, such as when a watchdog timeout happens, or when the application is killed due to memory constraints. We are not going to cover those here, because others have already done that.

A First Look

Let us dive right in and consider a full, real-world crash report from a production app. There is a lot of information shown there. We are going to break it up into more easily digestable fragments and discuss those individually.

The Header

At the start of every crash report, you’ll find the basic header:

Incident Identifier: A8111234-3CD8-4FF0-BD99-CFF7FDACB212
CrashReporter Key: A54D28AF-3010-5839-BBA6-FE72C8AFCC2E
Hardware Model: iPod3,1
Process: OurApp [476]
Path: /Users/USER/OurApp.app/OurApp
Identifier: coop.plausible.OurApp
Version: 48
Code Type: ARM
Parent Process: launchd [1]

Date/Time: 2013-03-30T04:42:07Z
OS Version: iPhone OS 5.1.1 (9B206)
Report Version: 104

Most of these fields are self-explanatory, but a few deserve note:

  • Incident Identifier: Client-assigned unique identifier for the report.
  • CrashReporter Key: This is a client-assigned, anonymized, per-device identifier, similar to the UDID. This helps in determining how widespread an issue is.
  • Hardware Model: This is the hardware on which a crash occurred, as available from the “hw.machine” sysctl. This can be useful for reproducing some bugs that are specific to a given phone model, but those cases are rare.
  • Code Type: This is the target processor type. On an iOS device, this will always be ‘ARM’, even if the code is ARMv7 or ARMv7s.
  • OS Version: The OS version on which the crash occurred, including the build number. This can be used to identify regressions that are specific to a given OS release. Note that while different models of iOS devices are assigned unique build numbers (eg, 9B206), crashes are only very rarely specific to a given OS build.
  • Report Version: This opaque value is used by Apple to version the actual format of the report. As the report format is changed, Apple may update this version number. In PLCrashReporter, we generate and store reports in our own structured protobuf-based format, and generate Apple-compatible reports on-demand.

The Stack Trace

On iOS, an application is a single process that typically contains multiple active threads, including the main UI thread, the dispatch manager thread, and other worker threads for things like I/O. Each thread executes code, and a thread’s stack trace shows a list of the function calls the thread took to ultimately end up at its current place. A good crash report contains a stack trace for every thread at the time of crashing, and will also tell us in which thread the crash occurred. We read this from the bottom up, with the topmost entry being the top stack item, i.e. the innermost function that was called. The following shows an example crash on the main thread:

Thread 0 Crashed:
0 libsystem_kernel.dylib 0x3466e32c ___pthread_kill + 8
1 libsystem_c.dylib 0x3526829f abort + 95
2 OurApp 0x0015dfc3 uncaught_exception_handler + 27
3 CoreFoundation 0x3601b957 __handleUncaughtException + 75
4 libobjc.A.dylib 0x30f91345 __objc_terminate + 129
5 libc++abi.dylib 0x34d333c5 __ZL19safe_handler_callerPFvvE + 77
6 libc++abi.dylib 0x34d33451 __ZdlPv + 1
7 libc++abi.dylib 0x34d34825 ___cxa_current_exception_type + 1
8 libobjc.A.dylib 0x30f912a9 _objc_exception_rethrow + 13
9 CoreFoundation 0x35f7150d _CFRunLoopRunSpecific + 405
10 CoreFoundation 0x35f7136d _CFRunLoopRunInMode + 105
11 GraphicsServices 0x31876439 _GSEventRunModal + 137
12 UIKit 0x3192ecd5 _UIApplicationMain + 1081
13 OurApp 0x000938e7 main (main.m:16)

Thread 1:
...

If we eyeball that stack trace, we can easily see that the cause of the crash is an unhandled exception. (If you find yourself getting a lot of these, you might want to set up an Exception Breakpoint in Xcode, which takes you to the function that throws the exception when testing your application during development.)

It is probably safe to say that a crash report’s stack traces are what most programmers first consider, as they are relatively easy to comprehend. Often but not always a stack trace is all that’s required to understand the underlying cause of a crash.

Debug Symbols

It is important to note that at the time an application is built for deployment, the debug symbols (which associate constructs of the programming language with the machine code that the compiler generated from them) will be stripped so as to produce a smaller build product. For iOS applications, it is therefore important to keep a copy of the .dSYM bundle that is generated alongside the binary, as it cannot easily be recovered even if the same set of source files is compiled again. The .dSYM bundle is generated by the dsymutil program, which crafts it from the executable and its intermediate object files (.o, which still contain the DWARF debug information).

Using a binary’s .dSYM, crash reporting services can later map the symbol addresses from the binary to more comprehensible, human-readable symbol names, and even file and line numbers.

Let’s illustrate the difference that symbolication makes using two short examples from stack traces.

// Before symbolication
8 OurApp 0x000029d4 0x1000 + 6612

The first column gives us the index of the stack frame in the stack trace. The second column indicates the name of the binary the function belongs to. The third column tells us the address of the function that was called in the process’ address space. The last column divides this into a base address for the library’s binary image (see section Binary Images) and an offset.

We can see that this is not all that intuitive. Let’s look at the same example after symbolication:

// After symbolication
8 OurApp 0x000029d4 -[OurAppDelegate applicationDidFinishLaunching:] (OurAppDelegate.m:128)

The first three columns are the same. The last column however, contains the actual file name, line number, and function name, which we humans can more easily look up.

The Exception Section

The exception section of a crash report provides us with the exception type, the exception codes, and the index of the thread where the crash occurred:

Exception Type: SIGABRT
Exception Codes: #0 at 0x3466e32c
Crashed Thread: 0

When we talk about ‘exceptions’ in this context, we do not refer to Objective-C exceptions (although those may be reason for a crash), but Mach Exceptions. The example also shows a UNIX signal, SIGABRT, which many UNIX programmers will find familiar. There is a whole ecosystem of APIs built around Mach Exceptions and UNIX signals (e.g. to attach custom signal/exception handlers to given types of UNIX signals/Mach Exceptions), that we’re not going to cover here. If you’re interested, see the Further Reading section below.

The kernel will send such exceptions and signals under a variety of circumstances. For the sake of brevity, we limit our discussion to the most common ones that either lead to process termination or that are otherwise of interest in the face of crash analysis.

Signals

The following is a list of commonly encountered, process-terminating signals and a brief description:

Signal Description
SIGILL Attempted to execute an illegal (malformed, unknown, or privileged) instruction. This may occur if your code jumps to an invalid but executable memory address.
SIGTRAP Mostly used for debugger watchpoints and other debugger features.
SIGABRT Tells the process to abort. It can only be initiated by the process itself using the abort() C stdlib function. Unless you’re using abort() yourself, this is probably most commonly encountered if an assert() or NSAssert() fails.
SIGFPE A floating point or arithmetic exception occurred, such as an attempted division by zero.
SIGBUS A bus error occurred, e.g. when trying to load an unaligned pointer.
SIGSEGV Sent when the kernel determines that the process is trying to access invalid memory, e.g. when an invalid pointer is dereferenced.

A signal has either a default signal handler, or a custom one (if the program set it up using sigaction). As the second argument to the signal handler, a siginfo_t structure is passed that contains further information about the error that occurred. Of special interest is the si_addr field, which indicates the address at which the fault occurred. The following is a quote of a comment from the kernel’s bsd/sys/signal.h file:

When the signal is SIGILL or SIGFPE, si_addr contains the address of the faulting
instruction. When the signal is SIGSEGV or SIGBUS, si_addr contains the address of
the faulting memory reference. Although for x86 there are cases of SIGSEGV for
which si_addr cannot be determined and is NULL.

Exceptions

On Darwin, UNIX signals are built on top of Mach Exceptions, and the kernel performs some mapping between the two. For a more comprehensive list of exception types, see osfmk/mach/exception_types.h. Again, we list only the most important exception types:

Exception Description
EXC_BAD_ACCESS Memory could not be accessed. The memory address where an access attempt was made is provided by the kernel.
EXC_BAD_INSTRUCTION Instruction failed. Illegal or undefined instruction or operand.
EXC_ARITHMETIC For arithmetic errors. The exact nature of the problem is also made available.

It is also possible for an exception to have an associated exception code that contains further information about the problem. For instance, EXC_BAD_ACCESS could point to a KERN_PROTECTION_FAILURE, which would indicate that the address being accessed is valid, but does not permit the required form of access (seeosfmk/mach/kern_return.h). EXC_ARITHMETIC exceptions will also include the precise nature of the problem as part of the exception code.

Example

The example exception section shown above is an excerpt from this crash report. We can see that the reason for the crash is a SIGABRT, which makes us think that this crash might have been caused by a failing assertion. If we inspect the exception code, we can see that the kernel included the address of the instruction in question (0x3466e32c), and the crashed thread’s index. Sure enough, if we search for that address in the report, we’ll find it in both the program counter register (see below), and the crashing thread’s stack trace:

0 libsystem_kernel.dylib 0x3466e32c ___pthread_kill + 8

In this example, we can see that there’s even more to discover in the ‘Application Specific Information’ section, which tells us that a NSInternalInconsistencyException (a Foundation exception) occurred which was not caught and led to a call to abort(), which is ultimately why we saw the SIGABRT signal.

Binary Images

At the end of a crash report, we find a list of the loaded binary images, which in essence tells us which libraries were loaded by the application, and what their address space is within the process. Each entry in this list also shows the UUID for the respective binary, which is generated and set by the linker as part of the build process. It is stored in the Mach-O binary and identified by the LC_UUID command. The UUID is the same for the binary and the .dSYM bundle generated for it, which ensures that there’s no mismatch during symbolication.

For example, we might find the following in the list of binary images:

0x35f62000 - 0x36079fff CoreFoundation armv7 /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation

The first two hexadecimal numbers indicate the beginning and end of the address space that the CoreFoundation image is loaded into. If we consider a line from a stack trace such as the following, we can see that the function that was traced falls into this library’s address space:

9 CoreFoundation 0x35fee2ad ___CFRunLoopRun + 1269

When is this information useful? Imagine that for some reason we desire to analyze the assembly of one of the libraries that our application is using, let’s say CoreFoundation. CoreFoundation is not statically linked (i.e. it’s not part of the application’s own binary), but is dynamically loaded at runtime. When such loading occurs, the library’s binary image ends up at some arbitrary location in the process’ address space.

Let’s now assume that we know the value of the program counter (PC, i.e. the address of the instruction to be executed next) of the process, and that the PC refers to an instruction somewhere in CoreFoundation’s address space, relative to the process. If on our development machine we disassemble a local, on-disk copy of the CoreFoundation binary that the application previously loaded, we’d not be able to map the process-relative PC to the address space of the local copy, given that CoreFoundation was mapped to some arbitrary address. If, however, we know the offset the CoreFoundation binary image was at during the process’ lifetime, we can easily map the process-relative PC to the corresponding value for the on-disk binary.

As an example, if CoreFoundation’s binary image was loaded into our process with an offset of 0x35f62000, and the PC is 0x35fee2ad, then we can compute the actual address of the CoreFoundation instruction as:

0x35fee2ad - 0x35f62000 == 0x8c2ad

In our locally disassembled CoreFoundation binary, we can now inspect the instruction at address 0x8c2ad.

Register State

Further down in the crash report we find the ARM thread state of the crashed thread, which is essentially a list of the CPU registers and their respective values at the time of the crash. The section may look like so:

Thread 0 crashed with ARM Thread State:
r0: 0x00000000 r1: 0x00000000 r2: 0x00000001 r3: 0x00000000
r4: 0x00000006 r5: 0x3f09cd98 r6: 0x00000002 r7: 0x2fe80a70
r8: 0x00000001 r9: 0x00000000 r10: 0x0000000c r11: 0x00000001
ip: 0x00000148 sp: 0x2fe80a64 lr: 0x3526f20f pc: 0x3466e32c
cpsr: 0x00000010

A crashing thread’s register state is not always required to read a crash report, but there are certainly instances where this information can be very useful. For instance, if the crashing instruction tries to access a register that has a value of 0x0, and the thread tries to access memory at that register’s address or with only a small offset the failure cause is extremely likely to be a NULL dereference. That’s because the entire page from 0-4095 is mapped with read/write/execution permissions disabled, i.e. no access is allowed.

In the following section, we’ll give another more elaborate example.

An Example

Let us now consider a contrived example that illustrates why it can be handy to have the register state of a crashing application.

Assume that the crash report tells us the thread that the crash happened in, and that we’ve identified the line in our program that causes the crash. Imagine that the line reads as such:

new_data->ptr2 = [myObject executeSomeMethod:old_data->ptr2];

If we consider the UNIX signal that got sent (SIGSEGV), we can guess that the crash happened due to the application trying to dereference a memory address that for some reason is invalid. In this example, there are two pointers being evidently dereferenced (new_data and old_data). The question then becomes: Which one is responsible for the crash?

Assembly to the Rescue

If we still have a copy of the crashing binary, we can disassemble it and look at the exact instruction that was being executed when the application crashed (the address of which is made available as part of the SIGSEGV‘ssi_addr).

Assume that the application at the time of crashing was executing the following ARM instruction:

str r0, [r1, #4]

There are two registers being used here: r0 and r1. Imagine that r1 points to the address of a C struct with the following declaration:

typedef struct { void *ptr1, void *ptr2 } data_t;

Then, given that pointers on ARM have a width of 4 bytes, we know that r1 plus four refers to the struct memberptr2.

In the form above, the str instruction takes the value stored in register r0 and attempts to store it at the address pointed to by r1, plus four. We could read the assembly like so:

*(r1 + 4) = r0;

That is, we can think of str being the equivalent of a C assignment here.

We now know two things:

  • The application received a SIGSEGV (invalid memory access we already knew this; see above).
  • The crash happened while trying to store a value to some address with an offset of 4.

At this point we should be able to suspect that the pointer value of new_data might not be what we were expecting it to be.

Looking at the ARM thread state (the registers and their respective values), we can confirm this theory:

r1: 0x00000000

In other words, we can now be certain that we are trying to dereference an address (which was computed based on an offset and a NULL pointer) which in all likelihood points to invalid memory. This was ultimately why the application crashed. If this was a real example, the next step would be to look at our code and determine what path the code could have taken such that we ended up on the crashing line with new_data == NULL, and to fix that.

Additional Notes

To drive the point home, dereferencing old_data can’t be the cause of the crash, given that the access to it only involves reading the value, not writing it (i.e. we wouldn’t be seeing a str instruction). That said, one should not be confused when looking at a more complete list of ARM assembly instructions, where one might see an instruction such as

str [r2, #4], r0

This is an example of how the argument is passed to the subroutine (assuming r2 points to a struct of typedata_t). That is, the value of the second struct member is stored in register r0 prior to jumping into the subroutine, which then performs its work.

When the subroutine is about to return (assuming the Apple ARM ABI), the return value of the function is placed in r0 (if it fits there). In the above case, that would be the value returned by the executeSomeMethod: call, which by the time the crashing instruction executes is already stored in r0.

Conclusion

A fair number of crashes are easy to comprehend. For many crashes, however, comprehensive data is required for crash analysis. In those cases, a reliable crash reporting facility is desirable. Since you can’t know in advance when a crash will occur, and because you might not be able to narrow the cause down without a report, it’s advisable to set up a crash reporting solution for your app early during development. Using iTunes Connect does get you crash reports, but you can’t use it before your app is on the App Store, which means it’s not suitable for beta testing.

Using a service such as HockeyApp has the following advantages over iTunes Connect:

  • You can get crash reports even during beta testing, before the app is on the iTunes Store.
  • You can access crash reports easily through a convenient web interface.
  • You can get notified via mail as soon as a crash happens.
  • Crash reports have already been symbolicated for you (assuming proper setup).
  • Users often opt-out of Apple’s data gathering, which means you wouldn’t get any crash reports. This is because Apple asks the user for permission to “improve its products and services by automatically sending daily diagnostics and usage data” once when a device is first used, which is a global setting that doesn’t easily convey the effect of declining the request.

It is therefore a good idea to find a crash reporting solution that works for you as soon as you deploy your application. (In the interest of full disclosure: HockeyApp has been a great sponsor of our open-source work on PLCrashReporter).

We hope that we have succeeded in shedding some light on the more advanced information provided by crash reports. In case you need some expert guidance regarding (our) crash reporting solutions, please note that we’re available for hire.

Further Reading


Plausible Blocks 1.1 Beta

February 8th, 2010 / Announcements / Open Source
By: landonf

Plausible Blocks (PLBlocks) provides a drop-in runtime and toolchain for using blocks in iPhone 2.2+ and Mac OS X 10.5 applications. We’ve started using PLBlocks in shipping iPhone applications, and soon-to-ship Mac OS X applications, and have been working to add support for some key features — the new PLBlocks 1.1-beta2 is the first release to include:

  • Objective-C Garbage Collection Support
  • C/C++ support

We’ve been using the new beta release for our own day-to-day development for a few weeks now, and hope you’ll help us test out some of the new features. The updated SDK is available for Leopard and Snow Leopard from the PLBlocks project page.

If you’d like to read more about using blocks in your own software, we recommend:

iPad Support

We’ve verified that both PLBlocks 1.0 and 1.1-beta2 work with the iPad SDK, and plan on integrating Apple’s beta iPhoneOS compiler updates in a future preview release of PLBlocks for iPad developers.

The new iPad compiler also appears to support the use of blocks on iPhone OS 3.2+; we’ll be very excited to see official block support for the platform. The iPhone OS 3.2 SDK GCC sources can be found at http://opensource.apple.com/tarballs/seeds/.

Tags: , , ,


New Releases: PLBlocks 1.0 and PLCrashReporter 1.0 (and more!)

September 6th, 2009 / Announcements / Open Source
By: landonf

We’ve been working our way through our open source TODO list, and we’ve finished up some new releases of our projects that we’re pleased to announce:

PLBlocks 1.0

Plausible Blocks (PLBlocks) provides a drop-in runtime and toolchain for using blocks in iPhone 2.2+ and Mac OS X 10.5 applications. Both the runtime and compiler patches are direct backports from Apple’s Snow Leopard source releases.

The final 1.0 release includes two fixes for issues reported against the beta release:

  • Fixed support for using pre-compiled headers with blocks.
  • Work-around for rdar://7189835 – Xcode rewrites all occurrence of ‘gcc’ in a
    compiler path when linking using g++

We’re now using PLBlocks 1.0 for our own internal and client projects. The updated SDK is available for Leopard and Snow Leopard from the PLBlocks project page.

If you’d like to read more about using blocks in your own software, we recommend:

PLCrashReporter 1.0

Plausible CrashReporter provides an in-process crash reporting framework for use on both the iPhone and Mac OS X.

  • iPhone 3GS-optimized (armv7) binaries
  • Mac OS X 10.5+ PowerPC and experimental x86-64 support.

The latest release may be downloaded from the PLCrashReporter project page.

Since crash reports are handled internally to your iPhone application, it supports crash reporting for in-development application versions, allows users to provide additional feedback when submitting a report, and even provides the opportunity to inform users of known issues and the need to upgrade.

If you’d like to include PLCrashReporter in your own application, we recommend perusing some of the open-source usage examples:

PLDatabase 1.2.1

Plausible Database is an SQL database access library for Objective-C, initially focused on SQLite as an application database. The library supports both Mac OS X and iPhone development.

The new 1.2.1 release includes:

The latest release may be downloaded from the PLDatabase project page.

PLInstrument 1.0

This is the first release of PLInstrument, a reproducible instrumentation library modeled on xUnit. The library is intended to facilitate the instrumentation of performance critical code, and provide easily comparable results over the lifetime of the code base.

We use PLInstrument to provide reproducible measurements of performance critical sections in our applications and libraries.

The 1.0 release may be downloaded from the PLInstrument project page.

Example Usage

// If for some reason you wanted to measure the runtime of
// CGAffineTransform
- (PLInstrumentResult *) instrumentMirrorTransform {
    PLIAbsoluteTime start, finish;
    int iterations = 25000;

    start = PLICurrentTime();
    for (int i = 0 ; i < iterations; i++) {
        CGAffineTransform mirrorTransform;
        mirrorTransform = CGAffineTransformMakeTranslation(0.0, 200.0f);
        mirrorTransform = CGAffineTransformScale(mirrorTransform, 1.0, -1.0);
    }
    finish = PLICurrentTime();

    return [PLInstrumentResult resultWithStartTime: start
                                           endTime: finish iterations: iterations];
}

Results:

Instrumentation suite 'PLCoreGraphicsDemoInstruments' started at
    2008-12-20 18:51:46 -0800
Instrumentation case -[PLCoreGraphicsDemoInstruments instrumentMirrorTransform]
    completed (0.710000 us/iteration) at 2008-12-20 18:51:46 -0800
Instrumentation suite 'PLCoreGraphicsDemoInstruments' finished at
    2008-12-20 18:51:53 -0800

Tags: , , ,


PLBlocks 1.0-beta2 Released

July 11th, 2009 / Announcements / Open Source
By: landonf

We’ve just released Plausible Blocks 1.0-beta2, which provides a drop-in runtime and Xcode-compatible compiler for using Blocks in your iPhone 2.2+ and Mac OS X 10.5 applications.

Changes

This release was focused on expanding the supported host and target architectures (thanks to everyone who provided testing!).

  • iPhone OS 2.2 and later are now supported.
  • The runtime is now available as an iPhone 3gs optimized armv6/armv7 universal binary.
  • Development is now supported on PowerPC systems.

Download

The initial beta of Plausible Blocks is available for Leopard and Snow Leopard:

This beta release is provided for developer testing and experimentation. Plausible Blocks supports targeting Mac OS X 10.5 (PPC, i386, x86-64), iPhone OS 2.2+ (armv6, armv7), and iPhoneSimulator 2.2+ (i386). Garbage collection and Mac OS X 10.4 are currently unsupported.

Further Reading

If you’re interested in learning more about blocks, here are a few articles to get your started:

Tags: , , ,


Blocks for iPhoneOS 3.0 and Mac OS X 10.5

July 2nd, 2009 / Announcements / Open Source
By: landonf

Introduction

Update Sept 3rd 2009: Check out our more recent posts on PLBlocks.

If you’ve been following the wide variety of developer features planned for Snow Leopard, you may have noticed Apple’s introduction of Blocks, which add closures to C and Objective-C, along with preliminary support for C++.

Blocks are a great addition to Objective-C, but unfortunately, are only available in Mac OS X 10.6. We have a quite a bit of code that could be greatly simplified using blocks, and so I decided to spend some time back-porting block support to iPhoneOS 3.0 and Mac OS X 10.5.

The result, Plausible Blocks, provides a drop-in runtime and Xcode compiler for using blocks in your iPhone and Mac OS X 10.5 applications, based on Apple’s Snow Leopard blocks runtime and compiler support.

Closures are not a new idea — originally conceived nearly 40 years ago, they’re a staple of many languages, from Lisp to JavaScript. If you’ve used a functional language (or a language that borrowed some ideas from one), chances are very good that you’ve made use of closures:

Ruby

books.each { |book| puts (library.to_s + ': ' + book.title) }

JavaScript

function setClickMessage (button, message) {
    button.addEventListener("click", function() {
        /* This is a closure */
        alert(message);
    }, false);
}

Scala

def findBooks (title:String): Seq[Book] = books.filter { book =>
    /* This is a closure */
    book.title == title
}

C and Objective-C Blocks

NSArray *result = [values mapConcurrent: ^(id value) {
    /* Execute closure concurrently on available CPUs, collecting the results */
    return ExpensiveComputation(value);
}];

Closures are well suited to modeling a wide variety of higher-level programming constructs, and in doing so, can greatly simplify your code and enable functionality that would simply be too cumbersome to implement any other way. For some additional information on blocks, and why they’re interesting, I’d suggest reading Mike Ash’s great Friday Q&A on Blocks, and my own Using Blocks post, which includes some sample code to get you started.

Download

The initial beta of Plausible Blocks is available for Leopard and Snow Leopard:

This beta release is provided for developer testing and experimentation, and should not be used for production software prior to further testing and review. Plausible Blocks supports targeting Mac OS X 10.5 (PPC, i386, x86-64), iPhone OS 3.0 (armv6), and iPhoneSimulator 3.0 (i386). Garbage collection and Mac OS X 10.4 are currently unsupported, and the SDK requires an Intel Mac.

The Plausible Blocks runtime makes use of custom, prefixed symbol names to avoid any binary conflicts that could occur should Apple add block support to iPhone OS, or when running your binaries on 10.6. The provided compilers are based directly on the Apple standard, stable compiler versions as shipped with the Mac OS X and iPhone SDKs.

Installation & Use

Plausible Blocks is composed of two pieces:

  • Plausible Blocks SDK: Supplies custom compilers for use in Xcode.
  • PLBlocks Runtime: A runtime library required by all applications making use of Plausible Blocks.

To install the SDK, simply install the included “Plausible Blocks SDK” package. Once installed, an additional “GCC 4.2 (Plausible Blocks)” compiler will be available for selection in your Xcode project and targets. To build with the new compiler, simply select in either your project’s build settings, or on a per-target basis:

In addition to the SDK, you’ll need to include the PLBlocks runtime framework in your application. It is provided as an embeddable framework for Mac OS X, and as a static framework for iPhone applications.

To include in your project:

  1. Copy the Mac OS X or iPhone PLBlocks.framework to your project directory
  2. Within Xcode, select “Add -> Existing frameworks” and add the copied PLBlocks.framework to your project.
  3. Ensure that PLBlocks.framework has been added to your targets “Link Binary With Libraries” section.
  4. (Mac OS X Only) Add a new “Copy Files” build phase to copy PLBlocks.framework to your application’s “Framework” directory.
  5. Set the project, or a specific target, to use the “GCC 4.2 (Plausible Blocks)” compiler.

Development

The full PLBlocks source code is available from the PLBlocks project page. If you’d like to contribute to the SDK, runtime, or simply discuss programming with blocks, please consider joining the development list at: http://groups.google.com/group/plblocks-devel

To build PLBlocks, select one of the following targets:

  • Disk Image: Builds entire project and generates a distribution DMG.
  • Package SDK: Builds SDK package, including all compilers, and Xcode plugins
  • Runtimes: Builds all runtimes

The project should build on Mac OS X 10.5 and 10.6. In addition to Xcode 3.1.3 or 3.2, the iPhone 3.0 SDK is required.

Building the full SDK, including compilers, may take an extraordinarily long time. Unless you are experimenting with the compiler toolchain — or you are the type to enjoy watching paint dry — building only the Runtime targets during development is highly recommended.

Tags: , , ,