1 // Inferno libmach/access.c
2 // http://code.google.com/p/inferno-os/source/browse/utils/libmach/access.c
3 //
4 // Copyright © 1994-1999 Lucent Technologies Inc.
5 // Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
6 // Portions Copyright © 1997-1999 Vita Nuova Limited.
7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
8 // Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
9 // Portions Copyright © 2009 The Go Authors. All rights reserved.
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28
29 /*
30 * functions to read and write an executable or file image
31 */
32
33 #include <u.h>
34 #include <libc.h>
35 #include <bio.h>
36 #include <mach.h>
37
38 static int mget(Map*, uvlong, void*, int);
39 static int mput(Map*, uvlong, void*, int);
40 static Seg* reloc(Map*, uvlong, vlong*);
41
42 /*
43 * routines to get/put various types
44 */
45 int
46 geta(Map *map, uvlong addr, uvlong *x)
47 {
48 uint32 l;
49 uvlong vl;
50
51 if (mach->szaddr == 8){
52 if (get8(map, addr, &vl) < 0)
53 return -1;
54 *x = vl;
55 return 1;
56 }
57
58 if (get4(map, addr, &l) < 0)
59 return -1;
60 *x = l;
61
62 return 1;
63 }
64
65 int
66 get8(Map *map, uvlong addr, uvlong *x)
67 {
68 if (!map) {
69 werrstr("get8: invalid map");
70 return -1;
71 }
72
73 if (map->nsegs == 1 && map->seg[0].fd < 0) {
74 *x = addr;
75 return 1;
76 }
77 if (mget(map, addr, x, 8) < 0)
78 return -1;
79 *x = machdata->swav(*x);
80 return 1;
81 }
82
83 int
84 get4(Map *map, uvlong addr, uint32 *x)
85 {
86 if (!map) {
87 werrstr("get4: invalid map");
88 return -1;
89 }
90
91 if (map->nsegs == 1 && map->seg[0].fd < 0) {
92 *x = addr;
93 return 1;
94 }
95 if (mget(map, addr, x, 4) < 0)
96 return -1;
97 *x = machdata->swal(*x);
98 return 1;
99 }
100
101 int
102 get2(Map *map, uvlong addr, ushort *x)
103 {
104 if (!map) {
105 werrstr("get2: invalid map");
106 return -1;
107 }
108
109 if (map->nsegs == 1 && map->seg[0].fd < 0) {
110 *x = addr;
111 return 1;
112 }
113 if (mget(map, addr, x, 2) < 0)
114 return -1;
115 *x = machdata->swab(*x);
116 return 1;
117 }
118
119 int
120 get1(Map *map, uvlong addr, uchar *x, int size)
121 {
122 uchar *cp;
123
124 if (!map) {
125 werrstr("get1: invalid map");
126 return -1;
127 }
128
129 if (map->nsegs == 1 && map->seg[0].fd < 0) {
130 cp = (uchar*)&addr;
131 while (cp < (uchar*)(&addr+1) && size-- > 0)
132 *x++ = *cp++;
133 while (size-- > 0)
134 *x++ = 0;
135 } else
136 return mget(map, addr, x, size);
137 return 1;
138 }
139
140 int
141 puta(Map *map, uvlong addr, uvlong v)
142 {
143 if (mach->szaddr == 8)
144 return put8(map, addr, v);
145
146 return put4(map, addr, v);
147 }
148
149 int
150 put8(Map *map, uvlong addr, uvlong v)
151 {
152 if (!map) {
153 werrstr("put8: invalid map");
154 return -1;
155 }
156 v = machdata->swav(v);
157 return mput(map, addr, &v, 8);
158 }
159
160 int
161 put4(Map *map, uvlong addr, uint32 v)
162 {
163 if (!map) {
164 werrstr("put4: invalid map");
165 return -1;
166 }
167 v = machdata->swal(v);
168 return mput(map, addr, &v, 4);
169 }
170
171 int
172 put2(Map *map, uvlong addr, ushort v)
173 {
174 if (!map) {
175 werrstr("put2: invalid map");
176 return -1;
177 }
178 v = machdata->swab(v);
179 return mput(map, addr, &v, 2);
180 }
181
182 int
183 put1(Map *map, uvlong addr, uchar *v, int size)
184 {
185 if (!map) {
186 werrstr("put1: invalid map");
187 return -1;
188 }
189 return mput(map, addr, v, size);
190 }
191
192 static int
193 mget(Map *map, uvlong addr, void *buf, int size)
194 {
195 uvlong off;
196 Seg *s;
197
198 s = reloc(map, addr, (vlong*)&off);
199 if (!s)
200 return -1;
201 if (s->rw == nil) {
202 werrstr("unreadable map");
203 return -1;
204 }
205 return s->rw(map, s, off, buf, size, 1);
206 }
207
208 static int
209 mput(Map *map, uvlong addr, void *buf, int size)
210 {
211 vlong off;
212 Seg *s;
213
214 s = reloc(map, addr, &off);
215 if (!s)
216 return -1;
217 if (s->rw == nil) {
218 werrstr("unwritable map");
219 return -1;
220 }
221 return s->rw(map, s, off, buf, size, 0);
222 }
223
224 /*
225 * convert address to file offset; returns nonzero if ok
226 */
227 static Seg*
228 reloc(Map *map, uvlong addr, vlong *offp)
229 {
230 int i;
231
232 for (i = 0; i < map->nsegs; i++) {
233 if (map->seg[i].inuse)
234 if (map->seg[i].b <= addr && addr < map->seg[i].e) {
235 *offp = addr + map->seg[i].f - map->seg[i].b;
236 return &map->seg[i];
237 }
238 }
239 werrstr("can't translate address %llux", addr);
240 return 0;
241 }