1#!/usr/bin/env bash
2
3# Copyright 2016 The Fuchsia Authors
4#
5# Use of this source code is governed by a MIT-style
6# license that can be found in the LICENSE file or at
7# https://opensource.org/licenses/MIT
8
9# This script reads the dynamic symbol table of a DSO (ELF file) via nm
10# and writes out a sequence of lines for each symbol in the DSO's ABI
11# that can be used as C macros.  The macro invocations it writes look like:
12#   TYPE(NAME, [ADDRESS,] SIZE)
13# The ADDRESS parameter is included only if the script is given the -a switch.
14# The SIZE is forced to 0 for functions if the script is given the -z switch.
15# The TYPE is one of:
16#   COMMON_OBJECT               STT_COMMON symbol
17#   UNDEFINED                   SHN_UNDEF symbol
18#   UNDEFINED_WEAK_OBJECT       SHN_UNDEF, STB_WEAK, STT_OBJECT symbol
19#   UNDEFINED_WEAK              SHN_UNDEF, STB_WEAK, STT_FUNC symbol
20#   WEAK_DATA_OBJECT            STB_WEAK, STT_OBJECT symbol
21#   WEAK_FUNCTION               STB_WEAK, STT_FUNC symbol
22#   FUNCTION                    STB_GLOBAL, STT_FUNC symbol
23#   RODATA_OBJECT               STB_GLOBAL, STT_OBJECT symbol in R/O section
24#   DATA_OBJECT                 STB_GLOBAL, STT_OBJECT symbol in R/W section
25#   BSS_OBJECT                  STB_GLOBAL symbol in SHT_NOBITS section
26# (nm actually uses a haphazard combination of ELF symbol details and
27# section details to choose its type letters rather than directly using the
28# ELF symbol bits consistently.  But the type letters map to these symbol
29# details when symbols are defined in the usual ways by a compiler.)
30
31if [ "$(basename $0)" = "sh" ]
32then
33  set -e
34else
35  set -o pipefail -e
36fi
37
38show_address=false
39zero_function_size=false
40while [ $# -gt 0 ]; do
41  case "$1" in
42  -a) show_address=true ;;
43  -z) zero_function_size=true ;;
44  *) break ;;
45  esac
46  shift
47done
48
49if [ $# -ne 2 ]; then
50  echo >&2 "Usage: $0 [-a] [-z] NM DSO"
51  exit 2
52fi
53
54NM="$1"
55DSO="$2"
56
57dump_names() {
58  "$NM" -P -g -D -S "$DSO"
59}
60
61massage() {
62  local read name type addr size
63  while read name type addr size; do
64
65    # The numbers are printed in hex, but without a leading "0x" indicator.
66    addr="0x$addr"
67    if [ -z "$size" ]; then
68      size="0x0"
69    else
70      size="0x$size"
71    fi
72
73    case "$name" in
74    # Linkers sometimes emit these symbols into .dynsym, but they are useless
75    # and should not be consider part of the ABI.
76    __bss_start|__bss_start__|__bss_end__|_bss_end__) continue ;;
77    __data_start|__end__|_stack|_etext|_edata|_end) continue ;;
78    esac
79
80    case "$type" in
81    C) type=COMMON_OBJECT ;;
82    U) type=UNDEFINED ;;
83    v) type=UNDEFINED_WEAK_OBJECT ;;
84    w) type=UNDEFINED_WEAK ;;
85    V) type=WEAK_DATA_OBJECT ;;
86    W) type=WEAK_FUNCTION ;;
87    T) type=FUNCTION ;;
88    R) type=RODATA_OBJECT ;;
89    D) type=DATA_OBJECT ;;
90    B) type=BSS_OBJECT ;;
91    *)
92      echo >&2 "$0: Unhandled type '${type}' for symbol '${name}'"
93      exit 1
94      ;;
95    esac
96
97    if $show_address; then
98      address_item=", $addr"
99    else
100      address_item=
101    fi
102
103    if $zero_function_size; then
104      case $type in
105      FUNCTION|WEAK_FUNCTION) size="0x0" ;;
106      esac
107    fi
108
109    echo "${type}(${name}${address_item}, ${size})"
110
111  done
112}
113
114dump_names | massage
115