1# This awk script processes the output of objdump --dynamic-syms
2# into a simple format that should not change when the ABI is not changing.
3
4BEGIN {
5  if (combine_fullname)
6    combine = 1;
7  if (combine)
8    parse_names = 1;
9}
10
11# Per-file header.
12/[^ :]+\.so\.[0-9.]+:[ 	]+.file format .*$/ {
13  emit(0);
14
15  seen_opd = 0;
16
17  sofullname = $1;
18  sub(/:$/, "", sofullname);
19  soname = sofullname;
20  sub(/^.*\//, "", soname);
21  sub(/\.so\.[0-9.]+$/, "", soname);
22
23  suppress = ((filename_regexp != "" && sofullname !~ filename_regexp) \
24	      || (libname_regexp != "" && soname !~ libname_regexp));
25
26  next
27}
28
29suppress { next }
30
31# Normalize columns.
32/^[0-9a-fA-F]+      / { sub(/      /, "  -   ") }
33
34# Skip undefineds.
35$4 == "*UND*" { next }
36
37# Skip locals.
38$2 == "l" { next }
39
40# If the target uses ST_OTHER, it will be output before the symbol name.
41$2 == "g" || $2 == "w" && (NF == 7 || NF == 8) {
42  type = $3;
43  size = $5;
44  sub(/^0*/, "", size);
45  if (size == "") {
46      size = " 0x0";
47  } else {
48      size = " 0x" size;
49  }
50  version = $6;
51  symbol = $NF;
52  gsub(/[()]/, "", version);
53
54  # binutils versions up through at least 2.23 have some bugs that
55  # caused STV_HIDDEN symbols to appear in .dynsym, though that is useless.
56  if (NF > 7 && $7 == ".hidden") next;
57
58  if (version == "GLIBC_PRIVATE" && !include_private) next;
59
60  desc = "";
61  if (type == "D" && ($4 == ".tbss" || $4 == ".tdata")) {
62    type = "T";
63  }
64  else if (type == "D" && $4 == ".opd") {
65    type = "F";
66    size = "";
67    if (seen_opd < 0)
68      type = "O";
69    seen_opd = 1;
70  }
71  else if (type == "D" && NF == 8 && $7 == "0x80") {
72    # Alpha functions avoiding plt entry in users
73    type = "F";
74    size = "";
75    seen_opd = -1;
76  }
77  else if ($4 == "*ABS*") {
78    next;
79  }
80  else if (type == "D") {
81    # Accept unchanged.
82  }
83  else if (type == "DO") {
84    type = "D";
85  }
86  else if (type == "DF") {
87    if (symbol ~ /^\./ && seen_opd >= 0)
88      next;
89    seen_opd = -1;
90    type = "F";
91    size = "";
92  }
93  else if (type == "iD" && ($4 == ".text" || $4 == ".opd")) {
94    # Indirect functions.
95    type = "F";
96    size = "";
97  }
98  else {
99    print "ERROR: Unable to handle this type of symbol:", $0
100    exit 1
101  }
102
103  if (desc == "")
104    desc = symbol " " type size;
105
106  if (combine)
107    version = soname " " version (combine_fullname ? " " sofullname : "");
108
109  # Append to the string which collects the results.
110  descs = descs version " " desc "\n";
111  next;
112}
113
114# Header crapola.
115NF == 0 || /DYNAMIC SYMBOL TABLE/ || /file format/ { next }
116
117{
118  print "ERROR: Unable to interpret this line:", $0
119  exit 1
120}
121
122function emit(end) {
123  if (!end && (combine || ! parse_names || soname == ""))
124    return;
125  tofile = parse_names && !combine;
126
127  if (tofile) {
128    out = prefix soname ".symlist";
129    if (soname in outfiles)
130      out = out "." ++outfiles[soname];
131    else
132      outfiles[soname] = 1;
133    outpipe = "LC_ALL=C sort -u > " out;
134  } else {
135    outpipe = "LC_ALL=C sort -u";
136  }
137
138  printf "%s", descs | outpipe;
139
140  descs = "";
141
142  if (tofile)
143    print "wrote", out, "for", sofullname;
144}
145
146END {
147  emit(1);
148}
149