1 #include "dat.h"
2 #include "fns.h"
3 #include "error.h"
4 #include <a.out.h>
5 #include <dynld.h>
6
7 #define DBG if(1) print
8
9 extern ulong ndevs;
10
11 enum
12 {
13 Qdir,
14 Qdynld,
15 Qdynsyms,
16
17 DEVCHAR = 'L',
18 };
19
20 static Dirtab dltab[] =
21 {
22 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
23 "dynld", {Qdynld}, 0, 0644,
24 "dynsyms", {Qdynsyms}, 0, 0444,
25 };
26
27 enum
28 {
29 DLdev,
30 DLudev,
31 };
32
33 static Cmdtab dlcmd[] =
34 {
35 DLdev, "dev", 2,
36 DLudev, "udev", 2,
37 };
38
39 typedef struct Dyndev Dyndev;
40
41 struct Dyndev
42 {
43 char *path;
44 Dynobj *o;
45 Dev *dev;
46 Dyndev *next;
47 };
48
49 static Dyndev *loaded;
50 static QLock dllock;
51
52 typedef struct Fd Fd;
53 struct Fd {
54 int fd;
55 };
56
57 static long
readfd(void * a,void * buf,long nbytes)58 readfd(void *a, void *buf, long nbytes)
59 {
60 return kread(((Fd*)a)->fd, buf, nbytes);
61 }
62
63 static vlong
seekfd(void * a,vlong off,int t)64 seekfd(void *a, vlong off, int t)
65 {
66 return kseek(((Fd*)a)->fd, off, t);
67 }
68
69 static void
errfd(char * s)70 errfd(char *s)
71 {
72 kstrcpy(up->env->errstr, s, ERRMAX);
73 }
74
75 static void
dlfree(Dyndev * l)76 dlfree(Dyndev *l)
77 {
78 if(l != nil){
79 free(l->path);
80 dynobjfree(l->o);
81 free(l);
82 }
83 }
84
85 static Dyndev*
dlload(char * path,Dynsym * tab,int ntab)86 dlload(char *path, Dynsym *tab, int ntab)
87 {
88 Fd f;
89 Dyndev *l;
90
91 f.fd = kopen(path, OREAD);
92 if(f.fd < 0)
93 error("cannot open");
94 if(waserror()){
95 kclose(f.fd);
96 nexterror();
97 }
98 l = mallocz(sizeof(Dyndev), 1);
99 if(l == nil)
100 error(Enomem);
101 if(waserror()){
102 dlfree(l);
103 nexterror();
104 }
105 l->path = strdup(path);
106 if(l->path == nil)
107 error(Enomem);
108 l->o = dynloadgen(&f, readfd, seekfd, errfd, tab, ntab, 0);
109 if(l->o == nil)
110 error(up->env->errstr);
111 poperror();
112 poperror();
113 kclose(f.fd);
114 return l;
115 }
116
117 static void
devload(char * path)118 devload(char *path)
119 {
120 int i;
121 Dyndev *l;
122 Dev *dev;
123 char devname[32];
124
125 l = dlload(path, _exporttab, dyntabsize(_exporttab));
126 if(waserror()){
127 dlfree(l);
128 nexterror();
129 }
130 snprint(devname, sizeof(devname), "%sdevtab", "XXX"); /* TO DO */
131 dev = dynimport(l->o, devname, signof(*dev));
132 if(dev == nil)
133 error("no devtab");
134 if(devno(dev->dc, 1) >= 0)
135 error("device loaded");
136 for(i = 0; devtab[i] != nil; i++)
137 ;
138 if(i >= ndevs || devtab[i+1] != nil)
139 error("device table full");
140 l->dev = devtab[i] = dev;
141 dev->init();
142 l->next = loaded;
143 loaded = l;
144 poperror();
145 }
146
147 static void
devunload(char * path)148 devunload(char *path)
149 {
150 int i, dc;
151 Dyndev *l, **ll;
152
153 dc = 0;
154 if(strlen(path) == 1)
155 dc = path[0];
156 for(ll = &loaded; *ll != nil; ll = &(*ll)->next){
157 if(path != nil && strcmp(path, (*ll)->path) == 0)
158 break;
159 if(dc != 0 && (*ll)->dev && dc == (*ll)->dev->dc)
160 break;
161 }
162 if((l = *ll) != nil){
163 for(i = 0; i < ndevs; i++)
164 if(l->dev == devtab[i]){
165 devtab[i] = nil;
166 break;
167 }
168 /*
169 if(l->dev)
170 l->dev->shutdown();
171 */
172 *ll = l->next;
173 dlfree(l);
174 }
175 }
176
177 static long
readdl(void * a,ulong n,ulong offset)178 readdl(void *a, ulong n, ulong offset)
179 {
180 char *p;
181 Dyndev *l;
182 int m, len;
183
184 m = 0;
185 for(l = loaded; l != nil; l = l->next)
186 m++;
187 m *= 48;
188 p = malloc(m);
189 if(p == nil)
190 error(Enomem);
191 if(waserror()){
192 free(p);
193 nexterror();
194 }
195 *p = 0;
196 len = 0;
197 for(l = loaded; l != nil; l = l->next)
198 if(l->dev)
199 len += snprint(p+len, m-len, "#%C\t%.8p\t%.8lux\t%s\n",
200 l->dev->dc, l->o->base, l->o->size, l->dev->name);
201 n = readstr(offset, a, n, p);
202 poperror();
203 free(p);
204 return n;
205 }
206
207 static long
readsyms(char * a,ulong n,ulong offset)208 readsyms(char *a, ulong n, ulong offset)
209 {
210 char *p;
211 Dynsym *t;
212 long l, nr;
213
214 p = malloc(READSTR);
215 if(p == nil)
216 error(Enomem);
217 if(waserror()){
218 free(p);
219 nexterror();
220 }
221 nr = 0;
222 for(t = _exporttab; n > 0 && t->name != nil; t++){
223 l = snprint(p, READSTR, "%.8lux %.8lux %s\n", t->addr, t->sig, t->name);
224 if(offset >= l){
225 offset -= l;
226 continue;
227 }
228 l = readstr(offset, a, n, p);
229 offset = 0;
230 n -= l;
231 a += l;
232 nr += l;
233 }
234 poperror();
235 free(p);
236 return nr;
237 }
238
239 static Chan*
dlattach(char * spec)240 dlattach(char *spec)
241 {
242 return devattach(DEVCHAR, spec);
243 }
244
245 static Walkqid*
dlwalk(Chan * c,Chan * nc,char ** name,int nname)246 dlwalk(Chan *c, Chan *nc, char **name, int nname)
247 {
248 return devwalk(c, nc, name, nname, dltab, nelem(dltab), devgen);
249 }
250
251 static int
dlstat(Chan * c,uchar * db,int n)252 dlstat(Chan *c, uchar *db, int n)
253 {
254 return devstat(c, db, n, dltab, nelem(dltab), devgen);
255 }
256
257 static Chan*
dlopen(Chan * c,int omode)258 dlopen(Chan *c, int omode)
259 {
260 return devopen(c, omode, dltab, nelem(dltab), devgen);
261 }
262
263 static void
dlclose(Chan * c)264 dlclose(Chan *c)
265 {
266 USED(c);
267 }
268
269 static long
dlread(Chan * c,void * a,long n,vlong voffset)270 dlread(Chan *c, void *a, long n, vlong voffset)
271 {
272 switch((ulong)c->qid.path){
273 case Qdir:
274 return devdirread(c, a, n, dltab, nelem(dltab), devgen);
275 case Qdynld:
276 return readdl(a, n, (ulong)voffset);
277 case Qdynsyms:
278 return readsyms(a, n, (ulong)voffset);
279 default:
280 error(Egreg);
281 }
282 return n;
283 }
284
285 static long
dlwrite(Chan * c,void * a,long n,vlong voffset)286 dlwrite(Chan *c, void *a, long n, vlong voffset)
287 {
288 Cmdbuf *cmd;
289 Cmdtab *ct;
290
291 USED(voffset);
292 switch((ulong)c->qid.path){
293 case Qdynld:
294 cmd = parsecmd(a, n);
295 qlock(&dllock);
296 if(waserror()){
297 qunlock(&dllock);
298 free(cmd);
299 nexterror();
300 }
301 ct = lookupcmd(cmd, dlcmd, nelem(dlcmd));
302 switch(ct->index){
303 case DLdev:
304 devload(cmd->f[1]);
305 break;
306 case DLudev:
307 devunload(cmd->f[1]);
308 break;
309 }
310 poperror();
311 qunlock(&dllock);
312 free(cmd);
313 break;
314 default:
315 error(Egreg);
316 }
317 return n;
318 }
319
320 Dev dynlddevtab = {
321 DEVCHAR,
322 "dynld",
323
324 devinit,
325 dlattach,
326 dlwalk,
327 dlstat,
328 dlopen,
329 devcreate,
330 dlclose,
331 dlread,
332 devbread,
333 dlwrite,
334 devbwrite,
335 devremove,
336 devwstat,
337 };
338
339 /* auxiliary routines for dynamic loading of C modules */
340
341 Dynobj*
dynld(int fd)342 dynld(int fd)
343 {
344 Fd f;
345
346 f.fd = fd;
347 return dynloadgen(&f, readfd, seekfd, errfd, _exporttab, dyntabsize(_exporttab), 0);
348 }
349
350 int
dynldable(int fd)351 dynldable(int fd)
352 {
353 Fd f;
354
355 f.fd = fd;
356 return dynloadable(&f, readfd, seekfd);
357 }
358