radare2/scripts/pebble.r2.js

698 lines
23 KiB
JavaScript

/* Pebble libpebble.a stub resolver for radare2/r2js.
*
* Usage:
* r2 -i examples/pebble.r2.js hello-world/build/aplite/pebble-app.elf
*
* The per-API stubs linked from libpebble.a look like this in Thumb bytes:
* 0f b4 push {r0, r1, r2, r3}
* 01 49 ldr r1, [pc, #4]
* ff f7 ?? ?? b.w jump_to_pbl_function
* ?? ?? ?? ?? little-endian firmware jump-table byte offset
*
* Objdump prints the same pattern as halfwords:
* b40f 4901 f7ff ???? <offset32>
*
* The shared trampoline usually looks like this in file/memory bytes:
* 03 a3 18 68 08 44 02 68 94 46 0f bc 60 47 00 bf ?? ?? ?? ??
* where the last word is pbl_table_addr and is patched by the firmware loader.
*/
const STUB_PATTERN = "0fb40149fff7............";
const TRAMPOLINE_PATTERN = "03a318680844026894460fbc604700bf........";
const PEBBLE_API_BY_INDEX = {
0: "accel_data_service_subscribe__deprecated",
1: "accel_data_service_unsubscribe",
2: "accel_service_peek",
3: "accel_service_set_samples_per_update",
4: "accel_service_set_sampling_rate",
5: "accel_tap_service_subscribe",
6: "accel_tap_service_unsubscribe",
7: "action_bar_layer_legacy2_add_to_window",
8: "action_bar_layer_legacy2_clear_icon",
9: "action_bar_layer_legacy2_create",
10: "action_bar_layer_legacy2_destroy",
11: "action_bar_layer_legacy2_get_layer",
12: "action_bar_layer_legacy2_remove_from_window",
13: "action_bar_layer_legacy2_set_background_color_2bit",
14: "action_bar_layer_legacy2_set_click_config_provider",
15: "action_bar_layer_legacy2_set_context",
16: "action_bar_layer_legacy2_set_icon",
17: "animation_legacy2_create",
18: "animation_legacy2_destroy",
19: "animation_legacy2_get_context",
20: "animation_legacy2_is_scheduled",
21: "animation_legacy2_schedule",
22: "animation_legacy2_set_curve",
23: "animation_legacy2_set_delay",
24: "animation_legacy2_set_duration",
25: "animation_legacy2_set_handlers",
26: "animation_legacy2_set_implementation",
27: "animation_legacy2_unschedule",
28: "animation_legacy2_unschedule_all",
29: "app_comm_get_sniff_interval",
30: "app_comm_set_sniff_interval",
31: "app_event_loop",
34: "app_log",
35: "app_message_deregister_callbacks",
36: "app_message_open",
43: "app_sync_deinit",
44: "app_sync_get",
45: "app_sync_init",
46: "app_sync_set",
47: "app_timer_cancel",
48: "app_timer_register",
49: "app_timer_reschedule",
50: "atan2_lookup",
51: "atoi",
52: "atol",
53: "battery_state_service_peek",
54: "battery_state_service_subscribe",
55: "battery_state_service_unsubscribe",
56: "bitmap_layer_create",
57: "bitmap_layer_destroy",
58: "bitmap_layer_get_layer",
59: "bitmap_layer_set_alignment",
60: "bitmap_layer_set_background_color_2bit",
61: "bitmap_layer_set_bitmap",
62: "bitmap_layer_set_compositing_mode",
63: "bluetooth_connection_service_peek",
64: "bluetooth_connection_service_subscribe",
65: "bluetooth_connection_service_unsubscribe",
66: "click_number_of_clicks_counted",
67: "click_recognizer_get_button_id",
68: "clock_copy_time_string",
69: "clock_is_24h_style",
70: "cos_lookup",
71: "data_logging_create",
72: "data_logging_finish",
73: "data_logging_log",
74: "dict_calc_buffer_size",
75: "dict_calc_buffer_size_from_tuplets",
76: "dict_find",
77: "dict_merge",
78: "dict_read_begin_from_buffer",
79: "dict_read_first",
80: "dict_read_next",
81: "dict_serialize_tuplets",
82: "dict_serialize_tuplets_to_buffer__deprecated",
83: "dict_serialize_tuplets_to_buffer_with_iter",
84: "dict_write_begin",
85: "dict_write_cstring",
86: "dict_write_data",
87: "dict_write_end",
88: "dict_write_int",
89: "dict_write_int16",
90: "dict_write_int32",
91: "dict_write_int8",
92: "dict_write_tuplet",
93: "dict_write_uint16",
94: "dict_write_uint32",
95: "dict_write_uint8",
96: "fonts_get_system_font",
97: "fonts_load_custom_font",
98: "fonts_unload_custom_font",
99: "free",
100: "gbitmap_create_as_sub_bitmap",
101: "gbitmap_create_with_data",
102: "gbitmap_create_with_resource",
103: "gbitmap_destroy",
104: "gmtime",
105: "gpath_create",
106: "gpath_destroy",
107: "gpath_draw_filled_legacy",
108: "gpath_draw_outline",
109: "gpath_move_to",
110: "gpath_rotate_to",
111: "gpoint_equal",
112: "graphics_context_set_compositing_mode",
113: "graphics_context_set_fill_color_2bit",
114: "graphics_context_set_stroke_color_2bit",
115: "graphics_context_set_text_color_2bit",
116: "graphics_draw_bitmap_in_rect",
117: "graphics_draw_circle",
118: "graphics_draw_line",
119: "graphics_draw_pixel",
120: "graphics_draw_rect",
121: "graphics_draw_round_rect",
122: "graphics_fill_circle",
123: "graphics_fill_rect",
125: "graphics_text_layout_get_max_used_size",
126: "grect_align",
127: "grect_center_point",
128: "grect_clip",
129: "grect_contains_point",
130: "grect_crop",
131: "grect_equal",
132: "grect_is_empty",
133: "grect_standardize",
134: "gsize_equal",
135: "inverter_layer_create",
136: "inverter_layer_destroy",
137: "inverter_layer_get_layer",
138: "layer_add_child",
139: "layer_create",
140: "layer_create_with_data",
141: "layer_destroy",
142: "layer_get_bounds",
143: "layer_get_clips",
144: "layer_get_data",
145: "layer_get_frame",
146: "layer_get_hidden",
147: "layer_get_window",
148: "layer_insert_above_sibling",
149: "layer_insert_below_sibling",
150: "layer_mark_dirty",
151: "layer_remove_child_layers",
152: "layer_remove_from_parent",
153: "layer_set_bounds",
154: "layer_set_clips",
155: "layer_set_frame",
156: "layer_set_hidden",
157: "layer_set_update_proc",
158: "light_enable",
159: "light_enable_interaction",
160: "localtime__deprecated",
161: "malloc",
162: "memcpy",
163: "memmove",
164: "memset",
165: "menu_cell_basic_draw",
166: "menu_cell_basic_header_draw",
167: "menu_cell_title_draw",
168: "menu_index_compare",
169: "menu_layer_legacy2_create",
170: "menu_layer_destroy",
171: "menu_layer_get_layer",
172: "menu_layer_get_scroll_layer",
173: "menu_layer_get_selected_index",
174: "menu_layer_reload_data",
175: "menu_layer_legacy2_set_callbacks__deprecated",
176: "menu_layer_set_click_config_onto_window",
177: "menu_layer_set_selected_index",
178: "menu_layer_set_selected_next",
179: "number_window_create",
180: "number_window_destroy",
181: "number_window_get_value",
182: "number_window_set_label",
183: "number_window_set_max",
184: "number_window_set_min",
185: "number_window_set_step_size",
186: "number_window_set_value",
187: "persist_delete",
188: "persist_exists",
189: "persist_get_size",
190: "persist_read_bool",
191: "persist_read_data__deprecated",
192: "persist_read_int",
193: "persist_read_string__deprecated",
194: "persist_write_bool",
195: "persist_write_data__deprecated",
196: "persist_write_int",
197: "persist_write_string",
198: "property_animation_legacy2_create",
199: "property_animation_legacy2_create_layer_frame",
200: "property_animation_legacy2_destroy",
201: "property_animation_legacy2_update_gpoint",
202: "property_animation_legacy2_update_grect",
203: "property_animation_legacy2_update_int16",
204: "psleep",
205: "rand",
206: "resource_get_handle",
207: "resource_load",
208: "resource_load_byte_range",
209: "resource_size",
210: "rot_bitmap_layer_create",
211: "rot_bitmap_layer_destroy",
212: "rot_bitmap_layer_increment_angle",
213: "rot_bitmap_layer_set_angle",
214: "rot_bitmap_layer_set_corner_clip_color_2bit",
215: "rot_bitmap_set_compositing_mode",
216: "rot_bitmap_set_src_ic",
217: "scroll_layer_add_child",
218: "scroll_layer_create",
219: "scroll_layer_destroy",
220: "scroll_layer_get_content_offset",
221: "scroll_layer_get_content_size",
222: "scroll_layer_get_layer",
223: "scroll_layer_get_shadow_hidden",
224: "scroll_layer_scroll_down_click_handler",
225: "scroll_layer_scroll_up_click_handler",
226: "scroll_layer_set_callbacks",
227: "scroll_layer_set_click_config_onto_window",
228: "scroll_layer_set_content_offset",
229: "scroll_layer_set_content_size",
230: "scroll_layer_set_context",
231: "scroll_layer_set_frame",
232: "scroll_layer_set_shadow_hidden",
233: "simple_menu_layer_create",
234: "simple_menu_layer_destroy",
235: "simple_menu_layer_get_layer",
236: "simple_menu_layer_get_selected_index",
237: "simple_menu_layer_set_selected_index",
238: "sin_lookup",
239: "snprintf",
240: "srand",
241: "strcat",
242: "strcmp",
243: "strcpy",
244: "strftime",
245: "strlen",
246: "strncat",
247: "strncmp",
248: "strncpy",
249: "text_layer_legacy2_create",
250: "text_layer_legacy2_destroy",
251: "text_layer_legacy2_get_content_size",
252: "text_layer_legacy2_get_layer",
253: "text_layer_legacy2_get_text",
254: "text_layer_legacy2_set_background_color_2bit",
255: "text_layer_legacy2_set_font",
256: "text_layer_legacy2_set_overflow_mode",
257: "text_layer_legacy2_set_size",
258: "text_layer_legacy2_set_text",
259: "text_layer_legacy2_set_text_alignment",
260: "text_layer_legacy2_set_text_color_2bit",
262: "tick_timer_service_subscribe",
263: "tick_timer_service_unsubscribe",
264: "time__deprecated",
265: "time_ms_deprecated",
266: "vibes_cancel",
267: "vibes_double_pulse",
268: "vibes_enqueue_custom_pattern",
269: "vibes_long_pulse",
270: "vibes_short_pulse",
271: "window_create",
272: "window_destroy",
273: "window_get_click_config_provider",
274: "window_get_fullscreen",
275: "window_get_root_layer",
276: "window_is_loaded",
277: "window_set_background_color_2bit",
278: "window_set_click_config_provider",
279: "window_set_click_config_provider_with_context",
280: "window_set_fullscreen",
281: "window_set_status_bar_icon",
282: "window_set_window_handlers",
283: "window_stack_contains_window",
284: "window_stack_get_top_window",
285: "window_stack_pop",
286: "window_stack_pop_all",
287: "window_stack_push",
288: "window_stack_remove",
289: "app_focus_service_subscribe",
290: "app_focus_service_unsubscribe",
291: "window_get_user_data",
292: "window_set_user_data",
293: "app_message_get_context",
294: "app_message_inbox_size_maximum",
295: "app_message_outbox_begin",
296: "app_message_outbox_send",
297: "app_message_outbox_size_maximum",
298: "app_message_register_inbox_dropped",
299: "app_message_register_inbox_received",
300: "app_message_register_outbox_failed",
301: "app_message_register_outbox_sent",
302: "app_message_set_context",
303: "window_long_click_subscribe",
304: "window_multi_click_subscribe",
305: "window_raw_click_subscribe",
306: "window_set_click_context",
307: "window_single_click_subscribe",
308: "window_single_repeating_click_subscribe",
309: "graphics_draw_text",
310: "dict_serialize_tuplets_to_buffer",
311: "persist_read_data",
312: "persist_read_string",
313: "persist_write_data",
314: "dict_size",
315: "graphics_text_layout_get_content_size",
316: "simple_menu_layer_get_menu_layer",
317: "accel_data_service_subscribe",
318: "calloc",
319: "bitmap_layer_get_bitmap",
320: "menu_layer_legacy2_set_callbacks",
321: "window_get_click_config_context",
322: "number_window_get_window",
323: "realloc",
324: "gbitmap_create_blank_2bit",
325: "click_recognizer_is_repeating",
326: "accel_raw_data_service_subscribe",
327: "app_worker_is_running",
328: "app_worker_kill",
329: "app_worker_launch",
330: "app_worker_message_subscribe",
331: "app_worker_message_unsubscribe",
332: "app_worker_send_message",
333: "worker_event_loop",
334: "worker_launch_app",
335: "heap_bytes_free",
336: "heap_bytes_used",
337: "compass_service_peek",
338: "compass_service_set_heading_filter",
339: "compass_service_subscribe",
340: "compass_service_unsubscribe",
341: "uuid_equal",
342: "uuid_to_string",
343: "gpath_draw_filled",
344: "animation_legacy2_set_custom_curve",
345: "watch_info_get_color",
346: "watch_info_get_firmware_version",
347: "watch_info_get_model",
348: "graphics_capture_frame_buffer_2bit",
349: "graphics_frame_buffer_is_captured",
350: "graphics_release_frame_buffer",
351: "clock_to_timestamp",
352: "launch_reason",
353: "wakeup_cancel",
354: "wakeup_cancel_all",
355: "wakeup_get_launch_event",
356: "wakeup_query",
357: "wakeup_schedule",
358: "wakeup_service_subscribe",
359: "clock_is_timezone_set",
360: "i18n_get_system_locale",
361: "_localeconv_r",
362: "setlocale",
363: "mktime",
364: "gcolor_equal",
365: "__profiler_init",
366: "__profiler_print_stats",
367: "__profiler_start",
368: "__profiler_stop",
370: "bitmap_layer_set_background_color",
371: "graphics_context_set_fill_color",
372: "graphics_context_set_stroke_color",
373: "graphics_context_set_text_color",
374: "rot_bitmap_layer_set_corner_clip_color",
377: "window_set_background_color",
378: "clock_get_timezone",
379: "localtime",
380: "animation_create",
381: "animation_destroy",
382: "animation_get_context",
383: "animation_is_scheduled",
384: "animation_schedule",
385: "animation_set_curve",
386: "animation_set_custom_curve",
387: "animation_set_delay",
388: "animation_set_duration",
389: "animation_set_handlers",
390: "animation_set_implementation",
391: "animation_unschedule",
392: "animation_unschedule_all",
393: "gbitmap_create_blank",
394: "graphics_capture_frame_buffer",
395: "graphics_capture_frame_buffer_format",
396: "property_animation_create",
397: "property_animation_create_layer_frame",
398: "property_animation_destroy",
399: "property_animation_from",
400: "property_animation_get_animation",
401: "property_animation_subject",
402: "property_animation_to",
403: "property_animation_update_gpoint",
404: "property_animation_update_grect",
405: "property_animation_update_int16",
406: "gbitmap_create_blank_with_palette",
407: "gbitmap_get_bounds",
408: "gbitmap_get_bytes_per_row",
409: "gbitmap_get_data",
410: "gbitmap_get_format",
411: "gbitmap_get_palette",
412: "gbitmap_set_bounds",
413: "gbitmap_set_data",
414: "gbitmap_set_palette",
415: "gbitmap_sequence_create_with_resource",
416: "gbitmap_sequence_destroy",
417: "gbitmap_sequence_get_bitmap_size",
418: "gbitmap_sequence_get_current_frame_idx",
419: "gbitmap_sequence_get_total_num_frames",
420: "gbitmap_sequence_update_bitmap_next_frame",
421: "gbitmap_create_from_png_data",
422: "animation_clone",
423: "animation_get_delay",
424: "animation_get_duration",
425: "animation_get_play_count",
426: "animation_get_elapsed",
427: "animation_get_reverse",
428: "animation_sequence_create",
429: "animation_sequence_create_from_array",
430: "animation_set_play_count",
431: "animation_set_elapsed",
432: "animation_set_reverse",
433: "animation_spawn_create",
434: "animation_spawn_create_from_array",
435: "animation_get_curve",
436: "animation_get_custom_curve",
437: "animation_get_implementation",
438: "launch_get_args",
439: "menu_layer_create",
441: "gbitmap_sequence_get_play_count",
442: "gbitmap_sequence_restart",
443: "gbitmap_sequence_set_play_count",
444: "graphics_context_set_antialiased",
445: "graphics_context_set_stroke_width",
446: "action_bar_layer_add_to_window",
447: "action_bar_layer_clear_icon",
448: "action_bar_layer_create",
449: "action_bar_layer_destroy",
450: "action_bar_layer_get_layer",
451: "action_bar_layer_remove_from_window",
452: "action_bar_layer_set_background_color",
453: "action_bar_layer_set_click_config_provider",
454: "action_bar_layer_set_context",
455: "action_bar_layer_set_icon",
456: "action_bar_layer_set_icon_animated",
457: "gbitmap_sequence_update_bitmap_by_elapsed",
458: "gbitmap_create_palettized_from_1bit",
459: "menu_cell_layer_is_highlighted",
460: "graphics_draw_rotated_bitmap",
461: "action_bar_layer_set_icon_press_animation",
462: "text_layer_create",
463: "text_layer_destroy",
464: "text_layer_get_content_size",
465: "text_layer_get_layer",
466: "text_layer_get_text",
467: "text_layer_set_background_color",
468: "text_layer_set_font",
469: "text_layer_set_overflow_mode",
470: "text_layer_set_size",
471: "text_layer_set_text",
472: "text_layer_set_text_alignment",
473: "text_layer_set_text_color",
474: "gdraw_command_draw",
475: "gdraw_command_frame_draw",
476: "gdraw_command_frame_get_duration",
477: "gdraw_command_frame_set_duration",
478: "gdraw_command_get_fill_color",
479: "gdraw_command_get_hidden",
480: "gdraw_command_get_num_points",
481: "gdraw_command_get_path_open",
482: "gdraw_command_get_point",
483: "gdraw_command_get_radius",
484: "gdraw_command_get_stroke_color",
485: "gdraw_command_get_stroke_width",
486: "gdraw_command_get_type",
487: "gdraw_command_image_clone",
488: "gdraw_command_image_create_with_resource",
489: "gdraw_command_image_destroy",
490: "gdraw_command_image_draw",
491: "gdraw_command_image_get_bounds_size",
492: "gdraw_command_image_get_command_list",
493: "gdraw_command_image_set_bounds_size",
494: "gdraw_command_list_draw",
495: "gdraw_command_list_get_command",
496: "gdraw_command_list_get_num_commands",
497: "gdraw_command_list_iterate",
498: "gdraw_command_sequence_clone",
499: "gdraw_command_sequence_create_with_resource",
500: "gdraw_command_sequence_destroy",
501: "gdraw_command_sequence_get_bounds_size",
502: "gdraw_command_sequence_get_frame_by_elapsed",
503: "gdraw_command_sequence_get_frame_by_index",
504: "gdraw_command_sequence_get_num_frames",
505: "gdraw_command_sequence_get_play_count",
506: "gdraw_command_sequence_get_total_duration",
507: "gdraw_command_sequence_set_bounds_size",
508: "gdraw_command_sequence_set_play_count",
509: "gdraw_command_set_fill_color",
510: "gdraw_command_set_hidden",
511: "gdraw_command_set_path_open",
512: "gdraw_command_set_point",
513: "gdraw_command_set_radius",
514: "gdraw_command_set_stroke_color",
515: "gdraw_command_set_stroke_width",
516: "property_animation_create_bounds_origin",
517: "property_animation_update_uint32",
518: "gpath_draw_outline_open",
519: "time",
520: "menu_layer_set_highlight_colors",
521: "menu_layer_set_normal_colors",
522: "menu_layer_set_callbacks",
523: "menu_layer_pad_bottom_enable",
524: "status_bar_layer_create",
525: "status_bar_layer_destroy",
526: "status_bar_layer_get_background_color",
527: "status_bar_layer_get_foreground_color",
528: "status_bar_layer_get_layer",
529: "status_bar_layer_set_colors",
530: "status_bar_layer_set_separator_mode",
531: "difftime",
532: "time_ms",
533: "gcolor_legible_over",
534: "property_animation_update_gcolor8",
535: "app_focus_service_subscribe_handlers",
536: "action_menu_close",
537: "action_menu_freeze",
538: "action_menu_get_context",
539: "action_menu_get_root_level",
540: "action_menu_hierarchy_destroy",
541: "action_menu_item_get_action_data",
542: "action_menu_item_get_label",
543: "action_menu_level_add_action",
544: "action_menu_level_add_child",
545: "action_menu_level_create",
546: "action_menu_level_set_display_mode",
547: "action_menu_open",
548: "action_menu_set_result_window",
549: "action_menu_unfreeze",
550: "dictation_session_create",
551: "dictation_session_destroy",
552: "dictation_session_enable_confirmation",
553: "dictation_session_start",
554: "dictation_session_stop",
555: "smartstrap_attribute_begin_write",
556: "smartstrap_attribute_create",
557: "smartstrap_attribute_destroy",
558: "smartstrap_attribute_end_write",
559: "smartstrap_attribute_get_attribute_id",
560: "smartstrap_attribute_get_service_id",
561: "smartstrap_attribute_read",
562: "smartstrap_service_is_available",
563: "smartstrap_set_timeout",
564: "smartstrap_subscribe",
565: "smartstrap_unsubscribe",
566: "connection_service_peek_pebble_app_connection",
567: "connection_service_peek_pebblekit_connection",
568: "connection_service_subscribe",
569: "connection_service_unsubscribe",
570: "dictation_session_enable_error_dialogs",
571: "gbitmap_get_data_row_info",
572: "content_indicator_configure_direction",
573: "content_indicator_create",
574: "content_indicator_destroy",
575: "content_indicator_get_content_available",
576: "content_indicator_set_content_available",
577: "scroll_layer_get_content_indicator",
578: "menu_layer_get_center_focused",
579: "menu_layer_set_center_focused",
580: "grect_inset",
581: "gpoint_from_polar",
582: "graphics_draw_arc",
583: "graphics_fill_radial",
584: "grect_centered_from_polar",
585: "graphics_text_attributes_create",
586: "graphics_text_attributes_destroy",
587: "graphics_text_attributes_enable_paging",
588: "graphics_text_attributes_enable_screen_text_flow",
589: "graphics_text_attributes_restore_default_paging",
590: "graphics_text_attributes_restore_default_text_flow",
591: "graphics_text_layout_get_content_size_with_attributes",
592: "layer_convert_point_to_screen",
593: "layer_convert_rect_to_screen",
594: "scroll_layer_get_paging",
595: "scroll_layer_set_paging",
596: "text_layer_enable_screen_text_flow_and_paging",
597: "text_layer_restore_default_text_flow_and_paging",
598: "menu_layer_is_index_selected",
599: "health_service_activities_iterate",
600: "health_service_any_activity_accessible",
601: "health_service_events_subscribe",
602: "health_service_events_unsubscribe",
603: "health_service_get_minute_history",
604: "health_service_metric_accessible",
605: "health_service_peek_current_activities",
606: "health_service_sum",
607: "health_service_sum_today",
608: "time_start_of_today",
609: "health_service_metric_averaged_accessible",
610: "health_service_sum_averaged",
611: "health_service_get_measurement_system_for_display",
612: "gdraw_command_frame_get_command_list",
};
function hex(addr) {
return "0x" + (addr >>> 0).toString(16);
}
function cleanName(name) {
return name.replace(/[^A-Za-z0-9_]/g, "_");
}
function u32leFromHex(hexstr, byteOffset) {
const p = byteOffset * 2;
return parseInt(hexstr.slice(p + 6, p + 8) + hexstr.slice(p + 4, p + 6) + hexstr.slice(p + 2, p + 4) + hexstr.slice(p, p + 2), 16) >>> 0;
}
function searchJson(pattern) {
const out = r2.cmd("/xj " + pattern).trim();
if (!out) {
return [];
}
try {
return JSON.parse(out);
} catch (e) {
console.log("Cannot parse /xj output for " + pattern + ": " + e);
return [];
}
}
function nameTrampoline() {
const hits = searchJson(TRAMPOLINE_PATTERN);
for (const hit of hits) {
const addr = hit.addr >>> 0;
r2.cmd("f sym.pebble.jump_to_pbl_function 16 @ " + hex(addr));
r2.cmd("f sym.pebble.pbl_table_addr 4 @ " + hex(addr + 16));
r2.cmd("CCu Pebble firmware API trampoline, pbl_table_addr is patched by loader @ " + hex(addr));
}
return hits.length;
}
function nameStubs() {
r2.cmd("e search.align=4");
const hits = searchJson(STUB_PATTERN);
let named = 0;
let unknown = 0;
for (const hit of hits) {
const addr = hit.addr >>> 0;
const data = (hit.data || "").replace(/[^0-9a-fA-F]/g, "").toLowerCase();
if (data.length < 24) {
continue;
}
const byteOffset = u32leFromHex(data, 8);
if ((byteOffset & 3) !== 0) {
continue;
}
const index = byteOffset >>> 2;
const apiName = PEBBLE_API_BY_INDEX[index] || ("unknown_" + index);
const flagName = "sym.pebble." + cleanName(apiName);
r2.cmd("f " + flagName + " 12 @ " + hex(addr));
r2.cmd("af @ " + hex(addr));
r2.cmd("afn " + flagName + " @ " + hex(addr));
r2.cmd("CCu Pebble API stub " + apiName + " index=" + index + " offset=0x" + byteOffset.toString(16) + " @ " + hex(addr));
if (PEBBLE_API_BY_INDEX[index]) {
named++;
} else {
unknown++;
}
}
console.log("Pebble stubs: named=" + named + " unknown=" + unknown + " total=" + hits.length);
return named;
}
r2.cmd("e search.align=4");
const trampolines = nameTrampoline();
const stubs = nameStubs();
console.log("Pebble trampoline hits: " + trampolines);
console.log("Pebble stub resolver complete: " + stubs + " named stubs");