From c6063fe27b94deb84da3d9b2b958b8be4915898b Mon Sep 17 00:00:00 2001 From: David Salinas Date: Tue, 17 Aug 2021 19:36:37 +0000 Subject: [PATCH] SWDEV-294828 - Move roc-obj binaries from hip to hipamd SWDEV-280149 - roc-obj-ls/roc-obj-extract don't extract all kernel code Change-Id: Ibe8aff5ff02fced4d9034740da72d3aa8d67c6ae [ROCm/clr commit: 64cbd7951d1ba588017fc4687172dd91a29c241e] --- projects/clr/hipamd/CMakeLists.txt | 1 + projects/clr/hipamd/bin/roc-obj | 265 ++++++++++++++++++++ projects/clr/hipamd/bin/roc-obj-extract | 229 +++++++++++++++++ projects/clr/hipamd/bin/roc-obj-ls | 191 ++++++++++++++ projects/clr/hipamd/packaging/hip-devel.txt | 1 + 5 files changed, 687 insertions(+) create mode 100644 projects/clr/hipamd/bin/roc-obj create mode 100755 projects/clr/hipamd/bin/roc-obj-extract create mode 100755 projects/clr/hipamd/bin/roc-obj-ls diff --git a/projects/clr/hipamd/CMakeLists.txt b/projects/clr/hipamd/CMakeLists.txt index 58b8ac6545..b1ab39e7f6 100755 --- a/projects/clr/hipamd/CMakeLists.txt +++ b/projects/clr/hipamd/CMakeLists.txt @@ -343,6 +343,7 @@ endif() if(HIP_PLATFORM STREQUAL "amd") install(FILES ${PROJECT_BINARY_DIR}/include/hip/amd_detail/hip_prof_str.h DESTINATION include/hip/amd_detail) +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin DESTINATION . USE_SOURCE_PERMISSIONS) endif() install(FILES ${PROJECT_BINARY_DIR}/include/hip/hip_version.h DESTINATION include/hip) diff --git a/projects/clr/hipamd/bin/roc-obj b/projects/clr/hipamd/bin/roc-obj new file mode 100644 index 0000000000..0b0d12f5f2 --- /dev/null +++ b/projects/clr/hipamd/bin/roc-obj @@ -0,0 +1,265 @@ +#!/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 diassemble 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() { + [[ -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)" +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 "$@" diff --git a/projects/clr/hipamd/bin/roc-obj-extract b/projects/clr/hipamd/bin/roc-obj-extract new file mode 100755 index 0000000000..d43e356d7d --- /dev/null +++ b/projects/clr/hipamd/bin/roc-obj-extract @@ -0,0 +1,229 @@ +#!/usr/bin/perl +# Copyright (c) 2020-2021 Advanced Micro Devices, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +use strict; +use File::Copy; +use File::Spec; +use File::Basename; +use File::Which; +use Cwd 'realpath'; +use Getopt::Std; +use List::Util qw(max); +use URI::Encode; + +my $extract_range_specifier; +my $extract_pid; +my $extract_file; +my $output_file; +my $output_path; +my $extract_offset; +my $extract_size; +my $pid_running; +my $verbose=0; +my $error=0; +my $output_to_stdout=0; + +sub usage { + print("Usage: $0 [-o|v|h] URI... \n"); + print(" URIs can be read from STDIN, one per line.\n"); + print(" From the URIs specified, extracts code objects into files named: "); + print("-[pid]-offset-size.co\n\n"); + print("Options:\n"); + print(" -o \tPath for output. If \"-\" specified, code object is printed to STDOUT.\n"); + print(" -v \tVerbose output to STDOUT (includes Entry ID).\n"); + print(" -h \tShow this help message.\n"); + print("\nURI syntax:\n"); + print("\tcode_object_uri ::== file_uri | memory_uri\n"); + print("\tfile_uri ::== \"file://\" extract_file [ range_specifier ]\n"); + print("\tmemory_uri ::== \"memory://\" process_id range_specifier\n"); + print("\trange_specifier ::== [ \"#\" | \"?\" ] \"offset=\" number \"&\" \"size=\" number\n"); + print("\textract_file ::== URI_ENCODED_OS_FILE_PATH\n"); + print("\tprocess_id ::== DECIMAL_NUMBER\n"); + print("\tnumber ::== HEX_NUMBER \| DECIMAL_NUMBER \| OCTAL_NUMBER\n\n"); + print("\tExample: file://dir1/dir2/hello_world#offset=133&size=14472 \n"); + print("\t memory://1234#offset=0x20000&size=3000\n\n"); + + exit($error); +} + +# Process options +my %options=(); +getopts('vho:', \%options); + +if (defined $options{h}) { + usage(); +} + +if (defined $options{v}) { + $verbose = 1; +} + +if (defined $options{o}) { + $output_path = $options{o}; + if ($output_path eq "-") { + $output_to_stdout=1; + } else { + (-d $output_path) || die("Error: Path \'$output_path\' cannot be found.\n"); + } +} + +# push STDIN to ARGV array. +push @ARGV, unless -t STDIN; + +# error check: enough arguments presented. +if ($#ARGV < 0) { + print(STDERR "Error: No arguments.\n"); $error++; + usage(); +} + +# error check: command dd is available. +my $dd_cmd = which("dd"); +(-f $dd_cmd) || die("Error: Can't find dd command\n"); + +foreach my $uri_str(@ARGV) { + chomp $uri_str; + + # we expect the URI to follow this BNF syntax: + # + # code_object_uri ::== file_uri | memory_uri + # file_uri ::== "file://" extract_file [ range_specifier ] + # memory_uri ::== "memory://" process_id range_specifier + # range_specifier ::== [ "#" | "?" ] "offset=" number "&" "size=" number + # extract_file ::== URI_ENCODED_OS_FILE_PATH + # process_id ::== DECIMAL_NUMBER + # number ::== HEX_NUMBER | DECIMAL_NUMBER | OCTAL_NUMBER + + # Example: file://dir1/dir2/hello_world#offset=133&size=14472 + # memory://1234#offset=0x20000&size=3000 + + my ($uri_protocol, $specs) = split(/:\/\//,$uri_str); + my $obj_uri_encode = URI::Encode->new(); + my $decoded_extract_file; + + if (lc($uri_protocol) eq "file") { + # expect file path + ($extract_file, $extract_range_specifier) = split(/[#,?]/,$specs); + + # decode the file name. URIs may have file/path names with non-alphanumeric characters, which will be encoded with %. We need to decode these. + $decoded_extract_file = $obj_uri_encode->decode($extract_file); + + # verify file exists: + if (! -e $decoded_extract_file) { + print(STDERR "Error: can't find file: $decoded_extract_file\n"); $error++; + next; + } + + # use the output_path is specified, otherwise use current working dir. + if ($output_path ne "") { + $output_file = File::Spec->catfile($output_path, basename($decoded_extract_file)); + } else { + $output_file = basename($decoded_extract_file); + } + + } elsif ( lc($uri_protocol) eq "memory") { + # expect memory specifier + ($extract_pid, $extract_range_specifier) = split(/[#,?]/,$specs); + + # verify pid is currently running + $pid_running = kill 0, $extract_pid; + if (! $pid_running) { + print(STDERR "Error: PID: $extract_pid is NOT running\n"); $error++; + next; + } + + # get pid filename: + $extract_file = "/proc/$extract_pid/mem"; + + # verify file exists: + if (! -e $extract_file) { + print(STDERR "Error: can't find file: $extract_file\n"); $error++; + next; + } + + # for extracting from a pid, make the output file in the current dir/path with the pid value as a name. + $output_file = "pid${extract_pid}"; + + # need to set $decoded_extract_file, because later we use this for other checks. + $decoded_extract_file = $extract_file; + + } else { + # error, unrecognized Code Object URI + print(STDERR "Error: \'$uri_protocol\' is not recognized as a supported code object URI.\n"); $error++; + next; + } + + # it is valid to not give a range specifier in a URI, in which case the entire code object will be extracted. + if ($extract_range_specifier ne "") { + ($extract_offset, $extract_size) = split(/[&]/,$extract_range_specifier); + (undef, $extract_offset) = split(/=/,$extract_offset); + (undef, $extract_size) = split(/=/,$extract_size); + } else { + # Error if URI is a memory request, and we have no range_specifier. + if ($pid_running) { + print(STDERR "Error: must specify a Range Specifier (offset and size) for a memory URI: $uri_str\n"); $error++; + next; + } + + $extract_offset = 0; + $extract_size = -s $decoded_extract_file; + } + + # We should have at least a valid size to extract; ignore cases with size=0. + if ($extract_size != 0) { + print("Reading input file \"$extract_file\" ...\n") if ($verbose); + + # only if this is a File URI. + if (lc($uri_protocol) eq "file") { + # verify that offset+size does not exceed file size: + my $file_size = -s $decoded_extract_file; + my $size = int($extract_offset) + int($extract_size); + if ( $size > $file_size ) { + print(STDERR "Error: requested offset($extract_offset) + size($extract_size) exceeds file size($file_size) for file \"$decoded_extract_file\".\n"); $error++; + next; + } + } + + open(INPUT_FP, "<", $decoded_extract_file) || die $!; + binmode INPUT_FP; + + # extract the code object + my $co_filename; + if (!$output_to_stdout) { + $co_filename = "of=\'${output_file}-offset${extract_offset}-size${extract_size}.co\'"; + } + + my $dd_cmd_str = "$dd_cmd if=\'$decoded_extract_file\' $co_filename skip=$extract_offset count=$extract_size bs=1 status=none"; + + print("DD Command: $dd_cmd_str\n") if ($verbose); + + my $dd_ret = system($dd_cmd_str); + if ($dd_ret != 0) { + print(STDERR "Error: DD command ($dd_cmd_str) failed with RC: $dd_ret\n"); $error++; + } + + print("Extract request: file: $extract_file offset: $extract_offset size: $extract_size\n") if ($verbose); + } else { + print("Warning: trying to extract from $extract_file at offset=$extract_offset with size=0. Nothing to extract.\n") if ($verbose); + } + +} # end of for each (URI) argument + +exit($error); diff --git a/projects/clr/hipamd/bin/roc-obj-ls b/projects/clr/hipamd/bin/roc-obj-ls new file mode 100755 index 0000000000..0fc0cb4657 --- /dev/null +++ b/projects/clr/hipamd/bin/roc-obj-ls @@ -0,0 +1,191 @@ +#!/usr/bin/perl +# Copyright (c) 2020 - 2021 Advanced Micro Devices, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +use strict; +use File::Copy; +use File::Spec; +use File::Basename; +use File::Which; +use Cwd 'realpath'; +use Getopt::Std; +use List::Util qw(max); +use URI::Encode; + +sub usage { + print("Usage: $0 [-v|h] executable...\n"); + print("List the URIs of the code objects embedded in the specfied host executables.\n"); + print("-v \tVerbose output (includes Entry ID)\n"); + print("-h \tShow this help message\n"); + exit; +} + +# sub to read a qword. 1st arg is a FP, 2nd arg is ref to destination var. +sub readq { + my ($input_fp, $qword) = @_; + read($input_fp, my $bytes, 8) == 8 or die("Error: Failed to read 8 bytes\n"); + ${$qword} = unpack("Q<", $bytes); +} + +# sub to move address to next alignment boundary +# first arg is address to move +# second arg is alignment requirement/boundary +sub align_up { + my ($address, $alignment) = @_; + $address = int(($address + ($alignment - 1)) / $alignment) * $alignment; +} + +# Process options +my %options=(); +getopts('vhd', \%options); + +if (defined $options{h}) { + usage(); +} + +my $verbose = $options{v}; +my $debug = $options{d}; + +my $num_bundles = 1; +my $bundle_alignment = 4096; + +# look for objdump +my $objdump = which("objdump"); +(-f $objdump) || die("Error: Can't find objdump command\n"); + +# for each argument (which should be an executable): +foreach my $executable_file(@ARGV) { + + # debug message + print("Reading input file \"$executable_file\" ...\n") if ($debug); + + # verify/open file specified. + open (INPUT_FP, "<", $executable_file) || die("Error: failed to open file: $executable_file\n"); + binmode INPUT_FP; + + # kernel section information + my $escaped_name=quotemeta($executable_file); + my $bundle_section_name = ".hip_fatbin"; + my $bundle_section_size = hex(`$objdump -h $escaped_name | grep $bundle_section_name | awk '{print \$3}'`); + my $bundle_section_offset = hex(`$objdump -h $escaped_name | grep $bundle_section_name | awk '{print \$6}'`); + + $bundle_section_size or die("Error: No kernel section found\n"); + + my $bundle_section_end = $bundle_section_offset + $bundle_section_size; + + if ($debug) { + printf("Code Objects Bundle section size: %x\n",$bundle_section_size); + printf("Code Objects Bundle section offset: %x\n",$bundle_section_offset); + printf("Code Objects Bundle section end: %x\n\n",$bundle_section_end); + } + + my $current_bundle_offset = $bundle_section_offset; + printf("Current Bundle offset: 0x%X\n",$current_bundle_offset) if ($debug); + + # move fp to current_bundle_offset. + seek(INPUT_FP, $current_bundle_offset, 0); + + while ($current_bundle_offset < $bundle_section_end) { + + # skip OFFLOAD_BUNDLER_MAGIC_STR + my $magic_str; + my $read_bytes = read(INPUT_FP, $magic_str, 24); + if (($read_bytes != 24) || ($magic_str ne "__CLANG_OFFLOAD_BUNDLE__")) { + print(STDERR "Error: Offload bundle magic string not detected\n") if ($debug); + } + + # read number of bundle entries, which are code objects. + my $num_codeobjects; + readq(\*INPUT_FP,\$num_codeobjects); + + # header with current bundle number and number of embedded code objcts in that bundle. + # print("Bundle Number: $num_bundles with $num_codeobjects Code Objects:\n") if ($very_verbose); + + my $end_of_current_bundle = $current_bundle_offset; + + # Column Header. + printf("%-8s%-40s%35s\n","Bundle#","Entry ID:","URI:") if ($verbose); + + # for each Bundle entry (code object) .... + for (my $iter = 0; $iter < $num_codeobjects; $iter++) { + + print("\nEntry #$iter\n") if $debug; + + # read bundle entry (code object) offset + my $entry_offset; + my $abs_offset; + readq(*INPUT_FP,\$entry_offset); + printf("entry_offset: 0x%X\n",$entry_offset) if $debug; + + # read bundle entry (code object) size + my $entry_size; + readq(*INPUT_FP,\$entry_size); + printf("entry_size: 0x%X\n",$entry_size) if $debug; + + # read triple size + my $triple_size; + readq(*INPUT_FP,\$triple_size); + printf("triple_size: 0x%X\n",$triple_size) if $debug; + + # read triple string + my $triple; + my $read_bytes = read(INPUT_FP, $triple, $triple_size); + $read_bytes == $triple_size or die("Error: Fail to parse triple\n"); + print("triple: $triple\n") if $debug; + + # because the bundle entry's offset is relative to the beginning of the bundled code object section. + $abs_offset = int($current_bundle_offset + $entry_offset); + + # and we need to keep track of where we are in the current bundle. + $end_of_current_bundle = int($abs_offset + $entry_size); + + printf("abs_offset: 0x%X\n",$abs_offset) if $debug; + + my $obj_uri_encode = URI::Encode->new(); + my $encoded_executable_file = $obj_uri_encode->encode($executable_file); + + printf("%-8s%-40s%35s%s%s%s%s%s%s\n",$num_bundles,$triple,"file:\/\/",$encoded_executable_file,"\#offset=",$abs_offset, "\&size=",$entry_size); + + printf("end_of_current_bundle: 0x%X\n",$end_of_current_bundle) if $debug; + printf("Hex values: file:\/\/$encoded_executable_file#offset=0x%X$abs_offset\&size=0x%X\n", $abs_offset, $entry_size) if $debug; + + } # End of for each Bundle entry (code object) ... + + printf("\n") if ($verbose); + + # we've finished listing this current bundle ... + printf("current_bundle_offset: %x \n",$current_bundle_offset) if ($debug); + printf("bundle_section_end: %x \n", $bundle_section_end) if ($debug); + + # move current_bundle_offset to next alignment boundary. + $current_bundle_offset = align_up($end_of_current_bundle,$bundle_alignment); + printf("Adjusting for alignment of next bundle: current_bundle_offset: %x \n\n\n", $current_bundle_offset) if ($debug); + + # seek to the end of the current bundle: + seek(INPUT_FP, $current_bundle_offset, 0); + + # increment the number of bundles listed. + $num_bundles = $num_bundles+1; + + } # End of while loop + +} # End of for each command line argument + +exit(0); diff --git a/projects/clr/hipamd/packaging/hip-devel.txt b/projects/clr/hipamd/packaging/hip-devel.txt index 6ea6064c64..ab001aa017 100644 --- a/projects/clr/hipamd/packaging/hip-devel.txt +++ b/projects/clr/hipamd/packaging/hip-devel.txt @@ -27,6 +27,7 @@ else() install(DIRECTORY @HIP_COMMON_DIR@/bin DESTINATION . USE_SOURCE_PERMISSIONS PATTERN *.bat EXCLUDE) endif() +install(DIRECTORY @hip_SOURCE_DIR@/bin DESTINATION . USE_SOURCE_PERMISSIONS) install(DIRECTORY @HIP_COMMON_DIR@/include DESTINATION .) install(DIRECTORY @hip_SOURCE_DIR@/include/hip/amd_detail DESTINATION include/hip) install(DIRECTORY @hip_SOURCE_DIR@/include/hip/nvidia_detail DESTINATION include/hip)