File: roc-obj

package info (click to toggle)
rocm-hipamd 6.4.3-5
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 23,036 kB
  • sloc: cpp: 211,057; ansic: 35,860; sh: 755; python: 623; perl: 275; asm: 166; makefile: 27
file content (267 lines) | stat: -rwxr-xr-x 10,184 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#!/bin/bash

#| Usage: roc-obj [-h] [-t REGEXP] [-o OUTDIR] [-I REPLACE-STRING|-i] [-d]
#|                EXECUTABLE... [: [SUFFIX COMMAND [ARGS...] ;]...]
#|
#| Wrapper for roc-obj-ls and roc-obj-extract which extracts code objects
#| embedded in each EXECUTABLE and optionally applies COMMANDs to them.
#|
#| If the POSIX extended regular expression REGEXP is specified, only embedded
#| code objects whose Target ID matches REGEXP are extracted; otherwise all
#| code objects are extracted.
#|
#| If the directory path OUTDIR is specified, it is created if it does not
#| already exist, and the code objects are extracted into it; otherwise they
#| are extracted into the current working directory.
#|
#| The extracted files are named by appending a ":" followed by the Target ID
#| of the extracted code object to the input filename EXECUTABLE they were
#| extracted from.
#|
#| If the list of EXECUTABLE arguments is terminated with ":" then after all
#| selected files are successfully extracted, zero or more additional embedded
#| command-lines, separated by ";", are read from the command-line starting
#| after the ":". These must specify a SUFFIX used to name the output of the
#| corresponding COMMAND, along with the COMMAND name and any ARGS to it.
#|
#| Then each COMMAND is executed, as if by a POSIX "execvp" function, once for
#| each embedded code object that was created in OUTDIR. (Note: Typically this
#| means the user must ensure the commands are present in at least one
#| directory of the "PATH" environment variable.) For each execution of
#| COMMAND:
#|
#| If REPLACE-STRING is specified, all instances of REPLACE-STRING in ARGS are
#| replaced with the file path of the extracted code object before executing
#| COMMAND.
#|
#| The standard input is redirected from the extracted code object.
#|
#| If SUFFIX is "-" the standard output is not redirected. If SUFFIX is "!" the
#| standard output is redirected to /dev/null. Otherwise, the standard output
#| is redirected to files named by the file path of the extracted code object
#| with SUFFIX appended.
#|
#| Note: The executables roc-obj-ls, roc-obj-extract, and llvm-objdump (in the
#| case of disassembly requested using the -d flag) are searched for in a
#| unique way. A series of directories are searched, some conditionally, until
#| a suitable executable is found. If all directories are searched without
#| finding the executable, an error occurs. The first directory searched is the
#| one containing the hard-link to the roc-obj being executed, known as the
#| "base directory". Next, if the environment variable HIP_CLANG_PATH is set,
#| it is searched; otherwise, the base directory path is appended with
#| "../llvm/bin" and it is searched. Finally, the PATH is searched as if by
#| a POSIX "execvp" function.
#|
#| Option Descriptions:
#|   -h, --help              print this help text and exit
#|   -t, --target-id         only extract code objects from EXECUTABLE whose Target ID
#|                           matches the POSIX extended regular expression REGEXP
#|   -o, --outdir            set the output directory, which is created if it
#|                           does not exist
#|   -I, --replace-string    replace all occurrences of the literal string
#|                           REPLACE-STRING in ARGS with the input filename
#|   -i, --replace           equivalent to -I{}
#|   -d, --disassemble       disassemble extracted code objects; equivalent to
#|                           : .s llvm-objdump -d - ;
#|
#| Example Usage:
#|
#| Extract all code objects embedded in a.so:
#| $ roc-obj a.so
#|
#| Extract all code objects embedded in a.so, b.so, and c.so:
#| $ roc-obj a.so b.so c.so
#|
#| Extract all code objects embedded in a.so with "gfx9" in their Target ID:
#| $ roc-obj -t gfx9 a.so
#|
#| Extract all code objects embedded in a.so into output/ (creating it if needed):
#| $ roc-obj -o output/ a.so
#|
#| Extract all code objects embedded in a.so with "gfx9" in their Target ID
#| into output/ (creating it if needed):
#| $ roc-obj -t gfx9 -o output/ a.so
#|
#| Extract all code objects embedded in a.so, and then disassemble each of them
#| to files ending with .s:
#| $ roc-obj -d a.so
#|
#| Extract all code objects embedded in a.so, and count the number of bytes in
#| each, writing the results to files ending with .count:
#| $ roc-obj a.so : .count wc -c
#|
#| Extract all code objects embedded in a.so, and inspect their ELF headers
#| using llvm-readelf (which will not read from standard input), writing to
#| files ending with .hdr:
#| $ roc-obj -I'{}' a.so : .hdr llvm-readelf -h '{}'
#|
#| Extract all code objects embedded in a.so, and then extract each of their
#| .text sections using llvm-objcopy (which won't read from standard input
#| or write to standard output):
#| $ roc-obj -I'{}' a.so : ! llvm-objcopy -O binary :only-section=.text '{}' '{}.text'
#|
#| Extract all code objects embedded in a.so, b.so, and c.so with target
#| feature xnack disabled into directory out/. Then, for each:
#| Write the size in bytes into a file ending with .count, and
#| Write a textual description of the ELF headers to a file ending with .hdr, and
#| Extract the .text section to a file ending with .text
#| $ roc-obj -I'{}' -t xnack- -o out/ a.so b.so c.so : \
#|     .count wc -c \;
#|     .hdr llvm-readelf -h '{}' \;
#|     ! llvm-objcopy -O binary --only-section=.text '{}' '{}.text'

