Index: head/contrib/elftoolchain/ar/ar.1 =================================================================== --- head/contrib/elftoolchain/ar/ar.1 (nonexistent) +++ head/contrib/elftoolchain/ar/ar.1 (revision 286070) @@ -0,0 +1,603 @@ +.\" Copyright (c) 2007,2009-2012 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: ar.1 3195 2015-05-12 17:22:19Z emaste $ +.\" +.Dd December 10, 2012 +.Os +.Dt AR 1 +.Sh NAME +.Nm ar +.Nd manage archives +.Sh SYNOPSIS +.Nm +.Fl d +.Op Fl T +.Op Fl f +.Op Fl j +.Op Fl v +.Op Fl z +.Ar archive +.Ar +.Nm +.Fl m +.Op Fl T +.Op Fl a Ar position-after +.Op Fl b Ar position-before +.Op Fl f +.Op Fl i Ar position-before +.Op Fl j +.Op Fl s | Fl S +.Op Fl z +.Ar archive +.Ar +.Nm +.Fl p +.Op Fl T +.Op Fl f +.Op Fl v +.Ar archive +.Op Ar +.Nm +.Fl q +.Op Fl T +.Op Fl c +.Op Fl D +.Op Fl f +.Op Fl F Ar flavor | Fl -flavor Ar flavor +.Op Fl s | Fl S +.Op Fl v +.Op Fl z +.Ar archive +.Ar +.Nm +.Fl r +.Op Fl T +.Op Fl a Ar position-after +.Op Fl b Ar position-before +.Op Fl c +.Op Fl D +.Op Fl f +.Op Fl F Ar flavor | Fl -flavor Ar flavor +.Op Fl i Ar position-before +.Op Fl j +.Op Fl s | Fl S +.Op Fl u +.Op Fl v +.Op Fl z +.Ar archive +.Ar +.Nm +.Fl s +.Op Fl D +.Op Fl j +.Op Fl z +.Ar archive +.Nm +.Fl t +.Op Fl f +.Op Fl T +.Op Fl v +.Ar archive +.Op Ar +.Nm +.Fl x +.Op Fl C +.Op Fl T +.Op Fl f +.Op Fl o +.Op Fl u +.Op Fl v +.Ar archive +.Op Ar +.Nm +.Fl M +.Nm +.Fl V +.Sh DESCRIPTION +The +.Nm +utility creates and maintains groups of files combined into an +archive. +Once an archive has been created, new files can be added to it, and +existing files can be extracted, deleted or replaced. +.Pp +Files are named in the archive by their last file name component, +so if a file referenced by a path containing a +.Dq / +is archived, it will be named by the last component of the path. +Similarly when matching paths listed on the command line against +file names stored in the archive, only the last component of the +path will be compared. +.Pp +The normal use of +.Nm +is for the creation and maintenance of libraries suitable for use +with the link editor +.Xr ld 1 , +although it is not restricted to this purpose. +The +.Nm +utility can create and manage an archive symbol table (see +.Xr ar 5 ) +used to speed up link editing operations. +If a symbol table is present in an archive, it will be +kept up-to-date by subsequent operations on the archive. +.Sh OPTIONS +The +.Nm +utility supports the following options: +.Bl -tag -width indent +.It Fl a Ar member-after +When used with option +.Fl m +this option specifies that the archive members specified by +arguments +.Ar +are moved to after the archive member named by argument +.Ar member-after . +When used with option +.Fl r +this option specifies that the files specified by arguments +.Ar +are added after the archive member named by argument +.Ar member-after . +.It Fl b Ar member-before +When used with option +.Fl m +this option specifies that the archive members specified by +arguments +.Ar +are moved to before the archive member named by argument +.Ar member-before . +When used with option +.Fl r +this option specifies that the files specified by arguments +.Ar +are added before the archive member named by argument +.Ar member-before . +.It Fl c +Suppress the informational message printed when a new archive is +created using the +.Fl r +and +.Fl q +options. +.It Fl C +Prevent extracted files from replacing like-named files +in the file system. +.It Fl d +Delete the members named by arguments +.Ar +from the archive specified by argument +.Ar archive . +The archive's symbol table, if present, is updated to reflect +the new contents of the archive. +.It Fl D +When used in combination with the +.Fl r +or +.Fl q +option, insert 0's instead of the real mtime, uid and gid values +and 0644 instead of file mode from the members named by arguments +.Ar . +This ensures that checksums on the resulting archives are reproducible +when member contents are identical. +.It Fl f +Synonymous with option +.Fl T . +.It Fl F Ar flavor | Fl -flavor Ar flavor +Create archives with the specified archive format. +Legal values for argument +.Ar flavor +are: +.Bl -tag -width indent -compact +.It Ar bsd +Create BSD format archives. +.It Ar gnu +An alias for +.Ar svr4 . +.It Ar svr4 +Create SVR4 format archives. +.El +If this option is not specified, +.Nm +will create archives using the SVR4 format. +.It Fl i Ar member-before +Synonymous with option +.Fl b . +.It Fl j +This option is accepted for compatibility with the +.Tn FreeBSD +version of the +.Nm +utility, but is ignored. +.It Fl l +This option is accepted for compatibility with GNU +.Xr ar 1 , +but is ignored. +.It Fl m +Move archive members specified by arguments +.Ar +within the archive. +If a position has been specified by one of the +.Fl a , +.Fl b +or +.Fl i +options, the members are moved to before or after the specified +position. +If no position has been specified, the specified members are moved +to the end of the archive. +If the archive has a symbol table, it is updated to reflect the +new contents of the archive. +.It Fl M +Read and execute MRI librarian commands from standard input. +The commands understood by the +.Nm +utility are described in the section +.Sx "MRI Librarian Commands" . +.It Fl o +Preserve the original modification times of members when extracting +them. +.It Fl p +Write the contents of the specified archive members named by +arguments +.Ar +to standard output. +If no members were specified, the contents of all the files in the +archive are written in the order they appear in the archive. +.It Fl q +Append the files specified by arguments +.Ar +to the archive specified by argument +.Ar archive +without checking if the files already exist in the archive. +The archive symbol table will be updated as needed. +If the file specified by the argument +.Ar archive +does not already exist, a new archive will be created. +.It Fl r +Replace (add) the files specified by arguments +.Ar +in the archive specified by argument +.Ar archive , +creating the archive if necessary. +Replacing existing members will not change the order of members within +the archive. +If a file named in arguments +.Ar +does not exist, existing members in the archive that match that +name are not changed. +New files are added to the end of the archive unless one of the +positioning options +.Fl a , +.Fl b +or +.Fl i +is specified. +The archive symbol table, if it exists, is updated to reflect the +new state of the archive. +.It Fl s +Add an archive symbol table (see +.Xr ar 5 ) +to the archive specified by argument +.Ar archive . +Invoking +.Nm +with the +.Fl s +option alone is equivalent to invoking +.Xr ranlib 1 . +.It Fl S +Do not generate an archive symbol table. +.It Fl t +For +.Nm , +list the files specified by arguments +.Ar +in the order in which they appear in the archive, one per line. +If no files are specified, all files in the archive are listed. +.It Fl T +Use only the first fifteen characters of the archive member name or +command line file name argument when naming archive members. +.It Fl u +Conditionally update the archive or extract members. +When used with the +.Fl r +option, files named by arguments +.Ar +will be replaced in the archive if they are newer than their +archived versions. +When used with the +.Fl x +option, the members specified by arguments +.Ar +will be extracted only if they are newer than the corresponding +files in the file system. +.It Fl v +Provide verbose output. +When used with the +.Fl d , +.Fl m , +.Fl q +or +.Fl x +options, +.Nm +gives a file-by-file description of the archive modification being +performed, which consists of three white-space separated fields: +the option letter, a dash +.Dq "-" , +and the file name. +When used with the +.Fl r +option, +.Nm +displays the description as above, but the initial letter is an +.Dq a +if the file is added to the archive, or an +.Dq r +if the file replaces a file already in the archive. +When used with the +.Fl p +option, the name of the file enclosed in +.Dq < +and +.Dq > +characters is written to standard output preceded by a single newline +character and followed by two newline characters. +The contents of the named file follow the file name. +When used with the +.Fl t +option, +.Nm +displays eight whitespace separated fields: +the file permissions as displayed by +.Xr strmode 3 , +decimal user and group IDs separated by a slash ( +.Dq / Ns ) , +the file size in bytes, the file modification time in +.Xr strftime 3 +format +.Dq "%b %e %H:%M %Y" , +and the name of the file. +.It Fl V +Print a version identifier and exit. +.It Fl x +Extract archive members specified by arguments +.Ar +into the current directory. +If no members have been specified, extract all members of the archive. +If the file corresponding to an extracted member does not exist it +will be created. +If the file corresponding to an extracted member does exist, its owner +and group will not be changed while its contents will be overwritten +and its permissions will set to that entered in the archive. +The file's access and modification time would be that of the time +of extraction unless the +.Fl o +option was specified. +.It Fl z +This option is accepted for compatibility with the +.Tn FreeBSD +version of the +.Nm +utility, but is ignored. +.El +.Ss "MRI Librarian Commands" +If the +.Fl M +option is specified, the +.Nm +utility will read and execute commands from its standard input. +If standard input is a terminal, the +.Nm +utility will display the prompt +.Dq Li "AR >" +before reading a line, and will continue operation even if errors are +encountered. +If standard input is not a terminal, the +.Nm +utility will not display a prompt and will terminate execution on +encountering an error. +.Pp +Each input line contains a single command. +Words in an input line are separated by whitespace characters. +The first word of the line is the command, the remaining words are +the arguments to the command. +The command word may be specified in either case. +Arguments may be separated by commas or blanks. +.Pp +Empty lines are allowed and are ignored. +Long lines are continued by ending them with the +.Dq Li + +character. +.Pp +The +.Dq Li * +and +.Dq Li "\;" +characters start a comment. +Comments extend till the end of the line. +.Pp +When executing an MRI librarian script the +.Nm +utility works on a temporary copy of an archive. +Changes to the copy are made permanent using the +.Ic save +command. +.Pp +Commands understood by the +.Nm +utility are: +.Bl -tag -width indent +.It Ic addlib Ar archive | Ic addlib Ar archive Pq Ar member Oo Li , Ar member Oc Ns ... +Add the contents of the archive named by argument +.Ar archive +to the current archive. +If specific members are named using the arguments +.Ar member , +then those members are added to the current archive. +If no members are specified, the entire contents of the archive +are added to the current archive. +.It Ic addmod Ar member Oo Li , Ar member Oc Ns ... +Add the files named by arguments +.Ar member +to the current archive. +.It Ic clear +Discard all the contents of the current archive. +.It Ic create Ar archive +Create a new archive named by the argument +.Ar archive , +and makes it the current archive. +If the named archive already exists, it will be overwritten +when the +.Ic save +command is issued. +.It Ic delete Ar module Oo Li , Ar member Oc Ns ... +Delete the modules named by the arguments +.Ar member +from the current archive. +.It Ic directory Ar archive Po Ar member Oo Li , Ar member Oc Ns ... Pc Op Ar outputfile +List each named module in the archive. +The format of the output depends on the verbosity setting set using +the +.Ic verbose +command. +Output is sent to standard output, or to the file specified by +argument +.Ar outputfile . +.It Ic end +Exit successfully from the +.Nm +utility. +Any unsaved changes to the current archive will be discarded. +.It Ic extract Ar member Oo Li , Ar member Oc Ns ... +Extract the members named by the arguments +.Ar member +from the current archive. +.It Ic list +Display the contents of the current archive in verbose style. +.It Ic open Ar archive +Open the archive named by argument +.Ar archive +and make it the current archive. +.It Ic replace Ar member Oo Li , Ar member Oc Ns ... +Replace named members in the current archive with the files specified +by arguments +.Ar member . +The files must be present in the current directory and the named +modules must already exist in the current archive. +.It Ic save +Commit all changes to the current archive. +.It Ic verbose +Toggle the verbosity of the +.Ic directory +command. +.El +.Sh EXAMPLES +To create a new archive +.Pa ex.a +containing three files +.Pa ex1.o , +.Pa ex2.o +and +.Pa ex3.o , +use: +.Dl "ar -rc ex.a ex1.o ex2.o ex3.o" +.Pp +To add an archive symbol table to an existing archive +.Pa ex.a , +use: +.Dl "ar -s ex.a" +.Pp +To delete file +.Pa ex1.o +from archive +.Pa ex.a , +use: +.D1 "ar -d ex.a ex1.o" +.Pp +To verbosely list the contents of archive +.Pa ex.a , +use: +.D1 "ar -tv ex.a" +.Pp +To create a new archive +.Pa ex.a +containing the files +.Pa ex1.o , +and +.Pa ex2.o , +using MRI librarian commands, use the following script: +.Bd -literal -offset indent +create ex.a * specify the output archive +addmod ex1.o ex2.o * add modules +save * save pending changes +end * exit the utility +.Ed +.Sh DIAGNOSTICS +.Ex -std +.Sh SEE ALSO +.Xr ld 1 , +.Xr ranlib 1 , +.Xr archive 3 , +.Xr elf 3 , +.Xr strftime 3 , +.Xr strmode 3 , +.Xr ar 5 +.Sh STANDARDS COMPLIANCE +The +.Nm +utility's support for the +.Fl a , +.Fl b , +.Fl c , +.Fl i , +.Fl m , +.Fl p , +.Fl q , +.Fl r , +.Fl s , +.Fl t , +.Fl u , +.Fl v , +.Fl C +and +.Fl T +options is believed to be compliant with +.St -p1003.2 . +.Sh HISTORY +An +.Nm +command first appeared in AT&T UNIX Version 1. +In +.Fx 8.0 , +.An Kai Wang Aq Mt kaiw@FreeBSD.org +reimplemented +.Nm +using the +.Lb libarchive +and the +.Lb libelf . Property changes on: head/contrib/elftoolchain/ar/ar.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/elftoolchain/ar/ar.5 =================================================================== --- head/contrib/elftoolchain/ar/ar.5 (nonexistent) +++ head/contrib/elftoolchain/ar/ar.5 (revision 286070) @@ -0,0 +1,327 @@ +.\" Copyright (c) 2010 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: ar.5 3182 2015-04-10 16:08:10Z emaste $ +.\" +.Dd November 28, 2010 +.Os +.Dt AR 5 +.Sh NAME +.Nm ar +.Nd archive file format for +.Xr ar 1 +and +.Xr ranlib 1 +.Sh SYNOPSIS +.In ar.h +.Sh DESCRIPTION +.Xr ar 1 +archives are created and managed by the +.Xr ar 1 +and +.Xr ranlib 1 +utilities. +These archives are typically used during program development to +hold libraries of program objects. +An +.Xr ar 1 +archive is contained in a single operating system file. +.Pp +This manual page documents two variants of the +.Xr ar 1 +archive format: the BSD archive format, and the SVR4/GNU archive +format. +.Pp +In both variants the archive file starts with an identifying byte +sequence of the seven ASCII characters +.Sq Li "!" +followed by a ASCII linefeed character +.Po +see the constant +.Dq ARMAG +in the header file +.In ar.h +.Pc . +.Pp +Archive members follow the initial identifying byte sequence. +Each archive member is prefixed by a fixed size header describing the +file attributes associated with the member. +.Ss "Archive Headers" +An archive header describes the file attributes for the archive member that +follows it. +The +.Xr ar 5 +format only supports a limited number of attributes: the file name, +the file creation time stamp, the uid and gid of the creator, the file +mode and the file size. +.Pp +Archive headers are placed at an even byte offset in the archive file. +If the data for an archive member ends at an odd byte offset, then a +padding byte with value 0x0A is used to position the next archive +header on an even byte offset. +.Pp +An archive header comprises the following fixed sized fields: +.Bl -tag -width "Li ar_name" +.It Ar ar_name +(16 bytes) The file name of the archive member. +The format of this field varies between the BSD and SVR4/GNU formats and +is described in more detail in the section +.Sx "Representing File Names" +below. +.It Ar ar_date +(12 bytes) The file modification time for the member in seconds since the +epoch, encoded as a decimal number. +.It Ar ar_uid +(6 bytes) The uid associated with the archive member, encoded as a +decimal number. +.It Ar ar_gid +(6 bytes) The gid associated with the archive member, encoded as a +decimal number. +.It Ar ar_mode +(8 bytes) The file mode for the archive member, encoded as an octal +number. +.It Ar ar_size +(10 bytes) In the SVR4/GNU archive format this field holds the size in +bytes of the archive member, encoded as a decimal number. +In the BSD archive format, for short file names, this field +holds the size in bytes of the archive member, encoded as a decimal +number. +For long file names +.Po +see +.Sx "Representing File Names" +below +.Pc , +the field contains the combined size of the +archive member and its file name, encoded as a decimal number. +.It Ar ar_fmag +(2 bytes) This field holds 2 bytes with values 0x96 and 0x0A +respectively, marking the end of the header. +.El +.Pp +Unused bytes in the fields of an archive header are set to the value +0x20. +.Ss "Representing File Names" +The BSD and SVR4/GNU variants use different schemes for encoding file +names for members. +.Bl -tag -width "SVR4/GNU" +.It "BSD" +File names that are up to 16 bytes long and which do not contain +embedded spaces are stored directly in the +.Ar ar_name +field of the archive header. +File names that are either longer than 16 bytes or which contain +embedded spaces are stored immediately after the archive header +and the +.Ar ar_name +field of the archive header is set to the string +.Dq "#1/" +followed by a decimal representation of the number of bytes needed for +the file name. +In addition, the +.Ar ar_size +field of the archive header is set to the decimal representation of +the combined sizes of the archive member and the file name. +The file contents of the member follows the file name without further +padding. +.Pp +As an example, if the file name for a member was +.Dq "A B" +and its contents was the string +.Dq "C D" , +then the +.Ar ar_name +field of the header would contain +.Dq Li "#1/3" , +the +.Ar ar_size +field of the header would contain +.Dq Li 6 , +and the bytes immediately following the header would be 0x41, 0x20, +0x42, 0x43, 0x20 and 0x44 +.Po +ASCII +.Dq "A BC D" +.Pc . +.It "SVR4/GNU" +File names that are up to 15 characters long are stored directly in the +.Ar ar_name +field of the header, terminated by a +.Dq Li / +character. +.Pp +If the file name is larger than would fit in space for the +.Ar ar_name +field, then the actual file name is kept in the archive +string table +.Po +see +.Sx "Archive String Tables" +below +.Pc , +and the decimal offset of the file name in the string table is stored +in the +.Ar ar_name +field, prefixed by a +.Dq Li / +character. +.Pp +As an example, if the real file name has been stored at offset 768 in +the archive string table, the +.Ar ar_name +field of the header will contain the string +.Dq /768 . +.El +.Ss "Special Archive Members" +The following archive members are special. +.Bl -tag -width indent +.It Dq Li / +In the SVR4/GNU variant of the archive format, the archive member with +name +.Dq Li / +denotes an archive symbol table. +If present, this member will be the very first member in the +archive. +.It Dq Li // +In the SVR4/GNU variant of the archive format, the archive member with +name +.Dq Li // +denotes the archive string table. +This special member is used to hold filenames that do not fit in the +file name field of the header +.Po +see +.Sx "Representing File Names" +above +.Pc . +If present, this member immediately follows the archive symbol table +if an archive symbol table is present, or is the first member otherwise. +.It Dq Li "__.SYMDEF" +This special member contains the archive symbol table in the BSD +variant of the archive format. +If present, this member will be the very first member in the +archive. +.El +.Ss "Archive String Tables" +An archive string table is used in the SVR4/GNU archive format to hold +file names that are too large to fit into the constraints of the +.Ar ar_name +field of the archive header. +An archive string table contains a sequence of file names. +Each file name in the archive string table is terminated by the +byte sequence 0x2F, 0x0A +.Po +the ASCII string +.Dq "/\en" +.Pc . +No padding is used to separate adjacent file names. +.Ss "Archive Symbol Tables" +Archive symbol tables are used to speed up link editing by providing a +mapping between the program symbols defined in the archive +and the corresponding archive members. +Archive symbol tables are managed by the +.Xr ranlib 1 +utility. +.Pp +The format of archive symbol tables is as follows: +.Bl -tag -width "SVR4/GNU" +.It BSD +In the BSD archive format, the archive symbol table comprises +of two parts: a part containing an array of +.Vt "struct ranlib" +descriptors, followed by a part containing a symbol string table. +The sizes and layout of the structures that make up a BSD format +archive symbol table are machine dependent. +.Pp +The part containing +.Vt "struct ranlib" +descriptors begins with a field containing the size in bytes of the +array of +.Vt "struct ranlib" +descriptors encoded as a C +.Vt long +value. +.Pp +The array of +.Vt "struct ranlib" +descriptors follows the size field. +Each +.Vt "struct ranlib" +descriptor describes one symbol. +.Pp +A +.Vt "struct ranlib" +descriptor comprises two fields: +.Bl -tag -width "Ar ran_strx" -compact +.It Ar ran_strx +.Pq C Vt long +This field contains the zero-based offset of the symbol name in the +symbol string table. +.It Ar ran_off +.Pq C Vt long +This field is the file offset to the archive header for the archive +member defining the symbol. +.El +.Pp +The part containing the symbol string table begins with a field +containing the size in bytes of the string table, encoded as a C +.Vt long +value. +This string table follows the size field, and contains +NUL-terminated strings for the symbols in the symbol table. +.It SVR4/GNU +In the SVR4/GNU archive format, the archive symbol table starts with a +4-byte binary value containing the number of entries contained in the +archive symbol table. +This count of entries is stored most significant byte first. +.Pp +Next, there are +.Ar count +4-byte numbers, each stored most significant byte first. +Each number is a binary offset to the archive header for the member in +the archive file for the corresponding symbol table entry. +.Pp +After the binary offset values, there are +.Ar count +NUL-terminated strings in sequence, holding the symbol names for +the corresponding symbol table entries. +.El +.Sh STANDARDS COMPLIANCE +The +.Xr ar 1 +archive format is not currently specified by a standard. +.Pp +This manual page documents the +.Xr ar 1 +archive formats used by the +.Bx 4.4 +and +.Ux SVR4 +operating system releases. +.Sh SEE ALSO +.Xr ar 1 , +.Xr ld 1 , +.Xr ranlib 1 , +.Xr elf 3 , +.Xr elf_getarsym 3 , +.Xr elf_rand 3 Property changes on: head/contrib/elftoolchain/ar/ar.5 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/elftoolchain/ar/ar.c =================================================================== --- head/contrib/elftoolchain/ar/ar.c (nonexistent) +++ head/contrib/elftoolchain/ar/ar.c (revision 286070) @@ -0,0 +1,433 @@ +/*- + * Copyright (c) 2007 Kai Wang + * Copyright (c) 2007 Tim Kientzle + * Copyright (c) 2007 Joseph Koshy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Hugh Smith at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar.h" + +ELFTC_VCSID("$Id: ar.c 3183 2015-04-10 16:18:42Z emaste $"); + +enum options +{ + OPTION_HELP +}; + +static struct option longopts[] = +{ + {"flavor", required_argument, NULL, 'F'}, + {"help", no_argument, NULL, OPTION_HELP}, + {"version", no_argument, NULL, 'V'}, + {NULL, 0, NULL, 0} +}; + +static void bsdar_usage(void); +static void ranlib_usage(void); +static void set_mode(struct bsdar *bsdar, char opt); +static void only_mode(struct bsdar *bsdar, const char *opt, + const char *valid_modes); +static void bsdar_version(void); + +int +main(int argc, char **argv) +{ + struct bsdar *bsdar, bsdar_storage; + char *arcmd, *argv1_saved; + size_t len; + int i, opt; + + bsdar = &bsdar_storage; + memset(bsdar, 0, sizeof(*bsdar)); + + arcmd = argv1_saved = NULL; + bsdar->output = stdout; + + if ((bsdar->progname = ELFTC_GETPROGNAME()) == NULL) + bsdar->progname = "ar"; + + if (elf_version(EV_CURRENT) == EV_NONE) + bsdar_errc(bsdar, 0, "ELF library initialization failed: %s", + elf_errmsg(-1)); + + /* + * Act like ranlib if our name ends in "ranlib"; this + * accommodates names like "arm-freebsd7.1-ranlib", + * "bsdranlib", etc. + */ + len = strlen(bsdar->progname); + if (len >= strlen("ranlib") && + strcmp(bsdar->progname + len - strlen("ranlib"), "ranlib") == 0) { + while ((opt = getopt_long(argc, argv, "tDV", longopts, + NULL)) != -1) { + switch(opt) { + case 't': + /* Ignored. */ + break; + case 'D': + bsdar->options |= AR_D; + break; + case 'V': + bsdar_version(); + break; + case OPTION_HELP: + ranlib_usage(); + default: + ranlib_usage(); + } + } + argv += optind; + argc -= optind; + + if (*argv == NULL) + ranlib_usage(); + + bsdar->options |= AR_S; + for (;(bsdar->filename = *argv++) != NULL;) + ar_write_archive(bsdar, 's'); + + exit(EXIT_SUCCESS); + } else { + if (argc < 2) + bsdar_usage(); + + /* + * Tack on a leading '-', for old-style usage. + */ + if (*argv[1] != '-') { + argv1_saved = argv[1]; + len = strlen(argv[1]) + 2; + if ((arcmd = malloc(len)) == NULL) + bsdar_errc(bsdar, errno, "malloc failed"); + (void) snprintf(arcmd, len, "-%s", argv[1]); + argv[1] = arcmd; + } + } + + while ((opt = getopt_long(argc, argv, "abCcdDfF:ijlMmopqrSsTtuVvxz", + longopts, NULL)) != -1) { + switch(opt) { + case 'a': + bsdar->options |= AR_A; + break; + case 'b': + case 'i': + bsdar->options |= AR_B; + break; + case 'C': + bsdar->options |= AR_CC; + break; + case 'c': + bsdar->options |= AR_C; + break; + case 'd': + set_mode(bsdar, opt); + break; + case 'D': + bsdar->options |= AR_D; + break; + case 'F': + if (!strcasecmp(optarg, "svr4") || + !strcasecmp(optarg, "gnu")) + bsdar->options &= ~AR_BSD; + else if (!strcasecmp(optarg, "bsd")) + bsdar->options |= AR_BSD; + else + bsdar_usage(); + break; + case 'f': + case 'T': + bsdar->options |= AR_TR; + break; + case 'j': + /* ignored */ + break; + case 'l': + /* ignored, for GNU ar comptibility */ + break; + case 'M': + set_mode(bsdar, opt); + break; + case 'm': + set_mode(bsdar, opt); + break; + case 'o': + bsdar->options |= AR_O; + break; + case 'p': + set_mode(bsdar, opt); + break; + case 'q': + set_mode(bsdar, opt); + break; + case 'r': + set_mode(bsdar, opt); + break; + case 'S': + bsdar->options |= AR_SS; + break; + case 's': + bsdar->options |= AR_S; + break; + case 't': + set_mode(bsdar, opt); + break; + case 'u': + bsdar->options |= AR_U; + break; + case 'V': + bsdar_version(); + break; + case 'v': + bsdar->options |= AR_V; + break; + case 'x': + set_mode(bsdar, opt); + break; + case 'z': + /* ignored */ + break; + case OPTION_HELP: + bsdar_usage(); + default: + bsdar_usage(); + } + } + + /* Restore argv[1] if we had modified it. */ + if (arcmd != NULL) { + argv[1] = argv1_saved; + free(arcmd); + arcmd = argv1_saved = NULL; + } + + argv += optind; + argc -= optind; + + if (*argv == NULL && bsdar->mode != 'M') + bsdar_usage(); + + if (bsdar->options & AR_A && bsdar->options & AR_B) + bsdar_errc(bsdar, 0, + "only one of -a and -[bi] options allowed"); + + if (bsdar->options & AR_J && bsdar->options & AR_Z) + bsdar_errc(bsdar, 0, + "only one of -j and -z options allowed"); + + if (bsdar->options & AR_S && bsdar->options & AR_SS) + bsdar_errc(bsdar, 0, + "only one of -s and -S options allowed"); + + if (bsdar->options & (AR_A | AR_B)) { + if (*argv == NULL) + bsdar_errc(bsdar, 0, + "no position operand specified"); + if ((bsdar->posarg = basename(*argv)) == NULL) + bsdar_errc(bsdar, errno, + "basename failed"); + argc--; + argv++; + } + + if (bsdar->options & AR_A) + only_mode(bsdar, "-a", "mqr"); + if (bsdar->options & AR_B) + only_mode(bsdar, "-b", "mqr"); + if (bsdar->options & AR_C) + only_mode(bsdar, "-c", "qr"); + if (bsdar->options & AR_CC) + only_mode(bsdar, "-C", "x"); + if (bsdar->options & AR_D) + only_mode(bsdar, "-D", "qr"); + if (bsdar->options & AR_O) + only_mode(bsdar, "-o", "x"); + if (bsdar->options & AR_SS) + only_mode(bsdar, "-S", "mqr"); + if (bsdar->options & AR_U) + only_mode(bsdar, "-u", "qrx"); + + if (bsdar->mode == 'M') { + ar_mode_script(bsdar); + exit(EXIT_SUCCESS); + } + + if ((bsdar->filename = *argv) == NULL) + bsdar_usage(); + + bsdar->argc = --argc; + bsdar->argv = ++argv; + + if ((!bsdar->mode || strchr("ptx", bsdar->mode)) && + bsdar->options & AR_S) { + ar_write_archive(bsdar, 's'); + if (!bsdar->mode) + exit(EXIT_SUCCESS); + } + + switch(bsdar->mode) { + case 'd': case 'm': case 'q': case 'r': + ar_write_archive(bsdar, bsdar->mode); + break; + + case 'p': case 't': case 'x': + ar_read_archive(bsdar, bsdar->mode); + break; + default: + bsdar_usage(); + /* NOTREACHED */ + } + + for (i = 0; i < bsdar->argc; i++) + if (bsdar->argv[i] != NULL) + bsdar_warnc(bsdar, 0, "%s: not found in archive", + bsdar->argv[i]); + + exit(EXIT_SUCCESS); +} + +static void +set_mode(struct bsdar *bsdar, char opt) +{ + + if (bsdar->mode != '\0' && bsdar->mode != opt) + bsdar_errc(bsdar, 0, "Can't specify both -%c and -%c", + opt, bsdar->mode); + bsdar->mode = opt; +} + +static void +only_mode(struct bsdar *bsdar, const char *opt, const char *valid_modes) +{ + + if (strchr(valid_modes, bsdar->mode) == NULL) + bsdar_errc(bsdar, 0, "Option %s is not permitted in mode -%c", + opt, bsdar->mode); +} + +#define AR_USAGE_MESSAGE "\ +Usage: %s [options] archive file...\n\ + Manage archives.\n\n\ + Where is one of:\n\ + -d Delete members from the archive.\n\ + -m Move archive members within the archive.\n\ + -p Write the contents of members to standard output.\n\ + -q Append files to an archive.\n\ + -r Replace (add) files to an archive.\n\ + -s Add an archive symbol to an archive.\n\ + -t List files in an archive.\n\ + -x Extract members from an archive.\n\ + -M Execute MRI librarian commands.\n\ + -V Print a version identifier and exit.\n\n\ + Options:\n\ + -a MEMBER Add members after the specified member.\n\ + -b MEMBER | -i MEMBER\n\ + Add members before the specified member.\n\ + -c Do not print a message when creating a new archive.\n\ + -f | -T Only use the first fifteen characters of the member name.\n\ + -j (This option is accepted, but is ignored).\n\ + -l (This option is accepted, but is ignored).\n\ + -o Preserve modification times when extracting members.\n\ + -u Conditionally update or extract members.\n\ + -v Be verbose.\n\ + -z (This option is accepted, but is ignored).\n\ + -C Do not overwrite existing files in the file system.\n\ + -D Use fixed metadata, for consistent archive checksums.\n\ + -F FORMAT | --flavor=FORMAT\n\ + Create archives with the specified format.\n\ + -S Do not generate an archive symbol table.\n" + +static void +bsdar_usage(void) +{ + (void) fprintf(stderr, AR_USAGE_MESSAGE, ELFTC_GETPROGNAME()); + exit(EXIT_FAILURE); +} + +#define RANLIB_USAGE_MESSAGE "\ +Usage: %s [options] archive...\n\ + Update or create archive symbol tables.\n\n\ + Options:\n\ + -t (This option is accepted, but ignored).\n\ + -D Use fixed metadata, for consistent archive checksums.\n\ + -V Print a version identifier and exit.\n" + +static void +ranlib_usage(void) +{ + (void)fprintf(stderr, RANLIB_USAGE_MESSAGE, ELFTC_GETPROGNAME()); + exit(EXIT_FAILURE); +} + +static void +bsdar_version(void) +{ + (void)printf("%s (%s, %s)\n", ELFTC_GETPROGNAME(), archive_version_string(), + elftc_version()); + exit(EXIT_SUCCESS); +} Property changes on: head/contrib/elftoolchain/ar/ar.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/elftoolchain/ar/ranlib.1 =================================================================== --- head/contrib/elftoolchain/ar/ranlib.1 (nonexistent) +++ head/contrib/elftoolchain/ar/ranlib.1 (revision 286070) @@ -0,0 +1,86 @@ +.\" Copyright (c) 2007,2009-2012 Joseph Koshy. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" This software is provided by Joseph Koshy ``as is'' and +.\" any express or implied warranties, including, but not limited to, the +.\" implied warranties of merchantability and fitness for a particular purpose +.\" are disclaimed. in no event shall Joseph Koshy be liable +.\" for any direct, indirect, incidental, special, exemplary, or consequential +.\" damages (including, but not limited to, procurement of substitute goods +.\" or services; loss of use, data, or profits; or business interruption) +.\" however caused and on any theory of liability, whether in contract, strict +.\" liability, or tort (including negligence or otherwise) arising in any way +.\" out of the use of this software, even if advised of the possibility of +.\" such damage. +.\" +.\" $Id: ranlib.1 3195 2015-05-12 17:22:19Z emaste $ +.\" +.Dd December 9, 2012 +.Os +.Dt RANLIB 1 +.Sh NAME +.Nm ranlib +.Nd update archive symbol tables +.Sh SYNOPSIS +.Nm +.Op Fl D +.Op Fl t +.Ar archive Ns ... +.Nm +.Fl V +.Sh DESCRIPTION +The +.Nm ranlib +utility is used to update an existing archive symbol table in an +.Xr ar 1 +archive, or to add an archive symbol table to an archive lacking one. +.Sh OPTIONS +The +.Nm +utility supports the following options: +.Bl -tag -width indent +.It Fl D +Use zeros for the mtime, uid and gid fields, and use mode 0644 for the +file mode field for all archive member headers. +This ensures that checksums on the resulting archives are reproducible +when member contents are identical. +.It Fl t +This option is accepted, but is ignored. +.It Fl V +Print a version identifier and exit. +.El +.Sh EXAMPLES +To update the archive symbol table for an archive +.Pa lib.a , +use: +.Dl "ranlib lib.a" +.Sh DIAGNOSTICS +.Ex -std +.Sh SEE ALSO +.Xr ar 1 , +.Xr ld 1 , +.Xr archive 3 , +.Xr elf 3 , +.Xr ar 5 +.Sh HISTORY +The +.Nm +command first appeared in AT&T UNIX Version 7. +.Pp +In +.Fx 8.0 , +.An Kai Wang Aq Mt kaiw@FreeBSD.org +reimplemented +.Nm +using the +.Lb libarchive +and the +.Lb libelf . Property changes on: head/contrib/elftoolchain/ar/ranlib.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/elftoolchain/ar/read.c =================================================================== --- head/contrib/elftoolchain/ar/read.c (nonexistent) +++ head/contrib/elftoolchain/ar/read.c (revision 286070) @@ -0,0 +1,199 @@ +/*- + * Copyright (c) 2007 Kai Wang + * Copyright (c) 2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ar.h" + +ELFTC_VCSID("$Id: read.c 3180 2015-04-09 15:13:57Z emaste $"); + +/* + * Handle read modes: 'x', 't' and 'p'. + */ +void +ar_read_archive(struct bsdar *bsdar, int mode) +{ + FILE *out; + struct archive *a; + struct archive_entry *entry; + struct stat sb; + struct tm *tp; + const char *bname; + const char *name; + mode_t md; + size_t size; + time_t mtime; + uid_t uid; + gid_t gid; + char **av; + char buf[25]; + char find; + int i, flags, r; + + assert(mode == 'p' || mode == 't' || mode == 'x'); + + if ((a = archive_read_new()) == NULL) + bsdar_errc(bsdar, 0, "archive_read_new failed"); + archive_read_support_format_ar(a); + AC(archive_read_open_filename(a, bsdar->filename, DEF_BLKSZ)); + + out = bsdar->output; + + for (;;) { + r = archive_read_next_header(a, &entry); + if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY || + r == ARCHIVE_FATAL) + bsdar_warnc(bsdar, 0, "%s", archive_error_string(a)); + if (r == ARCHIVE_EOF || r == ARCHIVE_FATAL) + break; + if (r == ARCHIVE_RETRY) { + bsdar_warnc(bsdar, 0, "Retrying..."); + continue; + } + + if (archive_format(a) == ARCHIVE_FORMAT_AR_BSD) + bsdar->options |= AR_BSD; + else + bsdar->options &= ~AR_BSD; + + if ((name = archive_entry_pathname(entry)) == NULL) + break; + + /* Skip pseudo members. */ + if (bsdar_is_pseudomember(bsdar, name)) + continue; + + if (bsdar->argc > 0) { + find = 0; + for(i = 0; i < bsdar->argc; i++) { + av = &bsdar->argv[i]; + if (*av == NULL) + continue; + if ((bname = basename(*av)) == NULL) + bsdar_errc(bsdar, errno, + "basename failed"); + if (strcmp(bname, name) != 0) + continue; + + *av = NULL; + find = 1; + break; + } + if (!find) + continue; + } + + if (mode == 't') { + if (bsdar->options & AR_V) { + md = archive_entry_mode(entry); + uid = archive_entry_uid(entry); + gid = archive_entry_gid(entry); + size = archive_entry_size(entry); + mtime = archive_entry_mtime(entry); + (void)fprintf(out, "%s %6d/%-6d %8ju ", + bsdar_strmode(md) + 1, uid, gid, + (uintmax_t)size); + tp = localtime(&mtime); + (void)strftime(buf, sizeof(buf), + "%b %e %H:%M %Y", tp); + (void)fprintf(out, "%s %s", buf, name); + } else + (void)fprintf(out, "%s", name); + r = archive_read_data_skip(a); + if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY || + r == ARCHIVE_FATAL) { + (void)fprintf(out, "\n"); + bsdar_warnc(bsdar, 0, "%s", + archive_error_string(a)); + } + + if (r == ARCHIVE_FATAL) + break; + + (void)fprintf(out, "\n"); + } else { + /* mode == 'x' || mode = 'p' */ + if (mode == 'p') { + if (bsdar->options & AR_V) { + (void)fprintf(out, "\n<%s>\n\n", + name); + fflush(out); + } + r = archive_read_data_into_fd(a, fileno(out)); + } else { + /* mode == 'x' */ + if (stat(name, &sb) != 0) { + if (errno != ENOENT) { + bsdar_warnc(bsdar, 0, + "stat %s failed", + bsdar->filename); + continue; + } + } else { + /* stat success, file exist */ + if (bsdar->options & AR_CC) + continue; + if (bsdar->options & AR_U && + archive_entry_mtime(entry) <= + sb.st_mtime) + continue; + } + + if (bsdar->options & AR_V) + (void)fprintf(out, "x - %s\n", name); + /* Disallow absolute paths. */ + if (name[0] == '/') { + bsdar_warnc(bsdar, 0, + "Absolute path '%s'", name); + continue; + } + /* Basic path security flags. */ + flags = ARCHIVE_EXTRACT_SECURE_SYMLINKS | + ARCHIVE_EXTRACT_SECURE_NODOTDOT; + if (bsdar->options & AR_O) + flags |= ARCHIVE_EXTRACT_TIME; + + r = archive_read_extract(a, entry, flags); + } + + if (r) + bsdar_warnc(bsdar, 0, "%s", + archive_error_string(a)); + } + } + AC(archive_read_close(a)); + ACV(archive_read_free(a)); +} Property changes on: head/contrib/elftoolchain/ar/read.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/elftoolchain/ar/write.c =================================================================== --- head/contrib/elftoolchain/ar/write.c (nonexistent) +++ head/contrib/elftoolchain/ar/write.c (revision 286070) @@ -0,0 +1,975 @@ +/*- + * Copyright (c) 2007 Kai Wang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar.h" + +ELFTC_VCSID("$Id: write.c 3183 2015-04-10 16:18:42Z emaste $"); + +#define _ARMAG_LEN 8 /* length of the magic string */ +#define _ARHDR_LEN 60 /* length of the archive header */ +#define _INIT_AS_CAP 128 /* initial archive string table size */ +#define _INIT_SYMOFF_CAP (256*(sizeof(uint32_t))) /* initial so table size */ +#define _INIT_SYMNAME_CAP 1024 /* initial sn table size */ +#define _MAXNAMELEN_SVR4 15 /* max member name length in svr4 variant */ +#define _MAXNAMELEN_BSD 16 /* max member name length in bsd variant */ +#define _TRUNCATE_LEN 15 /* number of bytes to keep for member name */ + +static void add_to_ar_str_table(struct bsdar *bsdar, const char *name); +static void add_to_ar_sym_table(struct bsdar *bsdar, const char *name); +static struct ar_obj *create_obj_from_file(struct bsdar *bsdar, + const char *name, time_t mtime); +static void create_symtab_entry(struct bsdar *bsdar, Elf *e); +static void free_obj(struct ar_obj *obj); +static void insert_obj(struct bsdar *bsdar, struct ar_obj *obj, + struct ar_obj *pos); +static void read_objs(struct bsdar *bsdar, const char *archive, + int checkargv); +static void write_cleanup(struct bsdar *bsdar); +static void write_data(struct bsdar *bsdar, struct archive *a, + const void *buf, size_t s); +static void write_objs(struct bsdar *bsdar); + +/* + * Create an object from a file, and return the created object + * descriptor. Return NULL if either an error occurs, or if the '-u' + * option was specified and the member is not newer than the existing + * one in the archive. + */ +static struct ar_obj * +create_obj_from_file(struct bsdar *bsdar, const char *name, time_t mtime) +{ + struct ar_obj *obj; + struct stat sb; + const char *bname; + char *tmpname; + int fd; + + if (name == NULL) + return (NULL); + + obj = malloc(sizeof(struct ar_obj)); + if (obj == NULL) + bsdar_errc(bsdar, errno, "malloc failed"); + + obj->elf = NULL; + + if ((fd = open(name, O_RDONLY, 0)) < 0) { + bsdar_warnc(bsdar, errno, "can't open file: %s", name); + free(obj); + return (NULL); + } + + tmpname = strdup(name); + if ((bname = basename(tmpname)) == NULL) + bsdar_errc(bsdar, errno, "basename failed"); + if (bsdar->options & AR_TR && strlen(bname) > _TRUNCATE_LEN) { + if ((obj->name = malloc(_TRUNCATE_LEN + 1)) == NULL) + bsdar_errc(bsdar, errno, "malloc failed"); + (void)strncpy(obj->name, bname, _TRUNCATE_LEN); + obj->name[_TRUNCATE_LEN] = '\0'; + } else + if ((obj->name = strdup(bname)) == NULL) + bsdar_errc(bsdar, errno, "strdup failed"); + free(tmpname); + + if (fstat(fd, &sb) < 0) { + bsdar_warnc(bsdar, errno, "can't fstat file: %s", obj->name); + goto giveup; + } + if (!S_ISREG(sb.st_mode)) { + bsdar_warnc(bsdar, 0, "%s is not an ordinary file", obj->name); + goto giveup; + } + + if (sb.st_dev == bsdar->ar_dev && sb.st_ino == bsdar->ar_ino) { + bsdar_warnc(bsdar, 0, "cannot add archive \"%s\" to itself", + obj->name); + goto giveup; + } + + /* + * If the '-u' option is specified and member is not newer + * than the existing one, we should not replace the member. + * However, if mtime == 0, i.e., if nonexistent members are to + * be forcibly replaced, then the '-u' option is to be ignored. + */ + if (mtime != 0 && bsdar->options & AR_U && sb.st_mtime <= mtime) + goto giveup; + + /* + * When the '-D' option is specified, the mtime and UID/GID of + * the member will be set to 0, and the file mode will be set + * to 644. This ensures that checksums will match for two + * archives containing identical content. + */ + if (bsdar->options & AR_D) { + obj->uid = 0; + obj->gid = 0; + obj->mtime = 0; + obj->md = S_IFREG | 0644; + } else { + obj->uid = sb.st_uid; + obj->gid = sb.st_gid; + obj->mtime = sb.st_mtime; + obj->md = sb.st_mode; + } + obj->size = sb.st_size; + obj->dev = sb.st_dev; + obj->ino = sb.st_ino; + + if (obj->size == 0) { + return (obj); + } + + if ((obj->elf = elf_open(fd)) == NULL) { + bsdar_warnc(bsdar, 0, "file initialization failed for %s: %s", + obj->name, elf_errmsg(-1)); + goto giveup; + } + + /* + * Read the object fully into memory and close its file + * descriptor. + */ + if (elf_cntl(obj->elf, ELF_C_FDREAD) < 0) { + bsdar_warnc(bsdar, 0, "%s could not be read in: %s", + obj->name, elf_errmsg(-1)); + goto giveup; + } + + if (close(fd) < 0) + bsdar_errc(bsdar, errno, "close failed: %s", + obj->name); + + return (obj); + +giveup: + if (obj->elf) + elf_end(obj->elf); + + if (close(fd) < 0) + bsdar_errc(bsdar, errno, "close failed: %s", + obj->name); + free(obj->name); + free(obj); + return (NULL); +} + +/* + * Free an object and its associated allocations. + */ +static void +free_obj(struct ar_obj *obj) +{ + if (obj->elf) + elf_end(obj->elf); + + free(obj->name); + free(obj); +} + +/* + * Insert an object into a list, either before/after the 'pos' obj or + * at the end of the list. + */ +static void +insert_obj(struct bsdar *bsdar, struct ar_obj *obj, struct ar_obj *pos) +{ + if (obj == NULL) + bsdar_errc(bsdar, 0, "try to insert a null obj"); + + if (pos == NULL || obj == pos) + /* + * If the object to move happens to be the position + * obj, or if there is no position obj, move the + * object to the end. + */ + goto tail; + + if (bsdar->options & AR_B) { + TAILQ_INSERT_BEFORE(pos, obj, objs); + return; + } + if (bsdar->options & AR_A) { + TAILQ_INSERT_AFTER(&bsdar->v_obj, pos, obj, objs); + return; + } + +tail: + TAILQ_INSERT_TAIL(&bsdar->v_obj, obj, objs); + +} + +/* + * Read objects from archive into the 'v_obj' list. Note that + * 'checkargv' is set when read_objs() is used to read objects from + * the target of 'ADDLIB' command in ar script mode; in this case the + * 'argv' array specifies the members that 'ADDLIB' is to operate on. + */ +static void +read_objs(struct bsdar *bsdar, const char *archive, int checkargv) +{ + struct archive *a; + struct archive_entry *entry; + struct ar_obj *obj; + const char *name; + const char *bname; + char *buff; + char **av; + size_t size; + int i, r, find; + + if ((a = archive_read_new()) == NULL) + bsdar_errc(bsdar, 0, "archive_read_new failed"); + archive_read_support_format_ar(a); + AC(archive_read_open_filename(a, archive, DEF_BLKSZ)); + for (;;) { + r = archive_read_next_header(a, &entry); + if (r == ARCHIVE_FATAL) + bsdar_errc(bsdar, 0, "%s", archive_error_string(a)); + if (r == ARCHIVE_EOF) + break; + if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY) + bsdar_warnc(bsdar, 0, "%s", archive_error_string(a)); + if (r == ARCHIVE_RETRY) { + bsdar_warnc(bsdar, 0, "Retrying..."); + continue; + } + + name = archive_entry_pathname(entry); + + /* + * Skip pseudo members. + */ + if (bsdar_is_pseudomember(bsdar, name)) + continue; + + /* + * If 'checkargv' is set, only read those members + * specified in argv. + */ + if (checkargv && bsdar->argc > 0) { + find = 0; + for(i = 0; i < bsdar->argc; i++) { + av = &bsdar->argv[i]; + if (*av == NULL) + continue; + if ((bname = basename(*av)) == NULL) + bsdar_errc(bsdar, errno, + "basename failed"); + if (strcmp(bname, name) != 0) + continue; + + *av = NULL; + find = 1; + break; + } + if (!find) + continue; + } + + size = archive_entry_size(entry); + + if (size > 0) { + if ((buff = malloc(size)) == NULL) + bsdar_errc(bsdar, errno, "malloc failed"); + if (archive_read_data(a, buff, size) != (ssize_t)size) { + bsdar_warnc(bsdar, 0, "%s", + archive_error_string(a)); + free(buff); + continue; + } + } else + buff = NULL; + + obj = malloc(sizeof(struct ar_obj)); + if (obj == NULL) + bsdar_errc(bsdar, errno, "malloc failed"); + obj->elf = NULL; + if (buff) { + obj->elf = elf_openmemory(buff, size); + if (obj->elf == NULL) { + bsdar_warnc(bsdar, 0, "elf_openmemory() " + "failed for %s: %s", name, + elf_errmsg(-1)); + free(buff); + free(obj); + continue; + } + } + if ((obj->name = strdup(name)) == NULL) + bsdar_errc(bsdar, errno, "strdup failed"); + obj->size = size; + obj->uid = archive_entry_uid(entry); + obj->gid = archive_entry_gid(entry); + obj->md = archive_entry_mode(entry); + obj->mtime = archive_entry_mtime(entry); + obj->dev = 0; + obj->ino = 0; + + TAILQ_INSERT_TAIL(&bsdar->v_obj, obj, objs); + } + AC(archive_read_close(a)); + ACV(archive_read_free(a)); +} + +/* + * Write an archive. + */ +void +ar_write_archive(struct bsdar *bsdar, int mode) +{ + struct ar_obj *nobj, *obj, *obj_temp, *pos; + struct stat sb; + const char *bname; + char **av; + int i; + + TAILQ_INIT(&bsdar->v_obj); + nobj = NULL; + pos = NULL; + memset(&sb, 0, sizeof(sb)); + + assert(mode == 'A' || mode == 'd' || mode == 'm' || mode == 'q' || + mode == 'r' || mode == 's'); + + /* + * Test if the specified archive exists, to determine + * whether we are creating a new archive. + */ + if (stat(bsdar->filename, &sb) != 0) { + if (errno != ENOENT) { + bsdar_warnc(bsdar, 0, "stat %s failed", + bsdar->filename); + return; + } + + /* We do not create archive in mode 'd', 'm' and 's'. */ + if (mode != 'r' && mode != 'q') { + bsdar_warnc(bsdar, 0, "%s: no such file", + bsdar->filename); + return; + } + + /* Issue a message if the '-c' option was not specified. */ + if (!(bsdar->options & AR_C)) + bsdar_warnc(bsdar, 0, "creating %s", bsdar->filename); + goto new_archive; + } + + bsdar->ar_dev = sb.st_dev; + bsdar->ar_ino = sb.st_ino; + + /* + * First read members from the existing archive. + */ + read_objs(bsdar, bsdar->filename, 0); + + /* + * For mode 's', no member will be moved, deleted or replaced. + */ + if (mode == 's') + goto write_objs; + + /* + * For mode 'q', we don't need to adjust existing members either. + * Also, -a, -b and -i are ignored in this mode. New members are + * always inserted at tail. + */ + if (mode == 'q') + goto new_archive; + + /* + * Mode 'A' adds the contents of another archive to the tail + * of current archive. Note that mode 'A' is a special mode + * for the 'ADDLIB' command in ar's script mode. Currently + * there is no option that invokes this function from ar's + * command line. + */ + if (mode == 'A') { + /* + * Read objects from the target archive of the + * 'ADDLIB' command. If there are members specified in + * 'argv', read those members only, otherwise the + * entire archive will be read. + */ + read_objs(bsdar, bsdar->addlib, 1); + goto write_objs; + } + + /* + * Try to find the position member specified by user. + */ + if (bsdar->options & AR_A || bsdar->options & AR_B) { + TAILQ_FOREACH(obj, &bsdar->v_obj, objs) { + if (strcmp(obj->name, bsdar->posarg) == 0) { + pos = obj; + break; + } + } + + /* + * If we cannot find the position specified by the + * user, silently insert objects at the tail of the + * list. + */ + if (pos == NULL) + bsdar->options &= ~(AR_A | AR_B); + } + + for (i = 0; i < bsdar->argc; i++) { + av = &bsdar->argv[i]; + + TAILQ_FOREACH_SAFE(obj, &bsdar->v_obj, objs, obj_temp) { + if ((bname = basename(*av)) == NULL) + bsdar_errc(bsdar, errno, "basename failed"); + if (bsdar->options & AR_TR) { + if (strncmp(bname, obj->name, _TRUNCATE_LEN)) + continue; + } else + if (strcmp(bname, obj->name) != 0) + continue; + + if (mode == 'r') { + /* + * If the new member should not + * replace the old one, skip it. + */ + nobj = create_obj_from_file(bsdar, *av, + obj->mtime); + if (nobj == NULL) + goto skip_obj; + } + + if (bsdar->options & AR_V) + (void)fprintf(bsdar->output, "%c - %s\n", + mode, *av); + + TAILQ_REMOVE(&bsdar->v_obj, obj, objs); + if (mode == 'd' || mode == 'r') + free_obj(obj); + + if (mode == 'm') + insert_obj(bsdar, obj, pos); + if (mode == 'r') + insert_obj(bsdar, nobj, pos); + + skip_obj: + *av = NULL; + break; + } + + } + +new_archive: + /* + * When operating in mode 'r', directly add the specified + * objects which do not exist in current archive. When + * operating in mode 'q', all objects specified by the command + * line args are appended to the archive, without checking + * existing members in the archive. + */ + for (i = 0; i < bsdar->argc; i++) { + av = &bsdar->argv[i]; + if (*av != NULL && (mode == 'r' || mode == 'q')) { + nobj = create_obj_from_file(bsdar, *av, 0); + if (nobj != NULL) + insert_obj(bsdar, nobj, pos); + if (bsdar->options & AR_V && nobj != NULL) + (void)fprintf(bsdar->output, "a - %s\n", *av); + *av = NULL; + } + } + +write_objs: + write_objs(bsdar); + write_cleanup(bsdar); +} + +/* + * Release memory. + */ +static void +write_cleanup(struct bsdar *bsdar) +{ + struct ar_obj *obj, *obj_temp; + + TAILQ_FOREACH_SAFE(obj, &bsdar->v_obj, objs, obj_temp) { + TAILQ_REMOVE(&bsdar->v_obj, obj, objs); + free_obj(obj); + } + + free(bsdar->as); + free(bsdar->s_so); + free(bsdar->s_sn); + bsdar->as = NULL; + bsdar->s_so = NULL; + bsdar->s_sn = NULL; +} + +/* + * Wrapper for archive_write_data(). + */ +static void +write_data(struct bsdar *bsdar, struct archive *a, const void *buf, size_t s) +{ + if (archive_write_data(a, buf, s) != (ssize_t)s) + bsdar_errc(bsdar, 0, "%s", archive_error_string(a)); +} + +/* + * Compute the size of the symbol table for an archive. + */ +static size_t +bsdar_symtab_size(struct bsdar *bsdar) +{ + size_t sz; + + if (bsdar->options & AR_BSD) { + /* + * A BSD style symbol table has two parts. + * Each part is preceded by its size in bytes, + * encoded as a C 'long'. In the first part, + * there are 's_cnt' entries, each entry being + * 2 'long's in size. The second part + * contains a string table. + */ + sz = 2 * sizeof(long) + (bsdar->s_cnt * 2 * sizeof(long)) + + bsdar->s_sn_sz; + } else { + /* + * An SVR4 style symbol table comprises of a 32 bit + * number holding the number of entries, followed by + * that many 32-bit offsets, followed by a string + * table. + */ + sz = sizeof(uint32_t) + bsdar->s_cnt * sizeof(uint32_t) + + bsdar->s_sn_sz; + } + + return (sz); +} + +static void +write_svr4_symtab_entry(struct bsdar *bsdar, struct archive *a) +{ + int nr; + uint32_t i; + + /* Translate offsets to big-endian form. */ + for (i = 0; i < bsdar->s_cnt; i++) + bsdar->s_so[i] = htobe32(bsdar->s_so[i]); + + nr = htobe32(bsdar->s_cnt); + write_data(bsdar, a, &nr, sizeof(uint32_t)); + write_data(bsdar, a, bsdar->s_so, sizeof(uint32_t) * + bsdar->s_cnt); + write_data(bsdar, a, bsdar->s_sn, bsdar->s_sn_sz); +} + +static void +write_bsd_symtab_entry(struct bsdar *bsdar, struct archive *a) +{ + long br_sz, br_off, br_strx; + char *s; + uint32_t i; + + /* + * Write out the size in the byte of the array of 'ranlib' + * descriptors to follow. + */ + + br_sz = (long) (bsdar->s_cnt * 2 * sizeof(long)); + write_data(bsdar, a, &br_sz, sizeof(long)); + + /* + * Write out the array of 'ranlib' descriptors. Each + * descriptor comprises of (a) an offset into the following + * string table and (b) a file offset to the relevant member. + */ + for (i = 0, s = bsdar->s_sn; i < bsdar->s_cnt; i++) { + br_strx = (long) (s - bsdar->s_sn); + br_off = (long) bsdar->s_so[i]; + write_data(bsdar, a, &br_strx, sizeof(long)); + write_data(bsdar, a, &br_off, sizeof(long)); + + /* Find the start of the next symbol in the string table. */ + while (*s++ != '\0') + ; + } + + /* + * Write out the size of the string table as a 'long', + * followed by the string table itself. + */ + br_sz = (long) bsdar->s_sn_sz; + write_data(bsdar, a, &br_sz, sizeof(long)); + write_data(bsdar, a, bsdar->s_sn, bsdar->s_sn_sz); +} + + +/* + * Write the resulting archive members. + */ +static void +write_objs(struct bsdar *bsdar) +{ + struct ar_obj *obj; + struct archive *a; + struct archive_entry *entry; + size_t s_sz; /* size of archive symbol table. */ + size_t pm_sz; /* size of pseudo members */ + size_t namelen; /* size of member name. */ + size_t obj_sz; /* size of object + extended header. */ + int i; + char *buf; + const char *entry_name; + + bsdar->rela_off = 0; + + /* + * Create the archive symbol table and the archive string + * table, if needed. + */ + TAILQ_FOREACH(obj, &bsdar->v_obj, objs) { + if (!(bsdar->options & AR_SS) && obj->elf != NULL) + create_symtab_entry(bsdar, obj->elf); + + obj_sz = 0; + namelen = strlen(obj->name); + if (bsdar->options & AR_BSD) { + /* Account for the space used by the file name. */ + if (namelen > _MAXNAMELEN_BSD || + strchr(obj->name, ' ')) + obj_sz += namelen; + } else if (namelen > _MAXNAMELEN_SVR4) + add_to_ar_str_table(bsdar, obj->name); + + obj_sz += obj->size; /* add the actual object size */ + + /* Roundup the final size and add the header length. */ + bsdar->rela_off += _ARHDR_LEN + obj_sz + (obj_sz & 1); + } + + /* + * Pad the symbol name string table. It is treated specially + * because symbol name table should be padded by a '\0', and + * not '\n' as for normal members. The size of the 'sn' table + * includes the pad byte. + */ + if (bsdar->s_cnt != 0 && bsdar->s_sn_sz % 2 != 0) + bsdar->s_sn[bsdar->s_sn_sz++] = '\0'; + + /* + * The archive string table is padded by a "\n" like a normal + * member. The difference is that the size of archive string + * table includes the pad byte, while normal members' size + * fields do not. + */ + if (bsdar->as != NULL && bsdar->as_sz % 2 != 0) + bsdar->as[bsdar->as_sz++] = '\n'; + + /* + * If there is a symbol table, calculate the size of pseudo + * members, and convert previously stored relative offsets to + * absolute ones. + * + * absolute_offset = relative_offset + size_of_pseudo_members) + */ + + s_sz = bsdar_symtab_size(bsdar); + if (bsdar->s_cnt != 0) { + pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz); + if (bsdar->as != NULL) /* SVR4 archives only */ + pm_sz += _ARHDR_LEN + bsdar->as_sz; + for (i = 0; (size_t) i < bsdar->s_cnt; i++) + bsdar->s_so[i] = bsdar->s_so[i] + pm_sz; + } + + if ((a = archive_write_new()) == NULL) + bsdar_errc(bsdar, 0, "archive_write_new failed"); + + if (bsdar->options & AR_BSD) + archive_write_set_format_ar_bsd(a); + else + archive_write_set_format_ar_svr4(a); + + AC(archive_write_open_filename(a, bsdar->filename)); + + /* + * Write the archive symbol table, if there is one. If + * options '-s' was explicitly specified or if we were invoked + * as 'ranlib', write the symbol table even if it is empty. + */ + if ((bsdar->s_cnt != 0 && !(bsdar->options & AR_SS)) || + bsdar->options & AR_S) { + if (bsdar->options & AR_BSD) + entry_name = AR_SYMTAB_NAME_BSD; + else + entry_name = AR_SYMTAB_NAME_SVR4; + + entry = archive_entry_new(); + archive_entry_copy_pathname(entry, entry_name); + if ((bsdar->options & AR_D) == 0) + archive_entry_set_mtime(entry, time(NULL), 0); + archive_entry_set_size(entry, s_sz); + AC(archive_write_header(a, entry)); + if (bsdar->options & AR_BSD) + write_bsd_symtab_entry(bsdar, a); + else + write_svr4_symtab_entry(bsdar, a); + archive_entry_free(entry); + } + + /* Write the archive string table, if any. */ + if (bsdar->as != NULL) { + entry = archive_entry_new(); + archive_entry_copy_pathname(entry, AR_STRINGTAB_NAME_SVR4); + archive_entry_set_size(entry, bsdar->as_sz); + AC(archive_write_header(a, entry)); + write_data(bsdar, a, bsdar->as, bsdar->as_sz); + archive_entry_free(entry); + } + + /* Write normal members. */ + TAILQ_FOREACH(obj, &bsdar->v_obj, objs) { + if ((buf = elf_rawfile(obj->elf, NULL)) == NULL) { + bsdar_warnc(bsdar, 0, "elf_rawfile() failed: %s", + elf_errmsg(-1)); + continue; + } + + entry = archive_entry_new(); + archive_entry_copy_pathname(entry, obj->name); + archive_entry_set_uid(entry, obj->uid); + archive_entry_set_gid(entry, obj->gid); + archive_entry_set_mode(entry, obj->md); + archive_entry_set_size(entry, obj->size); + archive_entry_set_mtime(entry, obj->mtime, 0); + archive_entry_set_dev(entry, obj->dev); + archive_entry_set_ino(entry, obj->ino); + archive_entry_set_filetype(entry, AE_IFREG); + AC(archive_write_header(a, entry)); + write_data(bsdar, a, buf, obj->size); + archive_entry_free(entry); + } + + AC(archive_write_close(a)); + ACV(archive_write_free(a)); +} + +/* + * Extract global symbols from ELF binary members. + */ +static void +create_symtab_entry(struct bsdar *bsdar, Elf *e) +{ + Elf_Scn *scn; + GElf_Shdr shdr; + GElf_Sym sym; + Elf_Data *data; + char *name; + size_t n, shstrndx; + int elferr, tabndx, len, i; + + if (elf_kind(e) != ELF_K_ELF) { + /* Silently a ignore non-ELF member. */ + return; + } + if (elf_getshstrndx(e, &shstrndx) == 0) { + bsdar_warnc(bsdar, 0, "elf_getshstrndx failed: %s", + elf_errmsg(-1)); + return; + } + + tabndx = -1; + scn = NULL; + while ((scn = elf_nextscn(e, scn)) != NULL) { + if (gelf_getshdr(scn, &shdr) != &shdr) { + bsdar_warnc(bsdar, 0, + "elf_getshdr failed: %s", elf_errmsg(-1)); + continue; + } + if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) { + bsdar_warnc(bsdar, 0, + "elf_strptr failed: %s", elf_errmsg(-1)); + continue; + } + if (strcmp(name, ".strtab") == 0) { + tabndx = elf_ndxscn(scn); + break; + } + } + elferr = elf_errno(); + if (elferr != 0) + bsdar_warnc(bsdar, 0, "elf_nextscn failed: %s", + elf_errmsg(elferr)); + if (tabndx == -1) { + bsdar_warnc(bsdar, 0, "can't find .strtab section"); + return; + } + + scn = NULL; + while ((scn = elf_nextscn(e, scn)) != NULL) { + if (gelf_getshdr(scn, &shdr) != &shdr) { + bsdar_warnc(bsdar, 0, "elf_getshdr failed: %s", + elf_errmsg(-1)); + continue; + } + if (shdr.sh_type != SHT_SYMTAB) + continue; + + data = NULL; + n = 0; + while (n < shdr.sh_size && + (data = elf_getdata(scn, data)) != NULL) { + len = data->d_size / shdr.sh_entsize; + for (i = 0; i < len; i++) { + if (gelf_getsym(data, i, &sym) != &sym) { + bsdar_warnc(bsdar, 0, + "gelf_getsym failed: %s", + elf_errmsg(-1)); + continue; + } + + /* Keep only global and weak symbols. */ + if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL && + GELF_ST_BIND(sym.st_info) != STB_WEAK) + continue; + + /* Keep only defined symbols. */ + if (sym.st_shndx == SHN_UNDEF) + continue; + + if ((name = elf_strptr(e, tabndx, + sym.st_name)) == NULL) { + bsdar_warnc(bsdar, 0, + "elf_strptr failed: %s", + elf_errmsg(-1)); + continue; + } + + add_to_ar_sym_table(bsdar, name); + } + } + } + elferr = elf_errno(); + if (elferr != 0) + bsdar_warnc(bsdar, 0, "elf_nextscn failed: %s", + elf_errmsg(elferr)); +} + +/* + * Append to the archive string table buffer. + */ +static void +add_to_ar_str_table(struct bsdar *bsdar, const char *name) +{ + + if (bsdar->as == NULL) { + bsdar->as_cap = _INIT_AS_CAP; + bsdar->as_sz = 0; + if ((bsdar->as = malloc(bsdar->as_cap)) == NULL) + bsdar_errc(bsdar, errno, "malloc failed"); + } + + /* + * The space required for holding one member name in the 'as' + * table includes: strlen(name) + (1 for '/') + (1 for '\n') + + * (possibly 1 for padding). + */ + while (bsdar->as_sz + strlen(name) + 3 > bsdar->as_cap) { + bsdar->as_cap *= 2; + bsdar->as = realloc(bsdar->as, bsdar->as_cap); + if (bsdar->as == NULL) + bsdar_errc(bsdar, errno, "realloc failed"); + } + strncpy(&bsdar->as[bsdar->as_sz], name, strlen(name)); + bsdar->as_sz += strlen(name); + bsdar->as[bsdar->as_sz++] = '/'; + bsdar->as[bsdar->as_sz++] = '\n'; +} + +/* + * Append to the archive symbol table buffer. + */ +static void +add_to_ar_sym_table(struct bsdar *bsdar, const char *name) +{ + + if (bsdar->s_so == NULL) { + if ((bsdar->s_so = malloc(_INIT_SYMOFF_CAP)) == + NULL) + bsdar_errc(bsdar, errno, "malloc failed"); + bsdar->s_so_cap = _INIT_SYMOFF_CAP; + bsdar->s_cnt = 0; + } + + if (bsdar->s_sn == NULL) { + if ((bsdar->s_sn = malloc(_INIT_SYMNAME_CAP)) == NULL) + bsdar_errc(bsdar, errno, "malloc failed"); + bsdar->s_sn_cap = _INIT_SYMNAME_CAP; + bsdar->s_sn_sz = 0; + } + + if (bsdar->s_cnt * sizeof(uint32_t) >= bsdar->s_so_cap) { + bsdar->s_so_cap *= 2; + bsdar->s_so = realloc(bsdar->s_so, bsdar->s_so_cap); + if (bsdar->s_so == NULL) + bsdar_errc(bsdar, errno, "realloc failed"); + } + bsdar->s_so[bsdar->s_cnt] = bsdar->rela_off; + bsdar->s_cnt++; + + /* + * The space required for holding one symbol name in the 'sn' + * table includes: strlen(name) + (1 for '\n') + (possibly 1 + * for padding). + */ + while (bsdar->s_sn_sz + strlen(name) + 2 > bsdar->s_sn_cap) { + bsdar->s_sn_cap *= 2; + bsdar->s_sn = realloc(bsdar->s_sn, bsdar->s_sn_cap); + if (bsdar->s_sn == NULL) + bsdar_errc(bsdar, errno, "realloc failed"); + } + strncpy(&bsdar->s_sn[bsdar->s_sn_sz], name, strlen(name)); + bsdar->s_sn_sz += strlen(name); + bsdar->s_sn[bsdar->s_sn_sz++] = '\0'; +} Property changes on: head/contrib/elftoolchain/ar/write.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/elftoolchain/ar/acplex.l =================================================================== --- head/contrib/elftoolchain/ar/acplex.l (nonexistent) +++ head/contrib/elftoolchain/ar/acplex.l (revision 286070) @@ -0,0 +1,83 @@ +%{ +/*- + * Copyright (c) 2008 Kai Wang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "_elftc.h" + +ELFTC_VCSID("$Id: acplex.l 3174 2015-03-27 17:13:41Z emaste $"); + +#include "acpyacc.h" + +#define YY_NO_UNPUT +#if !defined(ELFTC_BROKEN_YY_NO_INPUT) +#define YY_NO_INPUT +#endif + +int lineno = 1; + +int yylex(void); + +%} + +%option nounput +%option noyywrap + +%% + +ADDLIB|addlib { return (ADDLIB); } +ADDMOD|addmod { return (ADDMOD); } +CLEAR|clear { return (CLEAR); } +CREATE|create { return (CREATE); } +DELETE|delete { return (DELETE); } +DIRECTORY|directory { return (DIRECTORY); } +END|end { return (END); } +EXTRACT|extract { return (EXTRACT); } +LIST|list { return (LIST); } +OPEN|open { return (OPEN); } +REPLACE|replace { return (REPLACE); } +VERBOSE|verbose { return (VERBOSE); } +SAVE|save { return (SAVE); } +"(" { return (LP); } +")" { return (RP); } +"," { return (COMMA); } + +[-_A-Za-z0-9/:$.\\]+ { + yylval.str = strdup(yytext); + if (yylval.str == NULL) + err(EXIT_FAILURE, "strdup failed"); + return (FNAME); +} + +[ \t] /* whitespace */ +"*".* /* comment */ +";".* /* comment */ +"+\n" { lineno++; /* '+' is line continuation char */ } +"\n" { lineno++; return (EOL); } Index: head/contrib/elftoolchain/ar/acpyacc.y =================================================================== --- head/contrib/elftoolchain/ar/acpyacc.y (nonexistent) +++ head/contrib/elftoolchain/ar/acpyacc.y (revision 286070) @@ -0,0 +1,658 @@ +%{ +/*- + * Copyright (c) 2008 Kai Wang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libelftc.h" + +#include "ar.h" + +ELFTC_VCSID("$Id"); + + +#define TEMPLATE "arscp.XXXXXXXX" + +struct list { + char *str; + struct list *next; +}; + + +extern int yylex(void); +extern int yyparse(void); + +static void yyerror(const char *); +static void arscp_addlib(char *archive, struct list *list); +static void arscp_addmod(struct list *list); +static void arscp_clear(void); +static void arscp_create(char *in, char *out); +static void arscp_delete(struct list *list); +static void arscp_dir(char *archive, struct list *list, char *rlt); +static void arscp_end(int eval); +static void arscp_extract(struct list *list); +static void arscp_free_argv(void); +static void arscp_free_mlist(struct list *list); +static void arscp_list(void); +static struct list *arscp_mlist(struct list *list, char *str); +static void arscp_mlist2argv(struct list *list); +static int arscp_mlist_len(struct list *list); +static void arscp_open(char *fname); +static void arscp_prompt(void); +static void arscp_replace(struct list *list); +static void arscp_save(void); +static int arscp_target_exist(void); + +extern int lineno; + +static struct bsdar *bsdar; +static char *target; +static char *tmpac; +static int interactive; +static int verbose; + +%} + +%token ADDLIB +%token ADDMOD +%token CLEAR +%token CREATE +%token DELETE +%token DIRECTORY +%token END +%token EXTRACT +%token LIST +%token OPEN +%token REPLACE +%token VERBOSE +%token SAVE +%token LP +%token RP +%token COMMA +%token EOL +%token FNAME +%type mod_list + +%union { + char *str; + struct list *list; +} + +%% + +begin + : { arscp_prompt(); } ar_script + ; + +ar_script + : cmd_list + | + ; + +mod_list + : FNAME { $$ = arscp_mlist(NULL, $1); } + | mod_list separator FNAME { $$ = arscp_mlist($1, $3); } + ; + +separator + : COMMA + | + ; + +cmd_list + : rawcmd + | cmd_list rawcmd + ; + +rawcmd + : cmd EOL { arscp_prompt(); } + ; + +cmd + : addlib_cmd + | addmod_cmd + | clear_cmd + | create_cmd + | delete_cmd + | directory_cmd + | end_cmd + | extract_cmd + | list_cmd + | open_cmd + | replace_cmd + | verbose_cmd + | save_cmd + | invalid_cmd + | empty_cmd + | error + ; + +addlib_cmd + : ADDLIB FNAME LP mod_list RP { arscp_addlib($2, $4); } + | ADDLIB FNAME { arscp_addlib($2, NULL); } + ; + +addmod_cmd + : ADDMOD mod_list { arscp_addmod($2); } + ; + +clear_cmd + : CLEAR { arscp_clear(); } + ; + +create_cmd + : CREATE FNAME { arscp_create(NULL, $2); } + ; + +delete_cmd + : DELETE mod_list { arscp_delete($2); } + ; + +directory_cmd + : DIRECTORY FNAME { arscp_dir($2, NULL, NULL); } + | DIRECTORY FNAME LP mod_list RP { arscp_dir($2, $4, NULL); } + | DIRECTORY FNAME LP mod_list RP FNAME { arscp_dir($2, $4, $6); } + ; + +end_cmd + : END { arscp_end(EXIT_SUCCESS); } + ; + +extract_cmd + : EXTRACT mod_list { arscp_extract($2); } + ; + +list_cmd + : LIST { arscp_list(); } + ; + +open_cmd + : OPEN FNAME { arscp_open($2); } + ; + +replace_cmd + : REPLACE mod_list { arscp_replace($2); } + ; + +save_cmd + : SAVE { arscp_save(); } + ; + +verbose_cmd + : VERBOSE { verbose = !verbose; } + ; + +empty_cmd + : + ; + +invalid_cmd + : FNAME { yyerror(NULL); } + ; + +%% + +/* ARGSUSED */ +static void +yyerror(const char *s) +{ + + (void) s; + printf("Syntax error in archive script, line %d\n", lineno); +} + +/* + * The arscp_open() function will first open an archive and check its + * validity. If the archive format is valid, it will call + * arscp_create() to create a temporary copy of the archive. + */ +static void +arscp_open(char *fname) +{ + struct archive *a; + struct archive_entry *entry; + int r; + + if ((a = archive_read_new()) == NULL) + bsdar_errc(bsdar, 0, "archive_read_new failed"); + archive_read_support_format_ar(a); + AC(archive_read_open_filename(a, fname, DEF_BLKSZ)); + if ((r = archive_read_next_header(a, &entry))) + bsdar_warnc(bsdar, 0, "%s", archive_error_string(a)); + AC(archive_read_close(a)); + ACV(archive_read_free(a)); + if (r != ARCHIVE_OK) + return; + arscp_create(fname, fname); +} + +/* + * Create an archive. + * + * If the parameter 'in' is NULL (the 'CREATE' command), a new empty + * archive will be created. If the parameter 'in' is not NULL (the + * 'OPEN' command), the resulting archive will be a modified version + * of the existing archive. + */ +static void +arscp_create(char *in, char *out) +{ + struct archive *a; + int ifd, ofd; + + /* Delete the previously created temporary archive, if any. */ + if (tmpac) { + if (unlink(tmpac) < 0) + bsdar_errc(bsdar, errno, "unlink failed"); + free(tmpac); + } + + tmpac = strdup(TEMPLATE); + if (tmpac == NULL) + bsdar_errc(bsdar, errno, "strdup failed"); + if ((ofd = mkstemp(tmpac)) < 0) + bsdar_errc(bsdar, errno, "mkstemp failed"); + + if (in) { + /* + * The 'OPEN' command creates a temporary copy of the + * input archive. + */ + if ((ifd = open(in, O_RDONLY)) < 0 || + elftc_copyfile(ifd, ofd) < 0) { + bsdar_warnc(bsdar, errno, "'OPEN' failed"); + (void) close(ofd); + if (ifd != -1) + (void) close(ifd); + return; + } + (void) close(ifd); + (void) close(ofd); + } else { + /* + * The 'CREATE' command creates an "empty" archive (an + * archive consisting only of the archive header). + */ + if ((a = archive_write_new()) == NULL) + bsdar_errc(bsdar, 0, "archive_write_new failed"); + archive_write_set_format_ar_svr4(a); + AC(archive_write_open_fd(a, ofd)); + AC(archive_write_close(a)); + ACV(archive_write_free(a)); + } + + /* Override the previous target, if any. */ + if (target) + free(target); + + target = out; + bsdar->filename = tmpac; +} + +/* + * Add all modules of an archive to the current archive. If the + * parameter 'list' is not NULL, only those modules specified by + * 'list' will be added. + */ +static void +arscp_addlib(char *archive, struct list *list) +{ + + if (!arscp_target_exist()) + return; + arscp_mlist2argv(list); + bsdar->addlib = archive; + ar_write_archive(bsdar, 'A'); + arscp_free_argv(); + arscp_free_mlist(list); +} + +/* + * Add modules to the current archive. + */ +static void +arscp_addmod(struct list *list) +{ + + if (!arscp_target_exist()) + return; + arscp_mlist2argv(list); + ar_write_archive(bsdar, 'q'); + arscp_free_argv(); + arscp_free_mlist(list); +} + +/* + * Delete modules from the current archive. + */ +static void +arscp_delete(struct list *list) +{ + + if (!arscp_target_exist()) + return; + arscp_mlist2argv(list); + ar_write_archive(bsdar, 'd'); + arscp_free_argv(); + arscp_free_mlist(list); +} + +/* + * Extract modules from the current archive. + */ +static void +arscp_extract(struct list *list) +{ + + if (!arscp_target_exist()) + return; + arscp_mlist2argv(list); + ar_read_archive(bsdar, 'x'); + arscp_free_argv(); + arscp_free_mlist(list); +} + +/* + * List the contents of an archive (simple mode). + */ +static void +arscp_list(void) +{ + + if (!arscp_target_exist()) + return; + bsdar->argc = 0; + bsdar->argv = NULL; + /* Always verbose. */ + bsdar->options |= AR_V; + ar_read_archive(bsdar, 't'); + bsdar->options &= ~AR_V; +} + +/* + * List the contents of an archive (advanced mode). + */ +static void +arscp_dir(char *archive, struct list *list, char *rlt) +{ + FILE *out; + + /* If rlt != NULL, redirect the output to it. */ + out = NULL; + if (rlt) { + out = bsdar->output; + if ((bsdar->output = fopen(rlt, "w")) == NULL) + bsdar_errc(bsdar, errno, "fopen %s failed", rlt); + } + + bsdar->filename = archive; + if (list) + arscp_mlist2argv(list); + else { + bsdar->argc = 0; + bsdar->argv = NULL; + } + if (verbose) + bsdar->options |= AR_V; + ar_read_archive(bsdar, 't'); + bsdar->options &= ~AR_V; + + if (rlt) { + if (fclose(bsdar->output) == EOF) + bsdar_errc(bsdar, errno, "fclose %s failed", rlt); + bsdar->output = out; + free(rlt); + } + free(archive); + bsdar->filename = tmpac; + arscp_free_argv(); + arscp_free_mlist(list); +} + + +/* + * Replace modules in the current archive. + */ +static void +arscp_replace(struct list *list) +{ + + if (!arscp_target_exist()) + return; + arscp_mlist2argv(list); + ar_write_archive(bsdar, 'r'); + arscp_free_argv(); + arscp_free_mlist(list); +} + +/* + * Rename the temporary archive to the target archive. + */ +static void +arscp_save(void) +{ + mode_t mask; + + if (target) { + if (rename(tmpac, target) < 0) + bsdar_errc(bsdar, errno, "rename failed"); + /* + * Because mkstemp() creates temporary files with mode + * 0600, we set target archive's mode as per the + * process umask. + */ + mask = umask(0); + umask(mask); + if (chmod(target, 0666 & ~mask) < 0) + bsdar_errc(bsdar, errno, "chmod failed"); + free(tmpac); + free(target); + tmpac = NULL; + target= NULL; + bsdar->filename = NULL; + } else + bsdar_warnc(bsdar, 0, "no open output archive"); +} + +/* + * Discard the contents of the current archive. This is achieved by + * invoking the 'CREATE' cmd on the current archive. + */ +static void +arscp_clear(void) +{ + char *new_target; + + if (target) { + new_target = strdup(target); + if (new_target == NULL) + bsdar_errc(bsdar, errno, "strdup failed"); + arscp_create(NULL, new_target); + } +} + +/* + * Quit ar(1). Note that the 'END' cmd will not 'SAVE' the current + * archive before exiting. + */ +static void +arscp_end(int eval) +{ + + if (target) + free(target); + if (tmpac) { + if (unlink(tmpac) == -1) + bsdar_errc(bsdar, errno, "unlink %s failed", tmpac); + free(tmpac); + } + + exit(eval); +} + +/* + * Check if a target was specified, i.e, whether an 'OPEN' or 'CREATE' + * had been issued by the user. + */ +static int +arscp_target_exist(void) +{ + + if (target) + return (1); + + bsdar_warnc(bsdar, 0, "no open output archive"); + return (0); +} + +/* + * Construct the list of modules. + */ +static struct list * +arscp_mlist(struct list *list, char *str) +{ + struct list *l; + + l = malloc(sizeof(*l)); + if (l == NULL) + bsdar_errc(bsdar, errno, "malloc failed"); + l->str = str; + l->next = list; + + return (l); +} + +/* + * Calculate the length of an mlist. + */ +static int +arscp_mlist_len(struct list *list) +{ + int len; + + for(len = 0; list; list = list->next) + len++; + + return (len); +} + +/* + * Free the space allocated for a module list. + */ +static void +arscp_free_mlist(struct list *list) +{ + struct list *l; + + /* Note: list->str was freed in arscp_free_argv(). */ + for(; list; list = l) { + l = list->next; + free(list); + } +} + +/* + * Convert a module list to an 'argv' array. + */ +static void +arscp_mlist2argv(struct list *list) +{ + char **argv; + int i, n; + + n = arscp_mlist_len(list); + argv = malloc(n * sizeof(*argv)); + if (argv == NULL) + bsdar_errc(bsdar, errno, "malloc failed"); + + /* Note that module names are stored in reverse order. */ + for(i = n - 1; i >= 0; i--, list = list->next) { + if (list == NULL) + bsdar_errc(bsdar, errno, "invalid mlist"); + argv[i] = list->str; + } + + bsdar->argc = n; + bsdar->argv = argv; +} + +/* + * Free the space allocated for an argv array and its elements. + */ +static void +arscp_free_argv(void) +{ + int i; + + for(i = 0; i < bsdar->argc; i++) + free(bsdar->argv[i]); + + free(bsdar->argv); +} + +/* + * Show a prompt if we are in interactive mode. + */ +static void +arscp_prompt(void) +{ + + if (interactive) { + printf("AR >"); + fflush(stdout); + } +} + +/* + * The main function implementing script mode. + */ +void +ar_mode_script(struct bsdar *ar) +{ + + bsdar = ar; + interactive = isatty(fileno(stdin)); + while(yyparse()) { + if (!interactive) + arscp_end(EXIT_FAILURE); + } + + /* Script ends without END */ + arscp_end(EXIT_SUCCESS); +} Index: head/contrib/elftoolchain/ar/util.c =================================================================== --- head/contrib/elftoolchain/ar/util.c (nonexistent) +++ head/contrib/elftoolchain/ar/util.c (revision 286070) @@ -0,0 +1,184 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar.h" + +ELFTC_VCSID("$Id: util.c 3174 2015-03-27 17:13:41Z emaste $"); + +static void bsdar_vwarnc(struct bsdar *, int code, + const char *fmt, va_list ap); +static void bsdar_verrc(struct bsdar *bsdar, int code, + const char *fmt, va_list ap); + +static void +bsdar_vwarnc(struct bsdar *bsdar, int code, const char *fmt, va_list ap) +{ + + fprintf(stderr, "%s: warning: ", bsdar->progname); + vfprintf(stderr, fmt, ap); + if (code != 0) + fprintf(stderr, ": %s", strerror(code)); + fprintf(stderr, "\n"); +} + +void +bsdar_warnc(struct bsdar *bsdar, int code, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + bsdar_vwarnc(bsdar, code, fmt, ap); + va_end(ap); +} + +static void +bsdar_verrc(struct bsdar *bsdar, int code, const char *fmt, va_list ap) +{ + + fprintf(stderr, "%s: fatal: ", bsdar->progname); + vfprintf(stderr, fmt, ap); + if (code != 0) + fprintf(stderr, ": %s", strerror(code)); + fprintf(stderr, "\n"); +} + +void +bsdar_errc(struct bsdar *bsdar, int code, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + bsdar_verrc(bsdar, code, fmt, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +#define AR_STRMODE_SIZE 12 +const char * +bsdar_strmode(mode_t m) +{ + static char buf[AR_STRMODE_SIZE]; + +#if ELFTC_HAVE_STRMODE + /* Use the system's strmode(3). */ + strmode(m, buf); + return buf; + +#else + char c; + + /* + * The first character of the string denotes the type of the + * entry. + */ + if (S_ISBLK(m)) + c = 'b'; + else if (S_ISCHR(m)) + c = 'c'; + else if (S_ISDIR(m)) + c = 'd'; +#if defined(S_ISFIFO) + else if (S_ISFIFO(m)) + c = 'p'; +#endif +#if defined(S_ISLNK) + else if (S_ISLNK(m)) + c = 'l'; +#endif + else if (S_ISREG(m)) + c = '-'; +#if defined(S_ISSOCK) + else if (S_ISSOCK(m)) + c = 's'; +#endif + else + c = '?'; + buf[0] = c; + + /* The next 3 characters show permissions for the owner. */ + buf[1] = (m & S_IRUSR) ? 'r' : '-'; + buf[2] = m & S_IWUSR ? 'w' : '-'; + if (m & S_ISUID) + c = (m & S_IXUSR) ? 's' : 'S'; + else + c = (m & S_IXUSR) ? 'x' : '-'; + buf[3] = c; + + /* The next 3 characters describe permissions for the group. */ + buf[4] = (m & S_IRGRP) ? 'r' : '-'; + buf[5] = m & S_IWGRP ? 'w' : '-'; + if (m & S_ISGID) + c = (m & S_IXGRP) ? 's' : 'S'; + else + c = (m & S_IXGRP) ? 'x' : '-'; + buf[6] = c; + + + /* The next 3 characters describe permissions for others. */ + buf[7] = (m & S_IROTH) ? 'r' : '-'; + buf[8] = m & S_IWOTH ? 'w' : '-'; + if (m & S_ISVTX) /* sticky bit */ + c = (m & S_IXOTH) ? 't' : 'T'; + else + c = (m & S_IXOTH) ? 'x' : '-'; + buf[9] = c; + + /* End the string with a blank and NUL-termination. */ + buf[10] = ' '; + buf[11] = '\0'; + + return buf; +#endif /* !ELTC_HAVE_STRMODE */ +} + +int +bsdar_is_pseudomember(struct bsdar *bsdar, const char *name) +{ + /* + * The "__.SYMDEF" member is special in the BSD format + * variant. + */ + if (bsdar->options & AR_BSD) + return (strcmp(name, AR_SYMTAB_NAME_BSD) == 0); + else + /* + * The names "/ " and "// " are special in the SVR4 + * variant. + */ + return (strcmp(name, AR_STRINGTAB_NAME_SVR4) == 0 || + strcmp(name, AR_SYMTAB_NAME_SVR4) == 0); +} Property changes on: head/contrib/elftoolchain/ar/util.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/elftoolchain/ar/Makefile =================================================================== --- head/contrib/elftoolchain/ar/Makefile (nonexistent) +++ head/contrib/elftoolchain/ar/Makefile (revision 286070) @@ -0,0 +1,35 @@ +# $Id: Makefile 3107 2014-12-20 08:31:58Z kaiwang27 $ + +TOP= .. + +PROG= ar +SRCS= ar.c read.c util.c write.c +LSRC= acplex.l +YSRC= acpyacc.y + +WARNS?= 5 + +DPADD= ${LIBARCHIVE} ${LIBELFTC} ${LIBELF} ${LIBZ} +LDADD= -larchive -lelftc -lelf -lz + +CFLAGS+=-I. -I${.CURDIR} + +LINKS= ${BINDIR}/ar ${BINDIR}/ranlib + +EXTRA_TARGETS= ranlib + +CLEANFILES+= ${EXTRA_TARGETS} + +MAN= ar.1 ranlib.1 ar.5 + +all: ${EXTRA_TARGETS} + +${EXTRA_TARGETS}: ${PROG} + ln -s ${PROG} ${.TARGET} + +.include "${TOP}/mk/elftoolchain.prog.mk" + +.if ${OS_HOST} == "OpenBSD" +CFLAGS+= -I/usr/local/include +LDFLAGS+= -L/usr/local/lib +.endif Property changes on: head/contrib/elftoolchain/ar/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/elftoolchain/ar/os.Linux.mk =================================================================== --- head/contrib/elftoolchain/ar/os.Linux.mk (nonexistent) +++ head/contrib/elftoolchain/ar/os.Linux.mk (revision 286070) @@ -0,0 +1,9 @@ +.if ${OS_DISTRIBUTION} == "Ubuntu" +.if ${OS_DISTRIBUTION_VERSION} >= 14 +# Ubuntu Trusty Tahr and later. + +# Use the --nounput option to flex(1), to prevent unused functions from +# being generated. +LFLAGS += --nounput +.endif +.endif Property changes on: head/contrib/elftoolchain/ar/os.Linux.mk ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/elftoolchain/ar/ar.h =================================================================== --- head/contrib/elftoolchain/ar/ar.h (nonexistent) +++ head/contrib/elftoolchain/ar/ar.h (revision 286070) @@ -0,0 +1,143 @@ +/*- + * Copyright (c) 2007 Kai Wang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: ar.h 2496 2012-04-24 02:33:40Z jkoshy $ + */ + +#include + +#include "_elftc.h" + +/* + * ar(1) options. + */ +#define AR_A 0x0001 /* position-after */ +#define AR_B 0x0002 /* position-before */ +#define AR_C 0x0004 /* creating new archive */ +#define AR_CC 0x0008 /* do not overwrite when extracting */ +#define AR_J 0x0010 /* bzip2 compression */ +#define AR_O 0x0020 /* preserve original mtime when extracting */ +#define AR_S 0x0040 /* write archive symbol table */ +#define AR_SS 0x0080 /* do not write archive symbol table */ +#define AR_TR 0x0100 /* only keep first 15 chars for member name */ +#define AR_U 0x0200 /* only extract or update newer members.*/ +#define AR_V 0x0400 /* verbose mode */ +#define AR_Z 0x0800 /* gzip compression */ +#define AR_D 0x1000 /* insert dummy mode, mtime, uid and gid */ +#define AR_BSD 0x2000 /* use the BSD archive format */ + +#define DEF_BLKSZ 10240 /* default block size */ + +/* Special names. */ + +#define AR_STRINGTAB_NAME_SVR4 "//" +#define AR_SYMTAB_NAME_BSD "__.SYMDEF" +#define AR_SYMTAB_NAME_SVR4 "/" + +/* + * Convenient wrapper for general libarchive error handling. + */ +#define AC(CALL) do { \ + if ((CALL)) \ + bsdar_errc(bsdar, 0, "%s", \ + archive_error_string(a)); \ +} while (0) + +/* + * The 'ACV' wrapper is used for libarchive APIs that changed from + * returning 'void' to returning an 'int' in later versions of libarchive. + */ +#if ARCHIVE_VERSION_NUMBER >= 2000000 +#define ACV(CALL) AC(CALL) +#else +#define ACV(CALL) do { \ + (CALL); \ + } while (0) +#endif + +/* + * In-memory representation of archive member(object). + */ +struct ar_obj { + Elf *elf; /* object file descriptor */ + char *name; /* member name */ + uid_t uid; /* user id */ + gid_t gid; /* group id */ + mode_t md; /* octal file permissions */ + size_t size; /* member size */ + time_t mtime; /* modification time */ + dev_t dev; /* inode's device */ + ino_t ino; /* inode's number */ + + TAILQ_ENTRY(ar_obj) objs; +}; + +/* + * Structure encapsulates the "global" data for "ar" program. + */ +struct bsdar { + const char *filename; /* archive name. */ + const char *addlib; /* target of ADDLIB. */ + const char *posarg; /* position arg for modifiers -a, -b. */ + char mode; /* program mode */ + int options; /* command line options */ + FILE *output; /* default output stream */ + + const char *progname; /* program name */ + int argc; + char **argv; + + dev_t ar_dev; /* archive device. */ + ino_t ar_ino; /* archive inode. */ + + /* + * Fields for the archive string table. + */ + char *as; /* buffer for archive string table. */ + size_t as_sz; /* current size of as table. */ + size_t as_cap; /* capacity of as table buffer. */ + + /* + * Fields for the archive symbol table. + */ + uint32_t s_cnt; /* current number of symbols. */ + uint32_t *s_so; /* symbol offset table. */ + size_t s_so_cap; /* capacity of so table buffer. */ + char *s_sn; /* symbol name table */ + size_t s_sn_cap; /* capacity of sn table buffer. */ + size_t s_sn_sz; /* current size of sn table. */ + /* Current member's offset (relative to the end of pseudo members.) */ + off_t rela_off; + + TAILQ_HEAD(, ar_obj) v_obj; /* object(member) list */ +}; + +void ar_mode_script(struct bsdar *ar); +void ar_read_archive(struct bsdar *_ar, int _mode); +void ar_write_archive(struct bsdar *_ar, int _mode); +void bsdar_errc(struct bsdar *, int _code, const char *fmt, ...); +int bsdar_is_pseudomember(struct bsdar *_ar, const char *_name); +const char *bsdar_strmode(mode_t m); +void bsdar_warnc(struct bsdar *, int _code, const char *fmt, ...); Property changes on: head/contrib/elftoolchain/ar/ar.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/elftoolchain/ar/benchmark/acp.sh =================================================================== --- head/contrib/elftoolchain/ar/benchmark/acp.sh (nonexistent) +++ head/contrib/elftoolchain/ar/benchmark/acp.sh (revision 286070) @@ -0,0 +1,65 @@ +#!/bin/sh +# $Id: acp.sh 2086 2011-10-27 05:18:01Z jkoshy $ + +# This script is adapted from Jan Psota's Tar Comparison Program(TCP). + +n=3 # number of repetitions +AR="bsdar gnuar" # ar archivers to compare + +test $# -ge 2 || { + echo "usage: $0 source_dir where_to_place_archive [where_to_extract_it]" + exit 0 +} + +THISDIR=`/bin/pwd` +src=$1 +dst=$2/acp.a +ext=${3:-$2}/acptmp +test -e $dst -o -e /tmp/acp \ + && { echo "$dst or /tmp/acp exists, exiting"; exit 1; } +mkdir -p $ext || exit 1 + +show_result () +{ + awk -vL="`du -k $dst`" '{printf "%s\t%s\t%s\%10.1d KB/s\n", +$1, $3, $5, ($1>0?L/$1:0)}' /tmp/acp | sort | head -n 1 +} + +test -d $src || { echo "'$src' is not a directory"; exit 1; } + +# ar versions +for ar in $AR; do echo -n "$ar: "; $ar -V | head -n 1; +done + +echo +echo "best time of $n repetitions" +echo -n " src=$src, " +echo -n "`du -sh $src | awk '{print $1}'`" +echo -n " in " +echo "`find $src | wc -l` files" +echo " archive=$dst, extract to $ext" + +echo "program operation real user system speed" +for op in "cru $dst $src/*" "t $dst" "x `basename $dst`"; do + for ar in $AR; do + echo -n "$ar " + echo $op | grep -q ^cr && echo -n "create " + echo $op | grep -q ^t && echo -n "list " + echo $op | grep -q ^x && echo -n "extract " + num=0 + while [ $num -lt $n ]; do + echo $op | grep -q ^cr && rm -f $dst + echo $op | grep -q ^x && { rm -rf $ext; mkdir -p $ext + cp $dst $ext; cd $ext; } + sync + time $ar $op > /dev/null 2>> /tmp/acp + echo $op | grep -q ^x && cd $THISDIR + num=`expr $num + 1` + done + show_result + rm -rf /tmp/acp + done + echo +done +rm -rf $ext $dst +rm -f /tmp/acp Property changes on: head/contrib/elftoolchain/ar/benchmark/acp.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/elftoolchain/ar =================================================================== --- head/contrib/elftoolchain/ar (nonexistent) +++ head/contrib/elftoolchain/ar (revision 286070) Property changes on: head/contrib/elftoolchain/ar ___________________________________________________________________ Added: svn:mergeinfo ## -0,0 +0,0 ## Index: head/contrib/elftoolchain/elfdump/elfdump.c =================================================================== --- head/contrib/elftoolchain/elfdump/elfdump.c (nonexistent) +++ head/contrib/elftoolchain/elfdump/elfdump.c (revision 286070) @@ -0,0 +1,2819 @@ +/*- + * Copyright (c) 2007-2012 Kai Wang + * Copyright (c) 2003 David O'Brien. All rights reserved. + * Copyright (c) 2001 Jake Burkholder + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_LIBARCHIVE_AR +#include +#include +#endif + +#include "_elftc.h" + +ELFTC_VCSID("$Id: elfdump.c 3198 2015-05-14 18:36:19Z emaste $"); + +#if defined(ELFTC_NEED_ELF_NOTE_DEFINITION) +#include "native-elf-format.h" +#if ELFTC_CLASS == ELFCLASS32 +typedef Elf32_Nhdr Elf_Note; +#else +typedef Elf64_Nhdr Elf_Note; +#endif +#endif + +/* elfdump(1) options. */ +#define ED_DYN (1<<0) +#define ED_EHDR (1<<1) +#define ED_GOT (1<<2) +#define ED_HASH (1<<3) +#define ED_INTERP (1<<4) +#define ED_NOTE (1<<5) +#define ED_PHDR (1<<6) +#define ED_REL (1<<7) +#define ED_SHDR (1<<8) +#define ED_SYMTAB (1<<9) +#define ED_SYMVER (1<<10) +#define ED_CHECKSUM (1<<11) +#define ED_ALL ((1<<12)-1) + +/* elfdump(1) run control flags. */ +#define SOLARIS_FMT (1<<0) +#define PRINT_FILENAME (1<<1) +#define PRINT_ARSYM (1<<2) +#define ONLY_ARSYM (1<<3) + +/* Convenient print macro. */ +#define PRT(...) fprintf(ed->out, __VA_ARGS__) + +/* Internal data structure for sections. */ +struct section { + const char *name; /* section name */ + Elf_Scn *scn; /* section scn */ + uint64_t off; /* section offset */ + uint64_t sz; /* section size */ + uint64_t entsize; /* section entsize */ + uint64_t align; /* section alignment */ + uint64_t type; /* section type */ + uint64_t flags; /* section flags */ + uint64_t addr; /* section virtual addr */ + uint32_t link; /* section link ndx */ + uint32_t info; /* section info ndx */ +}; + +struct spec_name { + const char *name; + STAILQ_ENTRY(spec_name) sn_list; +}; + +/* Structure encapsulates the global data for readelf(1). */ +struct elfdump { + FILE *out; /* output redirection. */ + const char *filename; /* current processing file. */ + const char *archive; /* archive name */ + int options; /* command line options. */ + int flags; /* run control flags. */ + Elf *elf; /* underlying ELF descriptor. */ +#ifndef USE_LIBARCHIVE_AR + Elf *ar; /* ar(1) archive descriptor. */ +#endif + GElf_Ehdr ehdr; /* ELF header. */ + int ec; /* ELF class. */ + size_t shnum; /* #sections. */ + struct section *sl; /* list of sections. */ + STAILQ_HEAD(, spec_name) snl; /* list of names specified by -N. */ +}; + +/* Relocation entry. */ +struct rel_entry { + union { + GElf_Rel rel; + GElf_Rela rela; + } u_r; + const char *symn; + uint32_t type; +}; + +#if defined(ELFTC_NEED_BYTEORDER_EXTENSIONS) +static __inline uint32_t +be32dec(const void *pp) +{ + unsigned char const *p = (unsigned char const *)pp; + + return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); +} + +static __inline uint32_t +le32dec(const void *pp) +{ + unsigned char const *p = (unsigned char const *)pp; + + return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); +} +#endif + +/* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#tag_encodings */ +static const char * +d_tags(uint64_t tag) +{ + switch (tag) { + case 0: return "DT_NULL"; + case 1: return "DT_NEEDED"; + case 2: return "DT_PLTRELSZ"; + case 3: return "DT_PLTGOT"; + case 4: return "DT_HASH"; + case 5: return "DT_STRTAB"; + case 6: return "DT_SYMTAB"; + case 7: return "DT_RELA"; + case 8: return "DT_RELASZ"; + case 9: return "DT_RELAENT"; + case 10: return "DT_STRSZ"; + case 11: return "DT_SYMENT"; + case 12: return "DT_INIT"; + case 13: return "DT_FINI"; + case 14: return "DT_SONAME"; + case 15: return "DT_RPATH"; + case 16: return "DT_SYMBOLIC"; + case 17: return "DT_REL"; + case 18: return "DT_RELSZ"; + case 19: return "DT_RELENT"; + case 20: return "DT_PLTREL"; + case 21: return "DT_DEBUG"; + case 22: return "DT_TEXTREL"; + case 23: return "DT_JMPREL"; + case 24: return "DT_BIND_NOW"; + case 25: return "DT_INIT_ARRAY"; + case 26: return "DT_FINI_ARRAY"; + case 27: return "DT_INIT_ARRAYSZ"; + case 28: return "DT_FINI_ARRAYSZ"; + case 29: return "DT_RUNPATH"; + case 30: return "DT_FLAGS"; + case 32: return "DT_PREINIT_ARRAY"; /* XXX: DT_ENCODING */ + case 33: return "DT_PREINIT_ARRAYSZ"; + /* 0x6000000D - 0x6ffff000 operating system-specific semantics */ + case 0x6ffffdf5: return "DT_GNU_PRELINKED"; + case 0x6ffffdf6: return "DT_GNU_CONFLICTSZ"; + case 0x6ffffdf7: return "DT_GNU_LIBLISTSZ"; + case 0x6ffffdf8: return "DT_SUNW_CHECKSUM"; + case 0x6ffffdf9: return "DT_PLTPADSZ"; + case 0x6ffffdfa: return "DT_MOVEENT"; + case 0x6ffffdfb: return "DT_MOVESZ"; + case 0x6ffffdfc: return "DT_FEATURE"; + case 0x6ffffdfd: return "DT_POSFLAG_1"; + case 0x6ffffdfe: return "DT_SYMINSZ"; + case 0x6ffffdff: return "DT_SYMINENT (DT_VALRNGHI)"; + case 0x6ffffe00: return "DT_ADDRRNGLO"; + case 0x6ffffef5: return "DT_GNU_HASH"; + case 0x6ffffef8: return "DT_GNU_CONFLICT"; + case 0x6ffffef9: return "DT_GNU_LIBLIST"; + case 0x6ffffefa: return "DT_SUNW_CONFIG"; + case 0x6ffffefb: return "DT_SUNW_DEPAUDIT"; + case 0x6ffffefc: return "DT_SUNW_AUDIT"; + case 0x6ffffefd: return "DT_SUNW_PLTPAD"; + case 0x6ffffefe: return "DT_SUNW_MOVETAB"; + case 0x6ffffeff: return "DT_SYMINFO (DT_ADDRRNGHI)"; + case 0x6ffffff9: return "DT_RELACOUNT"; + case 0x6ffffffa: return "DT_RELCOUNT"; + case 0x6ffffffb: return "DT_FLAGS_1"; + case 0x6ffffffc: return "DT_VERDEF"; + case 0x6ffffffd: return "DT_VERDEFNUM"; + case 0x6ffffffe: return "DT_VERNEED"; + case 0x6fffffff: return "DT_VERNEEDNUM"; + case 0x6ffffff0: return "DT_GNU_VERSYM"; + /* 0x70000000 - 0x7fffffff processor-specific semantics */ + case 0x70000000: return "DT_IA_64_PLT_RESERVE"; + case 0x7ffffffd: return "DT_SUNW_AUXILIARY"; + case 0x7ffffffe: return "DT_SUNW_USED"; + case 0x7fffffff: return "DT_SUNW_FILTER"; + default: return "ERROR: TAG NOT DEFINED"; + } +} + +static const char * +e_machines(unsigned int mach) +{ + static char machdesc[64]; + + switch (mach) { + case EM_NONE: return "EM_NONE"; + case EM_M32: return "EM_M32"; + case EM_SPARC: return "EM_SPARC"; + case EM_386: return "EM_386"; + case EM_68K: return "EM_68K"; + case EM_88K: return "EM_88K"; + case EM_IAMCU: return "EM_IAMCU"; + case EM_860: return "EM_860"; + case EM_MIPS: return "EM_MIPS"; + case EM_PPC: return "EM_PPC"; + case EM_ARM: return "EM_ARM"; + case EM_ALPHA: return "EM_ALPHA (legacy)"; + case EM_SPARCV9:return "EM_SPARCV9"; + case EM_IA_64: return "EM_IA_64"; + case EM_X86_64: return "EM_X86_64"; + } + snprintf(machdesc, sizeof(machdesc), + "(unknown machine) -- type 0x%x", mach); + return (machdesc); +} + +static const char *e_types[] = { + "ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE" +}; + +static const char *ei_versions[] = { + "EV_NONE", "EV_CURRENT" +}; + +static const char *ei_classes[] = { + "ELFCLASSNONE", "ELFCLASS32", "ELFCLASS64" +}; + +static const char *ei_data[] = { + "ELFDATANONE", "ELFDATA2LSB", "ELFDATA2MSB" +}; + +static const char *ei_abis[] = { + "ELFOSABI_SYSV", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX", + "ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS", + "ELFOSABI_MONTEREY", "ELFOSABI_IRIX", "ELFOSABI_FREEBSD", + "ELFOSABI_TRU64", "ELFOSABI_MODESTO", "ELFOSABI_OPENBSD" +}; + +static const char *p_types[] = { + "PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", "PT_NOTE", + "PT_SHLIB", "PT_PHDR", "PT_TLS" +}; + +static const char *p_flags[] = { + "", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R", + "PF_X|PF_W|PF_R" +}; + +static const char * +sh_name(struct elfdump *ed, int ndx) +{ + static char num[10]; + + switch (ndx) { + case SHN_UNDEF: return "UNDEF"; + case SHN_ABS: return "ABS"; + case SHN_COMMON: return "COMMON"; + default: + if ((uint64_t)ndx < ed->shnum) + return (ed->sl[ndx].name); + else { + snprintf(num, sizeof(num), "%d", ndx); + return (num); + } + } +} + +/* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type */ +static const char * +sh_types(u_int64_t sht) { + switch (sht) { + case 0: return "SHT_NULL"; + case 1: return "SHT_PROGBITS"; + case 2: return "SHT_SYMTAB"; + case 3: return "SHT_STRTAB"; + case 4: return "SHT_RELA"; + case 5: return "SHT_HASH"; + case 6: return "SHT_DYNAMIC"; + case 7: return "SHT_NOTE"; + case 8: return "SHT_NOBITS"; + case 9: return "SHT_REL"; + case 10: return "SHT_SHLIB"; + case 11: return "SHT_DYNSYM"; + case 14: return "SHT_INIT_ARRAY"; + case 15: return "SHT_FINI_ARRAY"; + case 16: return "SHT_PREINIT_ARRAY"; + case 17: return "SHT_GROUP"; + case 18: return "SHT_SYMTAB_SHNDX"; + /* 0x60000000 - 0x6fffffff operating system-specific semantics */ + case 0x6ffffff0: return "XXX:VERSYM"; + case 0x6ffffff6: return "SHT_GNU_HASH"; + case 0x6ffffff7: return "SHT_GNU_LIBLIST"; + case 0x6ffffffc: return "XXX:VERDEF"; + case 0x6ffffffd: return "SHT_SUNW(GNU)_verdef"; + case 0x6ffffffe: return "SHT_SUNW(GNU)_verneed"; + case 0x6fffffff: return "SHT_SUNW(GNU)_versym"; + /* 0x70000000 - 0x7fffffff processor-specific semantics */ + case 0x70000000: return "SHT_IA_64_EXT"; + case 0x70000001: return "SHT_IA_64_UNWIND"; + case 0x7ffffffd: return "XXX:AUXILIARY"; + case 0x7fffffff: return "XXX:FILTER"; + /* 0x80000000 - 0xffffffff application programs */ + default: return "ERROR: SHT NOT DEFINED"; + } +} + +/* + * Define known section flags. These flags are defined in the order + * they are to be printed out. + */ +#define DEFINE_SHFLAGS() \ + DEFINE_SHF(WRITE) \ + DEFINE_SHF(ALLOC) \ + DEFINE_SHF(EXECINSTR) \ + DEFINE_SHF(MERGE) \ + DEFINE_SHF(STRINGS) \ + DEFINE_SHF(INFO_LINK) \ + DEFINE_SHF(LINK_ORDER) \ + DEFINE_SHF(OS_NONCONFORMING) \ + DEFINE_SHF(GROUP) \ + DEFINE_SHF(TLS) + +#undef DEFINE_SHF +#define DEFINE_SHF(F) "SHF_" #F "|" +#define ALLSHFLAGS DEFINE_SHFLAGS() + +static const char * +sh_flags(uint64_t shf) +{ + static char flg[sizeof(ALLSHFLAGS)+1]; + + flg[0] = '\0'; + +#undef DEFINE_SHF +#define DEFINE_SHF(N) \ + if (shf & SHF_##N) \ + strcat(flg, "SHF_" #N "|"); \ + + DEFINE_SHFLAGS() + + flg[strlen(flg) - 1] = '\0'; /* Remove the trailing "|". */ + + return (flg); +} + +static const char *st_types[] = { + "STT_NOTYPE", "STT_OBJECT", "STT_FUNC", "STT_SECTION", "STT_FILE", + "STT_COMMON", "STT_TLS" +}; + +static const char *st_types_S[] = { + "NOTY", "OBJT", "FUNC", "SECT", "FILE" +}; + +static const char *st_bindings[] = { + "STB_LOCAL", "STB_GLOBAL", "STB_WEAK" +}; + +static const char *st_bindings_S[] = { + "LOCL", "GLOB", "WEAK" +}; + +static unsigned char st_others[] = { + 'D', 'I', 'H', 'P' +}; + +static const char * +r_type(unsigned int mach, unsigned int type) +{ + switch(mach) { + case EM_NONE: return ""; + case EM_386: + case EM_IAMCU: + switch(type) { + case 0: return "R_386_NONE"; + case 1: return "R_386_32"; + case 2: return "R_386_PC32"; + case 3: return "R_386_GOT32"; + case 4: return "R_386_PLT32"; + case 5: return "R_386_COPY"; + case 6: return "R_386_GLOB_DAT"; + case 7: return "R_386_JMP_SLOT"; + case 8: return "R_386_RELATIVE"; + case 9: return "R_386_GOTOFF"; + case 10: return "R_386_GOTPC"; + case 14: return "R_386_TLS_TPOFF"; + case 15: return "R_386_TLS_IE"; + case 16: return "R_386_TLS_GOTIE"; + case 17: return "R_386_TLS_LE"; + case 18: return "R_386_TLS_GD"; + case 19: return "R_386_TLS_LDM"; + case 24: return "R_386_TLS_GD_32"; + case 25: return "R_386_TLS_GD_PUSH"; + case 26: return "R_386_TLS_GD_CALL"; + case 27: return "R_386_TLS_GD_POP"; + case 28: return "R_386_TLS_LDM_32"; + case 29: return "R_386_TLS_LDM_PUSH"; + case 30: return "R_386_TLS_LDM_CALL"; + case 31: return "R_386_TLS_LDM_POP"; + case 32: return "R_386_TLS_LDO_32"; + case 33: return "R_386_TLS_IE_32"; + case 34: return "R_386_TLS_LE_32"; + case 35: return "R_386_TLS_DTPMOD32"; + case 36: return "R_386_TLS_DTPOFF32"; + case 37: return "R_386_TLS_TPOFF32"; + default: return ""; + } + case EM_ARM: + switch(type) { + case 0: return "R_ARM_NONE"; + case 1: return "R_ARM_PC24"; + case 2: return "R_ARM_ABS32"; + case 3: return "R_ARM_REL32"; + case 4: return "R_ARM_PC13"; + case 5: return "R_ARM_ABS16"; + case 6: return "R_ARM_ABS12"; + case 7: return "R_ARM_THM_ABS5"; + case 8: return "R_ARM_ABS8"; + case 9: return "R_ARM_SBREL32"; + case 10: return "R_ARM_THM_PC22"; + case 11: return "R_ARM_THM_PC8"; + case 12: return "R_ARM_AMP_VCALL9"; + case 13: return "R_ARM_SWI24"; + case 14: return "R_ARM_THM_SWI8"; + case 15: return "R_ARM_XPC25"; + case 16: return "R_ARM_THM_XPC22"; + case 20: return "R_ARM_COPY"; + case 21: return "R_ARM_GLOB_DAT"; + case 22: return "R_ARM_JUMP_SLOT"; + case 23: return "R_ARM_RELATIVE"; + case 24: return "R_ARM_GOTOFF"; + case 25: return "R_ARM_GOTPC"; + case 26: return "R_ARM_GOT32"; + case 27: return "R_ARM_PLT32"; + case 100: return "R_ARM_GNU_VTENTRY"; + case 101: return "R_ARM_GNU_VTINHERIT"; + case 250: return "R_ARM_RSBREL32"; + case 251: return "R_ARM_THM_RPC22"; + case 252: return "R_ARM_RREL32"; + case 253: return "R_ARM_RABS32"; + case 254: return "R_ARM_RPC24"; + case 255: return "R_ARM_RBASE"; + default: return ""; + } + case EM_IA_64: + switch(type) { + case 0: return "R_IA_64_NONE"; + case 33: return "R_IA_64_IMM14"; + case 34: return "R_IA_64_IMM22"; + case 35: return "R_IA_64_IMM64"; + case 36: return "R_IA_64_DIR32MSB"; + case 37: return "R_IA_64_DIR32LSB"; + case 38: return "R_IA_64_DIR64MSB"; + case 39: return "R_IA_64_DIR64LSB"; + case 42: return "R_IA_64_GPREL22"; + case 43: return "R_IA_64_GPREL64I"; + case 44: return "R_IA_64_GPREL32MSB"; + case 45: return "R_IA_64_GPREL32LSB"; + case 46: return "R_IA_64_GPREL64MSB"; + case 47: return "R_IA_64_GPREL64LSB"; + case 50: return "R_IA_64_LTOFF22"; + case 51: return "R_IA_64_LTOFF64I"; + case 58: return "R_IA_64_PLTOFF22"; + case 59: return "R_IA_64_PLTOFF64I"; + case 62: return "R_IA_64_PLTOFF64MSB"; + case 63: return "R_IA_64_PLTOFF64LSB"; + case 67: return "R_IA_64_FPTR64I"; + case 68: return "R_IA_64_FPTR32MSB"; + case 69: return "R_IA_64_FPTR32LSB"; + case 70: return "R_IA_64_FPTR64MSB"; + case 71: return "R_IA_64_FPTR64LSB"; + case 72: return "R_IA_64_PCREL60B"; + case 73: return "R_IA_64_PCREL21B"; + case 74: return "R_IA_64_PCREL21M"; + case 75: return "R_IA_64_PCREL21F"; + case 76: return "R_IA_64_PCREL32MSB"; + case 77: return "R_IA_64_PCREL32LSB"; + case 78: return "R_IA_64_PCREL64MSB"; + case 79: return "R_IA_64_PCREL64LSB"; + case 82: return "R_IA_64_LTOFF_FPTR22"; + case 83: return "R_IA_64_LTOFF_FPTR64I"; + case 84: return "R_IA_64_LTOFF_FPTR32MSB"; + case 85: return "R_IA_64_LTOFF_FPTR32LSB"; + case 86: return "R_IA_64_LTOFF_FPTR64MSB"; + case 87: return "R_IA_64_LTOFF_FPTR64LSB"; + case 92: return "R_IA_64_SEGREL32MSB"; + case 93: return "R_IA_64_SEGREL32LSB"; + case 94: return "R_IA_64_SEGREL64MSB"; + case 95: return "R_IA_64_SEGREL64LSB"; + case 100: return "R_IA_64_SECREL32MSB"; + case 101: return "R_IA_64_SECREL32LSB"; + case 102: return "R_IA_64_SECREL64MSB"; + case 103: return "R_IA_64_SECREL64LSB"; + case 108: return "R_IA_64_REL32MSB"; + case 109: return "R_IA_64_REL32LSB"; + case 110: return "R_IA_64_REL64MSB"; + case 111: return "R_IA_64_REL64LSB"; + case 116: return "R_IA_64_LTV32MSB"; + case 117: return "R_IA_64_LTV32LSB"; + case 118: return "R_IA_64_LTV64MSB"; + case 119: return "R_IA_64_LTV64LSB"; + case 121: return "R_IA_64_PCREL21BI"; + case 122: return "R_IA_64_PCREL22"; + case 123: return "R_IA_64_PCREL64I"; + case 128: return "R_IA_64_IPLTMSB"; + case 129: return "R_IA_64_IPLTLSB"; + case 133: return "R_IA_64_SUB"; + case 134: return "R_IA_64_LTOFF22X"; + case 135: return "R_IA_64_LDXMOV"; + case 145: return "R_IA_64_TPREL14"; + case 146: return "R_IA_64_TPREL22"; + case 147: return "R_IA_64_TPREL64I"; + case 150: return "R_IA_64_TPREL64MSB"; + case 151: return "R_IA_64_TPREL64LSB"; + case 154: return "R_IA_64_LTOFF_TPREL22"; + case 166: return "R_IA_64_DTPMOD64MSB"; + case 167: return "R_IA_64_DTPMOD64LSB"; + case 170: return "R_IA_64_LTOFF_DTPMOD22"; + case 177: return "R_IA_64_DTPREL14"; + case 178: return "R_IA_64_DTPREL22"; + case 179: return "R_IA_64_DTPREL64I"; + case 180: return "R_IA_64_DTPREL32MSB"; + case 181: return "R_IA_64_DTPREL32LSB"; + case 182: return "R_IA_64_DTPREL64MSB"; + case 183: return "R_IA_64_DTPREL64LSB"; + case 186: return "R_IA_64_LTOFF_DTPREL22"; + default: return ""; + } + case EM_MIPS: + switch(type) { + case 0: return "R_MIPS_NONE"; + case 1: return "R_MIPS_16"; + case 2: return "R_MIPS_32"; + case 3: return "R_MIPS_REL32"; + case 4: return "R_MIPS_26"; + case 5: return "R_MIPS_HI16"; + case 6: return "R_MIPS_LO16"; + case 7: return "R_MIPS_GPREL16"; + case 8: return "R_MIPS_LITERAL"; + case 9: return "R_MIPS_GOT16"; + case 10: return "R_MIPS_PC16"; + case 11: return "R_MIPS_CALL16"; + case 12: return "R_MIPS_GPREL32"; + case 21: return "R_MIPS_GOTHI16"; + case 22: return "R_MIPS_GOTLO16"; + case 30: return "R_MIPS_CALLHI16"; + case 31: return "R_MIPS_CALLLO16"; + default: return ""; + } + case EM_PPC: + switch(type) { + case 0: return "R_PPC_NONE"; + case 1: return "R_PPC_ADDR32"; + case 2: return "R_PPC_ADDR24"; + case 3: return "R_PPC_ADDR16"; + case 4: return "R_PPC_ADDR16_LO"; + case 5: return "R_PPC_ADDR16_HI"; + case 6: return "R_PPC_ADDR16_HA"; + case 7: return "R_PPC_ADDR14"; + case 8: return "R_PPC_ADDR14_BRTAKEN"; + case 9: return "R_PPC_ADDR14_BRNTAKEN"; + case 10: return "R_PPC_REL24"; + case 11: return "R_PPC_REL14"; + case 12: return "R_PPC_REL14_BRTAKEN"; + case 13: return "R_PPC_REL14_BRNTAKEN"; + case 14: return "R_PPC_GOT16"; + case 15: return "R_PPC_GOT16_LO"; + case 16: return "R_PPC_GOT16_HI"; + case 17: return "R_PPC_GOT16_HA"; + case 18: return "R_PPC_PLTREL24"; + case 19: return "R_PPC_COPY"; + case 20: return "R_PPC_GLOB_DAT"; + case 21: return "R_PPC_JMP_SLOT"; + case 22: return "R_PPC_RELATIVE"; + case 23: return "R_PPC_LOCAL24PC"; + case 24: return "R_PPC_UADDR32"; + case 25: return "R_PPC_UADDR16"; + case 26: return "R_PPC_REL32"; + case 27: return "R_PPC_PLT32"; + case 28: return "R_PPC_PLTREL32"; + case 29: return "R_PPC_PLT16_LO"; + case 30: return "R_PPC_PLT16_HI"; + case 31: return "R_PPC_PLT16_HA"; + case 32: return "R_PPC_SDAREL16"; + case 33: return "R_PPC_SECTOFF"; + case 34: return "R_PPC_SECTOFF_LO"; + case 35: return "R_PPC_SECTOFF_HI"; + case 36: return "R_PPC_SECTOFF_HA"; + case 67: return "R_PPC_TLS"; + case 68: return "R_PPC_DTPMOD32"; + case 69: return "R_PPC_TPREL16"; + case 70: return "R_PPC_TPREL16_LO"; + case 71: return "R_PPC_TPREL16_HI"; + case 72: return "R_PPC_TPREL16_HA"; + case 73: return "R_PPC_TPREL32"; + case 74: return "R_PPC_DTPREL16"; + case 75: return "R_PPC_DTPREL16_LO"; + case 76: return "R_PPC_DTPREL16_HI"; + case 77: return "R_PPC_DTPREL16_HA"; + case 78: return "R_PPC_DTPREL32"; + case 79: return "R_PPC_GOT_TLSGD16"; + case 80: return "R_PPC_GOT_TLSGD16_LO"; + case 81: return "R_PPC_GOT_TLSGD16_HI"; + case 82: return "R_PPC_GOT_TLSGD16_HA"; + case 83: return "R_PPC_GOT_TLSLD16"; + case 84: return "R_PPC_GOT_TLSLD16_LO"; + case 85: return "R_PPC_GOT_TLSLD16_HI"; + case 86: return "R_PPC_GOT_TLSLD16_HA"; + case 87: return "R_PPC_GOT_TPREL16"; + case 88: return "R_PPC_GOT_TPREL16_LO"; + case 89: return "R_PPC_GOT_TPREL16_HI"; + case 90: return "R_PPC_GOT_TPREL16_HA"; + case 101: return "R_PPC_EMB_NADDR32"; + case 102: return "R_PPC_EMB_NADDR16"; + case 103: return "R_PPC_EMB_NADDR16_LO"; + case 104: return "R_PPC_EMB_NADDR16_HI"; + case 105: return "R_PPC_EMB_NADDR16_HA"; + case 106: return "R_PPC_EMB_SDAI16"; + case 107: return "R_PPC_EMB_SDA2I16"; + case 108: return "R_PPC_EMB_SDA2REL"; + case 109: return "R_PPC_EMB_SDA21"; + case 110: return "R_PPC_EMB_MRKREF"; + case 111: return "R_PPC_EMB_RELSEC16"; + case 112: return "R_PPC_EMB_RELST_LO"; + case 113: return "R_PPC_EMB_RELST_HI"; + case 114: return "R_PPC_EMB_RELST_HA"; + case 115: return "R_PPC_EMB_BIT_FLD"; + case 116: return "R_PPC_EMB_RELSDA"; + default: return ""; + } + case EM_SPARC: + case EM_SPARCV9: + switch(type) { + case 0: return "R_SPARC_NONE"; + case 1: return "R_SPARC_8"; + case 2: return "R_SPARC_16"; + case 3: return "R_SPARC_32"; + case 4: return "R_SPARC_DISP8"; + case 5: return "R_SPARC_DISP16"; + case 6: return "R_SPARC_DISP32"; + case 7: return "R_SPARC_WDISP30"; + case 8: return "R_SPARC_WDISP22"; + case 9: return "R_SPARC_HI22"; + case 10: return "R_SPARC_22"; + case 11: return "R_SPARC_13"; + case 12: return "R_SPARC_LO10"; + case 13: return "R_SPARC_GOT10"; + case 14: return "R_SPARC_GOT13"; + case 15: return "R_SPARC_GOT22"; + case 16: return "R_SPARC_PC10"; + case 17: return "R_SPARC_PC22"; + case 18: return "R_SPARC_WPLT30"; + case 19: return "R_SPARC_COPY"; + case 20: return "R_SPARC_GLOB_DAT"; + case 21: return "R_SPARC_JMP_SLOT"; + case 22: return "R_SPARC_RELATIVE"; + case 23: return "R_SPARC_UA32"; + case 24: return "R_SPARC_PLT32"; + case 25: return "R_SPARC_HIPLT22"; + case 26: return "R_SPARC_LOPLT10"; + case 27: return "R_SPARC_PCPLT32"; + case 28: return "R_SPARC_PCPLT22"; + case 29: return "R_SPARC_PCPLT10"; + case 30: return "R_SPARC_10"; + case 31: return "R_SPARC_11"; + case 32: return "R_SPARC_64"; + case 33: return "R_SPARC_OLO10"; + case 34: return "R_SPARC_HH22"; + case 35: return "R_SPARC_HM10"; + case 36: return "R_SPARC_LM22"; + case 37: return "R_SPARC_PC_HH22"; + case 38: return "R_SPARC_PC_HM10"; + case 39: return "R_SPARC_PC_LM22"; + case 40: return "R_SPARC_WDISP16"; + case 41: return "R_SPARC_WDISP19"; + case 42: return "R_SPARC_GLOB_JMP"; + case 43: return "R_SPARC_7"; + case 44: return "R_SPARC_5"; + case 45: return "R_SPARC_6"; + case 46: return "R_SPARC_DISP64"; + case 47: return "R_SPARC_PLT64"; + case 48: return "R_SPARC_HIX22"; + case 49: return "R_SPARC_LOX10"; + case 50: return "R_SPARC_H44"; + case 51: return "R_SPARC_M44"; + case 52: return "R_SPARC_L44"; + case 53: return "R_SPARC_REGISTER"; + case 54: return "R_SPARC_UA64"; + case 55: return "R_SPARC_UA16"; + case 56: return "R_SPARC_TLS_GD_HI22"; + case 57: return "R_SPARC_TLS_GD_LO10"; + case 58: return "R_SPARC_TLS_GD_ADD"; + case 59: return "R_SPARC_TLS_GD_CALL"; + case 60: return "R_SPARC_TLS_LDM_HI22"; + case 61: return "R_SPARC_TLS_LDM_LO10"; + case 62: return "R_SPARC_TLS_LDM_ADD"; + case 63: return "R_SPARC_TLS_LDM_CALL"; + case 64: return "R_SPARC_TLS_LDO_HIX22"; + case 65: return "R_SPARC_TLS_LDO_LOX10"; + case 66: return "R_SPARC_TLS_LDO_ADD"; + case 67: return "R_SPARC_TLS_IE_HI22"; + case 68: return "R_SPARC_TLS_IE_LO10"; + case 69: return "R_SPARC_TLS_IE_LD"; + case 70: return "R_SPARC_TLS_IE_LDX"; + case 71: return "R_SPARC_TLS_IE_ADD"; + case 72: return "R_SPARC_TLS_LE_HIX22"; + case 73: return "R_SPARC_TLS_LE_LOX10"; + case 74: return "R_SPARC_TLS_DTPMOD32"; + case 75: return "R_SPARC_TLS_DTPMOD64"; + case 76: return "R_SPARC_TLS_DTPOFF32"; + case 77: return "R_SPARC_TLS_DTPOFF64"; + case 78: return "R_SPARC_TLS_TPOFF32"; + case 79: return "R_SPARC_TLS_TPOFF64"; + default: return ""; + } + case EM_X86_64: + switch(type) { + case 0: return "R_X86_64_NONE"; + case 1: return "R_X86_64_64"; + case 2: return "R_X86_64_PC32"; + case 3: return "R_X86_64_GOT32"; + case 4: return "R_X86_64_PLT32"; + case 5: return "R_X86_64_COPY"; + case 6: return "R_X86_64_GLOB_DAT"; + case 7: return "R_X86_64_JMP_SLOT"; + case 8: return "R_X86_64_RELATIVE"; + case 9: return "R_X86_64_GOTPCREL"; + case 10: return "R_X86_64_32"; + case 11: return "R_X86_64_32S"; + case 12: return "R_X86_64_16"; + case 13: return "R_X86_64_PC16"; + case 14: return "R_X86_64_8"; + case 15: return "R_X86_64_PC8"; + case 16: return "R_X86_64_DTPMOD64"; + case 17: return "R_X86_64_DTPOFF64"; + case 18: return "R_X86_64_TPOFF64"; + case 19: return "R_X86_64_TLSGD"; + case 20: return "R_X86_64_TLSLD"; + case 21: return "R_X86_64_DTPOFF32"; + case 22: return "R_X86_64_GOTTPOFF"; + case 23: return "R_X86_64_TPOFF32"; + default: return ""; + } + default: return ""; + } +} + +static void add_name(struct elfdump *ed, const char *name); +static void elf_print_object(struct elfdump *ed); +static void elf_print_elf(struct elfdump *ed); +static void elf_print_ehdr(struct elfdump *ed); +static void elf_print_phdr(struct elfdump *ed); +static void elf_print_shdr(struct elfdump *ed); +static void elf_print_symtab(struct elfdump *ed, int i); +static void elf_print_symtabs(struct elfdump *ed); +static void elf_print_symver(struct elfdump *ed); +static void elf_print_verdef(struct elfdump *ed, struct section *s); +static void elf_print_verneed(struct elfdump *ed, struct section *s); +static void elf_print_interp(struct elfdump *ed); +static void elf_print_dynamic(struct elfdump *ed); +static void elf_print_rel_entry(struct elfdump *ed, struct section *s, + int j, struct rel_entry *r); +static void elf_print_rela(struct elfdump *ed, struct section *s, + Elf_Data *data); +static void elf_print_rel(struct elfdump *ed, struct section *s, + Elf_Data *data); +static void elf_print_reloc(struct elfdump *ed); +static void elf_print_got(struct elfdump *ed); +static void elf_print_got_section(struct elfdump *ed, struct section *s); +static void elf_print_note(struct elfdump *ed); +static void elf_print_svr4_hash(struct elfdump *ed, struct section *s); +static void elf_print_svr4_hash64(struct elfdump *ed, struct section *s); +static void elf_print_gnu_hash(struct elfdump *ed, struct section *s); +static void elf_print_hash(struct elfdump *ed); +static void elf_print_checksum(struct elfdump *ed); +static void find_gotrel(struct elfdump *ed, struct section *gs, + struct rel_entry *got); +static struct spec_name *find_name(struct elfdump *ed, const char *name); +static const char *get_symbol_name(struct elfdump *ed, int symtab, int i); +static const char *get_string(struct elfdump *ed, int strtab, size_t off); +static void get_versym(struct elfdump *ed, int i, uint16_t **vs, int *nvs); +static void load_sections(struct elfdump *ed); +static void unload_sections(struct elfdump *ed); +static void usage(void); +#ifdef USE_LIBARCHIVE_AR +static int ac_detect_ar(int fd); +static void ac_print_ar(struct elfdump *ed, int fd); +#else +static void elf_print_ar(struct elfdump *ed, int fd); +#endif /* USE_LIBARCHIVE_AR */ + +static struct option elfdump_longopts[] = +{ + { "help", no_argument, NULL, 'H' }, + { "version", no_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 } +}; + +int +main(int ac, char **av) +{ + struct elfdump *ed, ed_storage; + struct spec_name *sn; + int ch, i; + + ed = &ed_storage; + memset(ed, 0, sizeof(*ed)); + STAILQ_INIT(&ed->snl); + ed->out = stdout; + while ((ch = getopt_long(ac, av, "acdeiGHhknN:prsSvVw:", + elfdump_longopts, NULL)) != -1) + switch (ch) { + case 'a': + ed->options = ED_ALL; + break; + case 'c': + ed->options |= ED_SHDR; + break; + case 'd': + ed->options |= ED_DYN; + break; + case 'e': + ed->options |= ED_EHDR; + break; + case 'i': + ed->options |= ED_INTERP; + break; + case 'G': + ed->options |= ED_GOT; + break; + case 'h': + ed->options |= ED_HASH; + break; + case 'k': + ed->options |= ED_CHECKSUM; + break; + case 'n': + ed->options |= ED_NOTE; + break; + case 'N': + add_name(ed, optarg); + break; + case 'p': + ed->options |= ED_PHDR; + break; + case 'r': + ed->options |= ED_REL; + break; + case 's': + ed->options |= ED_SYMTAB; + break; + case 'S': + ed->flags |= SOLARIS_FMT; + break; + case 'v': + ed->options |= ED_SYMVER; + break; + case 'V': + (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), + elftc_version()); + exit(EXIT_SUCCESS); + break; + case 'w': + if ((ed->out = fopen(optarg, "w")) == NULL) + err(EXIT_FAILURE, "%s", optarg); + break; + case '?': + case 'H': + default: + usage(); + } + + ac -= optind; + av += optind; + + if (ed->options == 0) + ed->options = ED_ALL; + sn = NULL; + if (ed->options & ED_SYMTAB && + (STAILQ_EMPTY(&ed->snl) || (sn = find_name(ed, "ARSYM")) != NULL)) { + ed->flags |= PRINT_ARSYM; + if (sn != NULL) { + STAILQ_REMOVE(&ed->snl, sn, spec_name, sn_list); + if (STAILQ_EMPTY(&ed->snl)) + ed->flags |= ONLY_ARSYM; + } + } + if (ac == 0) + usage(); + if (ac > 1) + ed->flags |= PRINT_FILENAME; + if (elf_version(EV_CURRENT) == EV_NONE) + errx(EXIT_FAILURE, "ELF library initialization failed: %s", + elf_errmsg(-1)); + + for (i = 0; i < ac; i++) { + ed->filename = av[i]; + ed->archive = NULL; + elf_print_object(ed); + } + + exit(EXIT_SUCCESS); +} + +#ifdef USE_LIBARCHIVE_AR + +/* Archive symbol table entry. */ +struct arsym_entry { + char *sym_name; + size_t off; +}; + +/* + * Convenient wrapper for general libarchive error handling. + */ +#define AC(CALL) do { \ + if ((CALL)) { \ + warnx("%s", archive_error_string(a)); \ + return; \ + } \ +} while (0) + +/* + * Detect an ar(1) archive using libarchive(3). + */ +static int +ac_detect_ar(int fd) +{ + struct archive *a; + struct archive_entry *entry; + int r; + + r = -1; + if ((a = archive_read_new()) == NULL) + return (0); + archive_read_support_format_ar(a); + if (archive_read_open_fd(a, fd, 10240) == ARCHIVE_OK) + r = archive_read_next_header(a, &entry); + archive_read_close(a); + archive_read_free(a); + + return (r == ARCHIVE_OK); +} + +/* + * Dump an ar(1) archive using libarchive(3). + */ +static void +ac_print_ar(struct elfdump *ed, int fd) +{ + struct archive *a; + struct archive_entry *entry; + struct arsym_entry *arsym; + const char *name; + char idx[10], *b; + void *buff; + size_t size; + uint32_t cnt; + int i, r; + + if (lseek(fd, 0, SEEK_SET) == -1) + err(EXIT_FAILURE, "lseek failed"); + if ((a = archive_read_new()) == NULL) + errx(EXIT_FAILURE, "%s", archive_error_string(a)); + archive_read_support_format_ar(a); + AC(archive_read_open_fd(a, fd, 10240)); + for(;;) { + r = archive_read_next_header(a, &entry); + if (r == ARCHIVE_FATAL) + errx(EXIT_FAILURE, "%s", archive_error_string(a)); + if (r == ARCHIVE_EOF) + break; + if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY) + warnx("%s", archive_error_string(a)); + if (r == ARCHIVE_RETRY) + continue; + name = archive_entry_pathname(entry); + size = archive_entry_size(entry); + if (size == 0) + continue; + if ((buff = malloc(size)) == NULL) { + warn("malloc failed"); + continue; + } + if (archive_read_data(a, buff, size) != (ssize_t)size) { + warnx("%s", archive_error_string(a)); + free(buff); + continue; + } + + /* + * Note that when processing arsym via libarchive, there is + * no way to tell which member a certain symbol belongs to, + * since we can not just "lseek" to a member offset and read + * the member header. + */ + if (!strcmp(name, "/") && ed->flags & PRINT_ARSYM) { + b = buff; + cnt = be32dec(b); + if (cnt == 0) { + free(buff); + continue; + } + arsym = calloc(cnt, sizeof(*arsym)); + if (arsym == NULL) + err(EXIT_FAILURE, "calloc failed"); + b += sizeof(uint32_t); + for (i = 0; (size_t)i < cnt; i++) { + arsym[i].off = be32dec(b); + b += sizeof(uint32_t); + } + for (i = 0; (size_t)i < cnt; i++) { + arsym[i].sym_name = b; + b += strlen(b) + 1; + } + if (ed->flags & SOLARIS_FMT) { + PRT("\nSymbol Table: (archive)\n"); + PRT(" index offset symbol\n"); + } else + PRT("\nsymbol table (archive):\n"); + for (i = 0; (size_t)i < cnt; i++) { + if (ed->flags & SOLARIS_FMT) { + snprintf(idx, sizeof(idx), "[%d]", i); + PRT("%10s ", idx); + PRT("0x%8.8jx ", + (uintmax_t)arsym[i].off); + PRT("%s\n", arsym[i].sym_name); + } else { + PRT("\nentry: %d\n", i); + PRT("\toffset: %#jx\n", + (uintmax_t)arsym[i].off); + PRT("\tsymbol: %s\n", + arsym[i].sym_name); + } + } + free(arsym); + free(buff); + /* No need to continue if we only dump ARSYM. */ + if (ed->flags & ONLY_ARSYM) { + AC(archive_read_close(a)); + AC(archive_read_free(a)); + return; + } + continue; + } + if ((ed->elf = elf_memory(buff, size)) == NULL) { + warnx("elf_memroy() failed: %s", + elf_errmsg(-1)); + free(buff); + continue; + } + /* Skip non-ELF member. */ + if (elf_kind(ed->elf) == ELF_K_ELF) { + printf("\n%s(%s):\n", ed->archive, name); + elf_print_elf(ed); + } + elf_end(ed->elf); + free(buff); + } + AC(archive_read_close(a)); + AC(archive_read_free(a)); +} + +#else /* USE_LIBARCHIVE_AR */ + +/* + * Dump an ar(1) archive. + */ +static void +elf_print_ar(struct elfdump *ed, int fd) +{ + Elf *e; + Elf_Arhdr *arh; + Elf_Arsym *arsym; + Elf_Cmd cmd; + char idx[10]; + size_t cnt; + int i; + + ed->ar = ed->elf; + + if (ed->flags & PRINT_ARSYM) { + cnt = 0; + if ((arsym = elf_getarsym(ed->ar, &cnt)) == NULL) { + warnx("elf_getarsym failed: %s", elf_errmsg(-1)); + goto print_members; + } + if (cnt == 0) + goto print_members; + if (ed->flags & SOLARIS_FMT) { + PRT("\nSymbol Table: (archive)\n"); + PRT(" index offset member name and symbol\n"); + } else + PRT("\nsymbol table (archive):\n"); + for (i = 0; (size_t)i < cnt - 1; i++) { + if (elf_rand(ed->ar, arsym[i].as_off) != + arsym[i].as_off) { + warnx("elf_rand failed: %s", elf_errmsg(-1)); + break; + } + if ((e = elf_begin(fd, ELF_C_READ, ed->ar)) == NULL) { + warnx("elf_begin failed: %s", elf_errmsg(-1)); + break; + } + if ((arh = elf_getarhdr(e)) == NULL) { + warnx("elf_getarhdr failed: %s", + elf_errmsg(-1)); + break; + } + if (ed->flags & SOLARIS_FMT) { + snprintf(idx, sizeof(idx), "[%d]", i); + PRT("%10s ", idx); + PRT("0x%8.8jx ", + (uintmax_t)arsym[i].as_off); + PRT("(%s):%s\n", arh->ar_name, + arsym[i].as_name); + } else { + PRT("\nentry: %d\n", i); + PRT("\toffset: %#jx\n", + (uintmax_t)arsym[i].as_off); + PRT("\tmember: %s\n", arh->ar_name); + PRT("\tsymbol: %s\n", arsym[i].as_name); + } + elf_end(e); + } + + /* No need to continue if we only dump ARSYM. */ + if (ed->flags & ONLY_ARSYM) + return; + } + +print_members: + + /* Rewind the archive. */ + if (elf_rand(ed->ar, SARMAG) != SARMAG) { + warnx("elf_rand failed: %s", elf_errmsg(-1)); + return; + } + + /* Dump each member of the archive. */ + cmd = ELF_C_READ; + while ((ed->elf = elf_begin(fd, cmd, ed->ar)) != NULL) { + /* Skip non-ELF member. */ + if (elf_kind(ed->elf) == ELF_K_ELF) { + if ((arh = elf_getarhdr(ed->elf)) == NULL) { + warnx("elf_getarhdr failed: %s", + elf_errmsg(-1)); + break; + } + printf("\n%s(%s):\n", ed->archive, arh->ar_name); + elf_print_elf(ed); + } + cmd = elf_next(ed->elf); + elf_end(ed->elf); + } +} + +#endif /* USE_LIBARCHIVE_AR */ + +/* + * Dump an object. (ELF object or ar(1) archive) + */ +static void +elf_print_object(struct elfdump *ed) +{ + int fd; + + if ((fd = open(ed->filename, O_RDONLY)) == -1) { + warn("open %s failed", ed->filename); + return; + } + +#ifdef USE_LIBARCHIVE_AR + if (ac_detect_ar(fd)) { + ed->archive = ed->filename; + ac_print_ar(ed, fd); + return; + } +#endif /* USE_LIBARCHIVE_AR */ + + if ((ed->elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { + warnx("elf_begin() failed: %s", elf_errmsg(-1)); + return; + } + + switch (elf_kind(ed->elf)) { + case ELF_K_NONE: + warnx("Not an ELF file."); + return; + case ELF_K_ELF: + if (ed->flags & PRINT_FILENAME) + printf("\n%s:\n", ed->filename); + elf_print_elf(ed); + break; + case ELF_K_AR: +#ifndef USE_LIBARCHIVE_AR + ed->archive = ed->filename; + elf_print_ar(ed, fd); +#endif + break; + default: + warnx("Internal: libelf returned unknown elf kind."); + return; + } + + elf_end(ed->elf); +} + +/* + * Dump an ELF object. + */ +static void +elf_print_elf(struct elfdump *ed) +{ + + if (gelf_getehdr(ed->elf, &ed->ehdr) == NULL) { + warnx("gelf_getehdr failed: %s", elf_errmsg(-1)); + return; + } + if ((ed->ec = gelf_getclass(ed->elf)) == ELFCLASSNONE) { + warnx("gelf_getclass failed: %s", elf_errmsg(-1)); + return; + } + + if (ed->options & (ED_SHDR | ED_DYN | ED_REL | ED_GOT | ED_SYMTAB | + ED_SYMVER | ED_NOTE | ED_HASH)) + load_sections(ed); + + if (ed->options & ED_EHDR) + elf_print_ehdr(ed); + if (ed->options & ED_PHDR) + elf_print_phdr(ed); + if (ed->options & ED_INTERP) + elf_print_interp(ed); + if (ed->options & ED_SHDR) + elf_print_shdr(ed); + if (ed->options & ED_DYN) + elf_print_dynamic(ed); + if (ed->options & ED_REL) + elf_print_reloc(ed); + if (ed->options & ED_GOT) + elf_print_got(ed); + if (ed->options & ED_SYMTAB) + elf_print_symtabs(ed); + if (ed->options & ED_SYMVER) + elf_print_symver(ed); + if (ed->options & ED_NOTE) + elf_print_note(ed); + if (ed->options & ED_HASH) + elf_print_hash(ed); + if (ed->options & ED_CHECKSUM) + elf_print_checksum(ed); + + unload_sections(ed); +} + +/* + * Read the section headers from ELF object and store them in the + * internal cache. + */ +static void +load_sections(struct elfdump *ed) +{ + struct section *s; + const char *name; + Elf_Scn *scn; + GElf_Shdr sh; + size_t shstrndx, ndx; + int elferr; + + assert(ed->sl == NULL); + + if (!elf_getshnum(ed->elf, &ed->shnum)) { + warnx("elf_getshnum failed: %s", elf_errmsg(-1)); + return; + } + if (ed->shnum == 0) + return; + if ((ed->sl = calloc(ed->shnum, sizeof(*ed->sl))) == NULL) + err(EXIT_FAILURE, "calloc failed"); + if (!elf_getshstrndx(ed->elf, &shstrndx)) { + warnx("elf_getshstrndx failed: %s", elf_errmsg(-1)); + return; + } + if ((scn = elf_getscn(ed->elf, 0)) == NULL) { + warnx("elf_getscn failed: %s", elf_errmsg(-1)); + return; + } + (void) elf_errno(); + do { + if (gelf_getshdr(scn, &sh) == NULL) { + warnx("gelf_getshdr failed: %s", elf_errmsg(-1)); + (void) elf_errno(); + continue; + } + if ((name = elf_strptr(ed->elf, shstrndx, sh.sh_name)) == NULL) { + (void) elf_errno(); + name = "ERROR"; + } + if ((ndx = elf_ndxscn(scn)) == SHN_UNDEF) + if ((elferr = elf_errno()) != 0) { + warnx("elf_ndxscn failed: %s", + elf_errmsg(elferr)); + continue; + } + if (ndx >= ed->shnum) { + warnx("section index of '%s' out of range", name); + continue; + } + s = &ed->sl[ndx]; + s->name = name; + s->scn = scn; + s->off = sh.sh_offset; + s->sz = sh.sh_size; + s->entsize = sh.sh_entsize; + s->align = sh.sh_addralign; + s->type = sh.sh_type; + s->flags = sh.sh_flags; + s->addr = sh.sh_addr; + s->link = sh.sh_link; + s->info = sh.sh_info; + } while ((scn = elf_nextscn(ed->elf, scn)) != NULL); + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); +} + +/* + * Release section related resources. + */ +static void +unload_sections(struct elfdump *ed) +{ + if (ed->sl != NULL) { + free(ed->sl); + ed->sl = NULL; + } +} + +/* + * Add a name to the '-N' name list. + */ +static void +add_name(struct elfdump *ed, const char *name) +{ + struct spec_name *sn; + + if (find_name(ed, name)) + return; + if ((sn = malloc(sizeof(*sn))) == NULL) { + warn("malloc failed"); + return; + } + sn->name = name; + STAILQ_INSERT_TAIL(&ed->snl, sn, sn_list); +} + +/* + * Lookup a name in the '-N' name list. + */ +static struct spec_name * +find_name(struct elfdump *ed, const char *name) +{ + struct spec_name *sn; + + STAILQ_FOREACH(sn, &ed->snl, sn_list) { + if (!strcmp(sn->name, name)) + return (sn); + } + + return (NULL); +} + +/* + * Retrieve the name of a symbol using the section index of the symbol + * table and the index of the symbol within that table. + */ +static const char * +get_symbol_name(struct elfdump *ed, int symtab, int i) +{ + static char sname[64]; + struct section *s; + const char *name; + GElf_Sym sym; + Elf_Data *data; + int elferr; + + s = &ed->sl[symtab]; + if (s->type != SHT_SYMTAB && s->type != SHT_DYNSYM) + return (""); + (void) elf_errno(); + if ((data = elf_getdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_getdata failed: %s", elf_errmsg(elferr)); + return (""); + } + if (gelf_getsym(data, i, &sym) != &sym) + return (""); + if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) { + if (sym.st_shndx < ed->shnum) { + snprintf(sname, sizeof(sname), "%s (section)", + ed->sl[sym.st_shndx].name); + return (sname); + } else + return (""); + } + if ((name = elf_strptr(ed->elf, s->link, sym.st_name)) == NULL) + return (""); + + return (name); +} + +/* + * Retrieve a string using string table section index and the string offset. + */ +static const char* +get_string(struct elfdump *ed, int strtab, size_t off) +{ + const char *name; + + if ((name = elf_strptr(ed->elf, strtab, off)) == NULL) + return (""); + + return (name); +} + +/* + * Dump the ELF Executable Header. + */ +static void +elf_print_ehdr(struct elfdump *ed) +{ + + if (!STAILQ_EMPTY(&ed->snl)) + return; + + if (ed->flags & SOLARIS_FMT) { + PRT("\nELF Header\n"); + PRT(" ei_magic: { %#x, %c, %c, %c }\n", + ed->ehdr.e_ident[0], ed->ehdr.e_ident[1], + ed->ehdr.e_ident[2], ed->ehdr.e_ident[3]); + PRT(" ei_class: %-18s", + ei_classes[ed->ehdr.e_ident[EI_CLASS]]); + PRT(" ei_data: %s\n", ei_data[ed->ehdr.e_ident[EI_DATA]]); + PRT(" e_machine: %-18s", e_machines(ed->ehdr.e_machine)); + PRT(" e_version: %s\n", ei_versions[ed->ehdr.e_version]); + PRT(" e_type: %s\n", e_types[ed->ehdr.e_type]); + PRT(" e_flags: %18d\n", ed->ehdr.e_flags); + PRT(" e_entry: %#18jx", (uintmax_t)ed->ehdr.e_entry); + PRT(" e_ehsize: %6d", ed->ehdr.e_ehsize); + PRT(" e_shstrndx:%5d\n", ed->ehdr.e_shstrndx); + PRT(" e_shoff: %#18jx", (uintmax_t)ed->ehdr.e_shoff); + PRT(" e_shentsize: %3d", ed->ehdr.e_shentsize); + PRT(" e_shnum: %5d\n", ed->ehdr.e_shnum); + PRT(" e_phoff: %#18jx", (uintmax_t)ed->ehdr.e_phoff); + PRT(" e_phentsize: %3d", ed->ehdr.e_phentsize); + PRT(" e_phnum: %5d\n", ed->ehdr.e_phnum); + } else { + PRT("\nelf header:\n"); + PRT("\n"); + PRT("\te_ident: %s %s %s\n", + ei_classes[ed->ehdr.e_ident[EI_CLASS]], + ei_data[ed->ehdr.e_ident[EI_DATA]], + ei_abis[ed->ehdr.e_ident[EI_OSABI]]); + PRT("\te_type: %s\n", e_types[ed->ehdr.e_type]); + PRT("\te_machine: %s\n", e_machines(ed->ehdr.e_machine)); + PRT("\te_version: %s\n", ei_versions[ed->ehdr.e_version]); + PRT("\te_entry: %#jx\n", (uintmax_t)ed->ehdr.e_entry); + PRT("\te_phoff: %ju\n", (uintmax_t)ed->ehdr.e_phoff); + PRT("\te_shoff: %ju\n", (uintmax_t) ed->ehdr.e_shoff); + PRT("\te_flags: %u\n", ed->ehdr.e_flags); + PRT("\te_ehsize: %u\n", ed->ehdr.e_ehsize); + PRT("\te_phentsize: %u\n", ed->ehdr.e_phentsize); + PRT("\te_phnum: %u\n", ed->ehdr.e_phnum); + PRT("\te_shentsize: %u\n", ed->ehdr.e_shentsize); + PRT("\te_shnum: %u\n", ed->ehdr.e_shnum); + PRT("\te_shstrndx: %u\n", ed->ehdr.e_shstrndx); + } +} + +/* + * Dump the ELF Program Header Table. + */ +static void +elf_print_phdr(struct elfdump *ed) +{ + GElf_Phdr ph; + size_t phnum; + int header, i; + + if (elf_getphnum(ed->elf, &phnum) == 0) { + warnx("elf_getphnum failed: %s", elf_errmsg(-1)); + return; + } + header = 0; + for (i = 0; (u_int64_t) i < phnum; i++) { + if (gelf_getphdr(ed->elf, i, &ph) != &ph) { + warnx("elf_getphdr failed: %s", elf_errmsg(-1)); + continue; + } + if (!STAILQ_EMPTY(&ed->snl) && + find_name(ed, p_types[ph.p_type & 0x7]) == NULL) + continue; + if (ed->flags & SOLARIS_FMT) { + PRT("\nProgram Header[%d]:\n", i); + PRT(" p_vaddr: %#-14jx", (uintmax_t)ph.p_vaddr); + PRT(" p_flags: [ %s ]\n", p_flags[ph.p_flags]); + PRT(" p_paddr: %#-14jx", (uintmax_t)ph.p_paddr); + PRT(" p_type: [ %s ]\n", p_types[ph.p_type & 0x7]); + PRT(" p_filesz: %#-14jx", + (uintmax_t)ph.p_filesz); + PRT(" p_memsz: %#jx\n", (uintmax_t)ph.p_memsz); + PRT(" p_offset: %#-14jx", + (uintmax_t)ph.p_offset); + PRT(" p_align: %#jx\n", (uintmax_t)ph.p_align); + } else { + if (!header) { + PRT("\nprogram header:\n"); + header = 1; + } + PRT("\n"); + PRT("entry: %d\n", i); + PRT("\tp_type: %s\n", p_types[ph.p_type & 0x7]); + PRT("\tp_offset: %ju\n", (uintmax_t)ph.p_offset); + PRT("\tp_vaddr: %#jx\n", (uintmax_t)ph.p_vaddr); + PRT("\tp_paddr: %#jx\n", (uintmax_t)ph.p_paddr); + PRT("\tp_filesz: %ju\n", (uintmax_t)ph.p_filesz); + PRT("\tp_memsz: %ju\n", (uintmax_t)ph.p_memsz); + PRT("\tp_flags: %s\n", p_flags[ph.p_flags]); + PRT("\tp_align: %ju\n", (uintmax_t)ph.p_align); + } + } +} + +/* + * Dump the ELF Section Header Table. + */ +static void +elf_print_shdr(struct elfdump *ed) +{ + struct section *s; + int i; + + if (!STAILQ_EMPTY(&ed->snl)) + return; + + if ((ed->flags & SOLARIS_FMT) == 0) + PRT("\nsection header:\n"); + for (i = 0; (size_t)i < ed->shnum; i++) { + s = &ed->sl[i]; + if (ed->flags & SOLARIS_FMT) { + if (i == 0) + continue; + PRT("\nSection Header[%d]:", i); + PRT(" sh_name: %s\n", s->name); + PRT(" sh_addr: %#-14jx", (uintmax_t)s->addr); + if (s->flags != 0) + PRT(" sh_flags: [ %s ]\n", sh_flags(s->flags)); + else + PRT(" sh_flags: 0\n"); + PRT(" sh_size: %#-14jx", (uintmax_t)s->sz); + PRT(" sh_type: [ %s ]\n", sh_types(s->type)); + PRT(" sh_offset: %#-14jx", (uintmax_t)s->off); + PRT(" sh_entsize: %#jx\n", (uintmax_t)s->entsize); + PRT(" sh_link: %-14u", s->link); + PRT(" sh_info: %u\n", s->info); + PRT(" sh_addralign: %#jx\n", (uintmax_t)s->align); + } else { + PRT("\n"); + PRT("entry: %ju\n", (uintmax_t)i); + PRT("\tsh_name: %s\n", s->name); + PRT("\tsh_type: %s\n", sh_types(s->type)); + PRT("\tsh_flags: %s\n", sh_flags(s->flags)); + PRT("\tsh_addr: %#jx\n", (uintmax_t)s->addr); + PRT("\tsh_offset: %ju\n", (uintmax_t)s->off); + PRT("\tsh_size: %ju\n", (uintmax_t)s->sz); + PRT("\tsh_link: %u\n", s->link); + PRT("\tsh_info: %u\n", s->info); + PRT("\tsh_addralign: %ju\n", (uintmax_t)s->align); + PRT("\tsh_entsize: %ju\n", (uintmax_t)s->entsize); + } + } +} + +/* + * Retrieve the content of the corresponding SHT_SUNW_versym section for + * a symbol table section. + */ +static void +get_versym(struct elfdump *ed, int i, uint16_t **vs, int *nvs) +{ + struct section *s; + Elf_Data *data; + int j, elferr; + + s = NULL; + for (j = 0; (size_t)j < ed->shnum; j++) { + s = &ed->sl[j]; + if (s->type == SHT_SUNW_versym && s->link == (uint32_t)i) + break; + } + if ((size_t)j >= ed->shnum) { + *vs = NULL; + return; + } + (void) elf_errno(); + if ((data = elf_getdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_getdata failed: %s", elf_errmsg(elferr)); + *vs = NULL; + return; + } + + *vs = data->d_buf; + *nvs = data->d_size / s->entsize; +} + +/* + * Dump the symbol table section. + */ +static void +elf_print_symtab(struct elfdump *ed, int i) +{ + struct section *s; + const char *name; + uint16_t *vs; + char idx[10]; + Elf_Data *data; + GElf_Sym sym; + int len, j, elferr, nvs; + + s = &ed->sl[i]; + if (ed->flags & SOLARIS_FMT) + PRT("\nSymbol Table Section: %s\n", s->name); + else + PRT("\nsymbol table (%s):\n", s->name); + (void) elf_errno(); + if ((data = elf_getdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_getdata failed: %s", elf_errmsg(elferr)); + return; + } + vs = NULL; + nvs = 0; + len = data->d_size / s->entsize; + if (ed->flags & SOLARIS_FMT) { + if (ed->ec == ELFCLASS32) + PRT(" index value "); + else + PRT(" index value "); + PRT("size type bind oth ver shndx name\n"); + get_versym(ed, i, &vs, &nvs); + if (vs != NULL && nvs != len) { + warnx("#symbol not equal to #versym"); + vs = NULL; + } + } + for (j = 0; j < len; j++) { + if (gelf_getsym(data, j, &sym) != &sym) { + warnx("gelf_getsym failed: %s", elf_errmsg(-1)); + continue; + } + name = get_string(ed, s->link, sym.st_name); + if (ed->flags & SOLARIS_FMT) { + snprintf(idx, sizeof(idx), "[%d]", j); + if (ed->ec == ELFCLASS32) + PRT("%10s ", idx); + else + PRT("%10s ", idx); + PRT("0x%8.8jx ", (uintmax_t)sym.st_value); + if (ed->ec == ELFCLASS32) + PRT("0x%8.8jx ", (uintmax_t)sym.st_size); + else + PRT("0x%12.12jx ", (uintmax_t)sym.st_size); + PRT("%s ", st_types_S[GELF_ST_TYPE(sym.st_info)]); + PRT("%s ", st_bindings_S[GELF_ST_BIND(sym.st_info)]); + PRT("%c ", st_others[sym.st_other]); + PRT("%3u ", (vs == NULL ? 0 : vs[j])); + PRT("%-11.11s ", sh_name(ed, sym.st_shndx)); + PRT("%s\n", name); + } else { + PRT("\nentry: %d\n", j); + PRT("\tst_name: %s\n", name); + PRT("\tst_value: %#jx\n", (uintmax_t)sym.st_value); + PRT("\tst_size: %ju\n", (uintmax_t)sym.st_size); + PRT("\tst_info: %s %s\n", + st_types[GELF_ST_TYPE(sym.st_info)], + st_bindings[GELF_ST_BIND(sym.st_info)]); + PRT("\tst_shndx: %ju\n", (uintmax_t)sym.st_shndx); + } + } +} + +/* + * Dump the symbol tables. (.dynsym and .symtab) + */ +static void +elf_print_symtabs(struct elfdump *ed) +{ + int i; + + for (i = 0; (size_t)i < ed->shnum; i++) + if ((ed->sl[i].type == SHT_SYMTAB || + ed->sl[i].type == SHT_DYNSYM) && + (STAILQ_EMPTY(&ed->snl) || find_name(ed, ed->sl[i].name))) + elf_print_symtab(ed, i); +} + +/* + * Dump the content of .dynamic section. + */ +static void +elf_print_dynamic(struct elfdump *ed) +{ + struct section *s; + const char *name; + char idx[10]; + Elf_Data *data; + GElf_Dyn dyn; + int elferr, i, len; + + s = NULL; + for (i = 0; (size_t)i < ed->shnum; i++) { + s = &ed->sl[i]; + if (s->type == SHT_DYNAMIC && + (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name))) + break; + } + if ((size_t)i >= ed->shnum) + return; + + if (ed->flags & SOLARIS_FMT) { + PRT("Dynamic Section: %s\n", s->name); + PRT(" index tag value\n"); + } else + PRT("\ndynamic:\n"); + (void) elf_errno(); + if ((data = elf_getdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_getdata failed: %s", elf_errmsg(elferr)); + return; + } + len = data->d_size / s->entsize; + for (i = 0; i < len; i++) { + if (gelf_getdyn(data, i, &dyn) != &dyn) { + warnx("gelf_getdyn failed: %s", elf_errmsg(-1)); + continue; + } + + if (ed->flags & SOLARIS_FMT) { + snprintf(idx, sizeof(idx), "[%d]", i); + PRT("%10s %-16s ", idx, d_tags(dyn.d_tag)); + } else { + PRT("\n"); + PRT("entry: %d\n", i); + PRT("\td_tag: %s\n", d_tags(dyn.d_tag)); + } + switch(dyn.d_tag) { + case DT_NEEDED: + case DT_SONAME: + case DT_RPATH: + if ((name = elf_strptr(ed->elf, s->link, + dyn.d_un.d_val)) == NULL) + name = ""; + if (ed->flags & SOLARIS_FMT) + PRT("%#-16jx %s\n", (uintmax_t)dyn.d_un.d_val, + name); + else + PRT("\td_val: %s\n", name); + break; + case DT_PLTRELSZ: + case DT_RELA: + case DT_RELASZ: + case DT_RELAENT: + case DT_RELACOUNT: + case DT_STRSZ: + case DT_SYMENT: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_VERDEF: + case DT_VERDEFNUM: + case DT_VERNEED: + case DT_VERNEEDNUM: + case DT_VERSYM: + if (ed->flags & SOLARIS_FMT) + PRT("%#jx\n", (uintmax_t)dyn.d_un.d_val); + else + PRT("\td_val: %ju\n", + (uintmax_t)dyn.d_un.d_val); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_GNU_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_JMPREL: + case DT_DEBUG: + if (ed->flags & SOLARIS_FMT) + PRT("%#jx\n", (uintmax_t)dyn.d_un.d_ptr); + else + PRT("\td_ptr: %#jx\n", + (uintmax_t)dyn.d_un.d_ptr); + break; + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + default: + if (ed->flags & SOLARIS_FMT) + PRT("\n"); + break; + } + } +} + +/* + * Dump a .rel/.rela section entry. + */ +static void +elf_print_rel_entry(struct elfdump *ed, struct section *s, int j, + struct rel_entry *r) +{ + + if (ed->flags & SOLARIS_FMT) { + PRT(" %-23s ", r_type(ed->ehdr.e_machine, + GELF_R_TYPE(r->u_r.rel.r_info))); + PRT("%#12jx ", (uintmax_t)r->u_r.rel.r_offset); + if (r->type == SHT_RELA) + PRT("%10jd ", (intmax_t)r->u_r.rela.r_addend); + else + PRT(" "); + PRT("%-14s ", s->name); + PRT("%s\n", r->symn); + } else { + PRT("\n"); + PRT("entry: %d\n", j); + PRT("\tr_offset: %#jx\n", (uintmax_t)r->u_r.rel.r_offset); + if (ed->ec == ELFCLASS32) + PRT("\tr_info: %#jx\n", (uintmax_t) + ELF32_R_INFO(ELF64_R_SYM(r->u_r.rel.r_info), + ELF64_R_TYPE(r->u_r.rel.r_info))); + else + PRT("\tr_info: %#jx\n", (uintmax_t)r->u_r.rel.r_info); + if (r->type == SHT_RELA) + PRT("\tr_addend: %jd\n", + (intmax_t)r->u_r.rela.r_addend); + } +} + +/* + * Dump a relocation section of type SHT_RELA. + */ +static void +elf_print_rela(struct elfdump *ed, struct section *s, Elf_Data *data) +{ + struct rel_entry r; + int j, len; + + if (ed->flags & SOLARIS_FMT) { + PRT("\nRelocation Section: %s\n", s->name); + PRT(" type offset " + "addend section with respect to\n"); + } else + PRT("\nrelocation with addend (%s):\n", s->name); + r.type = SHT_RELA; + len = data->d_size / s->entsize; + for (j = 0; j < len; j++) { + if (gelf_getrela(data, j, &r.u_r.rela) != &r.u_r.rela) { + warnx("gelf_getrela failed: %s", + elf_errmsg(-1)); + continue; + } + r.symn = get_symbol_name(ed, s->link, + GELF_R_SYM(r.u_r.rela.r_info)); + elf_print_rel_entry(ed, s, j, &r); + } +} + +/* + * Dump a relocation section of type SHT_REL. + */ +static void +elf_print_rel(struct elfdump *ed, struct section *s, Elf_Data *data) +{ + struct rel_entry r; + int j, len; + + if (ed->flags & SOLARIS_FMT) { + PRT("\nRelocation Section: %s\n", s->name); + PRT(" type offset " + "section with respect to\n"); + } else + PRT("\nrelocation (%s):\n", s->name); + r.type = SHT_REL; + len = data->d_size / s->entsize; + for (j = 0; j < len; j++) { + if (gelf_getrel(data, j, &r.u_r.rel) != &r.u_r.rel) { + warnx("gelf_getrel failed: %s", elf_errmsg(-1)); + continue; + } + r.symn = get_symbol_name(ed, s->link, + GELF_R_SYM(r.u_r.rel.r_info)); + elf_print_rel_entry(ed, s, j, &r); + } +} + +/* + * Dump relocation sections. + */ +static void +elf_print_reloc(struct elfdump *ed) +{ + struct section *s; + Elf_Data *data; + int i, elferr; + + for (i = 0; (size_t)i < ed->shnum; i++) { + s = &ed->sl[i]; + if ((s->type == SHT_REL || s->type == SHT_RELA) && + (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name))) { + (void) elf_errno(); + if ((data = elf_getdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_getdata failed: %s", + elf_errmsg(elferr)); + continue; + } + if (s->type == SHT_REL) + elf_print_rel(ed, s, data); + else + elf_print_rela(ed, s, data); + } + } +} + +/* + * Dump the content of PT_INTERP segment. + */ +static void +elf_print_interp(struct elfdump *ed) +{ + const char *s; + GElf_Phdr phdr; + size_t phnum; + int i; + + if (!STAILQ_EMPTY(&ed->snl) && find_name(ed, "PT_INTERP") == NULL) + return; + + if ((s = elf_rawfile(ed->elf, NULL)) == NULL) { + warnx("elf_rawfile failed: %s", elf_errmsg(-1)); + return; + } + if (!elf_getphnum(ed->elf, &phnum)) { + warnx("elf_getphnum failed: %s", elf_errmsg(-1)); + return; + } + for (i = 0; (size_t)i < phnum; i++) { + if (gelf_getphdr(ed->elf, i, &phdr) != &phdr) { + warnx("elf_getphdr failed: %s", elf_errmsg(-1)); + continue; + } + if (phdr.p_type == PT_INTERP) { + PRT("\ninterp:\n"); + PRT("\t%s\n", s + phdr.p_offset); + } + } +} + +/* + * Search the relocation sections for entries refering to the .got section. + */ +static void +find_gotrel(struct elfdump *ed, struct section *gs, struct rel_entry *got) +{ + struct section *s; + struct rel_entry r; + Elf_Data *data; + int elferr, i, j, k, len; + + for(i = 0; (size_t)i < ed->shnum; i++) { + s = &ed->sl[i]; + if (s->type != SHT_REL && s->type != SHT_RELA) + continue; + (void) elf_errno(); + if ((data = elf_getdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_getdata failed: %s", + elf_errmsg(elferr)); + return; + } + memset(&r, 0, sizeof(struct rel_entry)); + r.type = s->type; + len = data->d_size / s->entsize; + for (j = 0; j < len; j++) { + if (s->type == SHT_REL) { + if (gelf_getrel(data, j, &r.u_r.rel) != + &r.u_r.rel) { + warnx("gelf_getrel failed: %s", + elf_errmsg(-1)); + continue; + } + } else { + if (gelf_getrela(data, j, &r.u_r.rela) != + &r.u_r.rela) { + warnx("gelf_getrel failed: %s", + elf_errmsg(-1)); + continue; + } + } + if (r.u_r.rel.r_offset >= gs->addr && + r.u_r.rel.r_offset < gs->addr + gs->sz) { + r.symn = get_symbol_name(ed, s->link, + GELF_R_SYM(r.u_r.rel.r_info)); + k = (r.u_r.rel.r_offset - gs->addr) / + gs->entsize; + memcpy(&got[k], &r, sizeof(struct rel_entry)); + } + } + } +} + +static void +elf_print_got_section(struct elfdump *ed, struct section *s) +{ + struct rel_entry *got; + Elf_Data *data, dst; + int elferr, i, len; + + if (s->entsize == 0) { + /* XXX IA64 GOT section generated by gcc has entry size 0. */ + if (s->align != 0) + s->entsize = s->align; + else + return; + } + + if (ed->flags & SOLARIS_FMT) + PRT("\nGlobal Offset Table Section: %s (%jd entries)\n", + s->name, s->sz / s->entsize); + else + PRT("\nglobal offset table: %s\n", s->name); + (void) elf_errno(); + if ((data = elf_getdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_getdata failed: %s", elf_errmsg(elferr)); + return; + } + + /* + * GOT section has section type SHT_PROGBITS, thus libelf treats it as + * byte stream and will not perfrom any translation on it. As a result, + * an exlicit call to gelf_xlatetom is needed here. Depends on arch, + * GOT section should be translated to either WORD or XWORD. + */ + if (ed->ec == ELFCLASS32) + data->d_type = ELF_T_WORD; + else + data->d_type = ELF_T_XWORD; + memcpy(&dst, data, sizeof(Elf_Data)); + if (gelf_xlatetom(ed->elf, &dst, data, ed->ehdr.e_ident[EI_DATA]) != + &dst) { + warnx("gelf_xlatetom failed: %s", elf_errmsg(-1)); + return; + } + len = dst.d_size / s->entsize; + if (ed->flags & SOLARIS_FMT) { + /* + * In verbose/Solaris mode, we search the relocation sections + * and try to find the corresponding reloc entry for each GOT + * section entry. + */ + if ((got = calloc(len, sizeof(struct rel_entry))) == NULL) + err(EXIT_FAILURE, "calloc failed"); + find_gotrel(ed, s, got); + if (ed->ec == ELFCLASS32) { + PRT(" ndx addr value reloc "); + PRT("addend symbol\n"); + } else { + PRT(" ndx addr value "); + PRT("reloc addend symbol\n"); + } + for(i = 0; i < len; i++) { + PRT("[%5.5d] ", i); + if (ed->ec == ELFCLASS32) { + PRT("%-8.8jx ", s->addr + i * s->entsize); + PRT("%-8.8x ", *((uint32_t *)dst.d_buf + i)); + } else { + PRT("%-16.16jx ", s->addr + i * s->entsize); + PRT("%-16.16jx ", *((uint64_t *)dst.d_buf + i)); + } + PRT("%-18s ", r_type(ed->ehdr.e_machine, + GELF_R_TYPE(got[i].u_r.rel.r_info))); + if (ed->ec == ELFCLASS32) + PRT("%-8.8jd ", + (intmax_t)got[i].u_r.rela.r_addend); + else + PRT("%-12.12jd ", + (intmax_t)got[i].u_r.rela.r_addend); + if (got[i].symn == NULL) + got[i].symn = ""; + PRT("%s\n", got[i].symn); + } + free(got); + } else { + for(i = 0; i < len; i++) { + PRT("\nentry: %d\n", i); + if (ed->ec == ELFCLASS32) + PRT("\t%#x\n", *((uint32_t *)dst.d_buf + i)); + else + PRT("\t%#jx\n", *((uint64_t *)dst.d_buf + i)); + } + } +} + +/* + * Dump the content of Global Offset Table section. + */ +static void +elf_print_got(struct elfdump *ed) +{ + struct section *s; + int i; + + if (!STAILQ_EMPTY(&ed->snl)) + return; + + s = NULL; + for (i = 0; (size_t)i < ed->shnum; i++) { + s = &ed->sl[i]; + if (s->name && !strncmp(s->name, ".got", 4) && + (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name))) + elf_print_got_section(ed, s); + } +} + +/* + * Dump the content of .note.ABI-tag section. + */ +static void +elf_print_note(struct elfdump *ed) +{ + struct section *s; + Elf_Data *data; + Elf_Note *en; + uint32_t namesz; + uint32_t descsz; + uint32_t desc; + size_t count; + int elferr, i; + char *src, idx[10]; + + s = NULL; + for (i = 0; (size_t)i < ed->shnum; i++) { + s = &ed->sl[i]; + if (s->type == SHT_NOTE && s->name && + !strcmp(s->name, ".note.ABI-tag") && + (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name))) + break; + } + if ((size_t)i >= ed->shnum) + return; + if (ed->flags & SOLARIS_FMT) + PRT("\nNote Section: %s\n", s->name); + else + PRT("\nnote (%s):\n", s->name); + (void) elf_errno(); + if ((data = elf_getdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_getdata failed: %s", elf_errmsg(elferr)); + return; + } + src = data->d_buf; + count = data->d_size; + while (count > sizeof(Elf_Note)) { + en = (Elf_Note *) (uintptr_t) src; + namesz = en->n_namesz; + descsz = en->n_descsz; + src += sizeof(Elf_Note); + count -= sizeof(Elf_Note); + if (ed->flags & SOLARIS_FMT) { + PRT("\n type %#x\n", en->n_type); + PRT(" namesz %#x:\n", en->n_namesz); + PRT("%s\n", src); + } else + PRT("\t%s ", src); + src += roundup2(namesz, 4); + count -= roundup2(namesz, 4); + + /* + * Note that we dump the whole desc part if we're in + * "Solaris mode", while in the normal mode, we only look + * at the first 4 bytes (a 32bit word) of the desc, i.e, + * we assume that it's always a FreeBSD version number. + */ + if (ed->flags & SOLARIS_FMT) { + PRT(" descsz %#x:", en->n_descsz); + for (i = 0; (uint32_t)i < descsz; i++) { + if ((i & 0xF) == 0) { + snprintf(idx, sizeof(idx), "desc[%d]", + i); + PRT("\n %-9s", idx); + } else if ((i & 0x3) == 0) + PRT(" "); + PRT(" %2.2x", src[i]); + } + PRT("\n"); + } else { + if (ed->ehdr.e_ident[EI_DATA] == ELFDATA2MSB) + desc = be32dec(src); + else + desc = le32dec(src); + PRT("%d\n", desc); + } + src += roundup2(descsz, 4); + count -= roundup2(descsz, 4); + } +} + +/* + * Dump a hash table. + */ +static void +elf_print_svr4_hash(struct elfdump *ed, struct section *s) +{ + Elf_Data *data; + uint32_t *buf; + uint32_t *bucket, *chain; + uint32_t nbucket, nchain; + uint32_t *bl, *c, maxl, total; + int i, j, first, elferr; + char idx[10]; + + if (ed->flags & SOLARIS_FMT) + PRT("\nHash Section: %s\n", s->name); + else + PRT("\nhash table (%s):\n", s->name); + (void) elf_errno(); + if ((data = elf_getdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_getdata failed: %s", + elf_errmsg(elferr)); + return; + } + if (data->d_size < 2 * sizeof(uint32_t)) { + warnx(".hash section too small"); + return; + } + buf = data->d_buf; + nbucket = buf[0]; + nchain = buf[1]; + if (nbucket <= 0 || nchain <= 0) { + warnx("Malformed .hash section"); + return; + } + if (data->d_size != (nbucket + nchain + 2) * sizeof(uint32_t)) { + warnx("Malformed .hash section"); + return; + } + bucket = &buf[2]; + chain = &buf[2 + nbucket]; + + if (ed->flags & SOLARIS_FMT) { + maxl = 0; + if ((bl = calloc(nbucket, sizeof(*bl))) == NULL) + err(EXIT_FAILURE, "calloc failed"); + for (i = 0; (uint32_t)i < nbucket; i++) + for (j = bucket[i]; j > 0 && (uint32_t)j < nchain; + j = chain[j]) + if (++bl[i] > maxl) + maxl = bl[i]; + if ((c = calloc(maxl + 1, sizeof(*c))) == NULL) + err(EXIT_FAILURE, "calloc failed"); + for (i = 0; (uint32_t)i < nbucket; i++) + c[bl[i]]++; + PRT(" bucket symndx name\n"); + for (i = 0; (uint32_t)i < nbucket; i++) { + first = 1; + for (j = bucket[i]; j > 0 && (uint32_t)j < nchain; + j = chain[j]) { + if (first) { + PRT("%10d ", i); + first = 0; + } else + PRT(" "); + snprintf(idx, sizeof(idx), "[%d]", j); + PRT("%-10s ", idx); + PRT("%s\n", get_symbol_name(ed, s->link, j)); + } + } + PRT("\n"); + total = 0; + for (i = 0; (uint32_t)i <= maxl; i++) { + total += c[i] * i; + PRT("%10u buckets contain %8d symbols\n", c[i], i); + } + PRT("%10u buckets %8u symbols (globals)\n", nbucket, + total); + } else { + PRT("\nnbucket: %u\n", nbucket); + PRT("nchain: %u\n\n", nchain); + for (i = 0; (uint32_t)i < nbucket; i++) + PRT("bucket[%d]:\n\t%u\n\n", i, bucket[i]); + for (i = 0; (uint32_t)i < nchain; i++) + PRT("chain[%d]:\n\t%u\n\n", i, chain[i]); + } +} + +/* + * Dump a 64bit hash table. + */ +static void +elf_print_svr4_hash64(struct elfdump *ed, struct section *s) +{ + Elf_Data *data, dst; + uint64_t *buf; + uint64_t *bucket, *chain; + uint64_t nbucket, nchain; + uint64_t *bl, *c, maxl, total; + int i, j, elferr, first; + char idx[10]; + + if (ed->flags & SOLARIS_FMT) + PRT("\nHash Section: %s\n", s->name); + else + PRT("\nhash table (%s):\n", s->name); + + /* + * ALPHA uses 64-bit hash entries. Since libelf assumes that + * .hash section contains only 32-bit entry, an explicit + * gelf_xlatetom is needed here. + */ + (void) elf_errno(); + if ((data = elf_rawdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_rawdata failed: %s", + elf_errmsg(elferr)); + return; + } + data->d_type = ELF_T_XWORD; + memcpy(&dst, data, sizeof(Elf_Data)); + if (gelf_xlatetom(ed->elf, &dst, data, + ed->ehdr.e_ident[EI_DATA]) != &dst) { + warnx("gelf_xlatetom failed: %s", elf_errmsg(-1)); + return; + } + if (dst.d_size < 2 * sizeof(uint64_t)) { + warnx(".hash section too small"); + return; + } + buf = dst.d_buf; + nbucket = buf[0]; + nchain = buf[1]; + if (nbucket <= 0 || nchain <= 0) { + warnx("Malformed .hash section"); + return; + } + if (dst.d_size != (nbucket + nchain + 2) * sizeof(uint64_t)) { + warnx("Malformed .hash section"); + return; + } + bucket = &buf[2]; + chain = &buf[2 + nbucket]; + + if (ed->flags & SOLARIS_FMT) { + maxl = 0; + if ((bl = calloc(nbucket, sizeof(*bl))) == NULL) + err(EXIT_FAILURE, "calloc failed"); + for (i = 0; (uint64_t)i < nbucket; i++) + for (j = bucket[i]; j > 0 && (uint64_t)j < nchain; + j = chain[j]) + if (++bl[i] > maxl) + maxl = bl[i]; + if ((c = calloc(maxl + 1, sizeof(*c))) == NULL) + err(EXIT_FAILURE, "calloc failed"); + for (i = 0; (uint64_t)i < nbucket; i++) + c[bl[i]]++; + PRT(" bucket symndx name\n"); + for (i = 0; (uint64_t)i < nbucket; i++) { + first = 1; + for (j = bucket[i]; j > 0 && (uint64_t)j < nchain; + j = chain[j]) { + if (first) { + PRT("%10d ", i); + first = 0; + } else + PRT(" "); + snprintf(idx, sizeof(idx), "[%d]", j); + PRT("%-10s ", idx); + PRT("%s\n", get_symbol_name(ed, s->link, j)); + } + } + PRT("\n"); + total = 0; + for (i = 0; (uint64_t)i <= maxl; i++) { + total += c[i] * i; + PRT("%10ju buckets contain %8d symbols\n", + (uintmax_t)c[i], i); + } + PRT("%10ju buckets %8ju symbols (globals)\n", + (uintmax_t)nbucket, (uintmax_t)total); + } else { + PRT("\nnbucket: %ju\n", (uintmax_t)nbucket); + PRT("nchain: %ju\n\n", (uintmax_t)nchain); + for (i = 0; (uint64_t)i < nbucket; i++) + PRT("bucket[%d]:\n\t%ju\n\n", i, (uintmax_t)bucket[i]); + for (i = 0; (uint64_t)i < nchain; i++) + PRT("chain[%d]:\n\t%ju\n\n", i, (uintmax_t)chain[i]); + } + +} + +/* + * Dump a GNU hash table. + */ +static void +elf_print_gnu_hash(struct elfdump *ed, struct section *s) +{ + struct section *ds; + Elf_Data *data; + uint32_t *buf; + uint32_t *bucket, *chain; + uint32_t nbucket, nchain, symndx, maskwords, shift2; + uint32_t *bl, *c, maxl, total; + int i, j, first, elferr, dynsymcount; + char idx[10]; + + if (ed->flags & SOLARIS_FMT) + PRT("\nGNU Hash Section: %s\n", s->name); + else + PRT("\ngnu hash table (%s):\n", s->name); + (void) elf_errno(); + if ((data = elf_getdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_getdata failed: %s", + elf_errmsg(elferr)); + return; + } + if (data->d_size < 4 * sizeof(uint32_t)) { + warnx(".gnu.hash section too small"); + return; + } + buf = data->d_buf; + nbucket = buf[0]; + symndx = buf[1]; + maskwords = buf[2]; + shift2 = buf[3]; + buf += 4; + ds = &ed->sl[s->link]; + dynsymcount = ds->sz / ds->entsize; + nchain = dynsymcount - symndx; + if (data->d_size != 4 * sizeof(uint32_t) + maskwords * + (ed->ec == ELFCLASS32 ? sizeof(uint32_t) : sizeof(uint64_t)) + + (nbucket + nchain) * sizeof(uint32_t)) { + warnx("Malformed .gnu.hash section"); + return; + } + bucket = buf + (ed->ec == ELFCLASS32 ? maskwords : maskwords * 2); + chain = bucket + nbucket; + + if (ed->flags & SOLARIS_FMT) { + maxl = 0; + if ((bl = calloc(nbucket, sizeof(*bl))) == NULL) + err(EXIT_FAILURE, "calloc failed"); + for (i = 0; (uint32_t)i < nbucket; i++) + for (j = bucket[i]; + j > 0 && (uint32_t)j - symndx < nchain; + j++) { + if (++bl[i] > maxl) + maxl = bl[i]; + if (chain[j - symndx] & 1) + break; + } + if ((c = calloc(maxl + 1, sizeof(*c))) == NULL) + err(EXIT_FAILURE, "calloc failed"); + for (i = 0; (uint32_t)i < nbucket; i++) + c[bl[i]]++; + PRT(" bucket symndx name\n"); + for (i = 0; (uint32_t)i < nbucket; i++) { + first = 1; + for (j = bucket[i]; + j > 0 && (uint32_t)j - symndx < nchain; + j++) { + if (first) { + PRT("%10d ", i); + first = 0; + } else + PRT(" "); + snprintf(idx, sizeof(idx), "[%d]", j ); + PRT("%-10s ", idx); + PRT("%s\n", get_symbol_name(ed, s->link, j)); + if (chain[j - symndx] & 1) + break; + } + } + PRT("\n"); + total = 0; + for (i = 0; (uint32_t)i <= maxl; i++) { + total += c[i] * i; + PRT("%10u buckets contain %8d symbols\n", c[i], i); + } + PRT("%10u buckets %8u symbols (globals)\n", nbucket, + total); + } else { + PRT("\nnbucket: %u\n", nbucket); + PRT("symndx: %u\n", symndx); + PRT("maskwords: %u\n", maskwords); + PRT("shift2: %u\n", shift2); + PRT("nchain: %u\n\n", nchain); + for (i = 0; (uint32_t)i < nbucket; i++) + PRT("bucket[%d]:\n\t%u\n\n", i, bucket[i]); + for (i = 0; (uint32_t)i < nchain; i++) + PRT("chain[%d]:\n\t%u\n\n", i, chain[i]); + } +} + +/* + * Dump hash tables. + */ +static void +elf_print_hash(struct elfdump *ed) +{ + struct section *s; + int i; + + for (i = 0; (size_t)i < ed->shnum; i++) { + s = &ed->sl[i]; + if ((s->type == SHT_HASH || s->type == SHT_GNU_HASH) && + (STAILQ_EMPTY(&ed->snl) || find_name(ed, s->name))) { + if (s->type == SHT_GNU_HASH) + elf_print_gnu_hash(ed, s); + else if (ed->ehdr.e_machine == EM_ALPHA && + s->entsize == 8) + elf_print_svr4_hash64(ed, s); + else + elf_print_svr4_hash(ed, s); + } + } +} + +/* + * Dump the content of a Version Definition(SHT_SUNW_Verdef) Section. + */ +static void +elf_print_verdef(struct elfdump *ed, struct section *s) +{ + Elf_Data *data; + Elf32_Verdef *vd; + Elf32_Verdaux *vda; + const char *str; + char idx[10]; + uint8_t *buf, *end, *buf2; + int i, j, elferr, count; + + if (ed->flags & SOLARIS_FMT) + PRT("Version Definition Section: %s\n", s->name); + else + PRT("\nversion definition section (%s):\n", s->name); + (void) elf_errno(); + if ((data = elf_getdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_getdata failed: %s", + elf_errmsg(elferr)); + return; + } + buf = data->d_buf; + end = buf + data->d_size; + i = 0; + if (ed->flags & SOLARIS_FMT) + PRT(" index version dependency\n"); + while (buf + sizeof(Elf32_Verdef) <= end) { + vd = (Elf32_Verdef *) (uintptr_t) buf; + if (ed->flags & SOLARIS_FMT) { + snprintf(idx, sizeof(idx), "[%d]", vd->vd_ndx); + PRT("%10s ", idx); + } else { + PRT("\nentry: %d\n", i++); + PRT("\tvd_version: %u\n", vd->vd_version); + PRT("\tvd_flags: %u\n", vd->vd_flags); + PRT("\tvd_ndx: %u\n", vd->vd_ndx); + PRT("\tvd_cnt: %u\n", vd->vd_cnt); + PRT("\tvd_hash: %u\n", vd->vd_hash); + PRT("\tvd_aux: %u\n", vd->vd_aux); + PRT("\tvd_next: %u\n\n", vd->vd_next); + } + buf2 = buf + vd->vd_aux; + j = 0; + count = 0; + while (buf2 + sizeof(Elf32_Verdaux) <= end && j < vd->vd_cnt) { + vda = (Elf32_Verdaux *) (uintptr_t) buf2; + str = get_string(ed, s->link, vda->vda_name); + if (ed->flags & SOLARIS_FMT) { + if (count == 0) + PRT("%-26.26s", str); + else if (count == 1) + PRT(" %-20.20s", str); + else { + PRT("\n%40.40s", ""); + PRT("%s", str); + } + } else { + PRT("\t\tvda: %d\n", j++); + PRT("\t\t\tvda_name: %s\n", str); + PRT("\t\t\tvda_next: %u\n", vda->vda_next); + } + if (vda->vda_next == 0) { + if (ed->flags & SOLARIS_FMT) { + if (vd->vd_flags & VER_FLG_BASE) { + if (count == 0) + PRT("%-20.20s", ""); + PRT("%s", "[ BASE ]"); + } + PRT("\n"); + } + break; + } + if (ed->flags & SOLARIS_FMT) + count++; + buf2 += vda->vda_next; + } + if (vd->vd_next == 0) + break; + buf += vd->vd_next; + } +} + +/* + * Dump the content of a Version Needed(SHT_SUNW_Verneed) Section. + */ +static void +elf_print_verneed(struct elfdump *ed, struct section *s) +{ + Elf_Data *data; + Elf32_Verneed *vn; + Elf32_Vernaux *vna; + uint8_t *buf, *end, *buf2; + int i, j, elferr, first; + + if (ed->flags & SOLARIS_FMT) + PRT("\nVersion Needed Section: %s\n", s->name); + else + PRT("\nversion need section (%s):\n", s->name); + (void) elf_errno(); + if ((data = elf_getdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_getdata failed: %s", + elf_errmsg(elferr)); + return; + } + buf = data->d_buf; + end = buf + data->d_size; + if (ed->flags & SOLARIS_FMT) + PRT(" file version\n"); + i = 0; + while (buf + sizeof(Elf32_Verneed) <= end) { + vn = (Elf32_Verneed *) (uintptr_t) buf; + if (ed->flags & SOLARIS_FMT) + PRT(" %-26.26s ", + get_string(ed, s->link, vn->vn_file)); + else { + PRT("\nentry: %d\n", i++); + PRT("\tvn_version: %u\n", vn->vn_version); + PRT("\tvn_cnt: %u\n", vn->vn_cnt); + PRT("\tvn_file: %s\n", + get_string(ed, s->link, vn->vn_file)); + PRT("\tvn_aux: %u\n", vn->vn_aux); + PRT("\tvn_next: %u\n\n", vn->vn_next); + } + buf2 = buf + vn->vn_aux; + j = 0; + first = 1; + while (buf2 + sizeof(Elf32_Vernaux) <= end && j < vn->vn_cnt) { + vna = (Elf32_Vernaux *) (uintptr_t) buf2; + if (ed->flags & SOLARIS_FMT) { + if (!first) + PRT("%40.40s", ""); + else + first = 0; + PRT("%s\n", get_string(ed, s->link, + vna->vna_name)); + } else { + PRT("\t\tvna: %d\n", j++); + PRT("\t\t\tvna_hash: %u\n", vna->vna_hash); + PRT("\t\t\tvna_flags: %u\n", vna->vna_flags); + PRT("\t\t\tvna_other: %u\n", vna->vna_other); + PRT("\t\t\tvna_name: %s\n", + get_string(ed, s->link, vna->vna_name)); + PRT("\t\t\tvna_next: %u\n", vna->vna_next); + } + if (vna->vna_next == 0) + break; + buf2 += vna->vna_next; + } + if (vn->vn_next == 0) + break; + buf += vn->vn_next; + } +} + +/* + * Dump the symbol-versioning sections. + */ +static void +elf_print_symver(struct elfdump *ed) +{ + struct section *s; + int i; + + for (i = 0; (size_t)i < ed->shnum; i++) { + s = &ed->sl[i]; + if (!STAILQ_EMPTY(&ed->snl) && !find_name(ed, s->name)) + continue; + if (s->type == SHT_SUNW_verdef) + elf_print_verdef(ed, s); + if (s->type == SHT_SUNW_verneed) + elf_print_verneed(ed, s); + } +} + +/* + * Dump the ELF checksum. See gelf_checksum(3) for details. + */ +static void +elf_print_checksum(struct elfdump *ed) +{ + + if (!STAILQ_EMPTY(&ed->snl)) + return; + + PRT("\nelf checksum: %#lx\n", gelf_checksum(ed->elf)); +} + +#define USAGE_MESSAGE "\ +Usage: %s [options] file...\n\ + Display information about ELF objects and ar(1) archives.\n\n\ + Options:\n\ + -a Show all information.\n\ + -c Show shared headers.\n\ + -d Show dynamic symbols.\n\ + -e Show the ELF header.\n\ + -G Show the GOT.\n\ + -H | --help Show a usage message and exit.\n\ + -h Show hash values.\n\ + -i Show the dynamic interpreter.\n\ + -k Show the ELF checksum.\n\ + -n Show the contents of note sections.\n\ + -N NAME Show the section named \"NAME\".\n\ + -p Show the program header.\n\ + -r Show relocations.\n\ + -s Show the symbol table.\n\ + -S Use the Solaris elfdump format.\n\ + -v Show symbol-versioning information.\n\ + -V | --version Print a version identifier and exit.\n\ + -w FILE Write output to \"FILE\".\n" + +static void +usage(void) +{ + fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); + exit(EXIT_FAILURE); +} Property changes on: head/contrib/elftoolchain/elfdump/elfdump.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/elftoolchain/elfdump/elfdump.1 =================================================================== --- head/contrib/elftoolchain/elfdump/elfdump.1 (nonexistent) +++ head/contrib/elftoolchain/elfdump/elfdump.1 (revision 286070) @@ -0,0 +1,158 @@ +.\" Copyright (c) 2003 David O'Brien +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: src/usr.bin/elfdump/elfdump.1,v 1.6 2005/01/18 13:43:48 ru Exp $ +.\" $Id: elfdump.1 3195 2015-05-12 17:22:19Z emaste $ +.\" +.Dd August 25, 2011 +.Dt ELFDUMP 1 +.Os +.Sh NAME +.Nm elfdump +.Nd "display information about" +.Tn ELF +files +.Sh SYNOPSIS +.Nm +.Fl a | cdeGhiknprsv +.Op Fl S +.Op Fl V +.Op Fl N Ar name +.Op Fl w Ar file +.Ar file ... +.Sh DESCRIPTION +The +.Nm +utility +dumps various information about the specified +.Tn ELF +.Ar file . +.Pp +The options are as follows: +.Bl -tag -width ".Fl w Ar file" +.It Fl a +Dump all information. +.It Fl c +Dump shared headers. +.It Fl d +Dump dynamic symbols. +.It Fl e +Dump ELF header. +.It Fl G +Dump the GOT. +.It Fl h +Dump the hash values. +.It Fl i +Dump the dynamic interpreter. +.It Fl k +Dump the ELF checksum. +.It Fl n +Dump note sections. +.It Fl N Ar name +Only dump the section with the specific +.Ar name . +Archive symbol table can be specified with +the special section name ARSYM. +More than one +.Fl N +option may appear. +.It Fl p +Dump the program header. +.It Fl r +Dump relocations. +.It Fl s +Dump the symbol table. +.It Fl S +Output in the Solaris +.Nm +format. +.It Fl v +Dump the symbol-versioning sections. +.It Fl V +Print a version identifier and exit. +.It Fl w Ar file +Write output to a +.Ar file +instead of the standard output. +.El +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +The following is an example of a typical usage +of the +.Nm +command: +.Pp +.Dl "elfdump -a -w output /bin/ls" +.Pp +To dump the content of '.dynsym' symbol table: +.Pp +.Dl "elfdump -s -N .dynsym /bin/ls" +.Pp +To dump the archive symbol table, +but not the symbol tables of archive members: +.Pp +.Dl "elfdump -s -N ARSYM /usr/lib/libelf.a" +.Pp +To dump the content of .got section and +the symbol-versioning sections in Solaris +.Nm +format: +.Pp +.Dl "elfdump -S -Gv /bin/ls" +.Sh SEE ALSO +.Xr objdump 1 , +.Xr readelf 1 , +.Xr elf 3 +.Rs +.%A "AT&T Unix Systems Labs" +.%T "System V Application Binary Interface" +.%O http://www.sco.com/developers/gabi/ +.Re +.Sh HISTORY +The +.Nm +utility first appeared in +.Fx 5.0 . +.Sh AUTHORS +.An -nosplit +The +.Nm +utility +was written by +.An Jake Burkholder Aq Mt jake@FreeBSD.org . +Later it was rewritten based on the +libelf library. +This +manual page was written by +.An David O'Brien Aq Mt obrien@FreeBSD.org . +.Pp +.An Kai Wang Aq Mt kaiw@FreeBSD.org +rewrote it using the +.Lb libelf +and implemented additional functionality. +.Sh BUGS +Does not fully implement the +.Tn ELF +gABI. Property changes on: head/contrib/elftoolchain/elfdump/elfdump.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/elftoolchain/elfdump/Makefile =================================================================== --- head/contrib/elftoolchain/elfdump/Makefile (nonexistent) +++ head/contrib/elftoolchain/elfdump/Makefile (revision 286070) @@ -0,0 +1,11 @@ +# $Id: Makefile 2289 2011-12-04 07:11:47Z jkoshy $ + +TOP= .. + +PROG= elfdump +WARNS?= 6 + +DPADD= ${LIBELFTC} ${LIBELF} +LDADD= -lelftc -lelf + +.include "${TOP}/mk/elftoolchain.prog.mk" Property changes on: head/contrib/elftoolchain/elfdump/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/elftoolchain/elfdump =================================================================== --- head/contrib/elftoolchain/elfdump (nonexistent) +++ head/contrib/elftoolchain/elfdump (revision 286070) Property changes on: head/contrib/elftoolchain/elfdump ___________________________________________________________________ Added: svn:mergeinfo ## -0,0 +0,0 ##