1# Copyright 2024 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14"""Rules for processing binary executables.""" 15 16load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") 17load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain") 18load("@rules_cc//cc/common:cc_common.bzl", "cc_common") 19load("//pw_toolchain/action:action_names.bzl", "PW_ACTION_NAMES") 20 21def run_action_on_executable( 22 ctx, 23 action_name, 24 action_args, 25 inputs, 26 output, 27 additional_outputs, 28 output_executable = False): 29 """Macro to be used in rule implementation to run an action on input executable. 30 31 Looks up the current toolchain to find the path to the specified action. 32 33 Args: 34 ctx: Rule context 35 action_name: The name of the action 36 action_args: Arguments to pass to the action 37 inputs: Input files to use in the action 38 output: The output generated by the action 39 additional_outputs: Extra output objects that should be bundled into the result 40 output_executable: True if the output is an executable 41 Returns: 42 DefaultInfo with the output and additional_outputs. 43 """ 44 cc_toolchain = find_cpp_toolchain(ctx) 45 46 feature_configuration = cc_common.configure_features( 47 ctx = ctx, 48 cc_toolchain = cc_toolchain, 49 requested_features = ctx.features, 50 unsupported_features = ctx.disabled_features, 51 ) 52 tool_path = cc_common.get_tool_for_action( 53 feature_configuration = feature_configuration, 54 action_name = action_name, 55 ) 56 57 ctx.actions.run_shell( 58 inputs = depset( 59 direct = inputs, 60 transitive = [ 61 cc_toolchain.all_files, 62 ], 63 ), 64 outputs = [output], 65 command = "{tool} {args}".format( 66 tool = tool_path, 67 args = action_args, 68 ), 69 ) 70 71 return DefaultInfo( 72 files = depset([output] + additional_outputs), 73 executable = output if output_executable else None, 74 ) 75 76def _pw_elf_to_bin_impl(ctx): 77 return run_action_on_executable( 78 ctx = ctx, 79 # TODO: https://github.com/bazelbuild/rules_cc/issues/292 - Add a helper 80 # to rules cc to make it possible to get this from ctx.attr._objcopy. 81 action_name = ACTION_NAMES.objcopy_embed_data, 82 action_args = "{args} {input} {output}".format( 83 args = "-Obinary", 84 input = ctx.executable.elf_input.path, 85 output = ctx.outputs.bin_out.path, 86 ), 87 inputs = [ctx.executable.elf_input], 88 output = ctx.outputs.bin_out, 89 additional_outputs = ctx.files.elf_input, 90 output_executable = True, 91 ) 92 93pw_elf_to_bin = rule( 94 implementation = _pw_elf_to_bin_impl, 95 doc = """Takes in an ELF executable and uses the toolchain objcopy tool to 96 create a binary file, not containing any ELF headers. This can be used to 97 create a bare-metal bootable image. 98 """, 99 attrs = { 100 "bin_out": attr.output(mandatory = True), 101 "elf_input": attr.label(mandatory = True, executable = True, cfg = "target"), 102 "_objcopy": attr.label( 103 default = "@rules_cc//cc/toolchains/actions:objcopy_embed_data", 104 ), 105 }, 106 executable = True, 107 toolchains = use_cpp_toolchain(), 108 fragments = ["cpp"], 109) 110 111def _pw_elf_to_dump_impl(ctx): 112 return run_action_on_executable( 113 ctx = ctx, 114 # TODO: https://github.com/bazelbuild/rules_cc/issues/292 - Add a helper 115 # to rules cc to make it possible to get this from ctx.attr._objdump. 116 action_name = PW_ACTION_NAMES.objdump_disassemble, 117 action_args = "{args} {input} > {output}".format( 118 args = "-dx", 119 input = ctx.executable.elf_input.path, 120 output = ctx.outputs.dump_out.path, 121 ), 122 inputs = [ctx.executable.elf_input], 123 output = ctx.outputs.dump_out, 124 additional_outputs = ctx.files.elf_input, 125 ) 126 127pw_elf_to_dump = rule( 128 implementation = _pw_elf_to_dump_impl, 129 doc = """Takes in an ELF executable and uses the toolchain objdump tool to 130 create a text file dump of the contents. 131 """, 132 attrs = { 133 "dump_out": attr.output(mandatory = True), 134 "elf_input": attr.label(mandatory = True, executable = True, cfg = "target"), 135 "_objdump": attr.label( 136 default = "//pw_toolchain/action:objdump_disassemble", 137 ), 138 }, 139 toolchains = use_cpp_toolchain(), 140 fragments = ["cpp"], 141) 142