Hopper Disassembler

You may have heard of Hex-Rays IDA Pro. You may even have used their demo version, to run into the 32-bit only code restriction. Not only that, the full version is also way too expensive for us hobby developers.

The good news is that we don’t have to use IDA Pro. I myself use the Hopper Disassembler. This is a very nice and affordable tool. Even the demo version supports 64-bit code, and the full version is only $59.99 so that is pie-nuts compared to IDA Pro. And here is an example of why I like it so much:

function X86PlatformShim::start(IOService*)
    r15 = rsi;
    rbx = rdi;
    var_4 = 0x0;
    *(rbx + 0x88) = 0x0;
    *(rbx + 0xd0) = 0x0;
    rax = (*(*0x5058 + 0x5d0))();
    r14 = rax;
    rax = loc_b8c();
    *(rbx + 0x90) = rax;
    if (rax == 0x0) goto loc_ec0;
    goto loc_b98;

    r14 = 0x0;
    loc_ed3(0x0, 0x3, 0x0);

    rax = r14;
    return rax;

    rax = loc_ba2(rbx, 0x0);
    *(rbx + 0x98) = rax;
    if (rax == 0x0) goto loc_bda;
    goto loc_bae;


    loc_bf1(0x0, 0x3, 0x0);

    rax = loc_bfd("CPU_Power_Limits");
    *_gIOPMCPUPowerLimitsKey = rax;
    rax = loc_c10("CPU_Speed_Limit");
    *_gIOPMCPUPowerLimitProcessorSpeedKey = rax;
    rax = loc_c23("CPU_Available_CPUs");
    *_gIOPMCPUPowerLimitProcessorCountKey = rax;
    rax = loc_c36("CPU_Scheduler_Limit");
    *_gIOPMCPUPowerLimitSchedulerTimeKey = rax;
    rax = loc_c49("cpu-plimit-notification");
    *(rbx + 0x108) = rax;
    if (rax == 0x0) goto loc_ec0;
    rax = loc_c65("cpu-idle-plimit-notification");
    *(rbx + 0x110) = rax;
    if (rax == 0x0) goto loc_ec0;
    rax = loc_c81("CPUCStates");
    *(rbx + 0xa0) = rax;
    if (rax == 0x0) goto loc_ec0;
    rax = loc_c9d("CPUOnACPower");
    *(rbx + 0xa8) = rax;
    if (rax == 0x0) goto loc_ec0;
    rax = loc_cbf(r15, **0x5018);
    *(rbx + 0x150) = rax;
    if (rax == 0x0) goto loc_ec0;
    rax = loc_cdd("IOPMrootDomain", 0x0);
    if (rax == 0x0) goto loc_eef;
    goto loc_ce9;

    r14 = 0x0;
    loc_f02(0x0, 0x3, 0x0);
    goto loc_ed3;

    rax = loc_cf8(r15, 0xffffffff);
    rax = loc_d0a(rax, **0x5010);
    *(rbx + 0xc8) = rax;
    (*(*r15 + 0x28))(r15);
    if (*(rbx + 0xc8) == 0x0) goto loc_eb9;
    goto loc_d28;

    goto loc_ec0;

    rax = loc_d36(0xc0045800, &var_4);
    if ((rax == 0x0) && (var_4 == 0x2)) goto loc_d48;
    goto loc_e07;

    *(int32_t *)(rbx + 0xc4) = 0x1;
    rax = loc_d5e("XCPM");
    *(rbx + 0x88) = rax;
    *(rbx + 0x128) = X86PlatformShim::setPStateEntryInfoXCPM(int, int, int);
    *(rbx + 0x130) = X86PlatformShim::sendPStateTableInfoXCPM(int);
    *(rbx + 0x138) = X86PlatformShim::sendPLimitXCPM(int);
    *(rbx + 0x140) = X86PlatformShim::sendIdlePLimitXCPM(int, int);
    *(rbx + 0x148) = X86PlatformShim::sendPStateStepperTableXCPM(IOService*);
    goto loc_ed3;

    *(int32_t *)(rbx + 0xc4) = 0x0;
    *(rbx + 0x128) = X86PlatformShim::setPStateEntryInfoAICPM(int, int, int);
    *(rbx + 0x130) = X86PlatformShim::sendPStateTableInfoAICPM(int);
    *(rbx + 0x138) = X86PlatformShim::sendPLimitAICPM(int);
    *(rbx + 0x140) = X86PlatformShim::sendIdlePLimitAICPM(int, int);
    *(rbx + 0x148) = X86PlatformShim::sendPStateStepperTableAICPM(IOService*);
    rax = loc_e65("AppleIntelCPUPowerManagement", 0x0);
    if (rax == 0x0) goto loc_ee1;
    goto loc_e6d;

    goto loc_eef;

    rax = loc_e8f(**0x5068, r15, X86PlatformShim::aicpmNotification(void*, IOService*, IONotifier*), rbx, 0x0, 0x0);
    *(rbx + 0xd0) = rax;
    (*(*r15 + 0x28))(r15);
    if (*(rbx + 0xd0) != 0x0) goto loc_ed3;
    goto loc_eef;

    rax = (*(**(rbx + 0x90) + 0x140))(*(rbx + 0x90), rax);
    if (rax == 0x0) goto loc_bf1;
    goto loc_be1;

This sort of pseudo code makes finding the stuff that we are interested in easy to locate. Let’s take a look at one particular line in the above code snippet:

if ((rax == 0x0) && (var_4 == 0x2)) goto loc_d48;

This selects the desired power management features. In our case we use XCPM but older (like Sandy Bridge) processors will fall back to using the AppleIntelCPUPowerManagement (kext).

Anyway. Next time you are looking for a disassembler… give Hopper Disassembler a go 😉

6 thoughts on “Hopper Disassembler

      • I think it covers Thin mini-itx AIO boards that have a desktop PCH.

        If they are configured as eDP (as intel suggest they should) then the output doesn’t go to the correct port.

        The only board I have far working so far has the output configured as HDMI. (H61H2-TI).

        You previous post on this seems like the explanation of the symptoms. The display output physically gets dumped down the VGA port instead.

        I expect a few laptops may suffer from this but I haven’t looked at the chipset diagram tbh. I think they still have native LVDS?

      • My point exactly, this eDP problem is going to become a bigger issue going forward.

        I’m guessing it affects modern laptops too?

  1. Having had a look with the hopper demo, I’m not convinced that the capribuffer is using port a, it doesn’t seem to support it. Blurry recordings of the logs suggest that it setup framebuffer 0 to port D pipe 0 and some long fbmem value. But it should be pipe 1 in my case. I think I’m back to square one!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s