| #!/usr/bin/env bash |
| |
| # Copyright 2016 The Fuchsia Authors |
| # |
| # Use of this source code is governed by a MIT-style |
| # license that can be found in the LICENSE file or at |
| # https://opensource.org/licenses/MIT |
| |
| # This script reads the dynamic symbol table of a DSO (ELF file) via nm |
| # and writes out a sequence of lines for each symbol in the DSO's ABI |
| # that can be used as C macros. The macro invocations it writes look like: |
| # TYPE(NAME, [ADDRESS,] SIZE) |
| # The ADDRESS parameter is included only if the script is given the -a switch. |
| # The SIZE is forced to 0 for functions if the script is given the -z switch. |
| # The TYPE is one of: |
| # COMMON_OBJECT STT_COMMON symbol |
| # UNDEFINED SHN_UNDEF symbol |
| # UNDEFINED_WEAK_OBJECT SHN_UNDEF, STB_WEAK, STT_OBJECT symbol |
| # UNDEFINED_WEAK SHN_UNDEF, STB_WEAK, STT_FUNC symbol |
| # WEAK_DATA_OBJECT STB_WEAK, STT_OBJECT symbol |
| # WEAK_FUNCTION STB_WEAK, STT_FUNC symbol |
| # FUNCTION STB_GLOBAL, STT_FUNC symbol |
| # RODATA_OBJECT STB_GLOBAL, STT_OBJECT symbol in R/O section |
| # DATA_OBJECT STB_GLOBAL, STT_OBJECT symbol in R/W section |
| # BSS_OBJECT STB_GLOBAL symbol in SHT_NOBITS section |
| # (nm actually uses a haphazard combination of ELF symbol details and |
| # section details to choose its type letters rather than directly using the |
| # ELF symbol bits consistently. But the type letters map to these symbol |
| # details when symbols are defined in the usual ways by a compiler.) |
| |
| if [ "$(basename $0)" = "sh" ] |
| then |
| set -e |
| else |
| set -o pipefail -e |
| fi |
| |
| usage() { |
| echo >&2 "Usage: $0 NM [-a] [-z] DSO OUTPUT [DEPFILE]" |
| exit 2 |
| } |
| |
| if [ $# -lt 3 ]; then |
| usage |
| fi |
| |
| NM="$1" |
| shift |
| |
| show_address=false |
| zero_function_size=false |
| while [ $# -gt 0 ]; do |
| case "$1" in |
| -a) show_address=true ;; |
| -z) zero_function_size=true ;; |
| *) break ;; |
| esac |
| shift |
| done |
| |
| if [ $# -ne 2 -a $# -ne 3 ]; then |
| usage |
| fi |
| |
| DSO="$1" |
| OUTPUT="$2" |
| DEPFILE="$3" |
| |
| USED_FILES=() |
| if [[ "$DSO" == @* ]]; then |
| rspfile="${DSO#@}" |
| DSO="$(< "$rspfile")" |
| USED_FILES+=("$rspfile" "$DSO") |
| else |
| USED_FILES+=("$DSO") |
| fi |
| |
| if [ -n "$DEPFILE" ]; then |
| echo "$OUTPUT: ${USED_FILES[*]}" > "$DEPFILE" |
| fi |
| |
| dump_names() { |
| "$NM" -P -g -D -S "$DSO" |
| } |
| |
| massage() { |
| local read name type addr size |
| while read name type addr size; do |
| |
| # The numbers are printed in hex, but without a leading "0x" indicator. |
| addr="0x$addr" |
| if [ -z "$size" ]; then |
| size="0x0" |
| else |
| size="0x$size" |
| fi |
| |
| case "$name" in |
| # Linkers sometimes emit these symbols into .dynsym, but they are useless |
| # and should not be consider part of the ABI. |
| __bss_start|__bss_start__|__bss_end__|_bss_end__) continue ;; |
| __data_start|__end__|_stack|_etext|_edata|_end) continue ;; |
| __start_xray_fn_idx|__stop_xray_fn_idx) continue ;; |
| __start_xray_instr_map|__stop_xray_instr_map) continue ;; |
| esac |
| |
| case "$type" in |
| C) type=COMMON_OBJECT ;; |
| U) type=UNDEFINED ;; |
| v) type=UNDEFINED_WEAK_OBJECT ;; |
| w) type=UNDEFINED_WEAK ;; |
| V) type=WEAK_DATA_OBJECT ;; |
| W) type=WEAK_FUNCTION ;; |
| T) type=FUNCTION ;; |
| R) type=RODATA_OBJECT ;; |
| D) type=DATA_OBJECT ;; |
| B) type=BSS_OBJECT ;; |
| *) |
| echo >&2 "$0: Unhandled type '${type}' for symbol '${name}'" |
| exit 1 |
| ;; |
| esac |
| |
| if $show_address; then |
| address_item=", $addr" |
| else |
| address_item= |
| fi |
| |
| if $zero_function_size; then |
| case $type in |
| FUNCTION|WEAK_FUNCTION) size="0x0" ;; |
| esac |
| fi |
| |
| echo "${type}(${name}${address_item}, ${size})" |
| |
| done |
| } |
| |
| trap 'rm -f "$OUTPUT" ${DEPFILE:+$"DEPFILE"}' ERR HUP INT TERM |
| dump_names | massage > "$OUTPUT" |