set -euo pipefail

usage() {
  sed -n 's/^#| \?\(.*\)$/\1/p' "$0"
}

usage_then_exit() {
  local -r status="$1"; shift
  usage >&$(( status ? 2 : 1 ))
  exit "$status"
}

fail() {
  printf "error: %s\n" "$*" >&2
  exit 1
}

# Account for the fact that we do not necessarily put ROCm tools in the PATH,
# nor do we have a single, unified ROCm "bin/" directory.
#
# Note that this is only used for roc-obj-ls, roc-obj-extract, and "shortcut"
# options like -d, and the user can still use any copy of llvm-* by explicitly
# invoking it with a full path, e.g. : /path/to/llvm-* ... ;
find_rocm_executable_or_fail() {
  local -r command="$1"; shift
  local file
  local searched=()
  for dir in "$BASE_DIR" "${HIP_CLANG_PATH:-"$BASE_DIR/../llvm/bin"}"; do
    file="$dir/$command"
    if [[ -x $file ]]; then
      printf "%s" "$file"
      return
    else
      searched+=("$dir")
    fi
  done
  if hash "$command" 2>/dev/null; then
    printf "%s" "$command"
  else
    fail could not find "$command" in "${searched[*]}" or PATH
  fi
}

# Extract the embedded code objects of the executable file given as the first
# argument into OPT_OUTDIR, filtering them via OPT_TARGET_ID.
#
# Deletes any resulting files which are empty, and prints the paths of the
# remaining files.
extract() {
  local -r executable="$1"; shift
  local prefix
  prefix="$(basename -- "$executable")"
  # We want the shell to split the result of roc-obj-ls on whitespace, as
  # neither the Target ID nor the URI can have embedded spaces.
  # shellcheck disable=SC2046
  set -- $("$ROC_OBJ_LS" -- "$executable" | awk "\$2~/$OPT_TARGET_ID/")
  while (( $# )); do
    local output="$prefix:$1"; shift
    output="$output.$1"; shift
    local uri="$1"; shift
    [[ -n $OPT_OUTDIR ]] && output="$OPT_OUTDIR/$output"
    "$ROC_OBJ_EXTRACT" -o - -- "$uri" >"$output"
    if [[ -s $output ]]; then
      printf '%s\n' "$output"
    else
      rm "$output"
    fi
  done
  (( $# )) && fail expected even number of fields from roc-obj-ls
}

# Run a command over a list of inputs, naming output files with the supplied
# suffix and applying OPT_REPLACE_STRING if needed.
#
# Arguments are of the form:
# $suffix $command $args... ; $inputs
run_command() {
  local -r suffix="$1"; shift
  local -r command="$1"; shift
  local args=()
  while (( $# )); do
    local arg="$1"; shift
    [[ $arg == ';' ]] && break
    args+=("$arg")
  done
  local inputs=("$@")
  for input in "${inputs[@]}"; do
    case "$suffix" in
      '-') output=/dev/stdout;;
      '!') output=/dev/null;;
      *) output="$input$suffix";;
    esac
    "$command" "${args[@]//$OPT_REPLACE_STRING/$input}" <"$input" >"$output"
  done
}

main() {
  printf "Warning: The roc-obj tools have been DEPRECATED. Similar functionality is provided by llvm-objdump in the rocm-llvm package.\n"

  [[ -n $OPT_OUTDIR ]] && mkdir -p "$OPT_OUTDIR"
  local inputs=()
  while (( $# )); do
    local executable="$1"; shift
    [[ $executable == : ]] && break
    # Append the file paths extracted from $executable to $inputs
    readarray -t -O "${#inputs[@]}" inputs < <(extract "$executable")
  done
  (( ${#inputs[@]} )) || fail no executables specified
  while (( $# )); do
    local suffix="$1"; shift
    local command="$1"; shift
    local args=()
    while (( $# )); do
      local arg="$1"; shift
      [[ $arg == \; ]] && break
      args+=("$arg")
    done
    run_command "$suffix" "$command" "${args[@]}" \; "${inputs[@]}"
  done
  (( OPT_DISASSEMBLE )) && run_command .s "$OBJDUMP" -d - \; "${inputs[@]}"
}

OPT_TARGET_ID=''
OPT_OUTDIR=''
OPT_REPLACE_STRING=''
OPT_DISASSEMBLE=0
! getopt -T || fail util-linux enhanced getopt required
getopt="$(getopt -o +ht:o:I:id \
          --long help,target-id:,outdir:,replace:,replace-default,disassemble \
          -n roc-obj -- "$@")"
eval set -- "$getopt"
unset getopt
while true; do
  case "$1" in
    -h | --help) usage_then_exit 0;;
    -t | --target-id) OPT_TARGET_ID="${2//\//\\\/}"; shift 2;;
    -o | --outdir) OPT_OUTDIR="$2"; shift 2;;
    -I | --replace-string) OPT_REPLACE_STRING="$2"; shift 2;;
    -i | --replace) OPT_REPLACE_STRING='{}'; shift;;
    -d | --disassemble) OPT_DISASSEMBLE=1; shift;;
    --) shift; break;;
    *) usage_then_exit 1;;
  esac
done
readonly -- OPT_TARGET_ID OPT_OUTDIR OPT_REPLACE_STRING OPT_DISASSEMBLE

# We expect to be installed as ROCM_PATH/hip/bin/roc-obj, which means BASE_DIR
# is ROCM_PATH/hip/bin.
BASE_DIR="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
(( OPT_DISASSEMBLE )) && OBJDUMP="$(find_rocm_executable_or_fail llvm-objdump-21)"
ROC_OBJ_LS="$(find_rocm_executable_or_fail roc-obj-ls)"
ROC_OBJ_EXTRACT="$(find_rocm_executable_or_fail roc-obj-extract)"
readonly -- BASE_DIR OBJDUMP ROC_OBJ_LS ROC_OBJ_EXTRACT

main "$@"