1 /* radare - LGPL - Copyright 2017 - rkx1209 */
2 
3 #include <r_debug.h>
4 #include <r_util/r_json.h>
5 
6 #define CMP_CNUM_REG(x, y) ((x) >= ((RDebugChangeReg *)y)->cnum ? 1 : -1)
7 #define CMP_CNUM_MEM(x, y) ((x) >= ((RDebugChangeMem *)y)->cnum ? 1 : -1)
8 #define CMP_CNUM_CHKPT(x, y) ((x) >= ((RDebugCheckpoint *)y)->cnum ? 1 : -1)
9 
r_debug_session_free(RDebugSession * session)10 R_API void r_debug_session_free(RDebugSession *session) {
11 	if (session) {
12 		r_vector_free (session->checkpoints);
13 		ht_up_free (session->registers);
14 		ht_up_free (session->memory);
15 		R_FREE (session);
16 	}
17 }
18 
r_debug_checkpoint_fini(void * element,void * user)19 static void r_debug_checkpoint_fini(void *element, void *user) {
20 	RDebugCheckpoint *checkpoint = element;
21 	size_t i;
22 	for (i = 0; i < R_REG_TYPE_LAST; i++) {
23 		r_reg_arena_free (checkpoint->arena[i]);
24 	}
25 	r_list_free (checkpoint->snaps);
26 }
27 
htup_vector_free(HtUPKv * kv)28 static void htup_vector_free(HtUPKv *kv) {
29 	r_vector_free (kv->value);
30 }
31 
r_debug_session_new(void)32 R_API RDebugSession *r_debug_session_new(void) {
33 	RDebugSession *session = R_NEW0 (RDebugSession);
34 	if (!session) {
35 		return NULL;
36 	}
37 
38 	session->checkpoints = r_vector_new (sizeof (RDebugCheckpoint), r_debug_checkpoint_fini, NULL);
39 	if (!session->checkpoints) {
40 		r_debug_session_free (session);
41 		return NULL;
42 	}
43 	session->registers = ht_up_new (NULL, htup_vector_free, NULL);
44 	if (!session->registers) {
45 		r_debug_session_free (session);
46 		return NULL;
47 	}
48 	session->memory = ht_up_new (NULL, htup_vector_free, NULL);
49 	if (!session->memory) {
50 		r_debug_session_free (session);
51 		return NULL;
52 	}
53 
54 	return session;
55 }
56 
r_debug_add_checkpoint(RDebug * dbg)57 R_API bool r_debug_add_checkpoint(RDebug *dbg) {
58 	r_return_val_if_fail (dbg->session, false);
59 	size_t i;
60 	RDebugCheckpoint checkpoint = { 0 };
61 
62 	// Save current registers arena iter
63 	r_debug_reg_sync (dbg, R_REG_TYPE_ALL, 0);
64 	for (i = 0; i < R_REG_TYPE_LAST; i++) {
65 		RRegArena *a = dbg->reg->regset[i].arena;
66 		RRegArena *b = r_reg_arena_new (a->size);
67 		if (a && a->bytes) {
68 			memcpy (b->bytes, a->bytes, b->size);
69 			checkpoint.arena[i] = b;
70 		}
71 	}
72 
73 	// Save current memory maps
74 	checkpoint.snaps = r_list_newf ((RListFree)r_debug_snap_free);
75 	if (!checkpoint.snaps) {
76 		return false;
77 	}
78 	RListIter *iter;
79 	RDebugMap *map;
80 	r_debug_map_sync (dbg);
81 	r_list_foreach (dbg->maps, iter, map) {
82 		if ((map->perm & R_PERM_RW) == R_PERM_RW) {
83 			RDebugSnap *snap = r_debug_snap_map (dbg, map);
84 			if (snap) {
85 				r_list_append (checkpoint.snaps, snap);
86 			}
87 		}
88 	}
89 
90 	checkpoint.cnum = dbg->session->cnum;
91 	r_vector_push (dbg->session->checkpoints, &checkpoint);
92 
93 	// Add PC register change so we can check for breakpoints when continue [back]
94 	RRegItem *ripc = r_reg_get (dbg->reg, dbg->reg->name[R_REG_NAME_PC], R_REG_TYPE_GPR);
95 	ut64 data = r_reg_get_value (dbg->reg, ripc);
96 	r_debug_session_add_reg_change (dbg->session, ripc->arena, ripc->offset, data);
97 
98 	return true;
99 }
100 
_set_initial_registers(RDebug * dbg)101 static void _set_initial_registers(RDebug *dbg) {
102 	size_t i;
103 	for (i = 0; i < R_REG_TYPE_LAST; i++) {
104 		RRegArena *a = dbg->session->cur_chkpt->arena[i];
105 		RRegArena *b = dbg->reg->regset[i].arena;
106 		if (a && b && a->bytes && b->bytes) {
107 			memcpy (b->bytes, a->bytes, a->size);
108 		}
109 	}
110 }
111 
_set_register(RDebug * dbg,RRegItem * ri,ut32 cnum)112 static void _set_register(RDebug *dbg, RRegItem *ri, ut32 cnum) {
113 	RVector *vreg = ht_up_find (dbg->session->registers, ri->offset | (ri->arena << 16), NULL);
114 	if (!vreg) {
115 		return;
116 	}
117 	size_t index;
118 	r_vector_upper_bound (vreg, cnum, index, CMP_CNUM_REG);
119 	if (index > 0 && index <= vreg->len) {
120 		RDebugChangeReg *reg = r_vector_index_ptr (vreg, index - 1);
121 		if (reg->cnum > dbg->session->cur_chkpt->cnum) {
122 			r_reg_set_value (dbg->reg, ri, reg->data);
123 		}
124 	}
125 }
126 
_restore_registers(RDebug * dbg,ut32 cnum)127 R_API void _restore_registers(RDebug *dbg, ut32 cnum) {
128 	RListIter *iter;
129 	RRegItem *ri;
130 	_set_initial_registers (dbg);
131 	r_list_foreach (dbg->reg->allregs, iter, ri) {
132 		_set_register (dbg, ri, cnum);
133 	}
134 }
135 
_set_initial_memory(RDebug * dbg)136 static void _set_initial_memory(RDebug *dbg) {
137 	RListIter *iter;
138 	RDebugSnap *snap;
139 	r_list_foreach (dbg->session->cur_chkpt->snaps, iter, snap) {
140 		dbg->iob.write_at (dbg->iob.io, snap->addr, snap->data, snap->size);
141 	}
142 }
143 
_restore_memory_cb(void * user,const ut64 key,const void * value)144 static bool _restore_memory_cb(void *user, const ut64 key, const void *value) {
145 	size_t index;
146 	RDebug *dbg = user;
147 	RVector *vmem = (RVector *)value;
148 
149 	r_vector_upper_bound (vmem, dbg->session->cnum, index, CMP_CNUM_MEM);
150 	if (index > 0 && index <= vmem->len) {
151 		RDebugChangeMem *mem = r_vector_index_ptr (vmem, index - 1);
152 		if (mem->cnum > dbg->session->cur_chkpt->cnum) {
153 			dbg->iob.write_at (dbg->iob.io, key, &mem->data, 1);
154 		}
155 	}
156 	return true;
157 }
158 
_restore_memory(RDebug * dbg,ut32 cnum)159 static void _restore_memory(RDebug *dbg, ut32 cnum) {
160 	_set_initial_memory (dbg);
161 	ht_up_foreach (dbg->session->memory, _restore_memory_cb, dbg);
162 }
163 
_get_checkpoint_before(RDebugSession * session,ut32 cnum)164 static RDebugCheckpoint *_get_checkpoint_before(RDebugSession *session, ut32 cnum) {
165 	RDebugCheckpoint *checkpoint = NULL;
166 	size_t index;
167 	r_vector_upper_bound (session->checkpoints, cnum, index, CMP_CNUM_CHKPT);
168 	if (index > 0 && index <= session->checkpoints->len) {
169 		checkpoint = r_vector_index_ptr (session->checkpoints, index - 1);
170 	}
171 	return checkpoint;
172 }
173 
r_debug_session_restore_reg_mem(RDebug * dbg,ut32 cnum)174 R_API void r_debug_session_restore_reg_mem(RDebug *dbg, ut32 cnum) {
175 	// Set checkpoint for initial registers and memory
176 	dbg->session->cur_chkpt = _get_checkpoint_before (dbg->session, cnum);
177 
178 	// Restore registers
179 	_restore_registers (dbg, cnum);
180 	r_debug_reg_sync (dbg, R_REG_TYPE_ALL, true);
181 
182 	// Restore memory
183 	_restore_memory (dbg, cnum);
184 }
185 
r_debug_session_list_memory(RDebug * dbg)186 R_API void r_debug_session_list_memory(RDebug *dbg) {
187 	RListIter *iter;
188 	RDebugMap *map;
189 	r_debug_map_sync (dbg);
190 	r_list_foreach (dbg->maps, iter, map) {
191 		if ((map->perm & R_PERM_RW) == R_PERM_RW) {
192 			RDebugSnap *snap = r_debug_snap_map (dbg, map);
193 			if (!snap) {
194 				return;
195 			}
196 
197 			ut8 *hash = r_debug_snap_get_hash (snap);
198 			if (!hash) {
199 				r_debug_snap_free (snap);
200 				return;
201 			}
202 
203 			char *hexstr = r_hex_bin2strdup (hash, R_HASH_SIZE_SHA256);
204 			if (!hexstr) {
205 				free (hash);
206 				r_debug_snap_free (snap);
207 				return;
208 			}
209 			dbg->cb_printf ("%s: %s\n", snap->name, hexstr);
210 
211 			free (hexstr);
212 			free (hash);
213 			r_debug_snap_free (snap);
214 		}
215 	}
216 }
217 
r_debug_session_add_reg_change(RDebugSession * session,int arena,ut64 offset,ut64 data)218 R_API bool r_debug_session_add_reg_change(RDebugSession *session, int arena, ut64 offset, ut64 data) {
219 	RVector *vreg = ht_up_find (session->registers, offset | (arena << 16), NULL);
220 	if (!vreg) {
221 		vreg = r_vector_new (sizeof (RDebugChangeReg), NULL, NULL);
222 		if (!vreg) {
223 			eprintf ("Error: creating a register vector.\n");
224 			return false;
225 		}
226 		ht_up_insert (session->registers, offset | (arena << 16), vreg);
227 	}
228 	RDebugChangeReg reg = { session->cnum, data };
229 	r_vector_push (vreg, &reg);
230 	return true;
231 }
232 
r_debug_session_add_mem_change(RDebugSession * session,ut64 addr,ut8 data)233 R_API bool r_debug_session_add_mem_change(RDebugSession *session, ut64 addr, ut8 data) {
234 	RVector *vmem = ht_up_find (session->memory, addr, NULL);
235 	if (!vmem) {
236 		vmem = r_vector_new (sizeof (RDebugChangeMem), NULL, NULL);
237 		if (!vmem) {
238 			eprintf ("Error: creating a memory vector.\n");
239 			return false;
240 		}
241 		ht_up_insert (session->memory, addr, vmem);
242 	}
243 	RDebugChangeMem mem = { session->cnum, data };
244 	r_vector_push (vmem, &mem);
245 	return true;
246 }
247 
248 /* Save and Load Session */
249 
250 // 0x<addr>=[<RDebugChangeReg>]
serialize_register_cb(void * db,const ut64 k,const void * v)251 static bool serialize_register_cb(void *db, const ut64 k, const void *v) {
252 	RDebugChangeReg *reg;
253 	RVector *vreg = (RVector *)v;
254 	PJ *j = pj_new ();
255 	if (!j) {
256 		return false;
257 	}
258 	pj_a (j);
259 
260 	r_vector_foreach (vreg, reg) {
261 		pj_o (j);
262 		pj_kN (j, "cnum", reg->cnum);
263 		pj_kn (j, "data", reg->data);
264 		pj_end (j);
265 	}
266 
267 	pj_end (j);
268 	sdb_set (db, sdb_fmt ("0x%"PFMT64x, k), pj_string (j), 0);
269 	pj_free (j);
270 	return true;
271 }
272 
serialize_registers(Sdb * db,HtUP * registers)273 static void serialize_registers(Sdb *db, HtUP *registers) {
274 	ht_up_foreach (registers, serialize_register_cb, db);
275 }
276 
277 // 0x<addr>={"size":<size_t>, "a":[<RDebugChangeMem>]}},
serialize_memory_cb(void * db,const ut64 k,const void * v)278 static bool serialize_memory_cb(void *db, const ut64 k, const void *v) {
279 	RDebugChangeMem *mem;
280 	RVector *vmem = (RVector *)v;
281 	PJ *j = pj_new ();
282 	if (!j) {
283 		return false;
284 	}
285 	pj_a (j);
286 
287 	r_vector_foreach (vmem, mem) {
288 		pj_o (j);
289 		pj_kN (j, "cnum", mem->cnum);
290 		pj_kn (j, "data", mem->data);
291 		pj_end (j);
292 	}
293 
294 	pj_end (j);
295 	sdb_set (db, sdb_fmt ("0x%"PFMT64x, k), pj_string (j), 0);
296 	pj_free (j);
297 	return true;
298 }
299 
serialize_memory(Sdb * db,HtUP * memory)300 static void serialize_memory(Sdb *db, HtUP *memory) {
301 	ht_up_foreach (memory, serialize_memory_cb, db);
302 }
303 
serialize_checkpoints(Sdb * db,RVector * checkpoints)304 static void serialize_checkpoints(Sdb *db, RVector *checkpoints) {
305 	size_t i;
306 	RDebugCheckpoint *chkpt;
307 	RDebugSnap *snap;
308 	RListIter *iter;
309 
310 	r_vector_foreach (checkpoints, chkpt) {
311 		// 0x<cnum>={
312 		//   registers:{"<RRegisterType>":<RRegArena>, ...},
313 		//   snaps:{"size":<size_t>, "a":[<RDebugSnap>]}
314 		// }
315 		PJ *j = pj_new ();
316 		if (!j) {
317 			return;
318 		}
319 		pj_o (j);
320 
321 		// Serialize RRegArena to "registers"
322 		// {"size":<int>, "bytes":"<base64>"}
323 		pj_ka (j, "registers");
324 		for (i = 0; i < R_REG_TYPE_LAST; i++) {
325 			RRegArena *arena = chkpt->arena[i];
326 			if (arena->bytes) {
327 				pj_o (j);
328 				pj_kn (j, "arena", i);
329 				char *ebytes = sdb_encode ((const void *)arena->bytes, arena->size);
330 				pj_ks (j, "bytes", ebytes);
331 				free (ebytes);
332 				pj_kn (j, "size", arena->size);
333 				pj_end (j);
334 			}
335 		}
336 		pj_end (j);
337 
338 		// Serialize RDebugSnap to "snaps"
339 		// {"name":<str>, "addr":<ut64>, "addr_end":<ut64>, "size":<ut64>,
340 		//  "data":"<base64>", "perm":<int>, "user":<int>, "shared":<bool>}
341 		pj_ka (j, "snaps");
342 		r_list_foreach (chkpt->snaps, iter, snap) {
343 			pj_o (j);
344 			pj_ks (j, "name", snap->name);
345 			pj_kn (j, "addr", snap->addr);
346 			pj_kn (j, "addr_end", snap->addr_end);
347 			pj_kn (j, "size", snap->size);
348 			char *edata = sdb_encode ((const void *)snap->data, snap->size);
349 			if (!edata) {
350 				pj_free (j);
351 				return;
352 			}
353 			pj_ks (j, "data", edata);
354 			free (edata);
355 			pj_kn (j, "perm", snap->perm);
356 			pj_kn (j, "user", snap->user);
357 			pj_kb (j, "shared", snap->shared);
358 			pj_end (j);
359 		}
360 		pj_end (j);
361 
362 		pj_end (j);
363 		sdb_set (db, sdb_fmt ("0x%x", chkpt->cnum), pj_string (j), 0);
364 		pj_free (j);
365 	}
366 }
367 
368 /*
369  * SDB Format:
370  *
371  * /
372  *   maxcnum=<maxcnum>
373  *
374  *   /registers
375  *     0x<addr>={"size":<size_t>, "a":[<RDebugChangeReg>]}
376  *
377  *   /memory
378  *     0x<addr>={"size":<size_t>, "a":[<RDebugChangeMem>]}
379  *
380  *   /checkpoints
381  *     0x<cnum>={
382  *       registers:{"<RRegisterType>":<RRegArena>, ...},
383  *       snaps:{"size":<size_t>, "a":[<RDebugSnap>]}
384  *     }
385  *
386  * RDebugChangeReg JSON:
387  * {"cnum":<int>, "data":<ut64>}
388  *
389  * RDebugChangeMem JSON:
390  * {"cnum":<int>, "data":<ut8>}
391  *
392  * RRegArena JSON:
393  * {"size":<int>, "bytes":"<base64>"}
394  *
395  * RDebugSnap JSON:
396  * {"name":<str>, "addr":<ut64>, "addr_end":<ut64>, "size":<ut64>,
397  *  "data":"<base64>", "perm":<int>, "user":<int>, "shared":<bool>}
398  *
399  * Notes:
400  * - This mostly follows r2db-style serialization and uses sdb_json as the parser.
401  */
r_debug_session_serialize(RDebugSession * session,Sdb * db)402 R_API void r_debug_session_serialize(RDebugSession *session, Sdb *db) {
403 	sdb_num_set (db, "maxcnum", session->maxcnum, 0);
404 	serialize_registers (sdb_ns (db, "registers", true), session->registers);
405 	serialize_memory (sdb_ns (db, "memory", true), session->memory);
406 	serialize_checkpoints (sdb_ns (db, "checkpoints", true), session->checkpoints);
407 }
408 
session_sdb_save(Sdb * db,const char * path)409 static bool session_sdb_save(Sdb *db, const char *path) {
410 	char *filename;
411 	if (!r_file_is_directory (path)) {
412 		eprintf ("Error: %s is not a directory\n", path);
413 		return false;
414 	}
415 
416 	filename = r_str_newf ("%s%ssession.sdb", path, R_SYS_DIR);
417 	sdb_file (db, filename);
418 	if (!sdb_sync (db)) {
419 		eprintf ("Failed to sync session to %s\n", filename);
420 		free (filename);
421 		sdb_close (db);
422 		return false;
423 	}
424 	free (filename);
425 	sdb_close (db);
426 
427 	SdbListIter *it;
428 	SdbNs *ns;
429 	ls_foreach (db->ns, it, ns) {
430 		char *filename = r_str_newf ("%s%s%s.sdb", path, R_SYS_DIR, ns->name);
431 		sdb_file (ns->sdb, filename);
432 		if (!sdb_sync (ns->sdb)) {
433 			eprintf ("Failed to sync %s to %s\n", ns->name, filename);
434 			free (filename);
435 			sdb_close (ns->sdb);
436 			return false;
437 		}
438 		free (filename);
439 		sdb_close (ns->sdb);
440 	}
441 
442 	return true;
443 }
444 
r_debug_session_save(RDebugSession * session,const char * path)445 R_API bool r_debug_session_save(RDebugSession *session, const char *path) {
446 	Sdb *db = sdb_new0 ();
447 	if (!db) {
448 		return false;
449 	}
450 	r_debug_session_serialize (session, db);
451 
452 	if (!session_sdb_save (db, path)) {
453 		sdb_free (db);
454 		return false;
455 	}
456 	sdb_free (db);
457 	return true;
458 }
459 
460 
461 #define CHECK_TYPE(v,t) \
462 	if (!v || v->type != t) \
463 		continue
464 
deserialize_memory_cb(void * user,const char * addr,const char * v)465 static bool deserialize_memory_cb(void *user, const char *addr, const char *v) {
466 	RJson *child;
467 	char *json_str = strdup (v);
468 	if (!json_str) {
469 		return true;
470 	}
471 	RJson *reg_json = r_json_parse (json_str);
472 	if (!reg_json || reg_json->type != R_JSON_ARRAY) {
473 		free (json_str);
474 		return true;
475 	}
476 
477 	HtUP *memory = user;
478 	// Insert a new vector into `memory` HtUP at `addr`
479 	RVector *vmem = r_vector_new (sizeof (RDebugChangeMem), NULL, NULL);
480 	if (!vmem) {
481 		eprintf ("Error: failed to allocate RVector vmem.\n");
482 		free (json_str);
483 		r_json_free (reg_json);
484 		return false;
485 	}
486 	ht_up_insert (memory, sdb_atoi (addr), vmem);
487 
488 	// Extract <RDebugChangeMem>'s into the new vector
489 	for (child = reg_json->children.first; child; child = child->next) {
490 		if (child->type != R_JSON_OBJECT) {
491 			continue;
492 		}
493 		const RJson *baby = r_json_get (child, "cnum");
494 		CHECK_TYPE (baby, R_JSON_INTEGER);
495 		int cnum = baby->num.s_value;
496 
497 		baby = r_json_get (child, "data");
498 		CHECK_TYPE (baby, R_JSON_INTEGER);
499 		ut64 data = baby->num.u_value;
500 
501 		RDebugChangeMem mem = { cnum, data };
502 		r_vector_push (vmem, &mem);
503 	}
504 
505 	free (json_str);
506 	r_json_free (reg_json);
507 	return true;
508 }
509 
deserialize_memory(Sdb * db,HtUP * memory)510 static void deserialize_memory(Sdb *db, HtUP *memory) {
511 	sdb_foreach (db, deserialize_memory_cb, memory);
512 }
513 
deserialize_registers_cb(void * user,const char * addr,const char * v)514 static bool deserialize_registers_cb(void *user, const char *addr, const char *v) {
515 	RJson *child;
516 	char *json_str = strdup (v);
517 	if (!json_str) {
518 		return true;
519 	}
520 	RJson *reg_json = r_json_parse (json_str);
521 	if (!reg_json || reg_json->type != R_JSON_ARRAY) {
522 		free (json_str);
523 		return true;
524 	}
525 
526 	// Insert a new vector into `registers` HtUP at `addr`
527 	HtUP *registers = user;
528 	RVector *vreg = r_vector_new (sizeof (RDebugChangeReg), NULL, NULL);
529 	if (!vreg) {
530 		eprintf ("Error: failed to allocate RVector vreg.\n");
531 		r_json_free (reg_json);
532 		free (json_str);
533 		return true;
534 	}
535 	ht_up_insert (registers, sdb_atoi (addr), vreg);
536 
537 	// Extract <RDebugChangeReg>'s into the new vector
538 	for (child = reg_json->children.first; child; child = child->next) {
539 		if (child->type != R_JSON_OBJECT) {
540 			continue;
541 		}
542 		const RJson *baby = r_json_get (child, "cnum");
543 		CHECK_TYPE (baby, R_JSON_INTEGER);
544 		int cnum = baby->num.s_value;
545 
546 		baby = r_json_get (child, "data");
547 		CHECK_TYPE (baby, R_JSON_INTEGER);
548 		ut64 data = baby->num.u_value;
549 
550 		RDebugChangeReg reg = { cnum, data };
551 		r_vector_push (vreg, &reg);
552 	}
553 
554 	r_json_free (reg_json);
555 	free (json_str);
556 	return true;
557 }
558 
deserialize_registers(Sdb * db,HtUP * registers)559 static void deserialize_registers(Sdb *db, HtUP *registers) {
560 	sdb_foreach (db, deserialize_registers_cb, registers);
561 }
562 
563 #define SNAPATTR(ATTR) sdb_fmt ("snaps.a[%u]." ATTR, i)
564 #define REGATTR(ATTR) sdb_fmt ("registers.%d." ATTR, i)
565 
deserialize_checkpoints_cb(void * user,const char * cnum,const char * v)566 static bool deserialize_checkpoints_cb(void *user, const char *cnum, const char *v) {
567 	const RJson *child;
568 	char *json_str = strdup (v);
569 	if (!json_str) {
570 		return true;
571 	}
572 	RJson *chkpt_json = r_json_parse (json_str);
573 	if (!chkpt_json || chkpt_json->type != R_JSON_OBJECT) {
574 		free (json_str);
575 		return true;
576 	}
577 
578 	RVector *checkpoints = user;
579 	RDebugCheckpoint checkpoint = { 0 };
580 	checkpoint.cnum = (int)sdb_atoi (cnum);
581 
582 	// Extract RRegArena's from "registers"
583 	const RJson *regs_json = r_json_get (chkpt_json, "registers");
584 	if (!regs_json || regs_json->type != R_JSON_ARRAY) {
585 		free (json_str);
586 		return true;
587 	}
588 	for (child = regs_json->children.first; child; child = child->next) {
589 		const RJson *baby;
590 		baby = r_json_get (child, "arena");
591 		CHECK_TYPE (baby, R_JSON_INTEGER);
592 		int arena = baby->num.s_value;
593 		if (arena < R_REG_TYPE_GPR || arena > R_REG_TYPE_SEG) {
594 			continue;
595 		}
596 		baby = r_json_get (child, "size");
597 		CHECK_TYPE (baby, R_JSON_INTEGER);
598 		int size = baby->num.s_value;
599 		if (size < 0) {
600 			continue;
601 		}
602 		baby = r_json_get (child, "bytes");
603 		CHECK_TYPE (baby, R_JSON_STRING);
604 		ut8 *bytes = sdb_decode (baby->str_value, NULL);
605 
606 		RRegArena *a = r_reg_arena_new (size);
607 		if (!a) {
608 			free (bytes);
609 			continue;
610 		}
611 		memcpy (a->bytes, bytes, a->size);
612 		checkpoint.arena[arena] = a;
613 		free (bytes);
614 	}
615 
616 	// Extract RDebugSnap's from "snaps"
617 	checkpoint.snaps = r_list_newf ((RListFree)r_debug_snap_free);
618 	const RJson *snaps_json = r_json_get (chkpt_json, "snaps");
619 	if (!snaps_json || snaps_json->type != R_JSON_ARRAY) {
620 		goto end;
621 	}
622 	for (child = snaps_json->children.first; child; child = child->next) {
623 		const RJson *namej = r_json_get (child, "name");
624 		CHECK_TYPE (namej, R_JSON_STRING);
625 		const RJson *dataj = r_json_get (child, "data");
626 		CHECK_TYPE (dataj, R_JSON_STRING);
627 		const RJson *sizej = r_json_get (child, "size");
628 		CHECK_TYPE (sizej, R_JSON_INTEGER);
629 		const RJson *addrj = r_json_get (child, "addr");
630 		CHECK_TYPE (addrj, R_JSON_INTEGER);
631 		const RJson *addr_endj = r_json_get (child, "addr_end");
632 		CHECK_TYPE (addr_endj, R_JSON_INTEGER);
633 		const RJson *permj = r_json_get (child, "perm");
634 		CHECK_TYPE (permj, R_JSON_INTEGER);
635 		const RJson *userj = r_json_get (child, "user");
636 		CHECK_TYPE (userj, R_JSON_INTEGER);
637 		const RJson *sharedj = r_json_get (child, "shared");
638 		CHECK_TYPE (sharedj, R_JSON_BOOLEAN);
639 
640 		RDebugSnap *snap = R_NEW0 (RDebugSnap);
641 		if (!snap) {
642 			eprintf ("Error: failed to allocate RDebugSnap snap");
643 			continue;
644 		}
645 		snap->name = strdup (namej->str_value);
646 		snap->addr = addrj->num.u_value;
647 		snap->addr_end = addr_endj->num.u_value;
648 		snap->size = sizej->num.u_value;
649 		snap->data = sdb_decode (dataj->str_value, NULL);
650 		snap->perm = permj->num.s_value;
651 		snap->user = userj->num.s_value;
652 		snap->shared = sharedj->num.u_value;
653 
654 		r_list_append (checkpoint.snaps, snap);
655 	}
656 end:
657 	free (json_str);
658 	r_json_free (chkpt_json);
659 	r_vector_push (checkpoints, &checkpoint);
660 	return true;
661 }
662 
deserialize_checkpoints(Sdb * db,RVector * checkpoints)663 static void deserialize_checkpoints(Sdb *db, RVector *checkpoints) {
664 	sdb_foreach (db, deserialize_checkpoints_cb, checkpoints);
665 }
666 
session_sdb_load_ns(Sdb * db,const char * nspath,const char * filename)667 static bool session_sdb_load_ns(Sdb *db, const char *nspath, const char *filename) {
668 	Sdb *tmpdb = sdb_new0 ();
669 	if (sdb_open (tmpdb, filename) == -1) {
670 		eprintf ("Error: failed to load %s into sdb\n", filename);
671 		sdb_free (tmpdb);
672 		return false;
673 	}
674 	Sdb *ns = sdb_ns_path (db, nspath, true);
675 	sdb_copy (tmpdb, ns);
676 	sdb_free (tmpdb);
677 	return true;
678 }
679 
session_sdb_load(const char * path)680 static Sdb *session_sdb_load(const char *path) {
681 	char *filename;
682 	Sdb *db = sdb_new0 ();
683 	if (!db) {
684 		return NULL;
685 	}
686 
687 #define SDB_LOAD(fn, ns) do { \
688 		filename = r_str_newf ("%s%s" fn ".sdb", path, R_SYS_DIR); \
689 		if (!session_sdb_load_ns (db, ns, filename)) { \
690 			free (filename); \
691 			goto error; \
692 		} \
693 		free (filename); \
694 	} while (0)
695 
696 	SDB_LOAD ("session", "");
697 	SDB_LOAD ("registers", "registers");
698 	SDB_LOAD ("memory", "memory");
699 	SDB_LOAD ("checkpoints", "checkpoints");
700 	return db;
701 error:
702 	sdb_free (db);
703 	return NULL;
704 }
705 
r_debug_session_deserialize(RDebugSession * session,Sdb * db)706 R_API void r_debug_session_deserialize(RDebugSession *session, Sdb *db) {
707 	Sdb *subdb;
708 
709 	session->maxcnum = sdb_num_get (db, "maxcnum", 0);
710 
711 #define DESERIALIZE(ns, func) do { \
712 		subdb = sdb_ns (db, ns, false); \
713 		if (!subdb) { \
714 			eprintf ("Error: missing " ns " namespace\n"); \
715 			return; \
716 		} \
717 		func; \
718 	} while (0)
719 
720 	DESERIALIZE ("memory", deserialize_memory (subdb, session->memory));
721 	DESERIALIZE ("registers", deserialize_registers (subdb, session->registers));
722 	DESERIALIZE ("checkpoints", deserialize_checkpoints (subdb, session->checkpoints));
723 }
724 
r_debug_session_load(RDebug * dbg,const char * path)725 R_API bool r_debug_session_load(RDebug *dbg, const char *path) {
726 	Sdb *db = session_sdb_load (path);
727 	if (!db) {
728 		return false;
729 	}
730 	r_debug_session_deserialize (dbg->session, db);
731 	// Restore debugger to the beginning of the session
732 	r_debug_session_restore_reg_mem (dbg, 0);
733 	sdb_free (db);
734 	return true;
735 }
736