Debugging Cortex M0 (error: Bad CPU type in executable)

Forgive my lack of experience here. I’m trying to debug a Cortex M0 MCU (Atmel SAMD21), and I’m not sure how to get lldb to start.

I’ve got an OpenOCD debugger that I can flash from an ELF file. For now that was built with gcc from the Arduino IDE. I’ve successfully flashed these in the past using OpenOCD.

Now I’m trying to use OpenOCD as a debug server, and lldb as the client. I’ve done the following:

(lldb) history
   0: file /var/folders/16/jfb809_s2fz01ql7k494f6pc0000gn/T/arduino_build_98039/Blink.ino.elf
   1: platform select remote-gdb-server
   2: platform connect connect://localhost:3333

But when I try process launch, I get

(lldb) process launch
error: Bad CPU type in executable

What’s the right way to debug a target like this?

This is with a recent build of lldb installed via Machomebrew.

On the microcontroller targets I’ve seen you have some out of band way to kick things off (e.g. serial connection to a bootloader), and then use lldb process connect (usually via the gdb-remote alias) to interface once it’s in a suitable state.

I suspect the process launch is trying to run an ARMv6M binary on the host machine. Generally it seems far too concerned about properly-hosted OS features (env, stdin/out, argv) to be what you want.

I’ve already got the “process” running. For example, I used the Arduino IDE to build the blinking LED example, and flashed that onto the board. The LED blinks.

I then connect with:

$ lldb /var/folders/16/jfb809_s2fz01ql7k494f6pc0000gn/T/arduino_build_98039/Blink.ino.elf
$ lldb /var/folders/16/jfb809_s2fz01ql7k494f6pc0000gn/T/arduino_build_98039/Blink.ino.elf
(lldb) target create "/var/folders/16/jfb809_s2fz01ql7k494f6pc0000gn/T/arduino_build_98039/Blink.ino.elf"
Current executable set to '/var/folders/16/jfb809_s2fz01ql7k494f6pc0000gn/T/arduino_build_98039/Blink.ino.elf' (arm).
(lldb) target list
Current targets:
* target #0: /var/folders/16/jfb809_s2fz01ql7k494f6pc0000gn/T/arduino_build_98039/Blink.ino.elf ( arch=arm-*-*-eabi, platform=host )
(lldb) platform select remote-gdb-server
  Platform: remote-gdb-server
 Connected: no
(lldb) platform connect connect://localhost:3333
  Platform: remote-gdb-server
  Hostname: (null)
 Connected: yes
(lldb) l
   44  	  TinyUSB_Device_Init(0);
   45  	#elif defined(USBCON)
   46  	  USBDevice.init();
   47  	  USBDevice.attach();
   48  	#endif
   50  	  setup();
   52  	  for (;;)
   53  	  {
(lldb) c
(lldb) n
error: Command requires a process which is currently stopped.

How do I get lldb to accept that there’s a “process?”

A bit more googling turned up gdb-remote:

(lldb) platform disconnect
(lldb) gdb-remote 3333
Process 1 stopped
* thread #1, stop reason = signal SIGINT
    frame #0: 0x00002280 Blink.ino.elf`micros at delay.c:54:13
   51  	    ticks=ticks2;
   52  	    pend=pend2;
   53  	    count=count2;
-> 54  	    ticks2  = SysTick->VAL;
   55  	    pend2   = !!(SCB->ICSR & SCB_ICSR_PENDSTSET_Msk)  ;
   56  	    count2  = _ulTickCount ;
   57  	  } while ((pend != pend2) || (count != count2) || (ticks < ticks2));

I wonder what that’s doing differently.

In any case, I still don’t really know how to get it to reset the processor and stop at the beginning of the program.

This was said before, but “launch” would have to know how to start something running, that’s its job. Of course, until you give it a target machine (in lldb’s terms a “platform”) to talk to then lldb can’t launch anything. “gdb-remote” creates the platform by connecting to the gdb-remote stub at the given IP address. The gdb-remote command follows the connection with queries to stub to see what’s there. If on connection the stub reports a process already running, lldb attaches to it. If there’s not something running, and the stub supports the “launch a process” packet, lldb will use that to implement the “launch” command (after the initial platform connection). But it looks like that isn’t supported in your scenario, and anyway, there IS already something running. So gdb-remote is the right thing to do in your case.


Okay, thanks. Now if I could just get breakpoints to work.