2010-11-22 05:27:15 +08:00
|
|
|
/* elfcomm.c -- common code for ELF format file.
|
2023-01-01 14:08:42 +08:00
|
|
|
Copyright (C) 2010-2023 Free Software Foundation, Inc.
|
2010-11-22 05:27:15 +08:00
|
|
|
|
|
|
|
Originally developed by Eric Youngdale <eric@andante.jic.com>
|
|
|
|
Modifications by Nick Clifton <nickc@redhat.com>
|
|
|
|
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
|
|
|
|
02110-1301, USA. */
|
|
|
|
|
2020-03-19 13:03:03 +08:00
|
|
|
/* Do not include bfd.h in this file. Functions in this file are used
|
|
|
|
by readelf.c and elfedit.c which define BFD64, and by objdump.c
|
|
|
|
which doesn't. */
|
2020-03-19 09:17:45 +08:00
|
|
|
|
2010-11-22 05:27:15 +08:00
|
|
|
#include "sysdep.h"
|
|
|
|
#include "libiberty.h"
|
2021-03-22 19:12:36 +08:00
|
|
|
#include "bfd.h"
|
2010-11-22 05:27:15 +08:00
|
|
|
#include "filenames.h"
|
|
|
|
#include "aout/ar.h"
|
|
|
|
#include "elfcomm.h"
|
2012-07-18 00:29:36 +08:00
|
|
|
#include <assert.h>
|
2010-11-22 05:27:15 +08:00
|
|
|
|
2020-03-19 13:03:03 +08:00
|
|
|
extern char *program_name;
|
|
|
|
|
2010-11-22 05:27:15 +08:00
|
|
|
void
|
|
|
|
error (const char *message, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
2013-03-04 22:22:25 +08:00
|
|
|
/* Try to keep error messages in sync with the program's normal output. */
|
|
|
|
fflush (stdout);
|
|
|
|
|
2010-11-22 05:27:15 +08:00
|
|
|
va_start (args, message);
|
|
|
|
fprintf (stderr, _("%s: Error: "), program_name);
|
|
|
|
vfprintf (stderr, message, args);
|
|
|
|
va_end (args);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
warn (const char *message, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
|
2013-03-04 22:22:25 +08:00
|
|
|
/* Try to keep warning messages in sync with the program's normal output. */
|
|
|
|
fflush (stdout);
|
2015-08-12 19:42:37 +08:00
|
|
|
|
2010-11-22 05:27:15 +08:00
|
|
|
va_start (args, message);
|
|
|
|
fprintf (stderr, _("%s: Warning: "), program_name);
|
|
|
|
vfprintf (stderr, message, args);
|
|
|
|
va_end (args);
|
|
|
|
}
|
|
|
|
|
2022-08-12 15:44:37 +08:00
|
|
|
void (*byte_put) (unsigned char *, uint64_t, unsigned int);
|
2010-11-22 05:27:15 +08:00
|
|
|
|
|
|
|
void
|
2022-08-12 15:44:37 +08:00
|
|
|
byte_put_little_endian (unsigned char *field, uint64_t value, unsigned int size)
|
2010-11-22 05:27:15 +08:00
|
|
|
{
|
2022-08-12 15:44:37 +08:00
|
|
|
if (size > sizeof (uint64_t))
|
2010-11-22 05:27:15 +08:00
|
|
|
{
|
|
|
|
error (_("Unhandled data length: %d\n"), size);
|
|
|
|
abort ();
|
|
|
|
}
|
2020-09-25 08:35:57 +08:00
|
|
|
while (size--)
|
|
|
|
{
|
|
|
|
*field++ = value & 0xff;
|
|
|
|
value >>= 8;
|
|
|
|
}
|
2010-11-22 05:27:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-08-12 15:44:37 +08:00
|
|
|
byte_put_big_endian (unsigned char *field, uint64_t value, unsigned int size)
|
2010-11-22 05:27:15 +08:00
|
|
|
{
|
2022-08-12 15:44:37 +08:00
|
|
|
if (size > sizeof (uint64_t))
|
2010-11-22 05:27:15 +08:00
|
|
|
{
|
|
|
|
error (_("Unhandled data length: %d\n"), size);
|
|
|
|
abort ();
|
|
|
|
}
|
2020-09-25 08:35:57 +08:00
|
|
|
while (size--)
|
|
|
|
{
|
|
|
|
field[size] = value & 0xff;
|
|
|
|
value >>= 8;
|
|
|
|
}
|
2010-11-22 05:27:15 +08:00
|
|
|
}
|
|
|
|
|
2022-08-12 15:44:37 +08:00
|
|
|
uint64_t (*byte_get) (const unsigned char *, unsigned int);
|
2010-11-22 05:27:15 +08:00
|
|
|
|
2022-08-12 15:44:37 +08:00
|
|
|
uint64_t
|
SAFE_BYTE_GET64
Functions dealing with lack of a 64-bit integer type can disappear now
that we require C99. Printing using dwarf_vmatoa is better too.
binutils/
* dwarf.c (dwarf_vmatoa64, SAFE_BYTE_GET64, add64): Delete.
(skip_attr_bytes): Replace use of SAFE_BYTE_GET64 with
SAFE_BYTE_GET_AND_INC.
(read_and_display_attr_value): Likewise. Print using dwarf_vmatoa.
(process_debug_info, process_cu_tu_index): Likewise.
* elfcomm.c (byte_put, byte_put_little_endian, byte_put_big_endian),
(byte_get, byte_get_little_endian, byte_get_big_endian),
(byte_get_signed): Make size param unsigned. Remove code dealing
with 4-byte elf_vma.
(byte_get_64): Delete.
* elfcomm.h (byte_put, byte_put_little_endian, byte_put_big_endian),
(byte_get, byte_get_little_endian, byte_get_big_endian),
(byte_get_signed): Update prototypes.
(byte_get_64): Delete.
gas/
* testsuite/gas/elf/dwarf-5-file0.d: Update.
* testsuite/gas/i386/dwarf5-line-1.d: Update.
2021-05-12 16:18:13 +08:00
|
|
|
byte_get_little_endian (const unsigned char *field, unsigned int size)
|
2010-11-22 05:27:15 +08:00
|
|
|
{
|
|
|
|
switch (size)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
return *field;
|
|
|
|
|
|
|
|
case 2:
|
2022-08-12 15:44:37 +08:00
|
|
|
return ((uint64_t) field[0]
|
|
|
|
| ((uint64_t) field[1] << 8));
|
2010-11-22 05:27:15 +08:00
|
|
|
|
|
|
|
case 3:
|
2022-08-12 15:44:37 +08:00
|
|
|
return ((uint64_t) field[0]
|
|
|
|
| ((uint64_t) field[1] << 8)
|
|
|
|
| ((uint64_t) field[2] << 16));
|
2010-11-22 05:27:15 +08:00
|
|
|
|
|
|
|
case 4:
|
2022-08-12 15:44:37 +08:00
|
|
|
return ((uint64_t) field[0]
|
|
|
|
| ((uint64_t) field[1] << 8)
|
|
|
|
| ((uint64_t) field[2] << 16)
|
|
|
|
| ((uint64_t) field[3] << 24));
|
2010-11-22 05:27:15 +08:00
|
|
|
|
2013-05-16 00:36:38 +08:00
|
|
|
case 5:
|
2022-08-12 15:44:37 +08:00
|
|
|
return ((uint64_t) field[0]
|
|
|
|
| ((uint64_t) field[1] << 8)
|
|
|
|
| ((uint64_t) field[2] << 16)
|
|
|
|
| ((uint64_t) field[3] << 24)
|
|
|
|
| ((uint64_t) field[4] << 32));
|
2013-05-16 00:36:38 +08:00
|
|
|
|
|
|
|
case 6:
|
2022-08-12 15:44:37 +08:00
|
|
|
return ((uint64_t) field[0]
|
|
|
|
| ((uint64_t) field[1] << 8)
|
|
|
|
| ((uint64_t) field[2] << 16)
|
|
|
|
| ((uint64_t) field[3] << 24)
|
|
|
|
| ((uint64_t) field[4] << 32)
|
|
|
|
| ((uint64_t) field[5] << 40));
|
2013-05-16 00:36:38 +08:00
|
|
|
|
|
|
|
case 7:
|
2022-08-12 15:44:37 +08:00
|
|
|
return ((uint64_t) field[0]
|
|
|
|
| ((uint64_t) field[1] << 8)
|
|
|
|
| ((uint64_t) field[2] << 16)
|
|
|
|
| ((uint64_t) field[3] << 24)
|
|
|
|
| ((uint64_t) field[4] << 32)
|
|
|
|
| ((uint64_t) field[5] << 40)
|
|
|
|
| ((uint64_t) field[6] << 48));
|
2013-05-16 00:36:38 +08:00
|
|
|
|
2010-11-22 05:27:15 +08:00
|
|
|
case 8:
|
2022-08-12 15:44:37 +08:00
|
|
|
return ((uint64_t) field[0]
|
|
|
|
| ((uint64_t) field[1] << 8)
|
|
|
|
| ((uint64_t) field[2] << 16)
|
|
|
|
| ((uint64_t) field[3] << 24)
|
|
|
|
| ((uint64_t) field[4] << 32)
|
|
|
|
| ((uint64_t) field[5] << 40)
|
|
|
|
| ((uint64_t) field[6] << 48)
|
|
|
|
| ((uint64_t) field[7] << 56));
|
2010-11-22 05:27:15 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
error (_("Unhandled data length: %d\n"), size);
|
|
|
|
abort ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-12 15:44:37 +08:00
|
|
|
uint64_t
|
SAFE_BYTE_GET64
Functions dealing with lack of a 64-bit integer type can disappear now
that we require C99. Printing using dwarf_vmatoa is better too.
binutils/
* dwarf.c (dwarf_vmatoa64, SAFE_BYTE_GET64, add64): Delete.
(skip_attr_bytes): Replace use of SAFE_BYTE_GET64 with
SAFE_BYTE_GET_AND_INC.
(read_and_display_attr_value): Likewise. Print using dwarf_vmatoa.
(process_debug_info, process_cu_tu_index): Likewise.
* elfcomm.c (byte_put, byte_put_little_endian, byte_put_big_endian),
(byte_get, byte_get_little_endian, byte_get_big_endian),
(byte_get_signed): Make size param unsigned. Remove code dealing
with 4-byte elf_vma.
(byte_get_64): Delete.
* elfcomm.h (byte_put, byte_put_little_endian, byte_put_big_endian),
(byte_get, byte_get_little_endian, byte_get_big_endian),
(byte_get_signed): Update prototypes.
(byte_get_64): Delete.
gas/
* testsuite/gas/elf/dwarf-5-file0.d: Update.
* testsuite/gas/i386/dwarf5-line-1.d: Update.
2021-05-12 16:18:13 +08:00
|
|
|
byte_get_big_endian (const unsigned char *field, unsigned int size)
|
2010-11-22 05:27:15 +08:00
|
|
|
{
|
|
|
|
switch (size)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
return *field;
|
|
|
|
|
|
|
|
case 2:
|
2022-08-12 15:44:37 +08:00
|
|
|
return ((uint64_t) field[1]
|
|
|
|
| ((uint64_t) field[0] << 8));
|
2010-11-22 05:27:15 +08:00
|
|
|
|
|
|
|
case 3:
|
2022-08-12 15:44:37 +08:00
|
|
|
return ((uint64_t) field[2]
|
|
|
|
| ((uint64_t) field[1] << 8)
|
|
|
|
| ((uint64_t) field[0] << 16));
|
2010-11-22 05:27:15 +08:00
|
|
|
|
|
|
|
case 4:
|
2022-08-12 15:44:37 +08:00
|
|
|
return ((uint64_t) field[3]
|
|
|
|
| ((uint64_t) field[2] << 8)
|
|
|
|
| ((uint64_t) field[1] << 16)
|
|
|
|
| ((uint64_t) field[0] << 24));
|
2010-11-22 05:27:15 +08:00
|
|
|
|
2013-05-16 00:36:38 +08:00
|
|
|
case 5:
|
2022-08-12 15:44:37 +08:00
|
|
|
return ((uint64_t) field[4]
|
|
|
|
| ((uint64_t) field[3] << 8)
|
|
|
|
| ((uint64_t) field[2] << 16)
|
|
|
|
| ((uint64_t) field[1] << 24)
|
|
|
|
| ((uint64_t) field[0] << 32));
|
2013-05-16 00:36:38 +08:00
|
|
|
|
|
|
|
case 6:
|
2022-08-12 15:44:37 +08:00
|
|
|
return ((uint64_t) field[5]
|
|
|
|
| ((uint64_t) field[4] << 8)
|
|
|
|
| ((uint64_t) field[3] << 16)
|
|
|
|
| ((uint64_t) field[2] << 24)
|
|
|
|
| ((uint64_t) field[1] << 32)
|
|
|
|
| ((uint64_t) field[0] << 40));
|
2013-05-16 00:36:38 +08:00
|
|
|
|
|
|
|
case 7:
|
2022-08-12 15:44:37 +08:00
|
|
|
return ((uint64_t) field[6]
|
|
|
|
| ((uint64_t) field[5] << 8)
|
|
|
|
| ((uint64_t) field[4] << 16)
|
|
|
|
| ((uint64_t) field[3] << 24)
|
|
|
|
| ((uint64_t) field[2] << 32)
|
|
|
|
| ((uint64_t) field[1] << 40)
|
|
|
|
| ((uint64_t) field[0] << 48));
|
2013-05-16 00:36:38 +08:00
|
|
|
|
2010-11-22 05:27:15 +08:00
|
|
|
case 8:
|
2022-08-12 15:44:37 +08:00
|
|
|
return ((uint64_t) field[7]
|
|
|
|
| ((uint64_t) field[6] << 8)
|
|
|
|
| ((uint64_t) field[5] << 16)
|
|
|
|
| ((uint64_t) field[4] << 24)
|
|
|
|
| ((uint64_t) field[3] << 32)
|
|
|
|
| ((uint64_t) field[2] << 40)
|
|
|
|
| ((uint64_t) field[1] << 48)
|
|
|
|
| ((uint64_t) field[0] << 56));
|
2010-11-22 05:27:15 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
error (_("Unhandled data length: %d\n"), size);
|
|
|
|
abort ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-12 15:44:37 +08:00
|
|
|
uint64_t
|
SAFE_BYTE_GET64
Functions dealing with lack of a 64-bit integer type can disappear now
that we require C99. Printing using dwarf_vmatoa is better too.
binutils/
* dwarf.c (dwarf_vmatoa64, SAFE_BYTE_GET64, add64): Delete.
(skip_attr_bytes): Replace use of SAFE_BYTE_GET64 with
SAFE_BYTE_GET_AND_INC.
(read_and_display_attr_value): Likewise. Print using dwarf_vmatoa.
(process_debug_info, process_cu_tu_index): Likewise.
* elfcomm.c (byte_put, byte_put_little_endian, byte_put_big_endian),
(byte_get, byte_get_little_endian, byte_get_big_endian),
(byte_get_signed): Make size param unsigned. Remove code dealing
with 4-byte elf_vma.
(byte_get_64): Delete.
* elfcomm.h (byte_put, byte_put_little_endian, byte_put_big_endian),
(byte_get, byte_get_little_endian, byte_get_big_endian),
(byte_get_signed): Update prototypes.
(byte_get_64): Delete.
gas/
* testsuite/gas/elf/dwarf-5-file0.d: Update.
* testsuite/gas/i386/dwarf5-line-1.d: Update.
2021-05-12 16:18:13 +08:00
|
|
|
byte_get_signed (const unsigned char *field, unsigned int size)
|
2010-11-22 05:27:15 +08:00
|
|
|
{
|
2022-08-12 15:44:37 +08:00
|
|
|
uint64_t x = byte_get (field, size);
|
2010-11-22 05:27:15 +08:00
|
|
|
|
|
|
|
switch (size)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
return (x ^ 0x80) - 0x80;
|
|
|
|
case 2:
|
|
|
|
return (x ^ 0x8000) - 0x8000;
|
2013-05-16 00:36:38 +08:00
|
|
|
case 3:
|
|
|
|
return (x ^ 0x800000) - 0x800000;
|
2010-11-22 05:27:15 +08:00
|
|
|
case 4:
|
|
|
|
return (x ^ 0x80000000) - 0x80000000;
|
2013-05-16 00:36:38 +08:00
|
|
|
case 5:
|
|
|
|
case 6:
|
|
|
|
case 7:
|
2010-11-22 05:27:15 +08:00
|
|
|
case 8:
|
2013-05-16 00:36:38 +08:00
|
|
|
/* Reads of 5-, 6-, and 7-byte numbers are the result of
|
|
|
|
trying to read past the end of a buffer, and will therefore
|
|
|
|
not have meaningful values, so we don't try to deal with
|
|
|
|
the sign in these cases. */
|
2010-11-22 05:27:15 +08:00
|
|
|
return x;
|
|
|
|
default:
|
|
|
|
abort ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the path name for a proxy entry in a thin archive, adjusted
|
|
|
|
relative to the path name of the thin archive itself if necessary.
|
|
|
|
Always returns a pointer to malloc'ed memory. */
|
|
|
|
|
|
|
|
char *
|
|
|
|
adjust_relative_path (const char *file_name, const char *name,
|
2014-12-01 19:19:39 +08:00
|
|
|
unsigned long name_len)
|
2010-11-22 05:27:15 +08:00
|
|
|
{
|
|
|
|
char * member_file_name;
|
|
|
|
const char * base_name = lbasename (file_name);
|
2014-12-01 19:19:39 +08:00
|
|
|
size_t amt;
|
2010-11-22 05:27:15 +08:00
|
|
|
|
|
|
|
/* This is a proxy entry for a thin archive member.
|
|
|
|
If the extended name table contains an absolute path
|
|
|
|
name, or if the archive is in the current directory,
|
|
|
|
use the path name as given. Otherwise, we need to
|
|
|
|
find the member relative to the directory where the
|
|
|
|
archive is located. */
|
|
|
|
if (IS_ABSOLUTE_PATH (name) || base_name == file_name)
|
|
|
|
{
|
2014-12-01 19:19:39 +08:00
|
|
|
amt = name_len + 1;
|
|
|
|
if (amt == 0)
|
|
|
|
return NULL;
|
|
|
|
member_file_name = (char *) malloc (amt);
|
2010-11-22 05:27:15 +08:00
|
|
|
if (member_file_name == NULL)
|
|
|
|
{
|
|
|
|
error (_("Out of memory\n"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
memcpy (member_file_name, name, name_len);
|
|
|
|
member_file_name[name_len] = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Concatenate the path components of the archive file name
|
|
|
|
to the relative path name from the extended name table. */
|
|
|
|
size_t prefix_len = base_name - file_name;
|
2014-12-01 19:19:39 +08:00
|
|
|
|
|
|
|
amt = prefix_len + name_len + 1;
|
|
|
|
/* PR 17531: file: 2896dc8b
|
|
|
|
Catch wraparound. */
|
|
|
|
if (amt < prefix_len || amt < name_len)
|
|
|
|
{
|
|
|
|
error (_("Abnormal length of thin archive member name: %lx\n"),
|
|
|
|
name_len);
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-08-12 19:42:37 +08:00
|
|
|
|
2014-12-01 19:19:39 +08:00
|
|
|
member_file_name = (char *) malloc (amt);
|
2010-11-22 05:27:15 +08:00
|
|
|
if (member_file_name == NULL)
|
|
|
|
{
|
|
|
|
error (_("Out of memory\n"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
memcpy (member_file_name, file_name, prefix_len);
|
|
|
|
memcpy (member_file_name + prefix_len, name, name_len);
|
|
|
|
member_file_name[prefix_len + name_len] = '\0';
|
|
|
|
}
|
|
|
|
return member_file_name;
|
|
|
|
}
|
|
|
|
|
2012-07-18 00:29:36 +08:00
|
|
|
/* Processes the archive index table and symbol table in ARCH.
|
|
|
|
Entries in the index table are SIZEOF_AR_INDEX bytes long.
|
|
|
|
Fills in ARCH->next_arhdr_offset and ARCH->arhdr.
|
|
|
|
If READ_SYMBOLS is true then fills in ARCH->index_num, ARCH->index_array,
|
|
|
|
ARCH->sym_size and ARCH->sym_table.
|
|
|
|
It is the caller's responsibility to free ARCH->index_array and
|
|
|
|
ARCH->sym_table.
|
2020-03-19 13:03:03 +08:00
|
|
|
Returns 1 upon success, 0 otherwise.
|
2012-07-18 00:29:36 +08:00
|
|
|
If failure occurs an error message is printed. */
|
|
|
|
|
2020-03-19 13:03:03 +08:00
|
|
|
static int
|
|
|
|
process_archive_index_and_symbols (struct archive_info *arch,
|
|
|
|
unsigned int sizeof_ar_index,
|
|
|
|
int read_symbols)
|
2012-07-18 00:29:36 +08:00
|
|
|
{
|
|
|
|
size_t got;
|
|
|
|
unsigned long size;
|
2017-10-28 19:01:16 +08:00
|
|
|
char fmag_save;
|
2012-07-18 00:29:36 +08:00
|
|
|
|
2017-10-28 19:01:16 +08:00
|
|
|
fmag_save = arch->arhdr.ar_fmag[0];
|
|
|
|
arch->arhdr.ar_fmag[0] = 0;
|
2012-07-18 00:29:36 +08:00
|
|
|
size = strtoul (arch->arhdr.ar_size, NULL, 10);
|
2017-10-28 19:01:16 +08:00
|
|
|
arch->arhdr.ar_fmag[0] = fmag_save;
|
2014-12-01 19:19:39 +08:00
|
|
|
/* PR 17531: file: 912bd7de. */
|
|
|
|
if ((signed long) size < 0)
|
|
|
|
{
|
|
|
|
error (_("%s: invalid archive header size: %ld\n"),
|
|
|
|
arch->file_name, size);
|
2020-03-19 13:03:03 +08:00
|
|
|
return 0;
|
2014-12-01 19:19:39 +08:00
|
|
|
}
|
|
|
|
|
2012-07-18 00:29:36 +08:00
|
|
|
size = size + (size & 1);
|
|
|
|
|
|
|
|
arch->next_arhdr_offset += sizeof arch->arhdr + size;
|
|
|
|
|
|
|
|
if (! read_symbols)
|
|
|
|
{
|
|
|
|
if (fseek (arch->file, size, SEEK_CUR) != 0)
|
|
|
|
{
|
|
|
|
error (_("%s: failed to skip archive symbol table\n"),
|
|
|
|
arch->file_name);
|
2020-03-19 13:03:03 +08:00
|
|
|
return 0;
|
2012-07-18 00:29:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned long i;
|
|
|
|
/* A buffer used to hold numbers read in from an archive index.
|
|
|
|
These are always SIZEOF_AR_INDEX bytes long and stored in
|
|
|
|
big-endian format. */
|
|
|
|
unsigned char integer_buffer[sizeof arch->index_num];
|
|
|
|
unsigned char * index_buffer;
|
|
|
|
|
|
|
|
assert (sizeof_ar_index <= sizeof integer_buffer);
|
2015-08-12 19:42:37 +08:00
|
|
|
|
2012-07-18 00:29:36 +08:00
|
|
|
/* Check the size of the archive index. */
|
|
|
|
if (size < sizeof_ar_index)
|
|
|
|
{
|
|
|
|
error (_("%s: the archive index is empty\n"), arch->file_name);
|
2020-03-19 13:03:03 +08:00
|
|
|
return 0;
|
2012-07-18 00:29:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Read the number of entries in the archive index. */
|
|
|
|
got = fread (integer_buffer, 1, sizeof_ar_index, arch->file);
|
|
|
|
if (got != sizeof_ar_index)
|
|
|
|
{
|
|
|
|
error (_("%s: failed to read archive index\n"), arch->file_name);
|
2020-03-19 13:03:03 +08:00
|
|
|
return 0;
|
2012-07-18 00:29:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
arch->index_num = byte_get_big_endian (integer_buffer, sizeof_ar_index);
|
|
|
|
size -= sizeof_ar_index;
|
|
|
|
|
2014-12-09 01:51:46 +08:00
|
|
|
if (size < arch->index_num * sizeof_ar_index
|
|
|
|
/* PR 17531: file: 585515d1. */
|
|
|
|
|| size < arch->index_num)
|
2012-07-18 00:29:36 +08:00
|
|
|
{
|
2014-12-09 01:51:46 +08:00
|
|
|
error (_("%s: the archive index is supposed to have 0x%lx entries of %d bytes, but the size is only 0x%lx\n"),
|
2012-07-18 00:29:36 +08:00
|
|
|
arch->file_name, (long) arch->index_num, sizeof_ar_index, size);
|
2020-03-19 13:03:03 +08:00
|
|
|
return 0;
|
2012-07-18 00:29:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Read in the archive index. */
|
|
|
|
index_buffer = (unsigned char *)
|
|
|
|
malloc (arch->index_num * sizeof_ar_index);
|
|
|
|
if (index_buffer == NULL)
|
|
|
|
{
|
|
|
|
error (_("Out of memory whilst trying to read archive symbol index\n"));
|
2020-03-19 13:03:03 +08:00
|
|
|
return 0;
|
2012-07-18 00:29:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
got = fread (index_buffer, sizeof_ar_index, arch->index_num, arch->file);
|
|
|
|
if (got != arch->index_num)
|
|
|
|
{
|
|
|
|
free (index_buffer);
|
|
|
|
error (_("%s: failed to read archive index\n"), arch->file_name);
|
2020-03-19 13:03:03 +08:00
|
|
|
return 0;
|
2012-07-18 00:29:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
size -= arch->index_num * sizeof_ar_index;
|
|
|
|
|
|
|
|
/* Convert the index numbers into the host's numeric format. */
|
2022-08-12 15:44:37 +08:00
|
|
|
arch->index_array = (uint64_t *)
|
|
|
|
malloc (arch->index_num * sizeof (*arch->index_array));
|
2012-07-18 00:29:36 +08:00
|
|
|
if (arch->index_array == NULL)
|
|
|
|
{
|
|
|
|
free (index_buffer);
|
|
|
|
error (_("Out of memory whilst trying to convert the archive symbol index\n"));
|
2020-03-19 13:03:03 +08:00
|
|
|
return 0;
|
2012-07-18 00:29:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < arch->index_num; i++)
|
|
|
|
arch->index_array[i] =
|
|
|
|
byte_get_big_endian ((unsigned char *) (index_buffer + (i * sizeof_ar_index)),
|
|
|
|
sizeof_ar_index);
|
|
|
|
free (index_buffer);
|
|
|
|
|
|
|
|
/* The remaining space in the header is taken up by the symbol table. */
|
|
|
|
if (size < 1)
|
|
|
|
{
|
|
|
|
error (_("%s: the archive has an index but no symbols\n"),
|
|
|
|
arch->file_name);
|
2020-03-19 13:03:03 +08:00
|
|
|
return 0;
|
2012-07-18 00:29:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
arch->sym_table = (char *) malloc (size);
|
|
|
|
if (arch->sym_table == NULL)
|
|
|
|
{
|
|
|
|
error (_("Out of memory whilst trying to read archive index symbol table\n"));
|
2020-03-19 13:03:03 +08:00
|
|
|
return 0;
|
2012-07-18 00:29:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
arch->sym_size = size;
|
|
|
|
got = fread (arch->sym_table, 1, size, arch->file);
|
|
|
|
if (got != size)
|
|
|
|
{
|
|
|
|
error (_("%s: failed to read archive index symbol table\n"),
|
|
|
|
arch->file_name);
|
2020-03-19 13:03:03 +08:00
|
|
|
return 0;
|
2012-07-18 00:29:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read the next archive header. */
|
|
|
|
got = fread (&arch->arhdr, 1, sizeof arch->arhdr, arch->file);
|
|
|
|
if (got != sizeof arch->arhdr && got != 0)
|
|
|
|
{
|
|
|
|
error (_("%s: failed to read archive header following archive index\n"),
|
|
|
|
arch->file_name);
|
2020-03-19 13:03:03 +08:00
|
|
|
return 0;
|
2012-07-18 00:29:36 +08:00
|
|
|
}
|
|
|
|
|
2020-03-19 13:03:03 +08:00
|
|
|
return 1;
|
2012-07-18 00:29:36 +08:00
|
|
|
}
|
|
|
|
|
2010-11-22 05:27:15 +08:00
|
|
|
/* Read the symbol table and long-name table from an archive. */
|
|
|
|
|
|
|
|
int
|
|
|
|
setup_archive (struct archive_info *arch, const char *file_name,
|
2020-03-19 09:17:45 +08:00
|
|
|
FILE *file, off_t file_size,
|
2020-03-19 13:03:03 +08:00
|
|
|
int is_thin_archive, int read_symbols)
|
2010-11-22 05:27:15 +08:00
|
|
|
{
|
|
|
|
size_t got;
|
|
|
|
|
|
|
|
arch->file_name = strdup (file_name);
|
|
|
|
arch->file = file;
|
|
|
|
arch->index_num = 0;
|
|
|
|
arch->index_array = NULL;
|
|
|
|
arch->sym_table = NULL;
|
|
|
|
arch->sym_size = 0;
|
|
|
|
arch->longnames = NULL;
|
|
|
|
arch->longnames_size = 0;
|
|
|
|
arch->nested_member_origin = 0;
|
|
|
|
arch->is_thin_archive = is_thin_archive;
|
2020-03-19 13:03:03 +08:00
|
|
|
arch->uses_64bit_indices = 0;
|
2010-11-22 05:27:15 +08:00
|
|
|
arch->next_arhdr_offset = SARMAG;
|
|
|
|
|
|
|
|
/* Read the first archive member header. */
|
|
|
|
if (fseek (file, SARMAG, SEEK_SET) != 0)
|
|
|
|
{
|
|
|
|
error (_("%s: failed to seek to first archive header\n"), file_name);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
got = fread (&arch->arhdr, 1, sizeof arch->arhdr, file);
|
|
|
|
if (got != sizeof arch->arhdr)
|
|
|
|
{
|
|
|
|
if (got == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error (_("%s: failed to read archive header\n"), file_name);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See if this is the archive symbol table. */
|
2021-03-22 19:12:36 +08:00
|
|
|
if (startswith (arch->arhdr.ar_name, "/ "))
|
2010-11-22 05:27:15 +08:00
|
|
|
{
|
2012-07-18 00:29:36 +08:00
|
|
|
if (! process_archive_index_and_symbols (arch, 4, read_symbols))
|
|
|
|
return 1;
|
|
|
|
}
|
2021-03-22 19:12:36 +08:00
|
|
|
else if (startswith (arch->arhdr.ar_name, "/SYM64/ "))
|
2012-07-18 00:29:36 +08:00
|
|
|
{
|
2020-03-19 13:03:03 +08:00
|
|
|
arch->uses_64bit_indices = 1;
|
2012-07-18 00:29:36 +08:00
|
|
|
if (! process_archive_index_and_symbols (arch, 8, read_symbols))
|
|
|
|
return 1;
|
2010-11-22 05:27:15 +08:00
|
|
|
}
|
|
|
|
else if (read_symbols)
|
|
|
|
printf (_("%s has no archive index\n"), file_name);
|
|
|
|
|
2021-03-22 19:12:36 +08:00
|
|
|
if (startswith (arch->arhdr.ar_name, "// "))
|
2010-11-22 05:27:15 +08:00
|
|
|
{
|
|
|
|
/* This is the archive string table holding long member names. */
|
2017-10-28 19:01:16 +08:00
|
|
|
char fmag_save = arch->arhdr.ar_fmag[0];
|
|
|
|
arch->arhdr.ar_fmag[0] = 0;
|
2010-11-22 05:27:15 +08:00
|
|
|
arch->longnames_size = strtoul (arch->arhdr.ar_size, NULL, 10);
|
2017-10-28 19:01:16 +08:00
|
|
|
arch->arhdr.ar_fmag[0] = fmag_save;
|
2014-12-01 19:19:39 +08:00
|
|
|
/* PR 17531: file: 01068045. */
|
|
|
|
if (arch->longnames_size < 8)
|
|
|
|
{
|
Don't use "long" in readelf for file offsets
The aim here is to improve readelf handling of large 64-bit object
files on LLP64 hosts (Windows) where long is only 32 bits. The patch
changes more than just file offsets. Addresses and sizes are also
changed to avoid "long". Most places get to use uint64_t even where
size_t may be more appropriate, because that allows some overflow
checks to be implemented easily (*alloc changes).
* dwarf.c (cmalloc, xcmalloc, xcrealloc, xcalloc2): Make nmemb
parameter uint64_t.
* dwarf.h: Update prototypes.
(struct dwarf_section): Make num_relocs uint64_t.
* elfcomm.c (setup_archive): Update error format.
* elfcomm.h (struct archive_info): Make sym_size, longnames_size,
nested_member_origin, next_arhdr_offset uint64_t.
* readelf.c (struct filedata): Make archive_file_offset,
archive_file_size, string_table_length, dynamic_addr,
dynamic_nent, dynamic_strings_length, num_dynamic_syms,
dynamic_syminfo_offset uint64_t.
(many functions): Replace uses of "unsigned long" with
"uint64_t" or "size_t".
2022-11-23 05:03:29 +08:00
|
|
|
error (_("%s: long name table is too small, (size = %" PRId64 ")\n"),
|
2014-12-01 19:19:39 +08:00
|
|
|
file_name, arch->longnames_size);
|
|
|
|
return 1;
|
|
|
|
}
|
2014-12-23 06:44:34 +08:00
|
|
|
/* PR 17531: file: 639d6a26. */
|
2020-03-19 09:17:45 +08:00
|
|
|
if ((off_t) arch->longnames_size > file_size
|
2020-03-14 09:20:22 +08:00
|
|
|
|| (signed long) arch->longnames_size < 0)
|
2014-12-23 06:44:34 +08:00
|
|
|
{
|
Don't use "long" in readelf for file offsets
The aim here is to improve readelf handling of large 64-bit object
files on LLP64 hosts (Windows) where long is only 32 bits. The patch
changes more than just file offsets. Addresses and sizes are also
changed to avoid "long". Most places get to use uint64_t even where
size_t may be more appropriate, because that allows some overflow
checks to be implemented easily (*alloc changes).
* dwarf.c (cmalloc, xcmalloc, xcrealloc, xcalloc2): Make nmemb
parameter uint64_t.
* dwarf.h: Update prototypes.
(struct dwarf_section): Make num_relocs uint64_t.
* elfcomm.c (setup_archive): Update error format.
* elfcomm.h (struct archive_info): Make sym_size, longnames_size,
nested_member_origin, next_arhdr_offset uint64_t.
* readelf.c (struct filedata): Make archive_file_offset,
archive_file_size, string_table_length, dynamic_addr,
dynamic_nent, dynamic_strings_length, num_dynamic_syms,
dynamic_syminfo_offset uint64_t.
(many functions): Replace uses of "unsigned long" with
"uint64_t" or "size_t".
2022-11-23 05:03:29 +08:00
|
|
|
error (_("%s: long name table is too big, (size = %#" PRIx64 ")\n"),
|
2014-12-23 06:44:34 +08:00
|
|
|
file_name, arch->longnames_size);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-11-22 05:27:15 +08:00
|
|
|
arch->next_arhdr_offset += sizeof arch->arhdr + arch->longnames_size;
|
|
|
|
|
2014-12-01 19:19:39 +08:00
|
|
|
/* Plus one to allow for a string terminator. */
|
|
|
|
arch->longnames = (char *) malloc (arch->longnames_size + 1);
|
2010-11-22 05:27:15 +08:00
|
|
|
if (arch->longnames == NULL)
|
|
|
|
{
|
|
|
|
error (_("Out of memory reading long symbol names in archive\n"));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fread (arch->longnames, arch->longnames_size, 1, file) != 1)
|
|
|
|
{
|
|
|
|
free (arch->longnames);
|
|
|
|
arch->longnames = NULL;
|
|
|
|
error (_("%s: failed to read long symbol name string table\n"),
|
|
|
|
file_name);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((arch->longnames_size & 1) != 0)
|
|
|
|
getc (file);
|
2014-12-23 06:44:34 +08:00
|
|
|
|
|
|
|
arch->longnames[arch->longnames_size] = 0;
|
2010-11-22 05:27:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Open and setup a nested archive, if not already open. */
|
|
|
|
|
|
|
|
int
|
|
|
|
setup_nested_archive (struct archive_info *nested_arch,
|
|
|
|
const char *member_file_name)
|
|
|
|
{
|
|
|
|
FILE * member_file;
|
2020-03-14 09:20:22 +08:00
|
|
|
struct stat statbuf;
|
2010-11-22 05:27:15 +08:00
|
|
|
|
|
|
|
/* Have we already setup this archive? */
|
|
|
|
if (nested_arch->file_name != NULL
|
|
|
|
&& streq (nested_arch->file_name, member_file_name))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Close previous file and discard cached information. */
|
|
|
|
if (nested_arch->file != NULL)
|
2020-06-27 11:17:45 +08:00
|
|
|
{
|
|
|
|
fclose (nested_arch->file);
|
|
|
|
nested_arch->file = NULL;
|
|
|
|
}
|
2010-11-22 05:27:15 +08:00
|
|
|
release_archive (nested_arch);
|
|
|
|
|
|
|
|
member_file = fopen (member_file_name, "rb");
|
|
|
|
if (member_file == NULL)
|
|
|
|
return 1;
|
2020-03-14 09:20:22 +08:00
|
|
|
if (fstat (fileno (member_file), &statbuf) < 0)
|
|
|
|
return 1;
|
2010-11-22 05:27:15 +08:00
|
|
|
return setup_archive (nested_arch, member_file_name, member_file,
|
2020-03-19 13:03:03 +08:00
|
|
|
statbuf.st_size, 0, 0);
|
2010-11-22 05:27:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Release the memory used for the archive information. */
|
|
|
|
|
|
|
|
void
|
|
|
|
release_archive (struct archive_info * arch)
|
|
|
|
{
|
2020-05-20 21:18:41 +08:00
|
|
|
free (arch->file_name);
|
|
|
|
free (arch->index_array);
|
|
|
|
free (arch->sym_table);
|
|
|
|
free (arch->longnames);
|
2020-06-27 11:17:45 +08:00
|
|
|
arch->file_name = NULL;
|
|
|
|
arch->index_array = NULL;
|
|
|
|
arch->sym_table = NULL;
|
|
|
|
arch->longnames = NULL;
|
2010-11-22 05:27:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the name of an archive member from the current archive header.
|
|
|
|
For simple names, this will modify the ar_name field of the current
|
|
|
|
archive header. For long names, it will return a pointer to the
|
|
|
|
longnames table. For nested archives, it will open the nested archive
|
|
|
|
and get the name recursively. NESTED_ARCH is a single-entry cache so
|
|
|
|
we don't keep rereading the same information from a nested archive. */
|
|
|
|
|
|
|
|
char *
|
|
|
|
get_archive_member_name (struct archive_info *arch,
|
|
|
|
struct archive_info *nested_arch)
|
|
|
|
{
|
|
|
|
unsigned long j, k;
|
|
|
|
|
|
|
|
if (arch->arhdr.ar_name[0] == '/')
|
|
|
|
{
|
|
|
|
/* We have a long name. */
|
|
|
|
char *endp;
|
|
|
|
char *member_file_name;
|
|
|
|
char *member_name;
|
2017-10-28 19:01:16 +08:00
|
|
|
char fmag_save;
|
2010-11-22 05:27:15 +08:00
|
|
|
|
2013-02-08 00:07:03 +08:00
|
|
|
if (arch->longnames == NULL || arch->longnames_size == 0)
|
|
|
|
{
|
|
|
|
error (_("Archive member uses long names, but no longname table found\n"));
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-08-12 19:42:37 +08:00
|
|
|
|
2010-11-22 05:27:15 +08:00
|
|
|
arch->nested_member_origin = 0;
|
2017-10-28 19:01:16 +08:00
|
|
|
fmag_save = arch->arhdr.ar_fmag[0];
|
|
|
|
arch->arhdr.ar_fmag[0] = 0;
|
2010-11-22 05:27:15 +08:00
|
|
|
k = j = strtoul (arch->arhdr.ar_name + 1, &endp, 10);
|
|
|
|
if (arch->is_thin_archive && endp != NULL && * endp == ':')
|
|
|
|
arch->nested_member_origin = strtoul (endp + 1, NULL, 10);
|
2017-10-28 19:01:16 +08:00
|
|
|
arch->arhdr.ar_fmag[0] = fmag_save;
|
2010-11-22 05:27:15 +08:00
|
|
|
|
2014-12-01 19:19:39 +08:00
|
|
|
if (j > arch->longnames_size)
|
|
|
|
{
|
|
|
|
error (_("Found long name index (%ld) beyond end of long name table\n"),j);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-11-22 05:27:15 +08:00
|
|
|
while ((j < arch->longnames_size)
|
|
|
|
&& (arch->longnames[j] != '\n')
|
|
|
|
&& (arch->longnames[j] != '\0'))
|
|
|
|
j++;
|
2014-12-01 19:19:39 +08:00
|
|
|
if (j > 0 && arch->longnames[j-1] == '/')
|
2010-11-22 05:27:15 +08:00
|
|
|
j--;
|
2014-12-01 19:19:39 +08:00
|
|
|
if (j > arch->longnames_size)
|
|
|
|
j = arch->longnames_size;
|
2010-11-22 05:27:15 +08:00
|
|
|
arch->longnames[j] = '\0';
|
|
|
|
|
|
|
|
if (!arch->is_thin_archive || arch->nested_member_origin == 0)
|
2020-03-13 10:51:15 +08:00
|
|
|
return xstrdup (arch->longnames + k);
|
2010-11-22 05:27:15 +08:00
|
|
|
|
2014-12-01 19:19:39 +08:00
|
|
|
/* PR 17531: file: 2896dc8b. */
|
|
|
|
if (k >= j)
|
|
|
|
{
|
|
|
|
error (_("Invalid Thin archive member name\n"));
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-08-12 19:42:37 +08:00
|
|
|
|
2010-11-22 05:27:15 +08:00
|
|
|
/* This is a proxy for a member of a nested archive.
|
|
|
|
Find the name of the member in that archive. */
|
|
|
|
member_file_name = adjust_relative_path (arch->file_name,
|
|
|
|
arch->longnames + k, j - k);
|
|
|
|
if (member_file_name != NULL
|
|
|
|
&& setup_nested_archive (nested_arch, member_file_name) == 0)
|
|
|
|
{
|
2020-03-13 10:51:15 +08:00
|
|
|
member_name = get_archive_member_name_at (nested_arch,
|
2010-11-22 05:27:15 +08:00
|
|
|
arch->nested_member_origin,
|
|
|
|
NULL);
|
|
|
|
if (member_name != NULL)
|
|
|
|
{
|
|
|
|
free (member_file_name);
|
|
|
|
return member_name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free (member_file_name);
|
|
|
|
|
|
|
|
/* Last resort: just return the name of the nested archive. */
|
2020-03-13 10:51:15 +08:00
|
|
|
return xstrdup (arch->longnames + k);
|
2010-11-22 05:27:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* We have a normal (short) name. */
|
|
|
|
for (j = 0; j < sizeof (arch->arhdr.ar_name); j++)
|
|
|
|
if (arch->arhdr.ar_name[j] == '/')
|
|
|
|
{
|
|
|
|
arch->arhdr.ar_name[j] = '\0';
|
2020-03-13 10:51:15 +08:00
|
|
|
return xstrdup (arch->arhdr.ar_name);
|
2010-11-22 05:27:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* The full ar_name field is used. Don't rely on ar_date starting
|
|
|
|
with a zero byte. */
|
|
|
|
{
|
|
|
|
char *name = xmalloc (sizeof (arch->arhdr.ar_name) + 1);
|
|
|
|
memcpy (name, arch->arhdr.ar_name, sizeof (arch->arhdr.ar_name));
|
|
|
|
name[sizeof (arch->arhdr.ar_name)] = '\0';
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the name of an archive member at a given OFFSET within an archive
|
|
|
|
ARCH. */
|
|
|
|
|
|
|
|
char *
|
|
|
|
get_archive_member_name_at (struct archive_info *arch,
|
|
|
|
unsigned long offset,
|
|
|
|
struct archive_info *nested_arch)
|
|
|
|
{
|
|
|
|
size_t got;
|
|
|
|
|
|
|
|
if (fseek (arch->file, offset, SEEK_SET) != 0)
|
|
|
|
{
|
|
|
|
error (_("%s: failed to seek to next file name\n"), arch->file_name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
got = fread (&arch->arhdr, 1, sizeof arch->arhdr, arch->file);
|
|
|
|
if (got != sizeof arch->arhdr)
|
|
|
|
{
|
|
|
|
error (_("%s: failed to read archive header\n"), arch->file_name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (memcmp (arch->arhdr.ar_fmag, ARFMAG, 2) != 0)
|
|
|
|
{
|
|
|
|
error (_("%s: did not find a valid archive header\n"),
|
|
|
|
arch->file_name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return get_archive_member_name (arch, nested_arch);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct a string showing the name of the archive member, qualified
|
|
|
|
with the name of the containing archive file. For thin archives, we
|
|
|
|
use square brackets to denote the indirection. For nested archives,
|
|
|
|
we show the qualified name of the external member inside the square
|
|
|
|
brackets (e.g., "thin.a[normal.a(foo.o)]"). */
|
|
|
|
|
|
|
|
char *
|
|
|
|
make_qualified_name (struct archive_info * arch,
|
|
|
|
struct archive_info * nested_arch,
|
|
|
|
const char *member_name)
|
|
|
|
{
|
2013-02-15 22:37:39 +08:00
|
|
|
const char * error_name = _("<corrupt>");
|
2010-11-22 05:27:15 +08:00
|
|
|
size_t len;
|
|
|
|
char * name;
|
|
|
|
|
|
|
|
len = strlen (arch->file_name) + strlen (member_name) + 3;
|
2013-02-15 22:37:39 +08:00
|
|
|
if (arch->is_thin_archive
|
|
|
|
&& arch->nested_member_origin != 0)
|
|
|
|
{
|
|
|
|
/* PR 15140: Allow for corrupt thin archives. */
|
|
|
|
if (nested_arch->file_name)
|
|
|
|
len += strlen (nested_arch->file_name) + 2;
|
|
|
|
else
|
|
|
|
len += strlen (error_name) + 2;
|
|
|
|
}
|
2010-11-22 05:27:15 +08:00
|
|
|
|
|
|
|
name = (char *) malloc (len);
|
|
|
|
if (name == NULL)
|
|
|
|
{
|
|
|
|
error (_("Out of memory\n"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-02-15 22:37:39 +08:00
|
|
|
if (arch->is_thin_archive
|
|
|
|
&& arch->nested_member_origin != 0)
|
|
|
|
{
|
|
|
|
if (nested_arch->file_name)
|
|
|
|
snprintf (name, len, "%s[%s(%s)]", arch->file_name,
|
|
|
|
nested_arch->file_name, member_name);
|
|
|
|
else
|
|
|
|
snprintf (name, len, "%s[%s(%s)]", arch->file_name,
|
2015-08-12 19:42:37 +08:00
|
|
|
error_name, member_name);
|
2013-02-15 22:37:39 +08:00
|
|
|
}
|
2010-11-22 05:27:15 +08:00
|
|
|
else if (arch->is_thin_archive)
|
|
|
|
snprintf (name, len, "%s[%s]", arch->file_name, member_name);
|
|
|
|
else
|
|
|
|
snprintf (name, len, "%s(%s)", arch->file_name, member_name);
|
|
|
|
|
|
|
|
return name;
|
|
|
|
}
|