[IMPROVE] install path: heuristic for Win like paths
[platform/core/system/swap-manager.git] / daemon / elf.c
1 #include <ctype.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <sys/mman.h>
5 #include <fcntl.h>
6 #include <unistd.h>
7 #include <elf.h>
8 #include <stdbool.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include <errno.h>
12 #include "elf.h"
13
14 #define SIZEOF_VOID_P 4
15 #if SIZEOF_VOID_P == 8
16 typedef Elf64_Ehdr Elf_Ehdr;
17 typedef Elf64_Shdr Elf_Shdr;
18 #elif SIZEOF_VOID_P == 4
19 typedef Elf32_Ehdr Elf_Ehdr;
20 typedef Elf32_Shdr Elf_Shdr;
21 #else
22 #error "Unknown void* size"
23 #endif
24
25 static size_t fsize(int fd)
26 {
27         struct stat buf;
28         fstat(fd, &buf);
29         return buf.st_size;
30 }
31
32 static void *mmap_file(const char *filepath, size_t * len)
33 {
34         int fd = open(filepath, O_RDONLY);
35         if (fd < 0)
36                 return NULL;
37         *len = fsize(fd);
38         void *mem = mmap(NULL, *len, PROT_READ, MAP_PRIVATE, fd, 0);
39         close(fd);
40         return mem == MAP_FAILED ? NULL : mem;
41 }
42
43 static const Elf_Shdr *elf_find_debug_header(const void *obj)
44 {
45         const Elf_Ehdr *elf_header = obj;
46         const Elf_Shdr *section_table = obj + elf_header->e_shoff;
47         const Elf_Shdr *string_entry = section_table + elf_header->e_shstrndx;
48         const char *string_section = obj + string_entry->sh_offset;
49         int index;
50
51         for (index = 0; index != elf_header->e_shnum; ++index) {
52                 const Elf_Shdr *entry = section_table + index;
53                 if (!strcmp(".debug_str", string_section + entry->sh_name))
54                         return entry;
55         }
56         return NULL;
57 }
58
59 static int read_elf_header(Elf_Ehdr * header, const char *filepath)
60 {
61         int fd = open(filepath, O_RDONLY);
62         if (fd < 0)
63                 return -ENOENT;
64         bool read_failed = read(fd, header, sizeof(*header)) != sizeof(*header);
65         close(fd);
66         return read_failed ? -EIO : 0;
67 }
68
69 static int elf_type(const char *filepath)
70 {
71         Elf_Ehdr header;
72         int err = read_elf_header(&header, filepath);
73         return err ? err : header.e_type;
74 }
75
76 uint32_t get_binary_type(const char *path)
77 {
78         int type = elf_type(path);
79
80         switch (type) {
81         case ET_DYN:
82                 return BINARY_TYPE_PIE;
83         case ET_EXEC:
84                 return BINARY_TYPE_NO_PIE;
85         default:
86                 return BINARY_TYPE_UNKNOWN;
87         }
88 }
89
90 static int is_like_absolute_path(const char *str)
91 {
92         if (*str == '/')
93                 return 1;
94         if (isupper(*str) && str[1] == ':' && str[2] == '\\')
95                 return 1;
96         return 0;
97 }
98
99 void get_build_dir(char builddir[PATH_MAX], const char *filename)
100 {
101         size_t len;
102         void *filemem = mmap_file(filename, &len);
103         if (filemem) {
104                 const Elf_Shdr *debug_header = elf_find_debug_header(filemem);
105                 if (debug_header) {
106                         const char *debug_section =
107                             filemem + debug_header->sh_offset;
108                         const char *debug_section_end =
109                             debug_section + debug_header->sh_size;
110                         const char *p = debug_section;
111                         /* `is_like_absolute_path' checks three chars forward. */
112                         while (p < debug_section_end - 3) {
113                                 if (is_like_absolute_path(p)) {
114                                         snprintf(builddir, PATH_MAX, "%s", p);
115                                         return;
116                                 }
117                                 p = 1 + memchr(p, '\0', debug_section_end - p);
118                         }
119                 }
120                 munmap(filemem, len);
121         }
122         *builddir = '\0';
123 }