fix dependency check logic cause config always disabled
[lunaix-os.git] / lunaix-os / kernel / exe / elf-generic / elfbfmt.c
1 #include <lunaix/exebi/elf.h>
2 #include <lunaix/fs.h>
3 #include <lunaix/mm/valloc.h>
4 #include <lunaix/spike.h>
5
6 #include <klibc/string.h>
7
8 static inline int
9 elf_read(struct v_file* elf, void* data, size_t off, size_t len)
10 {
11     // it is wise to do cached read
12     return pcache_read(elf->inode, data, len, off);
13 }
14
15 static int
16 elf_do_open(struct elf* elf, struct v_file* elf_file)
17 {
18     int status = 0;
19     elf->pheaders = NULL;
20     elf->elf_file = elf_file;
21
22     if ((status = elf_read_ehdr(elf)) < 0) {
23         elf_close(elf);
24         return status;
25     }
26
27     if (!elf_check_arch(elf)) {
28         return EINVAL;
29     }
30
31     if ((status = elf_read_phdr(elf)) < 0) {
32         elf_close(elf);
33         return status;
34     }
35
36     return 0;
37 }
38
39 _default int
40 elf_open(struct elf* elf, const char* path)
41 {
42     struct v_dnode* elfdn;
43     struct v_file* elffile;
44     int error = 0;
45
46     if ((error = vfs_walk_proc(path, &elfdn, NULL, 0))) {
47         return error;
48     }
49
50     if ((error = vfs_open(elfdn, &elffile))) {
51         return error;
52     }
53
54     return elf_do_open(elf, elffile);
55 }
56
57 _default int
58 elf_openat(struct elf* elf, void* elf_vfile)
59 {
60     // so the ref count kept in sync
61     vfs_ref_file(elf_vfile);
62     return elf_do_open(elf, elf_vfile);
63 }
64
65 _default int
66 elf_close(struct elf* elf)
67 {
68     if (elf->pheaders) {
69         vfree(elf->pheaders);
70     }
71
72     if (elf->elf_file) {
73         vfs_close((struct v_file*)elf->elf_file);
74     }
75
76     memset(elf, 0, sizeof(*elf));
77
78     return 0;
79 }
80
81 _default int
82 elf_static_linked(const struct elf* elf)
83 {
84     for (size_t i = 0; i < elf->eheader.e_phnum; i++) {
85         struct elf_phdr* phdre = &elf->pheaders[i];
86         if (phdre->p_type == PT_INTERP) {
87             return 0;
88         }
89     }
90     return 1;
91 }
92
93 _default size_t
94 elf_loadable_memsz(const struct elf* elf)
95 {
96     // XXX: Hmmmm, I am not sure if we need this. This is designed to be handy
97     // if we decided to map the heap region before transfer to loader. As
98     // currently, we push *everything* to user-space loader, thus we modify the
99     // brk syscall to do the initial heap mapping.
100
101     size_t sz = 0;
102     for (size_t i = 0; i < elf->eheader.e_phnum; i++) {
103         struct elf_phdr* phdre = &elf->pheaders[i];
104         if (phdre->p_type == PT_LOAD) {
105             sz += phdre->p_memsz;
106         }
107     }
108
109     return sz;
110 }
111
112 _default int
113 elf_find_loader(const struct elf* elf, char* path_out, size_t len)
114 {
115     int retval = NO_LOADER;
116
117     assert_msg(len >= sizeof(DEFAULT_LOADER), "path_out: too small");
118
119     struct v_file* elfile = (struct v_file*)elf->elf_file;
120
121     for (size_t i = 0; i < elf->eheader.e_phnum; i++) {
122         struct elf_phdr* phdre = &elf->pheaders[i];
123         if (phdre->p_type == PT_INTERP) {
124             if (len >= phdre->p_filesz) {
125                 return EINVAL;
126             }
127
128             retval =
129               elf_read(elfile, path_out, phdre->p_offset, phdre->p_filesz);
130
131             if (retval < 0) {
132                 return retval;
133             }
134
135             break;
136         }
137     }
138
139     return retval;
140 }
141
142 _default int
143 elf_read_ehdr(struct elf* elf)
144 {
145     struct v_file* elfile = (struct v_file*)elf->elf_file;
146
147     return elf_read(elfile, (void*)&elf->eheader, 0, SIZE_EHDR);
148 }
149
150 _default int
151 elf_read_phdr(struct elf* elf)
152 {
153     int status = 0;
154
155     struct v_file* elfile = (struct v_file*)elf->elf_file;
156
157     size_t entries = elf->eheader.e_phnum;
158     size_t tbl_sz = entries * SIZE_PHDR;
159
160     struct elf_phdr* phdrs = valloc(tbl_sz);
161
162     if (!phdrs) {
163         return ENOMEM;
164     }
165
166     status = elf_read(elfile, phdrs, elf->eheader.e_phoff, tbl_sz);
167
168     if (status < 0) {
169         vfree(phdrs);
170         return status;
171     }
172
173     elf->pheaders = phdrs;
174     return entries;
175 }
176
177 _default int
178 elf_check_exec(const struct elf* elf, int type)
179 {
180     const struct elf_ehdr* ehdr = &elf->eheader;
181
182     return (ehdr->e_entry) && ehdr->e_type == type;
183 }
184
185 _default int
186 elf_check_arch(const struct elf* elf)
187 {
188     const struct elf_ehdr* ehdr = &elf->eheader;
189
190     return *(u32_t*)(ehdr->e_ident) == ELFMAGIC_LE;
191 }