File: elf-get-needed.c

package info (click to toggle)
gobject-introspection 1.84.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 72,336 kB
  • sloc: ansic: 562,269; python: 23,692; xml: 16,240; yacc: 1,711; perl: 1,624; sh: 1,139; lex: 510; cpp: 487; makefile: 182; javascript: 15; lisp: 1
file content (153 lines) | stat: -rw-r--r-- 3,384 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
 * Copyright © 2019-2023 Collabora Ltd.
 * SPDX-License-Identifier: MIT
 *
 * Use libelf to parse ELF headers for DT_NEEDED, and fake the output
 * format of ldd closely enough that GObject-Introspection can parse it.
 *
 * Limitations when compared with real ldd:
 * - Only direct dependencies are output: unlike ldd, this is not recursive.
 *   For GObject-Introspection this is what we ideally want anyway.
 * - Only bare SONAMEs are output, no paths or other extraneous information.
 */

#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>

#include <elf.h>
#include <gelf.h>

#if 0
#define trace(...) fprintf(stderr, __VA_ARGS__)
#else
#define trace(...) do {} while (0)
#endif

int
main (int argc,
      char **argv)
{
  const char *library;
  Elf *elf = NULL;
  Elf_Scn *scn = NULL;
  GElf_Shdr shdr_mem;
  GElf_Shdr *shdr = NULL;
  size_t phnum;
  size_t i;
  Elf_Data *data;
  uintptr_t needed_offset = (uintptr_t) -1;
  const char *needed;
  size_t sh_entsize;
  int fd;

  if (argc != 2)
    {
      fprintf (stderr, "Usage: %s LIBRARY\n", argv[0]);
      return 2;
    }

  library = argv[1];

  if (elf_version (EV_CURRENT) == EV_NONE)
    {
      perror ("elf_version(EV_CURRENT)");
      return 1;
    }

  if ((fd = open (library, O_RDONLY | O_CLOEXEC, 0)) < 0)
    {
      perror (library);
      return 1;
    }

  if ((elf = elf_begin (fd, ELF_C_READ, NULL)) == NULL)
    {
      fprintf (stderr, "Error reading library %s: %s",
               library, elf_errmsg (elf_errno ()));
      return 1;
    }

  if (elf_getphdrnum (elf, &phnum) < 0)
    {

      fprintf (stderr, "Unable to determine the number of program headers: %s\n",
               elf_errmsg (elf_errno ()));

      return 1;
    }

  trace ("phnum=%zu\n", phnum);

  for (i = 0; i < phnum; i++)
    {
      GElf_Phdr phdr_mem;
      GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);

      if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
        {
          scn = gelf_offscn (elf, phdr->p_offset);
          trace ("scn=%p\n", scn);

          if (scn == NULL)
            {
              fprintf (stderr, "Unable to get the section: %s\n",

                       elf_errmsg (elf_errno ()));

              return 1;
            }

          shdr = gelf_getshdr (scn, &shdr_mem);
          trace ("shdr=%p, shdr_mem=%p\n", shdr, &shdr_mem);

          if (shdr == NULL)
            {
              fprintf (stderr, "Unable to get the section header: %s\n",

                       elf_errmsg (elf_errno ()));

              return 1;
            }
          break;
        }
    }

  if (shdr == NULL)
    {
      fprintf (stderr, "Unable to find the section header\n");
      return 1;
    }

  data = elf_getdata (scn, NULL);

  if (data == NULL)
    {
      fprintf (stderr, "Unable to get the dynamic section data: %s\n",
               elf_errmsg (elf_errno ()));

      return 1;
    }

  trace ("data=%p\n", data);

  sh_entsize = gelf_fsize (elf, ELF_T_DYN, 1, EV_CURRENT);
  trace ("sh_entsize=%zu\n", sh_entsize);

  for (i = 0; i < shdr->sh_size / sh_entsize; i++)
    {
      GElf_Dyn dyn_mem;
      GElf_Dyn *dyn = gelf_getdyn (data, i, &dyn_mem);

      if (dyn == NULL)
        break;

      if (dyn->d_tag == DT_NEEDED)
        printf ("%s\n", elf_strptr (elf, shdr->sh_link, dyn->d_un.d_ptr));
    }

  elf_end (elf);
  close (fd);
  return 0;
}