Rizin
unix-like reverse engineering framework and cli tools
p_cache.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2017-2018 condret <condr3t@protonmail.com>
2 // SPDX-FileCopyrightText: 2017-2018 alvaro <alvaro.felipe91@gmail.com>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include <rz_io.h>
6 #include <rz_types.h>
7 #include <string.h>
8 
9 const ut64 cleanup_masks[] = {
10  0x0000000000000001,
11  0x0000000000000003,
12  0x0000000000000007,
13  0x000000000000000f,
14  0x000000000000001f,
15  0x000000000000003f,
16  0x000000000000007f,
17  0x00000000000000ff,
18  0x00000000000001ff,
19  0x00000000000003ff,
20  0x00000000000007ff,
21  0x0000000000000fff,
22  0x0000000000001fff,
23  0x0000000000003fff,
24  0x0000000000007fff,
25  0x000000000000ffff,
26  0x000000000001ffff,
27  0x000000000003ffff,
28  0x000000000007ffff,
29  0x00000000000fffff,
30  0x00000000001fffff,
31  0x00000000003fffff,
32  0x00000000007fffff,
33  0x0000000000ffffff,
34  0x0000000001ffffff,
35  0x0000000003ffffff,
36  0x0000000007ffffff,
37  0x000000000fffffff,
38  0x000000001fffffff,
39  0x000000003fffffff,
40  0x000000007fffffff,
41  0x00000000ffffffff,
42  0x00000001ffffffff,
43  0x00000003ffffffff,
44  0x00000007ffffffff,
45  0x0000000fffffffff,
46  0x0000001fffffffff,
47  0x0000003fffffffff,
48  0x0000007fffffffff,
49  0x000000ffffffffff,
50  0x000001ffffffffff,
51  0x000003ffffffffff,
52  0x000007ffffffffff,
53  0x00000fffffffffff,
54  0x00001fffffffffff,
55  0x00003fffffffffff,
56  0x00007fffffffffff,
57  0x0000ffffffffffff,
58  0x0001ffffffffffff,
59  0x0003ffffffffffff,
60  0x0007ffffffffffff,
61  0x000fffffffffffff,
62  0x001fffffffffffff,
63  0x003fffffffffffff,
64  0x007fffffffffffff,
65  0x00ffffffffffffff,
66  0x01ffffffffffffff,
67  0x03ffffffffffffff,
68  0x07ffffffffffffff,
69  0x0fffffffffffffff,
70  0x1fffffffffffffff,
71  0x3fffffffffffffff,
72  0x7fffffffffffffff
73 };
74 
75 static void pcache_kv_free(HtUPKv *kv) {
76  free(kv->value);
77 }
78 
80  if (!desc || desc->cache) {
81  return false;
82  }
83  return (desc->cache = ht_up_new(NULL, pcache_kv_free, NULL)) ? true : false;
84 }
85 
87  RzIODescCache *cache;
88  ut64 caddr, desc_sz = rz_io_desc_size(desc);
89  int cbaddr, written = 0;
90  if ((len < 1) || !desc || (desc_sz <= paddr) ||
91  !desc->io || (!desc->cache && !rz_io_desc_cache_init(desc))) {
92  return 0;
93  }
94  if (len > desc_sz) {
95  len = (int)desc_sz;
96  }
97  if (paddr > (desc_sz - len)) {
98  len = (int)(desc_sz - paddr);
99  }
100  caddr = paddr / RZ_IO_DESC_CACHE_SIZE;
101  cbaddr = paddr % RZ_IO_DESC_CACHE_SIZE;
102  while (written < len) {
103  // get an existing desc-cache, if it exists
104  if (!(cache = (RzIODescCache *)ht_up_find(desc->cache, caddr, NULL))) {
105  // create new desc-cache
106  cache = RZ_NEW0(RzIODescCache);
107  if (!cache) {
108  return 0;
109  }
110  // feed ht with the new desc-cache
111  ht_up_insert(desc->cache, caddr, cache);
112  }
113  // check if the remaining data fits into the cache
114  if ((len - written) > (RZ_IO_DESC_CACHE_SIZE - cbaddr)) {
115  written += (RZ_IO_DESC_CACHE_SIZE - cbaddr);
116  // this can be optimized
117  for (; cbaddr < RZ_IO_DESC_CACHE_SIZE; cbaddr++) {
118  // write to cache
119  cache->cdata[cbaddr] = *buf;
120  // save, that its cached
121  cache->cached |= (0x1ULL << cbaddr);
122  buf++;
123  }
124  } else {
125  // XXX this looks like very suspicious
126  do {
127  cache->cdata[cbaddr] = *buf;
128  cache->cached |= (0x1ULL << cbaddr);
129  buf++;
130  written++;
131  cbaddr++;
132  } while (len > written);
133  }
134  caddr++;
135  cbaddr = 0;
136  }
137  RzEventIOWrite iow = { paddr, buf, len };
138  rz_event_send(desc->io->event, RZ_EVENT_IO_WRITE, &iow);
139  return written;
140 }
141 
143  RzIODescCache *cache;
144  ut8 *ptr = buf;
145  ut64 caddr, desc_sz = rz_io_desc_size(desc);
146  int cbaddr, amount = 0;
147  if ((len < 1) || !desc || (desc_sz <= paddr) || !desc->io || !desc->cache) {
148  return 0;
149  }
150  if (len > desc_sz) {
151  len = (int)desc_sz;
152  }
153  if (paddr > (desc_sz - len)) {
154  len = (int)(desc_sz - paddr);
155  }
156  caddr = paddr / RZ_IO_DESC_CACHE_SIZE;
157  cbaddr = paddr % RZ_IO_DESC_CACHE_SIZE;
158  while (amount < len) {
159  // get an existing desc-cache, if it exists
160  if (!(cache = (RzIODescCache *)ht_up_find(desc->cache, caddr, NULL))) {
161  amount += (RZ_IO_DESC_CACHE_SIZE - cbaddr);
162  ptr += (RZ_IO_DESC_CACHE_SIZE - cbaddr);
163  goto beach;
164  }
165  if ((len - amount) > (RZ_IO_DESC_CACHE_SIZE - cbaddr)) {
166  amount += (RZ_IO_DESC_CACHE_SIZE - cbaddr);
167  for (; cbaddr < RZ_IO_DESC_CACHE_SIZE; cbaddr++) {
168  if (cache->cached & (0x1ULL << cbaddr)) {
169  *ptr = cache->cdata[cbaddr];
170  }
171  ptr++;
172  }
173  } else {
174  do {
175  if (cache->cached & (0x1ULL << cbaddr)) {
176  *ptr = cache->cdata[cbaddr];
177  }
178  ptr++;
179  amount++;
180  cbaddr++;
181  } while (len > amount);
182  }
183  beach:
184  caddr++;
185  cbaddr = 0;
186  }
187  return amount;
188 }
189 
190 static void __riocache_free(void *user) {
191  RzIOCache *cache = (RzIOCache *)user;
192  if (cache) {
193  free(cache->data);
194  free(cache->odata);
195  }
196  free(cache);
197 }
198 
199 static bool __desc_cache_list_cb(void *user, const ut64 k, const void *v) {
200  RzList *writes = (RzList *)user;
201  RzIOCache *cache = NULL;
202  ut64 blockaddr;
203  int byteaddr, i;
204  if (!writes) {
205  return false;
206  }
207  const RzIODescCache *dcache = v;
208  blockaddr = k * RZ_IO_DESC_CACHE_SIZE;
209  for (i = byteaddr = 0; byteaddr < RZ_IO_DESC_CACHE_SIZE; byteaddr++) {
210  if (dcache->cached & (0x1LL << byteaddr)) {
211  if (!cache) {
212  cache = RZ_NEW0(RzIOCache);
213  if (!cache) {
214  return false;
215  }
216  cache->data = malloc(RZ_IO_DESC_CACHE_SIZE - byteaddr);
217  if (!cache->data) {
218  free(cache);
219  return false;
220  }
221  cache->itv.addr = blockaddr + byteaddr;
222  }
223  cache->data[i] = dcache->cdata[byteaddr];
224  i++;
225  } else if (cache) {
226  ut8 *data = realloc(cache->data, i);
227  if (!data) {
228  __riocache_free((void *)cache);
229  return false;
230  }
231  cache->data = data;
232  cache->itv.size = i;
233  i = 0;
234  rz_list_push(writes, cache);
235  cache = NULL;
236  }
237  }
238  if (cache) {
239 #if 0
240  cache->size = i;
241  cache->to = blockaddr + RZ_IO_DESC_CACHE_SIZE;
242 #endif
243  cache->itv.size = i;
244  rz_list_push(writes, cache);
245  }
246  return true;
247 }
248 
250  if (!desc || !desc->io || !desc->io->desc || !desc->io->p_cache || !desc->cache) {
251  return NULL;
252  }
254  if (!writes) {
255  return NULL;
256  }
257  ht_up_foreach(desc->cache, __desc_cache_list_cb, writes);
258  RzIODesc *current = desc->io->desc;
259  desc->io->desc = desc;
260  desc->io->p_cache = false;
261 
262  RzIOCache *c;
263  RzListIter *iter;
264  rz_list_foreach (writes, iter, c) {
265  const ut64 itvSize = rz_itv_size(c->itv);
266  c->odata = calloc(1, itvSize);
267  if (!c->odata) {
268  rz_list_free(writes);
269  return NULL;
270  }
271  rz_io_pread_at(desc->io, rz_itv_begin(c->itv), c->odata, itvSize);
272  }
273  desc->io->p_cache = true;
274  desc->io->desc = current;
275  return writes;
276 }
277 
278 static bool __desc_cache_commit_cb(void *user, const ut64 k, const void *v) {
279  RzIODesc *desc = (RzIODesc *)user;
280  int byteaddr, i;
281  ut8 buf[RZ_IO_DESC_CACHE_SIZE] = { 0 };
282  if (!desc || !desc->io) {
283  return false;
284  }
285  const RzIODescCache *dcache = v;
286  ut64 blockaddr = RZ_IO_DESC_CACHE_SIZE * k;
287  for (i = byteaddr = 0; byteaddr < RZ_IO_DESC_CACHE_SIZE; byteaddr++) {
288  if (dcache->cached & (0x1LL << byteaddr)) {
289  buf[i] = dcache->cdata[byteaddr];
290  i++;
291  } else if (i > 0) {
292  rz_io_pwrite_at(desc->io, blockaddr + byteaddr - i, buf, i);
293  i = 0;
294  }
295  }
296  if (i > 0) {
297  rz_io_pwrite_at(desc->io, blockaddr + RZ_IO_DESC_CACHE_SIZE - i, buf, i);
298  }
299  return true;
300 }
301 
303  RzIODesc *current;
304  if (!desc || !(desc->perm & RZ_PERM_W) || !desc->io || !desc->io->files || !desc->io->p_cache) {
305  return false;
306  }
307  if (!desc->cache) {
308  return true;
309  }
310  current = desc->io->desc;
311  desc->io->desc = desc;
312  desc->io->p_cache = false;
313  ht_up_foreach(desc->cache, __desc_cache_commit_cb, desc);
314  ht_up_free(desc->cache);
315  desc->cache = NULL;
316  desc->io->p_cache = true;
317  desc->io->desc = current;
318  return true;
319 }
320 
321 static bool __desc_cache_cleanup_cb(void *user, const ut64 k, const void *v) {
322  RzIODesc *desc = (RzIODesc *)user;
323  ut64 size, blockaddr;
324  int byteaddr;
325  if (!desc || !desc->cache) {
326  return false;
327  }
328  RzIODescCache *cache = (RzIODescCache *)v;
329  blockaddr = RZ_IO_DESC_CACHE_SIZE * k;
331  if (size <= blockaddr) {
332  ht_up_delete(desc->cache, k);
333  return true;
334  }
335  if (size <= (blockaddr + RZ_IO_DESC_CACHE_SIZE - 1)) {
336  // this looks scary, but it isn't
337  byteaddr = (int)(size - blockaddr) - 1;
338  cache->cached &= cleanup_masks[byteaddr];
339  }
340  return true;
341 }
342 
344  if (desc && desc->cache) {
345  ht_up_foreach(desc->cache, __desc_cache_cleanup_cb, desc);
346  }
347 }
348 
349 static bool __desc_fini_cb(void *user, void *data, ut32 id) {
350  RzIODesc *desc = (RzIODesc *)data;
351  if (desc->cache) {
352  ht_up_free(desc->cache);
353  desc->cache = NULL;
354  }
355  return true;
356 }
357 
359  __desc_fini_cb(NULL, (void *)desc, 0);
360 }
361 
363  if (io && io->files) {
365  }
366 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
const char * desc
Definition: bin_vsf.c:19
#define RZ_API
#define NULL
Definition: cris-opc.c:27
#define true
uint32_t ut32
const char * k
Definition: dsignal.c:11
const char * v
Definition: dsignal.c:12
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API RZ_BORROW RzListIter * rz_list_push(RZ_NONNULL RzList *list, void *item)
Alias for rz_list_append.
Definition: list.c:60
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
void * malloc(size_t size)
Definition: malloc.c:123
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
static bool __desc_fini_cb(void *user, void *data, ut32 id)
Definition: p_cache.c:349
static bool __desc_cache_cleanup_cb(void *user, const ut64 k, const void *v)
Definition: p_cache.c:321
const ut64 cleanup_masks[]
Definition: p_cache.c:9
RZ_API bool rz_io_desc_cache_commit(RzIODesc *desc)
Definition: p_cache.c:302
static void pcache_kv_free(HtUPKv *kv)
Definition: p_cache.c:75
RZ_API void rz_io_desc_cache_fini(RzIODesc *desc)
Definition: p_cache.c:358
RZ_API int rz_io_desc_cache_write(RzIODesc *desc, ut64 paddr, const ut8 *buf, int len)
Definition: p_cache.c:86
RZ_API int rz_io_desc_cache_read(RzIODesc *desc, ut64 paddr, ut8 *buf, int len)
Definition: p_cache.c:142
RZ_API RzList * rz_io_desc_cache_list(RzIODesc *desc)
Definition: p_cache.c:249
RZ_API void rz_io_desc_cache_fini_all(RzIO *io)
Definition: p_cache.c:362
static bool __desc_cache_commit_cb(void *user, const ut64 k, const void *v)
Definition: p_cache.c:278
static bool __desc_cache_list_cb(void *user, const ut64 k, const void *v)
Definition: p_cache.c:199
RZ_API void rz_io_desc_cache_cleanup(RzIODesc *desc)
Definition: p_cache.c:343
RZ_API bool rz_io_desc_cache_init(RzIODesc *desc)
Definition: p_cache.c:79
static void __riocache_free(void *user)
Definition: p_cache.c:190
RZ_API void rz_event_send(RzEvent *ev, int type, void *data)
Definition: event.c:115
@ RZ_EVENT_IO_WRITE
Definition: rz_event.h:42
RZ_API bool rz_id_storage_foreach(RzIDStorage *storage, RzIDStorageForeachCb cb, void *user)
Definition: idpool.c:254
RZ_API int rz_io_pwrite_at(RzIO *io, ut64 paddr, const ut8 *buf, int len)
Definition: io.c:277
RZ_API ut64 rz_io_desc_size(RzIODesc *desc)
Definition: io_desc.c:224
RZ_API int rz_io_pread_at(RzIO *io, ut64 paddr, ut8 *buf, int len)
Definition: io.c:269
#define RZ_IO_DESC_CACHE_SIZE
Definition: rz_io.h:169
static ut64 rz_itv_begin(RzInterval itv)
Definition: rz_itv.h:34
static ut64 rz_itv_size(RzInterval itv)
Definition: rz_itv.h:38
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_PERM_W
Definition: rz_types.h:94
static int
Definition: sfsocketcall.h:114
#define c(i)
Definition: sha256.c:43
ut64 addr
Definition: rz_itv.h:15
ut64 size
Definition: rz_itv.h:16
RzInterval itv
Definition: rz_io.h:163
ut8 * odata
Definition: rz_io.h:165
ut8 * data
Definition: rz_io.h:164
ut8 cdata[RZ_IO_DESC_CACHE_SIZE]
Definition: rz_io.h:172
Definition: rz_io.h:59
RzIDStorage * files
Definition: rz_io.h:75
ut64(WINAPI *w32_GetEnabledXStateFeatures)()