this is just a short one. as the developer of periscope i of course had to write homebrew software for the switch. this is all made possible by great work of the contributors of libnx, and writing applets is pretty alright. however, writing sysmodules (background processes) you lose a lot of what makes applets nice (nxlink, really just any ability to see any output...) etc.

i'd just kind of accepted it and dealt with it, but man it would be really nice to be able to debug in a way that didn't suck...

so i was vaguely aware you could attach gdb to ordinary application processes, turns out that you can also do it for sysmodules. this is really nice and (as far as I could tell?) not really written down anywhere? i used this to get started but it obviously doesn't mention anything about sysmodules.

here's my findings/sort of a guide(?)

setup

you'll need gdb-multiarch with xml support. these are both use flags on gentoo and i don't know on literally anything else.

put this in /atmosphere/config/system_settings.ini (taken directly from the link earlier)

[atmosphere]
enable_htc = u8!0x0
enable_standalone_gdbstub = u8!0x1

and reboot the switch

connecting gdb to the program

get your switch's ip address, run gdb, then run target extended-remote <ip>:22225 in gdb. you now have a few options from the debug monitor, or you can directly attach to a process. (in all of these, monitor can be shortened to, say, mon)

the latter is useful for sysmodules, because you probably set your sysmodule's program id. sys-scope's is 0x420000000005C09E.

once you get a PID, either independently or from waiting for it, type attach PID.

now you can, sort of, use GDB as normal. however, you have no symbols and only offsets, so you're probably kind of sad! this is probably the life for reverse-engineers, but we're forward-engineering today.

symbols

run monitor get info and you'll get some output like this:

Process:     0xa7 (sys-scope)
Program Id:  0x420000000005c09e
Application: 0
Hbl:         0
Layout:
  Alias: 0x0b0e800000 - 0x0c8e7fffff
  Heap:  0x07dfa00000 - 0x09df9fffff
  Aslr:  0x0008000000 - 0x0fffffffff
  Stack: 0x0008000000 - 0x007fffffff
Modules:
  0x001be00000 - 0x001be20fff sys-scope.elf

in the modules section will probably be the offset of a .elf file. this sysmodule has exactly one. it is, in fact, one of the output artifacts of the libnx build process, which by default builds with debug info enabled.

to make use of this, figure out what the offset is (in this case, 0x1be00000), and run the command symbol-file <path/to/whatever.elf> -o OFFSET.

in this case that would be symbol-file sys-scope.elf -o 0x1be00000.

now you can do normal things like set breakpoints at lines instead of offsets (hooray!) and print variable names, most of the time.

if you kill and restart the process, or otherwise detach and attach to another instance of it, when you do this, the symbol offsets will change. just run symbol-file and then press y to unload your previous symbol mapping, do mon get info again, and run the symbol-file command again with the new offset.

anyway, i'm not sure if this is broadly useful, or already written down somewhere else, but i ended up figuring it out on my own, so i thought i'd also write it down.