bazelembedded/bazel-embedded

Add support for generating .map files

Opened this issue · 7 comments

I'm not too familiar with bazel toolchain specifications, so I'm not sure which component would be responsible for this, but I'd like to have .map files generated alongside the elf files when using bazel_embedded platforms. Is that something that's been looked at?

This is something I'm also interested in, at the moment it looks like this will be a while off. There is an issue tracking this upstream.

bazelbuild/bazel#6718

I have a couple thoughts as to workarounds but it's unlikely I'll be able to do that in the near future.

@silvergasp can you share your thoughts on workarounds? Curious to understand the nature of them.

So when you create a bazel rule e.g. cc_binary, you have to explicitly declare the inputs and outputs.

If you don't declare an output bazel effectively prevents you from using it either by sandboxing or simply deleting undeclared outputs.

This is kind of annoying but it is also why bazel is a lot better at being deterministic than other build systems.

There is a further snag on top of this in that the cc_* rules don't use the starlark plugin API, instead they are 'native' rules written in Java. So modifying the rules and the declared outputs to include .map files is somewhat involved, and requires upstream changes to bazel.

There is an ongoing effort to 'starlarkify' the cc_* rules. So this leads to the first approach I had in mind and that is to create a starlark version on cc_binary and potentially upstream that to rules_cc, or host that here under a different name. There are some examples of starlark rules in the bazelbuild/rules_cc repository that you could use as a starting point.

The second approach is to make use of the aspects API in bazel to extract the command line during linking, then effectively redo the linking with map file flags and just emitting the .map file as a declared output. This second approach is probably easier though has some real performance problems as you effectively end up linking twice.

There would likely be a lot of shared code between both approaches so you could likely go the aspects approach and then convert that to a dedicated rule later.

Certainly happy to accept PRs if you have time to give it a go

Thanks for the brain dump @silvergasp !

No worries. Some alternatives that I've found for map files, and are enough for my use cases (but don't fully replace map files).

  • google/bloaty
  • objdump (can run directly from bazel as these are exported_files)
  • readelf (can run directly from bazel as these are exported_files)

I've found bloaty particularly useful for tracking down where modules that are taking up a lot of space. I've also found the output of the above tools a lot easier to interpret, especially when automating things, as map files are a little bit hard to parse.

A nice way to maximise your mileage with these tools is to compile with debugging symbols e.g. -g3 but on your release builds, i.e. with -Os or -O2. This tells the linker to store all the DWARF info in your release build and contains all the source file paths, symbol names etc. from your build. You can then use the resulting ELF file with bloaty and then when you build the stripped version it will remove all the debug symbols. What is nice about this approach is that you end up with stripped binaries that are exactly identical to your release build while the ELF contains debug symbols. You can also use this approach to debug release builds, but it can be a little funky so YMMV. This isn't directly built into bazel-embedded but it's relatively simple to do e.g. add --copt=-g3 and --linkopt=-Wl,--gdb-index to your command line.

Out of interest, what specific info would you want to extract from your map files?

I didn't have a specific use case. I'm just used to having map files accessible to cross reference for debugging purposes. I'll try out the -g3 and --gdb-index flags.