Skip to content

Commit 1960d10

Browse files
committed
Rewrite ELF parsing from scratch w/o dependency of elf(3) and gelf(3)
In order to make it portable on other Unix operating systems, use ELF structure definitions and memory mapping to parse the ELF binary.
1 parent e65a04f commit 1960d10

File tree

6 files changed

+171
-59
lines changed

6 files changed

+171
-59
lines changed

Makefile

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ BINDIR= ${PREFIX}/bin
55

66
PROG= elfdbg
77
MAN= elfdbg.1
8-
SRCS= elfdbg.c
9-
10-
LDADD= -lelf
8+
SRCS= elfdbg.c elf.c
119

1210
test:
1311
@(cd tests && kyua test && kyua report)

README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,43 @@
11
# elfdbg
2+
3+
## About
4+
5+
This project _elfdbg_ is a utility program to quickly identify if an ELF binary
6+
is built with [debug sections](https://en.wikipedia.org/wiki/Debug_symbol)
7+
8+
Debug sections in ELF binary usually are generated using the `-g` flag with the
9+
compiler. The compiler adds the new `.debug_*` sections in the binary.
10+
11+
The program is looking for the existence of sections with name starting with
12+
`.debug_` to determine if the binary has been built with debug information.
13+
14+
The [ELF][ELF] format is a well-known standard. ELF TIS reference specification
15+
is available [here][spec] and as a FreeBSD [elf(5)][man] man page.
16+
17+
## Build and install
18+
19+
The Makefile use the standard BSDMakefile to build the program.
20+
21+
```
22+
make && sudo make install
23+
```
24+
25+
## Test
26+
27+
The tests cases are implemented using the FreeBSD test suite framework with
28+
[kyua](https://github.com/jmmv/kyua) and [Kyuafile](./tests/Kyuafile).
29+
30+
```
31+
make test
32+
```
33+
34+
## History
35+
36+
* _2015_ I wrote this using libelf elf(3) and gelf(3) API
37+
[f4b470b](https://github.com/sbz/elfdbg/commit/f4b470b)
38+
* _2020_ I rewrote this without relying on libelf API
39+
[96010ce](https://github.com/sbz/eldbg/commit/96010ce)
40+
41+
[ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
42+
[spec]: http://refspecs.linuxbase.org/elf/elf.pdf
43+
[man]: https://www.freebsd.org/cgi/man.cgi?query=elf&sektion=5

elf.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#include <fcntl.h>
2+
#include <stdio.h>
3+
#include <stdlib.h>
4+
#include <string.h>
5+
#include <sys/mman.h>
6+
#include <unistd.h>
7+
8+
#include "elf.h"
9+
10+
11+
Elf_Obj *
12+
elf_init(const char *filename)
13+
{
14+
int fd;
15+
struct stat sb;
16+
Elf_Obj *e;
17+
18+
fd = open(filename, O_RDONLY);
19+
e = (Elf_Obj *)malloc(sizeof(Elf_Obj));
20+
e->fd = fd;
21+
fstat(fd, &sb);
22+
e->sb = sb;
23+
24+
e->mm = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
25+
e->ehdr = (Elf_Ehdr *) e->mm;
26+
e->ehdr_size = e->ehdr->e_ehsize;
27+
28+
e->shdr = (Elf_Shdr *) (e->mm + e->ehdr->e_shoff);
29+
e->shdr_size = e->ehdr->e_shnum;
30+
31+
e->strtab = NULL;
32+
e->strtab_size = 0;
33+
34+
return e;
35+
}
36+
37+
Elf_Shdr *
38+
elf_strtab(Elf_Obj *e)
39+
{
40+
Elf_Shdr *ptr;
41+
42+
ptr = &e->shdr[e->ehdr->e_shstrndx];
43+
e->strtab = malloc(ptr->sh_size);
44+
e->strtab_size = ptr->sh_size;
45+
46+
memcpy(e->strtab, (e->mm + ptr->sh_offset), ptr->sh_size);
47+
48+
return ptr;
49+
}
50+
51+
int
52+
elf_destroy(Elf_Obj *e)
53+
{
54+
if (e == NULL)
55+
return 1;
56+
57+
munmap(e->mm, e->sb.st_size);
58+
close(e->fd);
59+
if (e->strtab != NULL)
60+
free(e->strtab);
61+
free(e);
62+
63+
return 0;
64+
}
65+
66+
int
67+
elf_debug(Elf_Obj *e)
68+
{
69+
int i, has_debug = 0;
70+
char *debug_prefix = ".debug_";
71+
char *section_name = NULL;
72+
73+
for (i=0; i < e->shdr_size; i++) {
74+
section_name = &e->strtab[e->shdr[i].sh_name];
75+
if (strnstr(section_name, debug_prefix, strlen(debug_prefix))) {
76+
//printf("%s\n", section_name);
77+
has_debug++;
78+
}
79+
80+
}
81+
82+
return has_debug;
83+
}

elf.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <elf.h>
2+
#include <sys/stat.h>
3+
4+
typedef struct Elf_Obj {
5+
int fd;
6+
struct stat sb;
7+
char *mm;
8+
char *strtab;
9+
size_t strtab_size;
10+
Elf_Ehdr *ehdr;
11+
size_t ehdr_size;
12+
Elf_Shdr *shdr;
13+
size_t shdr_size;
14+
} Elf_Obj;
15+
16+
Elf_Obj *elf_init(const char *filename);
17+
int elf_destroy(Elf_Obj *);
18+
Elf_Shdr *elf_strtab(Elf_Obj *);
19+
int elf_debug(Elf_Obj *);

elfdbg.1

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,20 @@
3030
.Nd analyze if binary is compiled with debug sections
3131
.Sh SYNOPSIS
3232
.Nm
33-
.Ar file
33+
.Ar [-qv] file
3434
.Sh DESCRIPTION
3535
The
3636
.Nm
37-
utility reports if a binary is compiled with debug sections, commonly
38-
known as
39-
.Ar -g
37+
utility reports if a binary is compiled with debug sections commonly generated
38+
with the
39+
.Ar -g
4040
compiler toolchain flag.
41+
42+
The program lookup for the sections name starting with
43+
.Ar .debug_
44+
in order to determine if he has debug information.
4145
.Sh SEE ALSO
42-
.Xr elf 3 ,
43-
.Xr gelf 3
46+
.Xr elf 5
4447
.Sh AUTHORS
4548
.An -nosplit
4649
The

elfdbg.c

Lines changed: 17 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -23,79 +23,46 @@
2323
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2424
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2525
*/
26-
#include <err.h>
27-
#include <fcntl.h>
28-
#include <gelf.h>
29-
#include <stdint.h>
30-
#include <string.h>
26+
#include <errno.h>
3127
#include <stdio.h>
3228
#include <stdlib.h>
29+
#include <string.h>
3330
#include <sysexits.h>
3431
#include <unistd.h>
3532

36-
extern char *__progname;
37-
38-
static int
39-
elf_debug_sections(Elf *e)
40-
{
41-
Elf_Scn *scn = NULL;
42-
GElf_Shdr shdr;
43-
size_t n, shstrndx, sz;
44-
char *name;
45-
int has_debug = 0;
46-
47-
if (elf_getshdrstrndx(e, &shstrndx) != 0)
48-
errx(EX_SOFTWARE, "elf_getshdrstrndx() failed : %s . ",
49-
elf_errmsg(-1));
33+
#include "elf.h"
5034

51-
while ((scn = elf_nextscn(e, scn)) != NULL) {
52-
gelf_getshdr(scn, &shdr);
53-
54-
name = elf_strptr(e, shstrndx, shdr.sh_name);
55-
if (!strstr(name, "debug_"))
56-
continue;
57-
58-
has_debug++;
59-
}
60-
61-
return (has_debug > 0);
62-
}
35+
extern char *__progname;
6336

6437
static void
65-
usage(void) {
38+
usage(void)
39+
{
6640
fprintf(stderr, "Usage: %s file\n", __progname);
6741
exit(EX_USAGE);
6842
}
6943

7044
int
7145
main(int argc, char *argv[])
7246
{
73-
const char *filename;
74-
int fd, rc;
75-
Elf *e;
76-
int has_debug;
47+
int rc, has_debug;
48+
Elf_Obj *e = NULL;
49+
Elf_Shdr *shstr = NULL;
7750

7851
if (argc == 1)
7952
usage();
8053

81-
filename = argv[1];
54+
/* load elf binary in memory */
55+
e = elf_init(argv[1]);
8256

83-
if (elf_version(EV_CURRENT) == EV_NONE)
84-
errx(EX_SOFTWARE, "ELF library initialization failed : %s ",
85-
elf_errmsg(-1));
57+
/* load string stable */
58+
shstr = elf_strtab(e);
8659

87-
if ((fd = open(filename, O_RDONLY, 0)) < 0)
88-
err(EX_NOINPUT, "open %s failed ", filename);
89-
if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
90-
errx(EX_SOFTWARE, "elf_begin() failed : %s", elf_errmsg(-1));
91-
if (elf_kind(e) != ELF_K_ELF)
92-
errx(EX_DATAERR, "%s is not an ELF object", filename);
60+
/* search for sections name with debug prefix */
61+
has_debug = elf_debug(e);
9362

94-
has_debug = elf_debug_sections(e);
95-
printf(has_debug ? "HAS DEBUG\n" : "NO DEBUG\n");
63+
printf("%s\n", (has_debug > 0) ? "HAS DEBUG" : "NO DEBUG");
9664

97-
rc = close(fd);
98-
rc = elf_end(e);
65+
rc = elf_destroy(e);
9966

10067
return (rc);
10168
}

0 commit comments

Comments
 (0)