# How to Debug Startup Issues in MulleObjC: A Complete Guide

> Debug MulleObjC startup issues effectively. Learn to use debug symbols, mulle-sde, and GDB to trace failures before main() executes. Master MulleObjC debugging with this guide.

- Repository: [mulle-objc/mulleobjc-startup](https://github.com/mulle-objc/mulleobjc-startup)
- Tags: how-to-guide
- Published: 2026-03-07

---

**To debug startup issues in MulleObjC, build with debug symbols and use `mulle-sde debug stacktrace` or GDB to trace failures in `__register_mulle_objc_universe` before `main()` executes.**

When an executable links against the **mulle-objc/mulleobjc-startup** static library, the runtime initializes before your `main()` function ever runs. Any crash, missing symbol, or misconfiguration during this phase occurs inside the startup sequence defined in `src/MulleObjC-startup.m`, making standard debugging techniques ineffective. Understanding how to intercept and diagnose these early failures is essential for troubleshooting MulleObjC startup issues.

## Understanding the MulleObjC Startup Sequence

The startup sequence is a carefully orchestrated chain of events that creates the Objective-C universe before program entry. Debugging startup issues in MulleObjC requires knowing exactly where this process can fail.

### Entry Point and Symbol Registration

When the linker resolves symbols for your executable, it pulls in `__register_mulle_objc_universe` from `src/MulleObjC-startup.m`. This symbol is exported because the source defines `MULLE_OBJC_DEFINE__register_mulle_objc_universe`. The linker automatically calls this constructor function before `main()`, making it the absolute first point of entry for the MulleObjC runtime.

### Universe Creation and Initialization

The `__register_mulle_objc_universe` function includes `MulleObjC/mulle-objc-startup-private.inc` and calls `bang()`, which copies the global default universe configuration via `mulle_objc_global_get_default_universeconfiguration()`. It then passes this configuration to `MulleObjCBang`, which creates the `_mulle_objc_universe`, installs the basic class hierarchy, registers `atexit`/`atinit` handlers, and returns control to the program entry point.

## Common Causes of Startup Failures

Startup crashes in MulleObjC typically stem from three categories of problems:

- **Missing dependencies** – The startup library requires `mulle-atinit` and `mulle-atexit`. If these are not linked, symbol resolution fails before universe creation.
- **Misconfigured universe parameters** – Invalid configuration values passed through `mulle_objc_global_get_default_universeconfiguration()` can cause `MulleObjCBang` to abort.
- **Linker ordering issues** – Static library link order affects constructor execution. If `MulleObjC-startup` appears too late in the link command, initialization may not occur.

## Debugging Techniques for MulleObjC Startup Issues

Because failures occur before `main()`, you must use specialized tools to intercept the startup sequence.

### Building with Debug Symbols

Always build the startup library and your program with debug symbols to get meaningful stack traces. The Debug configuration adds `-g` and disables optimization in `cmake/share/CompilerFlagsObjC.cmake`.

```bash
mulle-sde dependency add mulle-objc/MulleObjC-startup --debug
mulle-sde build --configuration Debug

```

### Using mulle-sde debug stacktrace

The Mulle-SDE tool provides a convenient wrapper that runs your program and automatically prints a backtrace on crash, targeting the exact location in `src/MulleObjC-startup.m` where failure occurs.

```bash
mulle-sde debug stacktrace ./my-executable -- [program-args]

```

For detailed usage, see the built-in guide at [`.mulle/share/howto/debug.md`](https://github.com/mulle-objc/mulleobjc-startup/blob/main/.mulle/share/howto/debug.md).

### Interactive Debugging with GDB

Attach GDB to step through the startup sequence. Set breakpoints on the registration function and the bang routine to inspect universe configuration before creation.

```gdb
gdb ./my-executable
(gdb) break __register_mulle_objc_universe
(gdb) run [program-args]

# When breakpoint hits:

(gdb) step
(gdb) break MulleObjCBang
(gdb) continue
(gdb) bt  # Verify stack shows startup sequence

```

### Enabling Verbose Logging

The runtime respects `MULLE_OBJC_*` environment variables for diagnostic output. Set `MULLE_OBJC_LOGLEVEL` to debug to see the startup sequence progress in `src/MulleObjC-startup.m`.

```bash
export MULLE_OBJC_LOGLEVEL=debug
./my-executable

# Expected output:

# MULLE_OBJC[debug] creating universe "default"

# MULLE_OBJC[debug] installing atinit/atexit handlers

```

### Validating Dependencies

Verify that `mulle-atinit` and `mulle-atexit` are present in your link line. The library's `cmake/share/Environment.cmake` adds these automatically, but manual linker flags may omit them.

```bash

# Check linked libraries

mulle-sde show link-order | grep -E "(atinit|atexit)"

```

## Inspecting the Universe Configuration

If the startup completes but behaves incorrectly, inspect the universe configuration from within a breakpoint or helper function. The `bang()` function in `src/MulleObjC-startup.m` copies the global configuration before passing it to `MulleObjCBang`.

```c
#include <MulleObjC/MulleObjC.h>

void dump_universe_config(void)
{
    struct _mulle_objc_universe *universe = mulle_objc_global_get_universe();
    printf("Universe name: %s\n", universe->name);
    // Additional configuration inspection...
}

```

Call this from a breakpoint inside `bang()` to verify the configuration state before universe creation.

## Summary

- **MulleObjC startup** occurs in `src/MulleObjC-startup.m` via the `__register_mulle_objc_universe` constructor, which runs before `main()`.
- **Debug builds** with symbols are essential; use `mulle-sde build --configuration Debug` to enable them.
- **Stack traces** from crashes can be obtained via `mulle-sde debug stacktrace` or by attaching GDB to `__register_mulle_objc_universe`.
- **Verbose logging** via `MULLE_OBJC_LOGLEVEL=debug` reveals the startup sequence progress.
- **Dependencies** `mulle-atinit` and `mulle-atexit` must be linked correctly, as configured in `cmake/share/Environment.cmake`.

## Frequently Asked Questions

### What is the first function executed in MulleObjC startup?

The first function executed is `__register_mulle_objc_universe`, defined in `src/MulleObjC-startup.m`. This function is marked as a constructor and automatically invoked by the dynamic linker before the program's `main()` function begins execution.

### Why does my MulleObjC program crash before main()?

Crashes before `main()` typically indicate failures in the startup sequence within `src/MulleObjC-startup.m`. Common causes include missing dependencies (`mulle-atinit` or `mulle-atexit`), invalid universe configuration values, or linker ordering issues that prevent `__register_mulle_objc_universe` from executing properly.

### How do I set a breakpoint in MulleObjC startup code?

Use GDB or LLDB to set a breakpoint on the `__register_mulle_objc_universe` symbol. In GDB, run `break __register_mulle_objc_universe` before executing `run`. When the breakpoint hits, you can step into `MulleObjCBang` to trace the universe creation process.

### What dependencies are required for MulleObjC startup?

The startup library requires `mulle-atinit` and `mulle-atexit` to function correctly. These dependencies are automatically linked through the CMake configuration in `cmake/share/Environment.cmake`, but manual build systems must explicitly include them to avoid undefined symbol errors during startup.