root/tools/finsig_thumb2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bprintf
  2. add_blankline
  3. write_output
  4. add_prop_hit
  5. get_misc_val
  6. get_misc_val_value
  7. save_misc_val
  8. save_misc_val_blobs
  9. find_saved_sig_index
  10. find_saved_sig
  11. get_saved_sig_val
  12. find_saved_sig_index_by_adr
  13. find_saved_sig_by_val
  14. save_sig
  15. add_func_name
  16. save_sig_veneers
  17. save_sig_with_j
  18. find_next_sig_call_ex
  19. find_next_sig_call
  20. is_sig_call
  21. init_disasm_sig_ref
  22. sig_match_str_r0_call
  23. sig_match_reg_evp
  24. sig_match_reg_evp_table
  25. sig_match_reg_evp_alt2
  26. sig_match_unreg_evp_table
  27. sig_match_evp_table_veneer
  28. sig_match_createtaskstrictly_alt
  29. sig_match_createtask_alt
  30. sig_match_get_nd_value
  31. sig_match_get_current_exp
  32. sig_match_get_current_nd_value
  33. sig_match_get_current_deltasv
  34. sig_match_imager_active_callback
  35. sig_match_imager_active
  36. sig_match_screenlock_helper
  37. sig_match_fclose_low
  38. sig_match_screenunlock
  39. sig_match_log_camera_event
  40. sig_match_physw_misc
  41. sig_match_kbd_read_keys
  42. sig_match_get_kbd_state
  43. sig_match_get_dial_hw_position
  44. sig_match_create_jumptable
  45. sig_match_take_semaphore_strict
  46. sig_match_get_semaphore_value
  47. sig_match_stat
  48. sig_match_open
  49. sig_match_umalloc
  50. sig_match_ufree
  51. sig_match_deletefile_fut
  52. sig_match_closedir
  53. save_sig_match_call
  54. sig_match_readfastdir
  55. sig_match_strrchr
  56. sig_match_time
  57. sig_match_strncpy
  58. sig_match_strncmp
  59. sig_match_strtolx
  60. sig_match_exec_evp
  61. sig_match_fgets_fut
  62. sig_match_log
  63. sig_match_pow_dry_52
  64. sig_match_pow_dry_gt_52
  65. sig_match_sqrt
  66. sig_match_get_drive_cluster_size
  67. sig_match_mktime_ext
  68. sig_match_rec2pb
  69. sig_match_get_parameter_data
  70. sig_match_prepdir_x
  71. sig_match_prepdir_1
  72. sig_match_prepdir_0
  73. sig_match_mkdir
  74. sig_match_add_ptp_handler
  75. sig_match_qsort
  76. sig_match_deletedirectory_fut
  77. sig_match_set_control_event
  78. sig_match_displaybusyonscreen_52
  79. sig_match_undisplaybusyonscreen_52
  80. sig_match_try_take_sem_dry_gt_57
  81. sig_match_wait_all_eventflag_strict
  82. sig_match_get_num_posted_messages
  83. sig_match_set_hp_timer_after_now
  84. sig_match_transfer_src_overlay
  85. sig_match_exmem_vars
  86. sig_match_zicokick_52
  87. sig_match_zicokick_gt52
  88. sig_match_zicokick_copy
  89. sig_match_zicokick_values
  90. sig_match_init_ex_drivers
  91. sig_match_omar_init
  92. sig_match_init_error_handlers
  93. sig_match_default_assert_handler
  94. sig_match_default_exception_handler
  95. sig_match_default_panic_handler
  96. sig_match_get_task_properties
  97. sig_match_enable_hdmi_power
  98. sig_match_disable_hdmi_power
  99. sig_match_levent_table
  100. sig_match_flash_param_table
  101. sig_match_jpeg_count_str
  102. sig_match_misc_flag_named
  103. sig_match_dry_memset
  104. sig_match_dry_memzero
  105. sig_match_dry_memzero
  106. sig_match_dry_memcpy_bytes
  107. sig_match_cam_has_iris_diaphragm
  108. sig_match_cam_uncached_bit
  109. sig_match_umalloc_strictly
  110. sig_match_dcache_clean_flush_and_disable
  111. sig_match_get_rom_id
  112. sig_match_dcache_flush_and_enable
  113. sig_match_physw_event_table
  114. sig_match_uiprop_count
  115. sig_match_get_canon_mode_list
  116. sig_match_zoom_busy
  117. sig_match_focus_busy
  118. sig_match_aram_size
  119. sig_match_aram_size_gt58
  120. sig_match_aram_start
  121. sig_match_aram_start2
  122. sig_match_icache_flush_range
  123. sig_match__nrflag
  124. sig_match_var_struct_get
  125. sig_match_ui_mem_func_ptr
  126. sig_match_func_ptr_val
  127. sig_match_av_over_sem
  128. sig_match_canon_menu_active
  129. sig_match_file_counter_init
  130. sig_match_file_counter_var
  131. sig_match_palette_vars
  132. sig_match_live_free_cluster_count
  133. sig_match_debug_logging_ptr
  134. sig_match_debug_logging_flag
  135. sig_match_mzrm_sendmsg_ret_adr
  136. sig_match_fw_yuv_layer_buf_52
  137. sig_match_fw_yuv_layer_buf_gt52
  138. sig_match_rom_ptr_get
  139. find_call_near_str
  140. sig_match_near_str
  141. find_str_arg_call
  142. sig_match_str_arg_call
  143. sig_match_prop_string
  144. is_immediate_ret_sub
  145. sig_match_named_last
  146. sig_match_named_save_sig
  147. sig_match_named
  148. sig_rule_applies
  149. run_sig_rules
  150. add_event_proc
  151. process_reg_eventproc_call
  152. process_eventproc_table_call
  153. process_createtask_call
  154. save_ptp_handler_func
  155. process_add_ptp_handler_call
  156. add_generic_func_match
  157. add_generic_sig_match
  158. find_exception_handlers
  159. find_generic_funcs
  160. find_ctypes
  161. print_misc_val_makefile
  162. output_firmware_vals
  163. print_platform_misc_val_undef
  164. output_platform_vals
  165. output_propcases
  166. output_exmem_types
  167. print_misc_val_comment
  168. get_physw_table_entry
  169. find_physw_table_entry
  170. find_physw_table_max
  171. write_physw_event_table_dump
  172. print_kval
  173. add_kinfo
  174. add_kmval
  175. kinfo_compare
  176. print_kmvals
  177. do_km_vals
  178. output_physw_vals
  179. output_modemap
  180. compare_sig_names
  181. compare_func_addresses
  182. write_funcs
  183. write_func_lists
  184. print_other_stubs_min
  185. print_stubs_min_def
  186. find_other_stubs_min
  187. print_results
  188. write_stubs
  189. main

   1 #include <stdlib.h>
   2 #include <stdio.h>
   3 #include <stdint.h>
   4 #include <string.h>
   5 #include <time.h>
   6 #include <stdarg.h>
   7 
   8 #include <inttypes.h>
   9 
  10 #include <capstone.h>
  11 
  12 
  13 #include "stubs_load.h"
  14 #include "firmware_load_ng.h"
  15 #include "ptp_op_names.h"
  16 
  17 // arbitrary standardized constant for search "near" a string ref etc
  18 // could base on ADR etc reach
  19 #define SEARCH_NEAR_REF_RANGE 1024
  20 
  21 #define SIG_NEAR_OFFSET_MASK    0x00FF
  22 #define SIG_NEAR_COUNT_MASK     0xFF00
  23 #define SIG_NEAR_COUNT_SHIFT    8
  24 #define SIG_NEAR_REV            0x10000
  25 #define SIG_NEAR_INDIRECT       0x20000
  26 #define SIG_NEAR_JMP_SUB        0x40000
  27 #define SIG_NEAR_AFTER(max_insns,n) (((max_insns)&SIG_NEAR_OFFSET_MASK) \
  28                                 | (((n)<<SIG_NEAR_COUNT_SHIFT)&SIG_NEAR_COUNT_MASK))
  29 #define SIG_NEAR_BEFORE(max_insns,n) (SIG_NEAR_AFTER(max_insns,n)|SIG_NEAR_REV)
  30 
  31 #define SIG_STRCALL_ARG_MASK    0x3
  32 #define SIG_STRCALL_ARG(arg_num) (arg_num)
  33 #define SIG_STRCALL_TYPE_MASK  0xc
  34 #define SIG_STRCALL_TYPE_SHIFT 2
  35 #define SIG_STRCALL_CALL_IMM   0
  36 #define SIG_STRCALL_JMP_REG    4
  37 #define SIG_STRCALL_CALL_REG   8
  38 
  39 /* copied from finsig_dryos.c */
  40 char    out_buf[32*1024] = "";
  41 int     out_len = 0;
  42 char    hdr_buf[32*1024] = "";
  43 int     hdr_len = 0;
  44 int     out_hdr = 1;
  45 
  46 FILE *out_fp;
  47 
  48 void bprintf(char *fmt, ...)
  49 {
  50     va_list argp;
  51     va_start(argp, fmt);
  52 
  53     if (out_hdr)
  54         hdr_len += vsprintf(hdr_buf+hdr_len,fmt,argp);
  55     else
  56         out_len += vsprintf(out_buf+out_len,fmt,argp);
  57 
  58     va_end(argp);
  59 }
  60 
  61 void add_blankline()
  62 {
  63     if (strcmp(hdr_buf+hdr_len-2,"\n\n") != 0)
  64     {
  65         hdr_buf[hdr_len++] = '\n';
  66         hdr_buf[hdr_len] = 0;
  67     }
  68 }
  69 
  70 void write_output()
  71 {
  72     add_blankline();
  73     if (out_fp)
  74     {
  75         fprintf(out_fp,"%s",hdr_buf);
  76         fprintf(out_fp,"%s",out_buf);
  77     }
  78 }
  79 
  80 // Master list of functions / addresses to find
  81 
  82 #define DONT_EXPORT    0x01
  83 #define OPTIONAL       0x02
  84 #define UNUSED         0x04
  85 #define BAD_MATCH      0x08
  86 #define EV_MATCH       0x10
  87 #define LIST_ALWAYS    0x20
  88 // force an arm veneer (NHSTUB2)
  89 #define ARM_STUB       0x80
  90 #define DONT_EXPORT_ILC 0x100
  91 
  92 typedef struct {
  93     char        *name;
  94     int         flags;
  95     uint32_t    val;
  96 } sig_entry_t;
  97 
  98 int next_sig_entry = 0;
  99 
 100 #define MAX_SIG_ENTRY  5000
 101 
 102 sig_entry_t  sig_names[MAX_SIG_ENTRY] =
 103 {
 104     // Order here currently has no effect on search order, but mostly copied from finsig_dryos which did
 105     { "ExportToEventProcedure_FW", UNUSED|DONT_EXPORT },
 106     { "RegisterEventProcedure", UNUSED|DONT_EXPORT },
 107     { "RegisterEventProcedure_alt1", UNUSED|DONT_EXPORT },
 108     { "RegisterEventProcedure_alt2", UNUSED|DONT_EXPORT },
 109     { "RegisterEventProcTable", UNUSED|DONT_EXPORT },
 110     { "UnRegisterEventProcTable", UNUSED|DONT_EXPORT },
 111     { "UnRegisterEventProcedure", UNUSED|DONT_EXPORT },
 112     { "PrepareDirectory_1", UNUSED|DONT_EXPORT },
 113     { "PrepareDirectory_x", UNUSED|DONT_EXPORT },
 114     { "PrepareDirectory_0", UNUSED|DONT_EXPORT },
 115     { "CreateTaskStrictly", UNUSED|DONT_EXPORT },
 116     { "CreateTaskStrictly_alt", UNUSED|DONT_EXPORT },
 117     { "CreateTask_alt", UNUSED|DONT_EXPORT },
 118     { "CreateTask_low", UNUSED | OPTIONAL },
 119     { "CreateJumptable", UNUSED },
 120     { "_uartr_req", UNUSED },
 121     { "StartRecModeMenu", UNUSED },
 122     { "LogCameraEvent", UNUSED|DONT_EXPORT },
 123     { "getImageDirName", UNUSED|DONT_EXPORT },
 124 
 125     { "AllocateMemory", UNUSED|LIST_ALWAYS },
 126     { "AllocateUncacheableMemory" },
 127     { "Close" },
 128     { "CreateBinarySemaphore" },
 129     { "CreateCountingSemaphore", UNUSED|LIST_ALWAYS },
 130     { "CreateTask" },
 131     { "DebugAssert", OPTIONAL|LIST_ALWAYS },
 132     { "DeleteDirectory_Fut" },
 133     { "DeleteFile_Fut" },
 134     { "DeleteSemaphore", },
 135     { "DoAELock" },
 136     { "DoAFLock" },
 137     { "EnterToCompensationEVF" },
 138     { "ExecuteEventProcedure", ARM_STUB },
 139     { "ExitFromCompensationEVF" },
 140     { "ExitTask" },
 141     { "ExpCtrlTool_StartContiAE" },
 142     { "ExpCtrlTool_StopContiAE" },
 143     { "Fclose_Fut" },
 144     { "Feof_Fut" },
 145     { "Fflush_Fut" },
 146     { "Fgets_Fut" },
 147     { "Fopen_Fut" },
 148     { "Fread_Fut" },
 149     { "FreeMemory", UNUSED|LIST_ALWAYS },
 150     { "FreeUncacheableMemory" },
 151     { "Fseek_Fut" },
 152     { "Fwrite_Fut" },
 153     { "GetBatteryTemperature" },
 154     { "GetCCDTemperature" },
 155 
 156     { "GetCurrentAvValue" },
 157     { "GetCurrentShutterSpeed" },
 158     { "GetUsableMaxAv", OPTIONAL },
 159     { "GetUsableMinAv", OPTIONAL },
 160     { "GetUsableAvRange", UNUSED |OPTIONAL },
 161     { "get_nd_value", OPTIONAL },
 162     { "get_current_exp", UNUSED | OPTIONAL }, // helper, underlying function of ShowCurrentExp
 163     { "get_current_nd_value", OPTIONAL },
 164     { "get_current_deltasv", },
 165     { "GetCurrentDriveBaseSvValue", },
 166     { "GetDrive_ClusterSize" },
 167     { "GetDrive_FreeClusters", UNUSED }, // live_free_cluster_count variable is used instead
 168     { "GetDrive_TotalClusters" },
 169     { "GetFocusLensSubjectDistance" },
 170     { "GetFocusLensSubjectDistanceFromLens" },
 171     { "GetImageFolder", OPTIONAL },
 172     { "GetKbdState" },
 173     { "GetMemInfo" },
 174     { "GetOpticalTemperature" },
 175     { "GetParameterData" },
 176     { "GetPropertyCase" },
 177     { "GetSystemTime" },
 178     { "GetVRAMHPixelsSize" },
 179     { "GetVRAMVPixelsSize" },
 180     { "GetZoomLensCurrentPoint" },
 181     { "GetZoomLensCurrentPosition" },
 182     { "GiveSemaphore", OPTIONAL|LIST_ALWAYS },
 183     { "IsStrobeChargeCompleted" },
 184     { "LEDDrive", OPTIONAL },
 185     { "LocalTime" },
 186     { "LockMainPower" },
 187     { "Lseek", UNUSED|LIST_ALWAYS },
 188     { "MakeDirectory_Fut" },
 189     { "MakeSDCardBootable", OPTIONAL },
 190     { "MoveFocusLensToDistance" },
 191     { "MoveIrisWithAv", OPTIONAL },
 192     { "MoveZoomLensWithPoint", DONT_EXPORT_ILC},
 193     { "NewTaskShell", UNUSED },
 194     { "Open" },
 195     { "PB2Rec" },
 196     { "PT_MoveDigitalZoomToWide", OPTIONAL | DONT_EXPORT_ILC},
 197     { "PT_MoveOpticalZoomAt", OPTIONAL | DONT_EXPORT_ILC },
 198     { "MoveOpticalZoomAt", OPTIONAL | DONT_EXPORT_ILC },
 199     { "PT_PlaySound" },
 200     { "PostLogicalEventForNotPowerType" },
 201     { "PostLogicalEventToUI" },
 202     { "PutInNdFilter", OPTIONAL },
 203     { "PutOutNdFilter", OPTIONAL },
 204     { "Read" },
 205     { "ReadFastDir" },
 206     { "Rec2PB" },
 207     { "Remove", OPTIONAL|UNUSED },
 208     { "RenameFile_Fut" },
 209     { "Restart" },
 210     { "screenlock_helper", UNUSED|DONT_EXPORT },
 211     { "ScreenLock" },
 212     { "ScreenUnlock" },
 213     { "SetAE_ShutterSpeed" },
 214     { "SetAutoShutdownTime" },
 215     { "SetCurrentCaptureModeType" },
 216     { "SetDate" },
 217     { "SetFileAttributes" },
 218     { "SetFileTimeStamp" },
 219     { "SetLogicalEventActive" },
 220     { "SetParameterData" },
 221     { "SetPropertyCase" },
 222     { "SetScriptMode" },
 223     { "SleepTask" },
 224     { "TakeSemaphore" },
 225     { "TurnOffBackLight" },
 226     { "TurnOnBackLight" },
 227     { "TurnOnDisplay" },
 228     { "TurnOffDisplay" },
 229     { "UIFS_WriteFirmInfoToFile", OPTIONAL|UNUSED},
 230     { "UnlockAE" },
 231     { "UnlockAF" },
 232     { "UnlockMainPower" },
 233     { "UnsetZoomForMovie", OPTIONAL | DONT_EXPORT_ILC },
 234 //    { "UpdateMBROnFlash" },
 235     { "VbattGet" },
 236     { "Write" },
 237     { "WriteSDCard" },
 238 
 239     { "_log" },
 240     { "_log10" },
 241     { "_pow" },
 242     { "_sqrt" },
 243     { "add_ptp_handler" },
 244     { "apex2us" },
 245     { "close" },
 246     { "displaybusyonscreen", OPTIONAL },
 247     { "err_init_task", OPTIONAL },
 248     { "exmem_alloc", OPTIONAL },
 249     { "exmem_free", OPTIONAL|UNUSED },
 250     { "exmem_ualloc" },
 251     { "exmem_ufree" },
 252     { "free" },
 253 
 254     { "kbd_p1_f" },
 255     { "kbd_p1_f_cont" },
 256     { "kbd_p2_f" },
 257     { "kbd_read_keys" },
 258     { "kbd_read_keys_r2" },
 259 
 260     { "kbd_pwr_off", OPTIONAL },
 261     { "kbd_pwr_on", OPTIONAL },
 262     { "lseek" },
 263     { "malloc" },
 264     { "memcmp" },
 265     { "memcpy" },
 266     { "memset" },
 267 // identical to MakeDirectory_Fut for recent cams
 268 //    { "mkdir" },
 269     { "mktime_ext" },
 270     { "open" },
 271     { "OpenFastDir" },
 272     { "closedir" },
 273     { "get_fstype", OPTIONAL|LIST_ALWAYS },
 274     { "qsort" },
 275     { "rand" },
 276     { "read", UNUSED|OPTIONAL },
 277     { "realloc", OPTIONAL|LIST_ALWAYS },
 278     { "reboot_fw_update" },
 279     { "set_control_event" },
 280     { "srand" },
 281     { "stat" },
 282     { "strcat" },
 283     { "strchr" },
 284     { "strcmp" },
 285     { "strcpy" },
 286     { "strftime" },
 287     { "strlen" },
 288     { "strncmp" },
 289     { "strncpy" },
 290     { "strrchr" },
 291     { "strtol" },
 292     { "strtolx" },
 293     { "strstr", UNUSED|OPTIONAL},
 294 
 295     { "task_CaptSeq" },
 296     { "task_DvlpSeqTask", OPTIONAL },
 297     { "task_ExpDrv" },
 298     { "task_FileWrite", OPTIONAL },
 299     { "task_InitFileModules" },
 300     { "task_MovieRecord" },
 301     { "task_PhySw", OPTIONAL },
 302     { "task_RotaryEncoder", OPTIONAL },
 303     { "task_TouchPanel", OPTIONAL },
 304     { "task_TricInitTask", OPTIONAL },
 305 
 306     { "hook_CreateTask" },
 307     { "hook_CreateTask_low", UNUSED}, // unused changed at runtime if CreateTask in ROM
 308 
 309     { "time" },
 310     { "vsprintf" },
 311     { "write", UNUSED|OPTIONAL },
 312     { "undisplaybusyonscreen", OPTIONAL },
 313 
 314     { "EngDrvIn", OPTIONAL|UNUSED|LIST_ALWAYS },
 315     { "EngDrvOut", OPTIONAL|UNUSED|LIST_ALWAYS },
 316     { "EngDrvRead" },
 317     { "EngDrvBits", OPTIONAL|UNUSED|LIST_ALWAYS },
 318 
 319     { "PTM_GetCurrentItem" },
 320     { "PTM_SetCurrentItem", UNUSED|LIST_ALWAYS },
 321     { "PTM_NextItem", OPTIONAL|UNUSED|LIST_ALWAYS },
 322     { "PTM_PrevItem", OPTIONAL|UNUSED|LIST_ALWAYS },
 323     { "PTM_SetPropertyEnable", OPTIONAL|UNUSED|LIST_ALWAYS },
 324 
 325     { "DisableISDriveError", OPTIONAL },
 326 
 327     // OS functions, mostly to aid firmware analysis. Order is important!
 328     { "_GetSystemTime", OPTIONAL|UNUSED|LIST_ALWAYS }, // only for locating timer functions
 329     { "SetTimerAfter", OPTIONAL|UNUSED|LIST_ALWAYS },
 330     { "SetTimerWhen", OPTIONAL|UNUSED|LIST_ALWAYS },
 331     { "CancelTimer", OPTIONAL|UNUSED|LIST_ALWAYS },
 332     { "CancelHPTimer" },
 333     { "SetHPTimerAfterTimeout", OPTIONAL|UNUSED|LIST_ALWAYS },
 334     { "SetHPTimerAfterNow" },
 335     { "CreateTaskStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 336     { "CreateMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 337     { "CreateRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 338     { "GetSemaphoreValue", OPTIONAL|UNUSED|LIST_ALWAYS },
 339     { "TryTakeSemaphore", OPTIONAL|UNUSED|LIST_ALWAYS },
 340     { "CreateMessageQueueStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 341     { "CreateEventFlagStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 342     { "CreateBinarySemaphoreStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 343     { "CreateCountingSemaphoreStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 344     { "CreateRecursiveLockStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 345     { "TakeSemaphoreStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 346     { "ReceiveMessageQueueStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 347     { "PostMessageQueueStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },    // r23+
 348     { "WaitForAnyEventFlagStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 349     { "WaitForAllEventFlagStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 350     { "AcquireRecursiveLockStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 351     { "DeleteMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 352     { "PostMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 353     { "ReceiveMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 354     { "TryReceiveMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 355     { "TryPostMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 356     { "GetNumberOfPostedMessages", OPTIONAL|UNUSED|LIST_ALWAYS },
 357     { "DeleteRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 358     { "AcquireRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 359     { "ReleaseRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 360     { "WaitForAnyEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 361     { "WaitForAllEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 362     { "ClearEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 363     { "SetEventFlag", OPTIONAL|LIST_ALWAYS },
 364     { "GetEventFlagValue", OPTIONAL|UNUSED|LIST_ALWAYS },
 365     { "CreateEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 366     { "DeleteEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 367     { "CheckAnyEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 368     { "CheckAllEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 369     { "RegisterInterruptHandler", OPTIONAL|UNUSED|LIST_ALWAYS },
 370     { "UnregisterInterruptHandler", OPTIONAL|UNUSED|LIST_ALWAYS },
 371     { "GetSRAndDisableInterrupt", OPTIONAL|UNUSED|LIST_ALWAYS }, // disables IRQ, returns a value
 372     { "SetSR", OPTIONAL|UNUSED|LIST_ALWAYS }, // enables IRQ, puts back value returned by GetSR
 373     { "EnableInterrupt", OPTIONAL|UNUSED|LIST_ALWAYS }, // enables IRQ
 374     { "_divmod_signed_int", OPTIONAL|UNUSED|LIST_ALWAYS}, // division for signed integers, remainder is returned in r1
 375     { "_divmod_unsigned_int", OPTIONAL|UNUSED|LIST_ALWAYS}, // division for unsigned integers, remainder is returned in r1
 376     { "_dflt", OPTIONAL|UNUSED|LIST_ALWAYS}, // int -> double
 377     { "_dfltu", OPTIONAL|UNUSED|LIST_ALWAYS}, // uint -> double
 378     { "_dfix", OPTIONAL|UNUSED|LIST_ALWAYS}, // double -> int
 379     { "_dfixu", OPTIONAL|UNUSED|LIST_ALWAYS}, // double -> uint
 380     { "_dmul", OPTIONAL|UNUSED|LIST_ALWAYS}, // double precision float multiplication
 381     { "_ddiv", OPTIONAL|UNUSED|LIST_ALWAYS}, // double precision float division
 382     { "_dadd", OPTIONAL|UNUSED|LIST_ALWAYS}, // addition for doubles
 383     { "_dsub", OPTIONAL|UNUSED|LIST_ALWAYS}, // subtraction for doubles
 384     { "_drsb", OPTIONAL|UNUSED|LIST_ALWAYS}, // reverse subtraction for doubles (?)
 385     { "_dcmp", OPTIONAL|UNUSED|LIST_ALWAYS}, // comparison of 2 doubles, only updates condition flags
 386     { "_dcmp_reverse", OPTIONAL|UNUSED|LIST_ALWAYS}, // like _dcmp, but operands in reverse order, only updates condition flags
 387     { "_safe_sqrt", OPTIONAL|UNUSED|LIST_ALWAYS}, // only calls _sqrt for numbers >= 0
 388     { "_scalbn", OPTIONAL|UNUSED|LIST_ALWAYS}, // double scalbn (double x, long exp), returns x * FLT_RADIX ** exp
 389     { "_fflt", OPTIONAL|UNUSED|LIST_ALWAYS}, // int -> float
 390     { "_ffltu", OPTIONAL|UNUSED|LIST_ALWAYS}, // uint -> float
 391     { "_ffix", OPTIONAL|UNUSED|LIST_ALWAYS}, // float -> int
 392     { "_ffixu", OPTIONAL|UNUSED|LIST_ALWAYS}, // float -> uint
 393     { "_fmul", OPTIONAL|UNUSED|LIST_ALWAYS}, // single precision float multiplication
 394     { "_fdiv", OPTIONAL|UNUSED|LIST_ALWAYS}, // single precision float division
 395     { "_f2d", OPTIONAL|UNUSED|LIST_ALWAYS}, // float -> double
 396     { "DisplayBusyOnScreen", OPTIONAL|UNUSED|LIST_ALWAYS}, // displays full screen "busy" message
 397     { "UndisplayBusyOnScreen", OPTIONAL|UNUSED|LIST_ALWAYS},
 398     { "CreateDialogBox", OPTIONAL|UNUSED|LIST_ALWAYS},
 399     { "DisplayDialogBox", OPTIONAL|UNUSED|LIST_ALWAYS},
 400     { "add_ui_to_dialog", OPTIONAL|UNUSED|LIST_ALWAYS}, // name made up, assigns resources to a dialog
 401     { "get_string_by_id", OPTIONAL|UNUSED|LIST_ALWAYS}, // name made up, retrieves a localised or unlocalised string by its ID
 402     { "malloc_strictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // name made up
 403     { "GetCurrentMachineTime", OPTIONAL|UNUSED|LIST_ALWAYS }, // reads usec counter, name from ixus30
 404     { "HwOcReadICAPCounter", OPTIONAL|UNUSED|LIST_ALWAYS }, // reads usec counter, name from ixus30
 405     { "transfer_src_overlay_helper",UNUSED}, // helper for other related functions
 406     { "transfer_src_overlay" },
 407     { "GraphicSystemCoreFinish_helper", OPTIONAL|UNUSED }, // function that calls GraphicSystemCoreFinish
 408     { "GraphicSystemCoreFinish", OPTIONAL|UNUSED }, // used to identify mzrm message functions
 409     { "mzrm_createmsg", OPTIONAL|UNUSED },
 410     { "mzrm_sendmsg", OPTIONAL|UNUSED },
 411     { "zicokick_start", OPTIONAL|UNUSED }, // used to identify Zico core Xtensa blobs
 412     { "zicokick_copy", OPTIONAL|UNUSED }, // used to identify Zico core Xtensa blobs
 413     { "init_ex_drivers", OPTIONAL|UNUSED }, // used to identify Omar core ARM blobs
 414     { "omar_init", OPTIONAL|UNUSED }, // used to identify Omar core ARM blobs
 415     { "init_error_handlers", OPTIONAL|UNUSED }, // used to identify assert, exception and panic handlers
 416     { "set_assert_handler", OPTIONAL|UNUSED },
 417     { "set_exception_handler", OPTIONAL|UNUSED },
 418     { "set_panic_handler", OPTIONAL|UNUSED },
 419     { "default_assert_handler", OPTIONAL|UNUSED },
 420     { "default_exception_handler", OPTIONAL|UNUSED },
 421     { "default_panic_handler", OPTIONAL|UNUSED },
 422     { "get_self_task_errno_pointer", OPTIONAL|UNUSED },
 423     { "get_self_task_id", OPTIONAL|UNUSED },
 424     { "get_task_properties", OPTIONAL|UNUSED },
 425     { "dry_error_printf", OPTIONAL|UNUSED },
 426     { "heap_alloc", OPTIONAL|UNUSED },
 427     { "heap_free", OPTIONAL|UNUSED },
 428     { "umalloc_strictly", OPTIONAL|UNUSED },
 429     { "GetRomID", OPTIONAL|UNUSED },
 430     { "init_task_error", OPTIONAL|UNUSED },
 431     { "dry_panic", OPTIONAL|UNUSED },
 432     { "dry_panic_low", OPTIONAL|UNUSED },
 433     { "dry_con_printf", OPTIONAL|UNUSED },
 434     { "cameracon_set_state", UNUSED },
 435     { "cameracon_get_state", UNUSED },
 436 
 437     { "createsemaphore_low", OPTIONAL|UNUSED },
 438 //    { "deletesemaphore_low", UNUSED },
 439     { "givesemaphore_low", OPTIONAL|UNUSED}, // OPT_CONSOLE_REDIR_ENABLED
 440     { "takesemaphore_low", OPTIONAL|UNUSED },
 441     { "bzero" }, //
 442     { "memset32" }, // actually jump to 2nd instruction of bzero
 443     { "dry_memset", OPTIONAL|UNUSED },
 444     { "dry_memzero", OPTIONAL|UNUSED },
 445     { "dry_memcpy_bytes", OPTIONAL|UNUSED },
 446     { "dry_memmove_bytes", OPTIONAL|UNUSED },
 447     { "get_dial_hw_position", OPTIONAL },
 448 
 449 //    { "icache_flush_and_enable", OPTIONAL|UNUSED },
 450 //    { "icache_disable_and_flush", OPTIONAL|UNUSED },
 451     { "dcache_flush_and_enable", OPTIONAL|UNUSED },
 452     { "dcache_clean_flush_and_disable", OPTIONAL|UNUSED },
 453     { "dcache_flush_range", OPTIONAL|UNUSED },
 454     { "dcache_clean_range", OPTIONAL|UNUSED },
 455 //    { "dcache_clean_flush_range", OPTIONAL|UNUSED },
 456     { "icache_flush_range", OPTIONAL|UNUSED },
 457     { "data_synchronization_barrier", OPTIONAL|UNUSED },
 458 
 459     // Other stuff needed for finding misc variables - don't export to stubs_entry.S
 460     { "GetSDProtect", UNUSED },
 461     { "DispCon_ShowBitmapColorBar", UNUSED },
 462     { "ResetZoomLens", OPTIONAL|UNUSED },
 463     { "ResetFocusLens", OPTIONAL|UNUSED },
 464     { "NR_GetDarkSubType", OPTIONAL|UNUSED },
 465     { "NR_SetDarkSubType", OPTIONAL|UNUSED },
 466     { "SavePaletteData", OPTIONAL|UNUSED },
 467     { "GUISrv_StartGUISystem", OPTIONAL|UNUSED|LIST_ALWAYS },
 468     { "get_resource_pointer", OPTIONAL|UNUSED|LIST_ALWAYS }, // name made up, gets a pointer to a certain resource (font, dialog, icon)
 469     { "CalcLog10", OPTIONAL|UNUSED|LIST_ALWAYS }, // helper
 470     { "CalcSqrt", OPTIONAL|UNUSED }, // helper
 471     { "dry_memcpy", OPTIONAL|UNUSED }, // helper, memcpy-like function in dryos kernel code
 472     { "get_playrec_mode", OPTIONAL|UNUSED }, // helper, made up name
 473     { "DebugAssert2", OPTIONAL|UNUSED }, // helper, made up name, two arg form of DebugAssert
 474     { "get_canon_mode_list", OPTIONAL|UNUSED }, // helper, made up name
 475     { "taskcreate_LowConsole", OPTIONAL|UNUSED }, // helper, made up name
 476     { "ImagerActivate", OPTIONAL|UNUSED }, // helper
 477     { "imager_active_callback", OPTIONAL|UNUSED }, // helper
 478     { "file_counter_var_init", OPTIONAL|UNUSED }, // helper
 479     { "get_displaytype", OPTIONAL|UNUSED }, // for camera bitmap res change
 480     // dry >= 58 wrap "Open" and "Close" in additional functions
 481     { "Close_low", OPTIONAL|UNUSED },
 482     { "Open_low", OPTIONAL|UNUSED },
 483 
 484     // underlying functions of F*_Fut functions, for analysis
 485     { "fclose_low", OPTIONAL|UNUSED },
 486 //    { "feof_low", OPTIONAL|UNUSED },
 487 //    { "fflush_low", OPTIONAL|UNUSED },
 488     { "fgets_low", OPTIONAL|UNUSED },
 489     { "fopen_low", OPTIONAL|UNUSED },
 490     { "fut_prepare", OPTIONAL|UNUSED },
 491     { "fut_finish", OPTIONAL|UNUSED },
 492     { "fut_flush", OPTIONAL|UNUSED },
 493     { "fread_low", OPTIONAL|UNUSED },
 494     { "fseek_low", OPTIONAL|UNUSED },
 495     { "fwrite_low", OPTIONAL|UNUSED },
 496 
 497     { "MFOn", OPTIONAL },
 498     { "MFOff", OPTIONAL },
 499     { "PT_MFOn", OPTIONAL },
 500     { "PT_MFOff", OPTIONAL },
 501     { "SS_MFOn", OPTIONAL },
 502     { "SS_MFOff", OPTIONAL },
 503 
 504     { "GetAdChValue", OPTIONAL },
 505 
 506     // for HDMI remote support - optional, probably only present on cameras with HDMI
 507     { "EnableHDMIPower", OPTIONAL },
 508     { "DisableHDMIPower", OPTIONAL },
 509 
 510     { "SetVideoOutType", OPTIONAL },
 511     { "GetVideoOutType", OPTIONAL },
 512 
 513     { "is_movie_recording", OPTIONAL|UNUSED },
 514     { "IsWirelessConnect", OPTIONAL },
 515 
 516     { "ui_malloc", OPTIONAL|UNUSED },
 517     { "ui_malloc_default", OPTIONAL|UNUSED },
 518     { "ui_free", OPTIONAL|UNUSED },
 519     { "ui_free_default", OPTIONAL|UNUSED },
 520 
 521     // made up names, see https://chdk.setepontos.com/index.php?topic=11246.0
 522     { "pvm_get_largest_free_block_size_ptr", OPTIONAL|UNUSED }, // wrapper for following that puts return ptr arg
 523     { "pvm_get_largest_free_block_size", OPTIONAL|UNUSED },
 524     { "pvm_malloc", OPTIONAL|UNUSED },
 525     { "pvm_free", OPTIONAL|UNUSED },
 526     { "pvm_init_pool", OPTIONAL|UNUSED },
 527 
 528     { "fw_yuv_layer_buf_helper", UNUSED},
 529 
 530     {0,0,0},
 531 };
 532 
 533 typedef struct {
 534     char*   name;   // name
 535     int     id;     // propcase id, as found
 536     int     use;    // 0: informational only; 1: use for propset guess AND print as #define; 2: use for propset guess
 537 
 538     int     id_ps6; // id in propset 6
 539     int     id_ps7; // id in propset 7
 540     int     id_ps8; // id in propset 8
 541     int     id_ps9; // id in propset 9
 542     int     id_ps10;// id in propset 10
 543     int     id_ps11;// id in propset 11
 544     int     id_ps12;// id in propset 12
 545     int     id_ps13;// id in propset 13
 546 } known_prop_t;
 547 
 548 #define KNOWN_PROPSET_COUNT (13-5)
 549 
 550 known_prop_t knownprops[] =
 551 {   // name                          id  u ps6 ps7 ps8 ps9 ps10 ps11 ps12 ps13
 552     {"PROPCASE_AFSTEP"             , -1, 2, 13, 13, 13, 13,  13,  13,  13,  13},
 553     {"PROPCASE_FOCUS_STATE"        , -1, 1, 18, 18, 18, 18,  18,  18,  18,  18},
 554     {"PROPCASE_AV"                 , -1, 1, 23, 23, 23, 23,  23,  23,  23,  23},
 555     {"PROPCASE_BV"                 , -1, 1, 34, 38, 35, 38,  40,  40,  40,  40},
 556     {"PROPCASE_DELTA_DIGITALGAIN"  , -1, 2, 77, 82, 79, 82,  84,  85,  85,  84},
 557     {"PROPCASE_DELTA_SV"           , -1, 1, 79, 84, 81, 84,  86,  87,  87,  86},
 558     {"PROPCASE_DELTA_ND"           , -1, 2, 80, 85, 82, 85,  87,  88,  88,  87},
 559     {"PROPCASE_FELOCK"             , -1, 2,114,120,117,120, 122, 123, 123, 122},
 560     {"PROPCASE_FLASH_ADJUST_MODE"  , -1, 1,121,127,124,127, 129, 130, 130, 129},
 561     {"PROPCASE_FLASH_FIRE"         , -1, 1,122,128,125,128, 130, 131, 131, 130},
 562     {"PROPCASE_HSCAPTURE"          , -1, 2,138,144,141,144, 146, 147, 147, 146},
 563     {"PROPCASE_EV_CORRECTION_2"    , -1, 1,210,216,213,216, 218, 219, 220, 218},
 564     {"PROPCASE_ORIENTATION_SENSOR" , -1, 1,222,228,225,228, 230, 231, 232, 230},
 565     {"PROPCASE_SV_MARKET"          , -1, 1,249,255,252,255, 257, 259, 260, 258},
 566     {"PROPCASE_SVFIX"              , -1, 0,  0,  0,  0,  0,   0,   0,   0, 259},
 567     {"PROPCASE_TV"                 , -1, 1,265,272,269,272, 274, 276, 277, 275},
 568     {0,}
 569 };
 570 
 571 void add_prop_hit(char *name, int id)
 572 {
 573     int n = 0;
 574     while (knownprops[n].name) {
 575         if (strcmp(knownprops[n].name,name) == 0) {
 576             knownprops[n].id = id;
 577             break;
 578         }
 579         n++;
 580     }
 581 }
 582 
 583 #define MISC_BLOB_XTENSA_MAX    5
 584 #define MISC_BLOB_TYPE_NONE     0
 585 #define MISC_BLOB_TYPE_XTENSA   1
 586 #define MISC_BLOB_TYPE_OMAR     2
 587 typedef struct {
 588     int         type;
 589     uint32_t    rom_adr; // location of data in ROM, if copied
 590     uint32_t    ram_adr; // location of data in RAM
 591     uint32_t    size;
 592 } misc_blob_t;
 593 
 594 // for values that don't get a DEF etc
 595 #define MISC_VAL_NO_STUB    1
 596 // DEF_CONST instead of DEF
 597 #define MISC_VAL_DEF_CONST  2
 598 #define MISC_VAL_OPTIONAL   4
 599 // variables and constants
 600 typedef struct {
 601     char        *name;
 602     int         flags;
 603     uint32_t    val;
 604     // informational values
 605     uint32_t    base; // if stub is found as ptr + offset, record
 606     uint32_t    offset;
 607     uint32_t    ref_adr; // code address near where value found (TODO may want list)
 608     misc_blob_t *blobs; // malloc'd array of blobs if this is a blob type value, terminated with flags = 0
 609 } misc_val_t;
 610 
 611 misc_val_t misc_vals[]={
 612     // stubs_min variables / constants
 613     { "ctypes",             },
 614     { "physw_run",          },
 615     { "physw_sleep_delay",  },
 616     { "physw_status",       },
 617     { "fileio_semaphore",   },
 618     { "levent_table",       },
 619     { "FlashParamsTable",   },
 620     { "playrec_mode",       },
 621     { "jpeg_count_str",     },
 622     { "zoom_busy",          },
 623     { "focus_busy",         },
 624     { "imager_active",      },
 625     { "canon_menu_active",  },
 626     { "file_counter_var",   },
 627     { "cameracon_state",    },
 628     { "_nrflag",            MISC_VAL_OPTIONAL},
 629     { "av_override_semaphore",MISC_VAL_OPTIONAL},
 630     { "active_bitmap_buffer",MISC_VAL_OPTIONAL},
 631     { "displaytype",        MISC_VAL_OPTIONAL},
 632     { "bitmap_buffer",      MISC_VAL_OPTIONAL},
 633     { "palette_control",    MISC_VAL_OPTIONAL},
 634     { "palette_buffer_ptr", MISC_VAL_OPTIONAL},
 635     { "active_palette_buffer",MISC_VAL_OPTIONAL},
 636     { "live_free_cluster_count",MISC_VAL_OPTIONAL},
 637     { "CAM_UNCACHED_BIT",   MISC_VAL_NO_STUB},
 638     { "physw_event_table",  MISC_VAL_NO_STUB},
 639     { "uiprop_count",       MISC_VAL_DEF_CONST},
 640     { "canon_mode_list",    MISC_VAL_NO_STUB},
 641     { "ARAM_HEAP_START",    MISC_VAL_NO_STUB},
 642     { "ARAM_HEAP_SIZE",     MISC_VAL_NO_STUB},
 643     { "zicokick_values",    MISC_VAL_NO_STUB}, // used to identify Zico core Xtensa blobs (dummy for now)
 644     { "omar_init_data",     MISC_VAL_NO_STUB}, // structure containing pointers to Omar blogs
 645     { "omar_init_values",   MISC_VAL_NO_STUB}, // Omar blobs
 646     { "CAM_HAS_ND_FILTER",  MISC_VAL_NO_STUB},
 647     { "CAM_IS_ILC",         MISC_VAL_NO_STUB}, // used for finsig code that wants to check for interchangeable lens
 648     { "CAM_HAS_IRIS_DIAPHRAGM",MISC_VAL_NO_STUB},
 649     { "CAM_HAS_WIFI",       MISC_VAL_NO_STUB},
 650     { "exmem_alloc_table",  },
 651     { "exmem_types_table",  },
 652     { "exmem_type_count",   MISC_VAL_DEF_CONST},
 653     { "ui_malloc_ptr",      MISC_VAL_NO_STUB}, // currently only used to find functions
 654     { "ui_free_ptr",        MISC_VAL_NO_STUB},
 655     { "debug_logging_ptr", }, // debug log function for mzrm, tric calls
 656     { "debug_logging_flag", },
 657     { "mzrm_sendmsg_ret_adr", }, // return address for hooking log call
 658     { "fw_yuv_layer_buf",   MISC_VAL_DEF_CONST},
 659 
 660     {0,0,0},
 661 };
 662 
 663 misc_val_t *get_misc_val(const char *name)
 664 {
 665     misc_val_t *p=misc_vals;
 666     while(p->name) {
 667         if(strcmp(name,p->name) == 0) {
 668             return p;
 669         }
 670         p++;
 671     }
 672     return NULL;
 673 }
 674 
 675 // get value of misc val, if set. Name :<
 676 uint32_t get_misc_val_value(const char *name)
 677 {
 678     misc_val_t *p=get_misc_val(name);
 679     if(!p) {
 680         printf("get_misc_val_value: invalid name %s\n",name);
 681         return 0;
 682     }
 683     return p->val;
 684 }
 685 void save_misc_val(const char *name, uint32_t base, uint32_t offset, uint32_t ref_adr)
 686 {
 687     misc_val_t *p=get_misc_val(name);
 688     if(!p) {
 689         printf("save_misc_val: invalid name %s\n",name);
 690         return;
 691     }
 692     p->val = base + offset;
 693     p->base = base;
 694     p->offset = offset;
 695     p->ref_adr = ref_adr;
 696     p->blobs = NULL;
 697 }
 698 void save_misc_val_blobs(const char *name, misc_blob_t *blobs, uint32_t ref_adr)
 699 {
 700     misc_val_t *p=get_misc_val(name);
 701     if(!p) {
 702         printf("save_misc_val: invalid name %s\n",name);
 703         return;
 704     }
 705     p->val = p->base = p->offset = 0;
 706     p->ref_adr = ref_adr;
 707     p->blobs = blobs;
 708 }
 709 
 710 // Return the array index of a named function in the array above
 711 #if 0
 712 int find_saved_sig_index(const char *name)
 713 {
 714     int i;
 715     for (i=0; sig_names[i].name != 0; i++)
 716     {
 717         if (strcmp(name,sig_names[i].name) == 0)
 718         {
 719             return i;
 720         }
 721     }
 722     return -1;
 723 }
 724 #endif
 725 
 726 sig_entry_t * find_saved_sig(const char *name)
 727 {
 728     int i;
 729     for (i=0; sig_names[i].name != 0; i++)
 730     {
 731         if (strcmp(name,sig_names[i].name) == 0)
 732         {
 733             return &sig_names[i];
 734         }
 735     }
 736     return NULL;
 737 }
 738 
 739 // return value of saved sig, or 0 if not found / doesn't exist
 740 uint32_t get_saved_sig_val(const char *name)
 741 {
 742     sig_entry_t *sig=find_saved_sig(name);
 743     if(!sig) {
 744         // printf("get_saved_sig_val: missing %s\n",name);
 745         return 0;
 746     }
 747     return sig->val;
 748 }
 749 
 750 // unused for now
 751 // Return the array index of of function with given address
 752 #if 0
 753 int find_saved_sig_index_by_adr(uint32_t adr)
 754 {
 755     if(!adr) {
 756         return  -1;
 757     }
 758     int i;
 759     for (i=0; sig_names[i].name != 0; i++)
 760     {
 761         if (sig_names[i].val == adr)
 762         {
 763             return i;
 764         }
 765     }
 766     return -1;
 767 }
 768 #endif
 769 #if 0
 770 sig_entry_t* find_saved_sig_by_val(uint32_t val)
 771 {
 772     if(!val) {
 773         return NULL;
 774     }
 775     int i;
 776     for (i=0; sig_names[i].name != 0; i++)
 777     {
 778         if (sig_names[i].val == val)
 779         {
 780             return &sig_names[i];
 781         }
 782     }
 783     return NULL;
 784 }
 785 #endif
 786 
 787 // Save the address value found for a function in the above array
 788 void save_sig(firmware *fw, const char *name, uint32_t val)
 789 {
 790     sig_entry_t *sig = find_saved_sig(name);
 791     if (!sig)
 792     {
 793         printf("save_sig: refusing to save unknown name %s\n",name);
 794         return;
 795     }
 796     // if we end up needed these, can add a flag
 797     if(!adr_is_main_fw_code(fw,val)) {
 798         printf("save_sig: refusing to save %s with out of range address 0x%08x\n",name,val);
 799         return;
 800     }
 801     if(sig->val && sig->val != val) {
 802         printf("save_sig: duplicate name %s existing 0x%08x != new 0x%08x\n",name,sig->val,val);
 803     }
 804     sig->val = val;
 805 }
 806 
 807 void add_func_name(firmware *fw, char *n, uint32_t eadr, char *suffix)
 808 {
 809     int k;
 810 
 811     char *s = n;
 812     int mallocd = 0;
 813     if (suffix != 0)
 814     {
 815         s = malloc(strlen(n) + strlen(suffix) + 1);
 816         sprintf(s, "%s%s", n, suffix);
 817         mallocd = 1;
 818     }
 819 
 820     // if we end up needed these, can add a flag
 821     if(!adr_is_main_fw_code(fw,eadr)) {
 822         printf("save_sig: refusing to save %s with out of range address 0x%08x\n",s,eadr);
 823         if(mallocd) {
 824             free(s);
 825         }
 826         return;
 827     }
 828 
 829     for (k=0; sig_names[k].name != 0; k++)
 830     {
 831         if (strcmp(sig_names[k].name, s) == 0)
 832         {
 833             if (sig_names[k].val == 0)             // same name, no address
 834             {
 835                 sig_names[k].val = eadr;
 836                 sig_names[k].flags |= EV_MATCH;
 837                 if (mallocd)
 838                     free(s);
 839                 return;
 840             }
 841             else if (sig_names[k].val == eadr)     // same name, same address
 842             {
 843                 if (mallocd)
 844                     free(s);
 845                 return;
 846             }
 847             else // same name, different address
 848             {
 849                 printf("add_func_name: duplicate name %s existing 0x%08x != new 0x%08x\n",s, sig_names[k].val, eadr);
 850             }
 851         }
 852     }
 853 
 854     sig_names[next_sig_entry].name = s;
 855     sig_names[next_sig_entry].flags = OPTIONAL|UNUSED;
 856     sig_names[next_sig_entry].val = eadr;
 857     next_sig_entry++;
 858     sig_names[next_sig_entry].name = 0;
 859 }
 860 
 861 // save up to 10 veneers starting at adr, return final non-veneer address, or 0 on failure
 862 uint32_t save_sig_veneers(firmware *fw, const char *name, uint32_t adr)
 863 {
 864     // attempt to disassemble target
 865     if(!fw_disasm_iter_single(fw,adr)) {
 866         printf("save_sig_veneers: %s disassembly failed at 0x%08x\n",name,adr);
 867         return 0;
 868     }
 869     // handle functions that immediately jump
 870     // doesn't check for conditionals, but first insn shouldn't be conditional
 871     uint32_t b_adr;
 872     int v_cnt;
 873     for(v_cnt = 0, b_adr = get_direct_jump_target(fw,fw->is);
 874             v_cnt < 10 && b_adr;
 875             v_cnt++,b_adr = get_direct_jump_target(fw,fw->is)) {
 876         char *buf=malloc(strlen(name)+7);
 877         if(v_cnt) {
 878             sprintf(buf,"j%d_%s",v_cnt,name);
 879         } else { // first level is just j_ for backward compatiblity
 880             // TODO could check for existing veeners, allowing for different paths
 881             sprintf(buf,"j_%s",name);
 882         }
 883         add_func_name(fw,buf,adr,NULL); // this is the orignal named address
 884         adr=b_adr; // thumb bit already handled by get_direct...
 885         if(!fw_disasm_iter_single(fw,adr)) {
 886             printf("save_sig_veneers: %s disassembly failed at 0x%08x\n",name,adr);
 887             return 0;
 888         }
 889     }
 890     return adr;
 891 }
 892 
 893 // save sig, with veneers added as j_... , j1_... etc
 894 int save_sig_with_j(firmware *fw, char *name, uint32_t adr)
 895 {
 896     if(!adr) {
 897         printf("save_sig_with_j: %s null adr\n",name);
 898         return 0;
 899     }
 900     adr = save_sig_veneers(fw, name, adr);
 901     if(adr) {
 902         save_sig(fw,name,adr);
 903         return 1;
 904     }
 905     return 0;
 906 }
 907 
 908 #define FIND_SIG_CALL_NO_UNK_VENEER 1
 909 // find next call to func named "name" or j_name, up to max_offset form the current is address
 910 // TODO max_offset is in bytes, unlike insn search functions that use insn counts
 911 int find_next_sig_call_ex(firmware *fw, iter_state_t *is, uint32_t max_offset, const char *name, uint32_t flags)
 912 {
 913     uint32_t adr=get_saved_sig_val(name);
 914 
 915     if(!adr) {
 916         printf("find_next_sig_call: missing %s\n",name);
 917         return 0;
 918     }
 919 
 920     search_calls_multi_data_t match_fns[12];
 921 
 922     match_fns[0].adr=adr;
 923     match_fns[0].fn=search_calls_multi_end;
 924     char veneer[128];
 925     int i;
 926     for(i = 1; i<11; i++) {
 927         // match convention in save_sig_veneers
 928         if(i>1) {
 929             sprintf(veneer,"j%d_%s",i-1,name);
 930         } else {
 931             sprintf(veneer,"j_%s",name);
 932         }
 933         adr=get_saved_sig_val(veneer);
 934         if(!adr) {
 935             break;
 936         } else {
 937             match_fns[i].adr=adr;
 938             match_fns[i].fn=search_calls_multi_end;
 939         }
 940     }
 941     search_insn_fn search_fn;
 942     if(flags & FIND_SIG_CALL_NO_UNK_VENEER) {
 943         search_fn = search_disasm_calls_multi;
 944     } else {
 945         search_fn = search_disasm_calls_veneer_multi;
 946     }
 947     match_fns[i].adr=0;
 948     return fw_search_insn(fw,is,search_fn,0,match_fns,is->adr + max_offset);
 949 }
 950 // as above, but default flags (resolving unknown veneers)
 951 int find_next_sig_call(firmware *fw, iter_state_t *is, uint32_t max_offset, const char *name)
 952 {
 953     return find_next_sig_call_ex(fw,is,max_offset,name,0);
 954 }
 955 
 956 // is the insn pointed to by is a call to "name" or one of it's veneers?
 957 // note: inefficient, should not be used for large searches
 958 int is_sig_call(firmware *fw, iter_state_t *is, const char *name)
 959 {
 960     uint32_t adr=get_branch_call_insn_target(fw,is);
 961     // not a call at all
 962     // TODO could check if unknown veneer
 963     if(!adr) {
 964         return 0;
 965     }
 966     uint32_t sig_adr=get_saved_sig_val(name);
 967     osig* ostub2 = find_sig(fw->sv->stubs,name);
 968     if (ostub2 && ostub2->val)
 969         sig_adr = ostub2->val;
 970     if(!sig_adr) {
 971         printf("is_sig_call: missing %s\n",name);
 972         return 0;
 973     }
 974     if(adr == sig_adr) {
 975         return 1;
 976     }
 977     char veneer[128];
 978     sprintf(veneer,"j_%s",name);
 979     sig_adr=get_saved_sig_val(veneer);
 980     if(!sig_adr) {
 981         return 0;
 982     }
 983     return (adr == sig_adr);
 984 }
 985 
 986 // macros for dry_min, dry_max fields
 987 #define SIG_DRY_MIN(min_rel) (min_rel)*FW_DRYOS_VER_MUL,0
 988 #define SIG_DRY_MAX(max_rel) 0,(max_rel)*FW_DRYOS_VER_MUL+(FW_DRYOS_VER_MUL-1)
 989 #define SIG_DRY_RANGE(min_rel,max_rel) (min_rel)*FW_DRYOS_VER_MUL,\
 990                                        (max_rel)*FW_DRYOS_VER_MUL+(FW_DRYOS_VER_MUL-1)
 991 // patch level specifc
 992 #define SIG_DRY_MINP(min_rel,min_patch) (min_rel)*FW_DRYOS_VER_MUL + (min_patch),0
 993 #define SIG_DRY_MAXP(max_rel,max_patch) 0,(max_rel)*FW_DRYOS_VER_MUL + (max_patch)
 994 #define SIG_DRY_RANGEP(min_rel,min_patch,max_rel,max_patch) \
 995                                         (min_rel)*FW_DRYOS_VER_MUL + (min_patch), \
 996                                         (max_rel)*FW_DRYOS_VER_MUL + (max_patch)
 997 
 998 #define SIG_DRY_ANY 0,0
 999 
1000 // defines for flags field
1001 #define SIG_NO_D6 1
1002 #define SIG_NO_D7 2
1003 
1004 typedef struct sig_rule_s sig_rule_t;
1005 typedef int (*sig_match_fn)(firmware *fw, iter_state_t *is, sig_rule_t *rule);
1006 // signature matching structure
1007 struct sig_rule_s {
1008     sig_match_fn    match_fn;       // function to locate function
1009     char        *name;              // function name used in CHDK
1010     char        *ref_name;          // event / other name to match in the firmware
1011     int         param;              // function specific param/offset
1012     int         dryos_min;          // minimum fw->dryos_ver_full version (0 = any)
1013     int         dryos_max;          // max fw->dryos_ver_full version to apply this sig to (0 = any)
1014     unsigned    flags;              // non rule specific match flags
1015 };
1016 
1017 // initialize iter state using address from ref_name, print error and return 0 if not found
1018 int init_disasm_sig_ref(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1019 {
1020     if(!rule->ref_name) {
1021         printf("init_disasm_sig_ref: %s missing ref_name\n",rule->name);
1022         return 0;
1023     }
1024     uint32_t adr=get_saved_sig_val(rule->ref_name);
1025     if(!adr) {
1026         printf("init_disasm_sig_ref: %s missing %s\n",rule->name,rule->ref_name);
1027         return 0;
1028     }
1029     if(!disasm_iter_init(fw,is,adr)) {
1030         printf("init_disasm_sig_ref: %s bad address 0x%08x for %s\n",rule->name,adr,rule->ref_name);
1031         return 0;
1032     }
1033     return 1;
1034 }
1035 
1036 int sig_match_near_str(firmware *fw, iter_state_t *is, sig_rule_t *rule);
1037 uint32_t find_str_arg_call(firmware *fw, iter_state_t *is, sig_rule_t *rule);
1038 
1039 // match
1040 // r0=ref value
1041 //...
1042 // bl=<our func>
1043 int sig_match_str_r0_call(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1044 {
1045     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
1046     if(!str_adr) {
1047         printf("sig_match_str_r0_call: %s failed to find ref %s\n",rule->name,rule->ref_name);
1048         return  0;
1049     }
1050 
1051 //    printf("sig_match_str_r0_call: %s ref str %s 0x%08x\n",rule->name,rule->ref_name,str_adr);
1052 
1053     // TODO should handle multiple instances of string
1054     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
1055     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
1056         if(is->insn->detail->arm.operands[0].reg == ARM_REG_R0) {
1057             // printf("sig_match_str_r0_call: %s ref str %s ref 0x%"PRIx64"\n",rule->name,rule->ref_name,is->insn->address);
1058             // TODO should check if intervening insn nuke r0
1059             if(insn_match_find_next(fw,is,4,match_b_bl_blximm)) {
1060                 uint32_t adr=get_branch_call_insn_target(fw,is);
1061                 // printf("sig_match_str_r0_call: thumb %s call 0x%08x\n",rule->name,adr);
1062                 return save_sig_with_j(fw,rule->name,adr);
1063             }
1064         }
1065     }
1066     return 0;
1067 }
1068 
1069 // find RegisterEventProcedure
1070 int sig_match_reg_evp(firmware *fw, iter_state_t *is, __attribute__ ((unused))sig_rule_t *rule)
1071 {
1072     const insn_match_t reg_evp_match[]={
1073         {MATCH_INS(MOV,   2),  {MATCH_OP_REG(R2),  MATCH_OP_REG(R1)}},
1074         {MATCH_INS(LDR,   2),  {MATCH_OP_REG(R1),  MATCH_OP_MEM_ANY}},
1075         {MATCH_INS(B,     MATCH_OPCOUNT_IGNORE)},
1076         {ARM_INS_ENDING}
1077     };
1078 
1079     uint32_t e_to_evp=get_saved_sig_val("ExportToEventProcedure_FW");
1080     if(!e_to_evp) {
1081         printf("sig_match_reg_evp: failed to find ExportToEventProcedure, giving up\n");
1082         return 0;
1083     }
1084 
1085     //look for the underlying RegisterEventProcedure function (not currently used)
1086     uint32_t reg_evp=0;
1087     // start at identified Export..
1088     disasm_iter_init(fw,is,e_to_evp);
1089     if(insn_match_seq(fw,is,reg_evp_match)) {
1090         reg_evp=ADR_SET_THUMB(is->insn->detail->arm.operands[0].imm);
1091         //printf("RegisterEventProcedure found 0x%08x at %"PRIx64"\n",reg_evp,is->insn->address);
1092         save_sig(fw,"RegisterEventProcedure",reg_evp);
1093     }
1094     return (reg_evp != 0);
1095 }
1096 
1097 // find event proc table registration, and some other stuff
1098 // TODO this should be broken up to some generic parts
1099 int sig_match_reg_evp_table(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1100 {
1101     // ref to find RegisterEventProcTable
1102     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name); // note this string may appear more than once, assuming want first
1103     if(!str_adr) {
1104         printf("sig_match_reg_evp_table: failed to find %s\n",rule->ref_name);
1105         return 0;
1106     }
1107     //printf("sig_match_reg_evp_table: DispDev_EnableEventProc 0x%08x\n",str_adr);
1108     uint32_t reg_evp_alt1=0;
1109     uint32_t reg_evp_tbl=0;
1110     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
1111     uint32_t dd_enable_p=0;
1112     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
1113         if(is->insn->detail->arm.operands[0].reg != ARM_REG_R0) {
1114             continue;
1115         }
1116         if(!insn_match_find_next(fw,is,2,match_b_bl)) {
1117             continue;
1118         }
1119         reg_evp_alt1=ADR_SET_THUMB(is->insn->detail->arm.operands[0].imm);
1120         //printf("RegisterEventProcedure_alt1 found 0x%08x at %"PRIx64"\n",reg_evp_alt1,is->insn->address);
1121         save_sig(fw,"RegisterEventProcedure_alt1",reg_evp_alt1);
1122 
1123         uint32_t regs[4];
1124 
1125         // get r0 and r1, backtracking up to 4 instructions
1126         if((get_call_const_args(fw,is,4,regs)&3)==3) {
1127             // sanity check, arg0 was the original thing we were looking for
1128             if(regs[0]==str_adr) {
1129                 dd_enable_p=regs[1]; // constant value should already have correct ARM/THUMB bit
1130                 //printf("DispDev_EnableEventProc found 0x%08x at %"PRIx64"\n",dd_enable_p,is->insn->address);
1131                 add_func_name(fw,"DispDev_EnableEventProc",dd_enable_p,NULL);
1132                 break;
1133             }
1134         }
1135     }
1136     // found candidate function
1137     if(dd_enable_p) {
1138         disasm_iter_init(fw,is,dd_enable_p); // start at found func
1139         if(insn_match_find_next(fw,is,4,match_b_bl)) { // find the first bl
1140             // sanity check, make sure we get a const in r0
1141             uint32_t regs[4];
1142             if(get_call_const_args(fw,is,4,regs)&1) {
1143                 reg_evp_tbl=ADR_SET_THUMB(is->insn->detail->arm.operands[0].imm);
1144                 // printf("RegisterEventProcTable found 0x%08x at %"PRIx64"\n",reg_evp_tbl,is->insn->address);
1145                 save_sig(fw,"RegisterEventProcTable",reg_evp_tbl);
1146             }
1147         }
1148     }
1149     return (reg_evp_tbl != 0);
1150 }
1151 
1152 // find an alternate eventproc registration call
1153 int sig_match_reg_evp_alt2(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1154 {
1155     uint32_t reg_evp_alt2=0;
1156     // TODO could make this a param for different fw variants
1157     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
1158     if(!str_adr) {
1159         printf("sig_match_reg_evp_alt2: failed to find %s\n",rule->ref_name);
1160         return 0;
1161     }
1162     //printf("sig_match_reg_evp_alt2: EngApp.Delete 0x%08x\n",str_adr);
1163     uint32_t reg_evp_alt1=get_saved_sig_val("RegisterEventProcedure_alt1");
1164 
1165     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
1166     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
1167         if(is->insn->detail->arm.operands[0].reg != ARM_REG_R0) {
1168             continue;
1169         }
1170         if(!insn_match_find_next(fw,is,3,match_b_bl)) {
1171             continue;
1172         }
1173         uint32_t regs[4];
1174         // sanity check, constants in r0, r1 and r0 was the original thing we were looking for
1175         if((get_call_const_args(fw,is,4,regs)&3)==3) {
1176             if(regs[0]==str_adr) {
1177                 reg_evp_alt2=ADR_SET_THUMB(is->insn->detail->arm.operands[0].imm);
1178                 // TODO could keep looking
1179                 if(reg_evp_alt2 == reg_evp_alt1) {
1180                     printf("RegisterEventProcedure_alt2 == _alt1 at %"PRIx64"\n",is->insn->address);
1181                     reg_evp_alt2=0;
1182                 } else {
1183                     save_sig(fw,"RegisterEventProcedure_alt2",reg_evp_alt2);
1184                    // printf("RegisterEventProcedure_alt2 found 0x%08x at %"PRIx64"\n",reg_evp_alt2,is->insn->address);
1185                     // TODO could follow alt2 and make sure it matches expected mov r2,0, bl register..
1186                 }
1187                 break;
1188             }
1189         }
1190     }
1191     return (reg_evp_alt2 != 0);
1192 }
1193 
1194 // find UnRegisterEventProc (made up name) for reference, finding tables missed by reg_event_proc_table
1195 int sig_match_unreg_evp_table(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1196 {
1197     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
1198     if(!str_adr) {
1199         printf("sig_match_unreg_evp_table: failed to find %s\n",rule->ref_name);
1200         return 0;
1201     }
1202     // for checks
1203     uint32_t reg_evp_alt1=get_saved_sig_val("RegisterEventProcedure_alt1");
1204     uint32_t reg_evp_alt2=get_saved_sig_val("RegisterEventProcedure_alt2");
1205 
1206     uint32_t mecha_unreg=0;
1207     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
1208     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
1209         //printf("sig_match_unreg_evp_table: found ref 0x%"PRIx64"\n",is->insn->address);
1210         if(is->insn->detail->arm.operands[0].reg != ARM_REG_R0) {
1211             continue;
1212         }
1213         if(!insn_match_find_next(fw,is,3,match_b_bl)) {
1214             continue;
1215         }
1216         uint32_t reg_call=get_branch_call_insn_target(fw,is);
1217         // wasn't a registration call (could be unreg)
1218         // TODO could check veneers
1219         if(!reg_call || (reg_call != reg_evp_alt1 && reg_call != reg_evp_alt2)) {
1220             continue;
1221         }
1222         uint32_t regs[4];
1223         if((get_call_const_args(fw,is,4,regs)&3)==3) {
1224             // sanity check we got the right string
1225             if(regs[0]==str_adr) {
1226                 mecha_unreg=ADR_SET_THUMB(regs[1]);
1227                 break;
1228             }
1229         }
1230     }
1231     if(!mecha_unreg) {
1232         return 0;
1233     }
1234     // follow
1235     disasm_iter_init(fw,is,mecha_unreg);
1236     // find first func call
1237     if(!insn_match_find_next(fw,is,7,match_b_bl)) {
1238         return 0;
1239     }
1240     // now find next ldr pc. Could follow above func, but this way picks up veneer on many fw
1241     const insn_match_t match_ldr_r0[]={
1242         {MATCH_INS(LDR, 2),   {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(PC)}},
1243         {ARM_INS_ENDING}
1244     };
1245     if(!insn_match_find_next(fw,is,18,match_ldr_r0)) {
1246         return 0;
1247     }
1248     uint32_t tbl=LDR_PC2val(fw,is->insn);
1249     if(!tbl) {
1250         return 0;
1251     }
1252     if(!disasm_iter(fw,is)) {
1253         printf("sig_match_unreg_evp_table: disasm failed\n");
1254         return 0;
1255     }
1256     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1257 }
1258 // find some veneers of RegisterEventProcTable/UnRegisterEventProcTable
1259 // expects b <something else>, b <ref_name>
1260 // TODO should be a generic find veneer near?
1261 int sig_match_evp_table_veneer(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1262 {
1263     uint32_t ref_adr = get_saved_sig_val(rule->ref_name);
1264     int prevb = 0;
1265     uint32_t cadr;
1266     // following should probably be done using fw_search_insn
1267     // both veneers consist of a single b instruction, always preceded by another b instruction
1268     disasm_iter_init(fw,is,ref_adr); // start at our known function
1269     while (is->adr < (ref_adr+0x800)) {
1270         cadr = is->adr;
1271         if (!disasm_iter(fw,is)) {
1272             disasm_iter_set(fw,is,(is->adr+2) | fw->thumb_default);
1273         }
1274         else {
1275             if (is->insn->id == ARM_INS_B) {
1276                 uint32_t b_adr = get_branch_call_insn_target(fw,is);
1277                 if (prevb && (b_adr == ref_adr)) {
1278                     // this doesn't use _with_j since we want identify the veneer
1279                     add_func_name(fw,rule->name,cadr | is->thumb,NULL);
1280                     return 1;
1281                 }
1282                 prevb = 1;
1283             }
1284         }
1285     }
1286     return 0;
1287 }
1288 
1289 // like sig_match_str_r0_call, but check whether it's the same as existing func
1290 int sig_match_createtaskstrictly_alt(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1291 {
1292     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
1293     if(!str_adr) {
1294         printf("sig_match_createtaskstrictly_alt: %s failed to find ref %s\n",rule->name,rule->ref_name);
1295         return  0;
1296     }
1297 
1298     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
1299     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
1300         if(is->insn->detail->arm.operands[0].reg == ARM_REG_R0) {
1301             // printf("sig_match_str_r0_call: %s ref str %s ref 0x%"PRIx64"\n",rule->name,rule->ref_name,is->insn->address);
1302             // TODO should check if intervening insn nuke r0
1303             if(insn_match_find_next(fw,is,4,match_b_bl_blximm)) {
1304                 uint32_t adr=get_branch_call_insn_target(fw,is);
1305                 uint32_t adr2 = get_saved_sig_val("CreateTaskStrictly");
1306                 // only save IFF not identical to CreateTaskStrictly
1307                 if(adr == adr2) {
1308                     // printf("sig_match_createtaskstrictly_alt: adr == CreateTaskStrictly\n");
1309                     return 0;
1310                 }
1311                 adr2 = get_saved_sig_val("j_CreateTaskStrictly");
1312                 if(adr == adr2) {
1313                     // printf("sig_match_createtaskstrictly_alt: adr == j_CreateTaskStrictly\n");
1314                     return 0;
1315                 }
1316                 return save_sig_with_j(fw,rule->name,adr);
1317             }
1318         }
1319     }
1320     return 0;
1321 }
1322 
1323 // like named sub, but check if identical to existing CreateTask
1324 int sig_match_createtask_alt(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1325 {
1326     // if ref doesn't exist, quietly bail
1327     if(!get_saved_sig_val(rule->ref_name)) {
1328         return 0;
1329     }
1330 
1331     if(!init_disasm_sig_ref(fw,is,rule)) {
1332         return 0;
1333     }
1334     if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
1335         printf("sig_match_createtask_alt: bl match failed\n");
1336         return 0;
1337     }
1338     uint32_t adr = get_branch_call_insn_target(fw,is);
1339     uint32_t adr2 = get_saved_sig_val("CreateTask");
1340     // only save IFF not identical to CreateTask
1341     if(adr == adr2) {
1342         // printf("sig_match_createtask_alt: adr == CreateTask\n");
1343         return 0;
1344     }
1345     adr2 = get_saved_sig_val("j_CreateTask");
1346     if(adr == adr2) {
1347         // printf("sig_match_createtask_alt: adr == j_CreateTask\n");
1348         return 0;
1349     }
1350     return save_sig_with_j(fw,rule->name,adr);
1351 }
1352 
1353 
1354 int sig_match_get_nd_value(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1355 {
1356     // this match is only valid for cameras with both ND and Iris
1357     if(!get_misc_val_value("CAM_HAS_ND_FILTER") || !get_misc_val_value("CAM_HAS_IRIS_DIAPHRAGM")) {
1358         return 0;
1359     }
1360 
1361     if(!init_disasm_sig_ref(fw,is,rule)) {
1362         return 0;
1363     }
1364     if(!find_next_sig_call(fw,is,16,"ClearEventFlag")) {
1365         printf("sig_match_get_nd_value: no match ClearEventFlag\n");
1366         return 0;
1367     }
1368     if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
1369         printf("sig_match_get_nd_value: bl match 1 failed\n");
1370         return 0;
1371     }
1372     // follow
1373     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1374     disasm_iter(fw,is);
1375     if (B_target(fw,is->insn))
1376         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1377     // first call should be either get_nd_value or GetUsableAvRange
1378     if(!insn_match_find_next(fw,is,5,match_bl_blximm)) {
1379         printf("sig_match_get_nd_value: bl match 2 failed\n");
1380         return 0;
1381     }
1382     uint32_t addr=get_branch_call_insn_target(fw,is);
1383     if(addr == get_saved_sig_val("GetUsableAvRange")) {
1384         printf("sig_match_get_nd_value: found GetUsableAvRange, iris or ND only?\n");
1385         return 0;
1386     }
1387     return save_sig_with_j(fw,rule->name,addr);
1388 }
1389 
1390 int sig_match_get_current_exp(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1391 {
1392     if(!init_disasm_sig_ref(fw,is,rule)) {
1393         return 0;
1394     }
1395     if(!insn_match_find_next(fw,is,2,match_bl_blximm)) {
1396         printf("sig_match_get_current_exp: bl match 1 failed\n");
1397         return 0;
1398     }
1399     // follow
1400     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1401     if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
1402         printf("sig_match_get_current_exp: bl match 2 failed\n");
1403         return 0;
1404     }
1405     // follow
1406     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1407     if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
1408         printf("sig_match_get_current_exp: bl match 3 failed\n");
1409         return 0;
1410     }
1411     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1412 }
1413 
1414 int sig_match_get_current_nd_value(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1415 {
1416     // this match is only valid for cameras with both ND and Iris
1417     if(!get_misc_val_value("CAM_HAS_ND_FILTER") || !get_misc_val_value("CAM_HAS_IRIS_DIAPHRAGM")) {
1418         return 0;
1419     }
1420     if(!init_disasm_sig_ref(fw,is,rule)) {
1421         return 0;
1422     }
1423     if(!find_next_sig_call(fw,is,36,"GetCurrentShutterSpeed_FW")) {
1424         printf("sig_match_get_current_nd_value: no match GetCurrentShutterSpeed_FW\n");
1425         return 0;
1426     }
1427     // bl <func we want>
1428     // strh r0, [rN,8]
1429     const insn_match_t match_bl_strh[]={
1430         {MATCH_INS(BL,MATCH_OPCOUNT_IGNORE)},
1431         {MATCH_INS(STRH,2), {MATCH_OP_REG(R0),  MATCH_OP_MEM(INVALID,INVALID,0x8)}},
1432         {ARM_INS_ENDING}
1433     };
1434     if(!insn_match_find_next_seq(fw,is,10,match_bl_strh)) {
1435         printf("sig_match_get_current_nd_value: match failed\n");
1436         return 0;
1437     }
1438     // rewind one for call
1439     disasm_iter_init(fw,is,adr_hist_get(&is->ah,1));
1440     disasm_iter(fw,is);
1441     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1442 }
1443 
1444 int sig_match_get_current_deltasv(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1445 {
1446     if(!init_disasm_sig_ref(fw,is,rule)) {
1447         return 0;
1448     }
1449     if(!find_next_sig_call(fw,is,36,"GetCurrentShutterSpeed_FW")) {
1450         printf("sig_match_get_current_deltasv: no match GetCurrentShutterSpeed_FW\n");
1451         return 0;
1452     }
1453     // bl <func we want>
1454     // strh r0, [rN,4]
1455     const insn_match_t match_bl_strh[]={
1456         {MATCH_INS(BL,MATCH_OPCOUNT_IGNORE)},
1457         {MATCH_INS(STRH,2), {MATCH_OP_REG(R0),  MATCH_OP_MEM(INVALID,INVALID,0x4)}},
1458         {ARM_INS_ENDING}
1459     };
1460     if(!insn_match_find_next_seq(fw,is,8,match_bl_strh)) {
1461         printf("sig_match_get_current_deltasv: match failed\n");
1462         return 0;
1463     }
1464     // rewind one for call
1465     disasm_iter_init(fw,is,adr_hist_get(&is->ah,1));
1466     disasm_iter(fw,is);
1467     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1468 }
1469 
1470 
1471 int sig_match_imager_active_callback(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1472 {
1473     if(!init_disasm_sig_ref(fw,is,rule)) {
1474         return 0;
1475     }
1476     const insn_match_t match_ldr_bl_mov_pop[]={
1477         {MATCH_INS(LDR, 2),   {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(PC)}},
1478         {MATCH_INS(BL, MATCH_OPCOUNT_IGNORE)},
1479         {MATCH_INS(MOV,2),  {MATCH_OP_REG(R0),  MATCH_OP_IMM(0)}},
1480         {MATCH_INS(POP, MATCH_OPCOUNT_IGNORE)},
1481         {ARM_INS_ENDING}
1482     };
1483 
1484     if(!insn_match_find_next_seq(fw,is,28,match_ldr_bl_mov_pop)) {
1485         printf("sig_match_imager_active_callback: match failed\n");
1486         return 0;
1487     }
1488     // rewind to LDR r0,...
1489     disasm_iter_init(fw,is,adr_hist_get(&is->ah,3));
1490     // get LDR value
1491     disasm_iter(fw,is);
1492     uint32_t f1=LDR_PC2val(fw,is->insn);
1493 //    printf("f1 0x%08x\n",f1);
1494     // thumb bit should be set correctly
1495     return save_sig_with_j(fw,rule->name,f1);
1496 }
1497 int sig_match_imager_active(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1498 {
1499     if(!init_disasm_sig_ref(fw,is,rule)) {
1500         return 0;
1501     }
1502 
1503     const insn_match_t match_ldr_mov_str_pop[]={
1504         {MATCH_INS(LDR, 2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM_BASE(PC)}},
1505         {MATCH_INS(MOV,2), {MATCH_OP_REG_ANY,  MATCH_OP_IMM(1)}},
1506         {MATCH_INS(STR, 2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM_ANY}},
1507         {MATCH_INS(POP, MATCH_OPCOUNT_IGNORE)},
1508         {ARM_INS_ENDING}
1509     };
1510 
1511     int backtrack=3;
1512     if(!insn_match_find_next_seq(fw,is,10,match_ldr_mov_str_pop)) {
1513         // re-init and try reverse mov/ldr order
1514         init_disasm_sig_ref(fw,is,rule);
1515         const insn_match_t match_mov_ldr_str_pop[]={
1516             {MATCH_INS(MOV,2), {MATCH_OP_REG_ANY,  MATCH_OP_IMM(1)}},
1517             {MATCH_INS(LDR, 2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM_BASE(PC)}},
1518             {MATCH_INS(STR, 2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM_ANY}},
1519             {MATCH_INS(POP, MATCH_OPCOUNT_IGNORE)},
1520             {ARM_INS_ENDING}
1521         };
1522         if(!insn_match_find_next_seq(fw,is,10,match_mov_ldr_str_pop)) {
1523             printf("sig_match_imager_active: match failed\n");
1524             return 0;
1525         }
1526         backtrack=2;
1527     }
1528     // rewind to LDR
1529     disasm_iter_init(fw,is,adr_hist_get(&is->ah,backtrack));
1530     disasm_iter(fw,is);
1531     uint32_t base=LDR_PC2val(fw,is->insn);
1532     uint32_t reg=is->insn->detail->arm.operands[0].reg;
1533 //    printf("base 0x%08x @0x%08x\n",base,(uint32_t)is->insn->address);
1534     // skip mov if after LDR
1535     if(backtrack == 3) {
1536         disasm_iter(fw,is);
1537     }
1538     disasm_iter(fw,is);
1539     // sanity check base is the same as LDR'd to
1540     if(is->insn->detail->arm.operands[1].mem.base != reg) {
1541         printf("sig_match_imager_active: reg mismatch\n");
1542         return 0;
1543     }
1544     uint32_t off=is->insn->detail->arm.operands[1].mem.disp;
1545 //    printf("off 0x%08x @0x%08x\n",off,(uint32_t)is->insn->address);
1546     save_misc_val("imager_active",base,off,(uint32_t)is->insn->address);
1547     return 1;
1548 }
1549 
1550 int sig_match_screenlock_helper(firmware *fw, iter_state_t *is, sig_rule_t *rule) {
1551     if(!init_disasm_sig_ref(fw,is,rule)) {
1552         return 0;
1553     }
1554     uint32_t init_adr = (uint32_t)is->adr | is->thumb;
1555     // match specific instruction sequence instead of first call because g3x, g5x have different code
1556     // not by dryos rev, sx710 has same code as earlier cams
1557     const insn_match_t match_cmp_bne_bl[]={
1558         {MATCH_INS(CMP, 2), {MATCH_OP_REG(R0),  MATCH_OP_IMM(0)}},
1559         {MATCH_INS_CC(B,NE,MATCH_OPCOUNT_IGNORE)},
1560         {MATCH_INS(BL,MATCH_OPCOUNT_IGNORE)},
1561         {ARM_INS_ENDING}
1562     };
1563     const insn_match_t match_ldrpc_mov_b[]={
1564         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(PC)}},
1565         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R1),  MATCH_OP_IMM(0)}},
1566         {MATCH_INS_CC(B,AL,MATCH_OPCOUNT_IGNORE)},
1567         {ARM_INS_ENDING}
1568     };
1569     // match first seq, this is the func we want
1570     if(insn_match_find_next_seq(fw,is,6,match_cmp_bne_bl)) {
1571         return save_sig_with_j(fw,rule->name,init_adr);
1572 
1573     }
1574     // try alternate match on newer cameras (around r57, but some variation)
1575     // this version puts a pointer to the function used in normal match in r0, 0 in R1, and jumps
1576     // go back to start
1577     disasm_iter_init(fw,is,init_adr);
1578     if(!insn_match_find_next_seq(fw,is,1,match_ldrpc_mov_b)) {
1579         printf("sig_match_screenlock_helper: match 2 failed 0x%"PRIx64"\n",is->insn->address);
1580         return 0;
1581     }
1582     disasm_iter_init(fw,is,init_adr);
1583     disasm_iter(fw,is);
1584     uint32_t adr = LDR_PC2val(fw,is->insn);
1585     if(!adr) {
1586         printf("sig_match_screenlock_helper: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
1587         return 0;
1588     }
1589     disasm_iter_init(fw,is,adr);
1590     // retry original match on pointer
1591     if(!insn_match_find_next_seq(fw,is,6,match_cmp_bne_bl)) {
1592         printf("sig_match_screenlock_helper: match failed 0x%8x\n",init_adr);
1593         return 0;
1594     }
1595     return save_sig_with_j(fw,rule->name,adr);
1596 }
1597 
1598 int sig_match_fclose_low(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1599 {
1600     if(!init_disasm_sig_ref(fw,is,rule)) {
1601         // printf("sig_match_fclose_low: missing ref\n");
1602         return 0;
1603     }
1604     if(!find_next_sig_call(fw,is,24,"strlen")) {
1605         // printf("sig_match_fclose_low: no strlen\n");
1606         return 0;
1607     }
1608     if(!find_next_sig_call(fw,is,26,"malloc")) {
1609         // printf("sig_match_fclose_low: no malloc\n");
1610         return 0;
1611     }
1612     if(!find_next_sig_call(fw,is,14,"strcpy")) {
1613         // printf("sig_match_fclose_low: no strcpy\n");
1614         return 0;
1615     }
1616 
1617     if(!insn_match_find_nth(fw,is,12,3,match_bl_blximm)) {
1618         // printf("sig_match_fclose_low: no bl\n");
1619         return 0;
1620     }
1621     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1622 }
1623 
1624 int sig_match_screenunlock(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1625 {
1626     if(!init_disasm_sig_ref(fw,is,rule)) {
1627         return 0;
1628     }
1629     // look for ScreenLock call to verify right version of UIFS_DisplayFirmUpdateView
1630     if(!find_next_sig_call(fw,is,14,"ScreenLock")) {
1631         // printf("sig_match_screenunlock: no ScreenLock\n");
1632         return 0;
1633     }
1634 
1635     // expect tail call to ScreenUnlock
1636     const insn_match_t match_end[]={
1637         {MATCH_INS(POP, MATCH_OPCOUNT_IGNORE)},
1638         {MATCH_INS_CC(B,AL,MATCH_OPCOUNT_IGNORE)},
1639         {ARM_INS_ENDING}
1640     };
1641     if(!insn_match_find_next_seq(fw,is,38,match_end)) {
1642         // printf("sig_match_screenunlock: match failed\n");
1643         return 0;
1644     }
1645     // TODO would be nice to have some validation
1646     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1647 }
1648 
1649 // look for f(0x60,"_Simage") at start of task_StartupImage
1650 int sig_match_log_camera_event(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1651 {
1652     if(!init_disasm_sig_ref(fw,is,rule)) {
1653         return 0;
1654     }
1655     if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
1656         // printf("sig_match_log_camera_event: bl match failed\n");
1657         return 0;
1658     }
1659     uint32_t regs[4];
1660     if((get_call_const_args(fw,is,4,regs)&3)!=3) {
1661         // printf("sig_match_log_camera_event: get args failed\n");
1662         return 0;
1663     }
1664     if(regs[0] != 0x60) {
1665         // printf("sig_match_log_camera_event: bad r0 0x%x\n",regs[0]);
1666         return 0;
1667     }
1668     const char *str=(char *)adr2ptr(fw,regs[1]);
1669     if(!str || strcmp(str,"_SImage") != 0) {
1670         // printf("sig_match_log_camera_event: bad r1 0x%x\n",regs[1]);
1671         return 0;
1672     }
1673     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1674 }
1675 
1676 // TODO this finds multiple values in PhySwTask main function
1677 int sig_match_physw_misc(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1678 {
1679     if(!init_disasm_sig_ref(fw,is,rule)) {
1680         osig* ostub2 = find_sig(fw->sv->stubs,rule->ref_name);
1681         if (ostub2 && ostub2->val)
1682         {
1683             disasm_iter_init(fw,is,ostub2->val);
1684         }
1685         else
1686         {
1687             return 0;
1688         }
1689     }
1690     int i;
1691     uint32_t physw_run=0;
1692     for(i=0; i<3; i++) {
1693         if(!disasm_iter(fw,is)) {
1694             printf("sig_match_physw_misc: disasm failed\n");
1695             return 0;
1696         }
1697         physw_run=LDR_PC2val(fw,is->insn);
1698         if(physw_run) {
1699             if(adr_is_var(fw,physw_run)) {
1700                 save_misc_val("physw_run",physw_run,0,(uint32_t)is->insn->address);
1701                 break;
1702             } else {
1703                 printf("sig_match_physw_misc: adr not data? 0x%08x\n",physw_run);
1704                 return 0;
1705             }
1706         }
1707     }
1708     if(!physw_run) {
1709         return 0;
1710     }
1711 
1712     // look for physw_sleep_delay, offset from physw_run, loaded before SleepTask
1713     if(!insn_match_find_next(fw,is,7,match_bl_blximm)) {
1714         return 0;
1715     }
1716     uint32_t sleeptask=get_saved_sig_val("SleepTask");
1717     if(!sleeptask) {
1718         printf("sig_match_physw_misc: missing SleepTask\n");
1719         return 0;
1720     }
1721     uint32_t f=get_branch_call_insn_target(fw,is);
1722 
1723     // call wasn't direct, check for veneer
1724     if(f != sleeptask) {
1725         fw_disasm_iter_single(fw,f);
1726         uint32_t f2=get_direct_jump_target(fw,fw->is);
1727         if(f2 != sleeptask) {
1728             return 0;
1729         }
1730         // sleeptask veneer is useful for xref
1731         // re-adding existing won't hurt
1732         save_sig_with_j(fw,"SleepTask",f);
1733     }
1734     // rewind 1 for r0
1735     disasm_iter_init(fw,is,adr_hist_get(&is->ah,1));
1736     if(!disasm_iter(fw,is)) {
1737         printf("sig_match_physw_misc: disasm failed\n");
1738         return 0;
1739     }
1740     // TODO could check base is same reg physw_run was loaded into
1741     if(is->insn->id != ARM_INS_LDR
1742         || is->insn->detail->arm.operands[0].reg != ARM_REG_R0) {
1743         return 0;
1744     }
1745     save_misc_val("physw_sleep_delay",physw_run,is->insn->detail->arm.operands[1].mem.disp,(uint32_t)is->insn->address);
1746     // skip over sleeptask to next insn
1747     if(!disasm_iter(fw,is)) {
1748         printf("sig_match_physw_misc: disasm failed\n");
1749         return 0;
1750     }
1751 
1752     // look for kbd_p1_f
1753     if(!insn_match_find_next(fw,is,2,match_bl_blximm)) {
1754         return 0;
1755     }
1756     save_sig(fw,"kbd_p1_f",get_branch_call_insn_target(fw,is));
1757 
1758     // look for kbd_p2_f
1759     if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
1760         return 0;
1761     }
1762     save_sig(fw,"kbd_p2_f",get_branch_call_insn_target(fw,is));
1763     return 1;
1764 }
1765 // TODO also finds p1_f_cont, physw_status
1766 int sig_match_kbd_read_keys(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1767 {
1768     if(!init_disasm_sig_ref(fw,is,rule)) {
1769         return 0;
1770     }
1771     // look for kbd_read_keys
1772     if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
1773         return 0;
1774     }
1775     save_sig(fw,"kbd_read_keys",get_branch_call_insn_target(fw,is));
1776     if(!disasm_iter(fw,is)) {
1777         printf("sig_match_kbd_read_keys: disasm failed\n");
1778         return 0;
1779     }
1780     uint32_t physw_status=LDR_PC2val(fw,is->insn);
1781     if(physw_status) {
1782         save_misc_val("physw_status",physw_status,0,(uint32_t)is->insn->address);
1783         save_sig(fw,"kbd_p1_f_cont",(uint32_t)(is->insn->address) | is->thumb);
1784         return 1;
1785     }
1786     return 0;
1787 }
1788 
1789 // TODO also finds kbd_read_keys_r2
1790 int sig_match_get_kbd_state(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1791 {
1792     if(!init_disasm_sig_ref(fw,is,rule)) {
1793         return 0;
1794     }
1795     // instructions that zero out physw_status
1796     insn_match_t match[]={
1797         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(PC)}},
1798         {MATCH_INS(BL,  MATCH_OPCOUNT_IGNORE)},
1799         {ARM_INS_ENDING}
1800     };
1801 
1802     if(!insn_match_find_next_seq(fw,is,11,match)) {
1803         return 0;
1804     }
1805     save_sig_with_j(fw,"GetKbdState",get_branch_call_insn_target(fw,is));
1806     // look for kbd_read_keys_r2
1807     if(!insn_match_find_next(fw,is,5,match_b_bl_blximm)) {
1808         return 0;
1809     }
1810     save_sig_with_j(fw,"kbd_read_keys_r2",get_branch_call_insn_target(fw,is));
1811     return 1;
1812 }
1813 
1814 int sig_match_get_dial_hw_position(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1815 {
1816     if(!init_disasm_sig_ref(fw,is,rule)) {
1817         return 0;
1818     }
1819     uint32_t adr = find_last_call_from_func(fw,is,18,50);
1820     if(!adr) {
1821         // printf("sig_match_get_dial_hw_position: no match call 1 at 0x%"PRIx64"\n",is->insn->address);
1822         return 0;
1823     }
1824     // follow
1825     disasm_iter_init(fw,is,adr);
1826     adr = find_last_call_from_func(fw,is,16,32);
1827     if(!adr) {
1828         // printf("sig_match_get_dial_hw_position: no match call 2 at 0x%"PRIx64"\n",is->insn->address);
1829         return 0;
1830     }
1831     // follow
1832     disasm_iter_init(fw,is,adr);
1833     // find next function call
1834     if(!insn_match_find_next(fw,is,30,match_bl_blximm)) {
1835         // printf("sig_match_get_dial_hw_position: no match call 3 at 0x%"PRIx64"\n",is->insn->address);
1836         return 0;
1837     }
1838     uint32_t fadr = get_branch_call_insn_target(fw,is);
1839     // rewind and match instructions for sanity check
1840     disasm_iter_init(fw,is,adr_hist_get(&is->ah,4));
1841     const insn_match_t match_hw_dial_call[]={
1842         {MATCH_INS(ADD,MATCH_OPCOUNT_ANY), {MATCH_OP_REG(R0)}},
1843         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0),MATCH_OP_MEM_BASE(PC)}},
1844         {MATCH_INS(BL,MATCH_OPCOUNT_IGNORE)},
1845         {ARM_INS_ENDING}
1846     };
1847     if(!insn_match_find_next(fw,is,4,match_hw_dial_call)) {
1848         // printf("sig_match_get_dial_hw_position: no match seq 0x%"PRIx64"\n",is->insn->address);
1849         return 0;
1850     }
1851     return save_sig_with_j(fw,rule->name,fadr);
1852 }
1853 
1854 int sig_match_create_jumptable(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1855 {
1856     if(!init_disasm_sig_ref(fw,is,rule)) {
1857         return 0;
1858     }
1859     // find second function call
1860     if(!insn_match_find_nth(fw,is,20,2,match_bl_blximm)) {
1861         return 0;
1862     }
1863     // follow
1864     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1865     if(!insn_match_find_next(fw,is,15,match_bl_blximm)) {
1866         return 0;
1867     }
1868     // TODO could verify it looks right (version string)
1869     save_sig(fw,"CreateJumptable",get_branch_call_insn_target(fw,is));
1870     return 1;
1871 }
1872 
1873 // TODO this actually finds a bunch of different stuff
1874 int sig_match_take_semaphore_strict(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1875 {
1876     if(!init_disasm_sig_ref(fw,is,rule)) {
1877         return 0;
1878     }
1879     // find first function call
1880     if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
1881         return 0;
1882     }
1883     // follow
1884     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1885     // find second call
1886     if(!insn_match_find_nth(fw,is,10,2,match_bl_blximm)) {
1887         return 0;
1888     }
1889     // follow
1890     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1891     // skip two calls, next should be DebugAssert
1892     if(!insn_match_find_nth(fw,is,20,3,match_bl_blximm)) {
1893         return 0;
1894     }
1895     save_sig_with_j(fw,"DebugAssert",get_branch_call_insn_target(fw,is));
1896 
1897     // next should be TakeSemaphoreStrictly
1898     if(!insn_match_find_next(fw,is,7,match_bl_blximm)) {
1899         return 0;
1900     }
1901     save_sig_with_j(fw,"TakeSemaphoreStrictly",get_branch_call_insn_target(fw,is));
1902     arm_reg ptr_reg = ARM_REG_INVALID;
1903     uint32_t sem_adr=0;
1904     int i;
1905     // iterate backwards looking for the value put in r0
1906     for(i=1; i<7; i++) {
1907         fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i));
1908         cs_insn *insn=fw->is->insn;
1909         if(insn->id != ARM_INS_LDR) {
1910             continue;
1911         }
1912         if(ptr_reg == ARM_REG_INVALID
1913             && insn->detail->arm.operands[0].reg == ARM_REG_R0
1914             && insn->detail->arm.operands[1].mem.base != ARM_REG_PC) {
1915             ptr_reg = insn->detail->arm.operands[1].mem.base;
1916             continue;
1917         }
1918         if(ptr_reg == ARM_REG_INVALID || !isLDR_PC(insn) || (arm_reg)insn->detail->arm.operands[0].reg != ptr_reg) {
1919             continue;
1920         }
1921         sem_adr=LDR_PC2val(fw,insn);
1922         if(sem_adr) {
1923             break;
1924         }
1925     }
1926     if(!sem_adr) {
1927         return 0;
1928     }
1929     save_misc_val("fileio_semaphore",sem_adr,0,(uint32_t)is->insn->address);
1930     // look for next call: GetDrive_FreeClusters
1931     if(!insn_match_find_next(fw,is,10,match_bl_blximm)) {
1932         return 0;
1933     }
1934     return save_sig_with_j(fw,"GetDrive_FreeClusters",get_branch_call_insn_target(fw,is));
1935 }
1936 
1937 int sig_match_get_semaphore_value(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1938 {
1939     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
1940     if(!str_adr) {
1941         printf("sig_get_semaphore_value: failed to find ref %s\n",rule->ref_name);
1942         return 0;
1943     }
1944 
1945     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
1946     // assume first / only ref
1947     if(!fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
1948         // printf("sig_get_semaphore_value: failed to find code ref to %s\n",rule->ref_name);
1949         return 0;
1950     }
1951     // search backwards for func call
1952     uint32_t fadr=0;
1953     int i;
1954     for(i=1; i<=5; i++) {
1955         if(!fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i))) {
1956             // printf("sig_get_semaphore_value: disasm failed\n");
1957             return 0;
1958         }
1959         if(insn_match_any(fw->is->insn,match_bl_blximm)){
1960             fadr=get_branch_call_insn_target(fw,fw->is);
1961             break;
1962         }
1963     }
1964     if(!fadr) {
1965         // printf("sig_get_semaphore_value: failed to find bl 1\n");
1966         return 0;
1967     }
1968     // follow
1969     disasm_iter_init(fw,is,fadr);
1970     // look for first call
1971     if(!insn_match_find_next(fw,is,9,match_bl_blximm)) {
1972         // printf("sig_get_semaphore_value: failed to find bl 2\n");
1973         return 0;
1974     }
1975     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1976 }
1977 // similar to sig_match_str_r0_call, but string also appears with Fopen_Fut
1978 int sig_match_stat(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1979 {
1980     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
1981     if(!str_adr) {
1982         printf("sig_match_stat: %s failed to find ref %s\n",rule->name,rule->ref_name);
1983         return  0;
1984     }
1985 
1986     // TODO should handle multiple instances of string
1987     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
1988     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
1989         if(is->insn->detail->arm.operands[0].reg == ARM_REG_R0) {
1990             if(insn_match_find_next(fw,is,2,match_bl_blximm)) {
1991                 uint32_t adr=get_branch_call_insn_target(fw,is);
1992                 // same string ref'd by Fopen
1993                 if(is_sig_call(fw,is,"Fopen_Fut_FW")) {
1994                     continue;
1995                 }
1996                 // TODO could check r1 not a const
1997                 return save_sig_with_j(fw,rule->name,adr);
1998             }
1999         }
2000     }
2001     return 0;
2002 }
2003 static const insn_match_t match_open_mov_call[]={
2004     // 3 reg / reg movs, followed by a call
2005     {MATCH_INS(MOV, 2), {MATCH_OP_REG_ANY,  MATCH_OP_REG_ANY}},
2006     {MATCH_INS(MOV, 2), {MATCH_OP_REG_ANY,  MATCH_OP_REG_ANY}},
2007     {MATCH_INS(MOV, 2), {MATCH_OP_REG_ANY,  MATCH_OP_REG_ANY}},
2008     {MATCH_INS(BL,  MATCH_OPCOUNT_IGNORE)},
2009     {ARM_INS_ENDING}
2010 };
2011 
2012 
2013 // find low level open
2014 int sig_match_open(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2015 {
2016     if(!init_disasm_sig_ref(fw,is,rule)) {
2017         return 0;
2018     }
2019     if(!insn_match_find_next_seq(fw,is,48,match_open_mov_call)) {
2020         return 0;
2021     }
2022     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2023 }
2024 
2025 // AllocateUncacheableMemory
2026 int sig_match_umalloc(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2027 {
2028     if(!init_disasm_sig_ref(fw,is,rule)) {
2029         return 0;
2030     }
2031     // looking for 3rd call
2032     if(!insn_match_find_nth(fw,is,15,3,match_bl_blximm)) {
2033         return 0;
2034     }
2035     //follow
2036     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2037     // looking for 3rd call again
2038     if(!insn_match_find_nth(fw,is,14,3,match_bl_blximm)) {
2039         return 0;
2040     }
2041     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2042 }
2043 
2044 // FreeUncacheableMemory
2045 int sig_match_ufree(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2046 {
2047     if(!init_disasm_sig_ref(fw,is,rule)) {
2048         return 0;
2049     }
2050     // find the first call to strcpy
2051     if(!find_next_sig_call(fw,is,60,"strcpy_FW")) {
2052         return 0;
2053     }
2054     // find 3rd call
2055     if(!insn_match_find_nth(fw,is,12,3,match_bl_blximm)) {
2056         return 0;
2057     }
2058     // follow
2059     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2060     // Look for Close call
2061     if(!find_next_sig_call(fw,is,40,"Close_FW")) {
2062         return 0;
2063     }
2064     // next call should be FreeUncacheableMemory
2065     if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
2066         return 0;
2067     }
2068     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2069 }
2070 
2071 int sig_match_deletefile_fut(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2072 {
2073     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2074     if(!str_adr) {
2075         printf("sig_match_deletefile_fut: %s failed to find ref %s\n",rule->name,rule->ref_name);
2076         return  0;
2077     }
2078     // TODO should handle multiple instances of string
2079     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
2080     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2081         // next call should be DeleteFile_Fut
2082         if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
2083             continue;
2084         }
2085         // follow
2086         uint32_t adr=get_branch_call_insn_target(fw,is);
2087         if(!fw_disasm_iter_single(fw,adr)) {
2088             printf("sig_match_deletefile_fut: disasm failed\n");
2089             return 0;
2090         }
2091         const insn_match_t match_mov_r1[]={
2092             {MATCH_INS(MOV,     2), {MATCH_OP_REG(R1),  MATCH_OP_IMM_ANY}},
2093 #if CS_API_MAJOR < 4
2094             {MATCH_INS(MOVS,    2), {MATCH_OP_REG(R1),  MATCH_OP_IMM_ANY}},
2095 #endif
2096             {ARM_INS_ENDING}
2097         };
2098 
2099         if(!insn_match_any(fw->is->insn,match_mov_r1)){
2100             continue;
2101         }
2102         return save_sig_with_j(fw,rule->name,adr);
2103     }
2104     return 0;
2105 }
2106 
2107 uint32_t find_call_near_str(firmware *fw, iter_state_t *is, sig_rule_t *rule);
2108 
2109 int sig_match_closedir(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2110 {
2111     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2112     if(!str_adr) {
2113         printf("sig_match_closedir: %s failed to find ref %s\n",rule->name,rule->ref_name);
2114         return  0;
2115     }
2116     // TODO should handle multiple instances of string
2117     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
2118     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2119         if(!find_next_sig_call(fw,is,60,"sprintf_FW")) {
2120             continue;
2121         }
2122         if(insn_match_find_nth(fw,is,7,2,match_bl_blximm)) {
2123             return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2124         }
2125     }
2126 
2127     uint32_t call_adr = find_call_near_str(fw,is,rule);
2128     if(call_adr) {
2129         disasm_iter_init(fw,is,call_adr); // reset to a bit before where the string was found
2130         const insn_match_t match_closedir[]={
2131             {MATCH_INS(BL,MATCH_OPCOUNT_IGNORE)},
2132             {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0),  MATCH_OP_REG_ANY}},
2133             {MATCH_INS(BL,MATCH_OPCOUNT_IGNORE)},
2134             {ARM_INS_ENDING}
2135         };
2136         if(insn_match_seq(fw,is,match_closedir)){
2137             return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2138         }
2139     }
2140 
2141     return 0;
2142 }
2143 
2144 // Save sig for function call (BL/BLX) at current instruction
2145 int save_sig_match_call(firmware* fw, sig_rule_t *rule, uint32_t call_adr)
2146 {
2147     disasm_iter_init(fw,fw->is,call_adr); // reset to a bit before where the string was found
2148     disasm_iter(fw,fw->is);
2149     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,fw->is));
2150 }
2151 
2152 int sig_match_readfastdir(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2153 {
2154     uint32_t str_adr;
2155     str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2156     if(!str_adr) {
2157         printf("sig_match_readfastdir: %s failed to find ref %s\n",rule->name,rule->ref_name);
2158         return 0;
2159     }
2160     const insn_match_t match_cbnz_r0[]={
2161         {MATCH_INS(CBNZ, 2), {MATCH_OP_REG(R0), MATCH_OP_IMM_ANY}},
2162         {ARM_INS_ENDING}
2163     };
2164     const insn_match_t match_cbz_r0[]={
2165         {MATCH_INS(CBZ, 2), {MATCH_OP_REG(R0), MATCH_OP_IMM_ANY}},
2166         {ARM_INS_ENDING}
2167     };
2168     int max_insns=rule->param&SIG_NEAR_OFFSET_MASK;
2169     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
2170     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2171         uint32_t ref_adr = iter_state_adr(is);
2172         // Check for bl followed by cbnz in previous 2 instructions
2173         fw_disasm_iter_single(fw,adr_hist_get(&is->ah,2));
2174         if(insn_match_any(fw->is->insn,match_bl_blximm)) {
2175             uint32_t call_adr = iter_state_adr(fw->is);
2176             fw_disasm_iter_single(fw,adr_hist_get(&is->ah,1));
2177             if(insn_match_any(fw->is->insn,match_cbnz_r0)) {
2178                 return save_sig_match_call(fw, rule, call_adr);
2179             }
2180         }
2181         int i;
2182         for(i=3; i<=max_insns; i++) {
2183             // Check for bl followed by cbz branching to ref_adr
2184             fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i));
2185             if(insn_match_any(fw->is->insn,match_bl_blximm)) {
2186                 uint32_t call_adr = iter_state_adr(fw->is);
2187                 fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i-1));
2188                 if(insn_match_any(fw->is->insn,match_cbz_r0)) {
2189                     uint32_t b_adr = get_branch_call_insn_target(fw,fw->is);
2190                     if (ref_adr == b_adr) {
2191                         return save_sig_match_call(fw, rule, call_adr);
2192                     }
2193                 }
2194             }
2195         }
2196     }
2197     printf("sig_match_readfastdir: no match %s\n",rule->name);
2198     return 0;
2199 }
2200 
2201 int sig_match_strrchr(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2202 {
2203     uint32_t sig_adr=get_saved_sig_val(rule->name);
2204     if (sig_adr == 0)
2205     {
2206         uint32_t call_adr = find_call_near_str(fw,is,rule);
2207         if(call_adr) {
2208             disasm_iter_init(fw,is,call_adr-4); // reset to a bit before where the string was found
2209             const insn_match_t match_mov_r1_imm[]={
2210                 {MATCH_INS(MOV, 2), {MATCH_OP_REG(R1),  MATCH_OP_IMM_ANY}},
2211                 {ARM_INS_ENDING}
2212             };
2213             if(insn_match_find_next(fw,is,2,match_mov_r1_imm)){
2214                 return save_sig_match_call(fw, rule, call_adr);
2215             }
2216         }
2217     }
2218     return 0;
2219 }
2220 
2221 int sig_match_time(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2222 {
2223     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2224     if(!str_adr) {
2225         printf("sig_match_time: %s failed to find ref %s\n",rule->name,rule->ref_name);
2226         return  0;
2227     }
2228     uint32_t fadr=0;
2229     // TODO should handle multiple instances of string
2230     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
2231     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2232         // find second func after str ref
2233         if(insn_match_find_nth(fw,is,6,2,match_bl_blximm)) {
2234             fadr=get_branch_call_insn_target(fw,is);
2235             break;
2236         }
2237     }
2238     if(!fadr) {
2239         return 0;
2240     }
2241     // follow found func
2242     disasm_iter_init(fw,is,fadr);
2243     // find second call
2244     if(insn_match_find_nth(fw,is,11,2,match_bl_blximm)) {
2245         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2246     }
2247     return 0;
2248 }
2249 
2250 int sig_match_strncpy(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2251 {
2252     if(!init_disasm_sig_ref(fw,is,rule)) {
2253         return 0;
2254     }
2255     if(!find_next_sig_call(fw,is,60,"strcpy_FW")) {
2256         return 0;
2257     }
2258     if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
2259         return 0;
2260     }
2261     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2262 }
2263 
2264 int sig_match_strncmp(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2265 {
2266     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2267     if(!str_adr) {
2268         printf("sig_match_strncmp: failed to find ref %s\n",rule->ref_name);
2269         return  0;
2270     }
2271     // TODO should handle multiple instances of string
2272     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
2273     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2274         if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
2275             continue;
2276         }
2277         uint32_t regs[4];
2278         if((get_call_const_args(fw,is,4,regs)&6)==6) {
2279             // sanity check we got the right string
2280             if(regs[1]==str_adr &&  regs[2] == strlen(rule->ref_name)) {
2281                 return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2282             }
2283         }
2284     }
2285     return 0;
2286 }
2287 
2288 int sig_match_strtolx(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2289 {
2290     if(!init_disasm_sig_ref(fw,is,rule)) {
2291         return 0;
2292     }
2293     if(!find_next_sig_call(fw,is,130,"strncpy")) {
2294         return 0;
2295     }
2296     // find first call after strncpy
2297     if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
2298         return 0;
2299     }
2300     uint32_t adr=get_branch_call_insn_target(fw,is);
2301     if(!adr) {
2302         return 0;
2303     }
2304     // follow
2305     disasm_iter_init(fw,is,adr);
2306     if(!disasm_iter(fw,is)) {
2307         printf("sig_match_strtolx: disasm failed\n");
2308         return 0;
2309     }
2310     // expect
2311     // mov r3, #0
2312     // b ...
2313     const insn_match_t match_mov_r3_imm[]={
2314         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R3),  MATCH_OP_IMM_ANY}},
2315         {ARM_INS_ENDING}
2316     };
2317     if(!insn_match(is->insn,match_mov_r3_imm)){
2318         return 0;
2319     }
2320     if(!disasm_iter(fw,is)) {
2321         printf("sig_match_strtolx: disasm failed\n");
2322         return 0;
2323     }
2324     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2325 }
2326 
2327 // find the version of ExecuteEventProcedure that doesn't assert evp isn't reg'd
2328 int sig_match_exec_evp(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2329 {
2330     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2331     if(!str_adr) {
2332         printf("sig_match_exec_evp: failed to find ref %s\n",rule->ref_name);
2333         return  0;
2334     }
2335     // TODO should handle multiple instances of string
2336     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
2337     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2338         // search backwards for push {r0,...}
2339         int i;
2340         for(i=1; i<=18; i++) {
2341             if(!fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i))) {
2342                 break;
2343             }
2344             if(fw->is->insn->id == ARM_INS_PUSH && fw->is->insn->detail->arm.operands[0].reg == ARM_REG_R0) {
2345                 // push should be start of func
2346                 uint32_t adr=(uint32_t)(fw->is->insn->address) | is->thumb;
2347                 // search forward in original iter_state for DebugAssert. If found, in the wrong ExecuteEventProcedure
2348                 if(find_next_sig_call(fw,is,28,"DebugAssert")) {
2349                     break;
2350                 }
2351                 return save_sig_with_j(fw,rule->name,adr);
2352             }
2353         }
2354     }
2355     return 0;
2356 }
2357 
2358 int sig_match_fgets_fut(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2359 {
2360     if(!init_disasm_sig_ref(fw,is,rule)) {
2361         return 0;
2362     }
2363     if(!find_next_sig_call(fw,is,16,"Fopen_Fut_FW")) {
2364         return 0;
2365     }
2366     disasm_iter(fw,is);
2367     disasm_iter(fw,is);
2368     if (B_target(fw,is->insn) && (is->insn->detail->arm.cc == ARM_CC_NE)) {
2369         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2370     } else {
2371         if (B_target(fw,is->insn) && (is->insn->detail->arm.cc == ARM_CC_NE)) {
2372             disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2373         }
2374     }
2375     if(!insn_match_find_nth(fw,is,20,1,match_bl_blximm)) {
2376         return 0;
2377     }
2378     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2379 }
2380 
2381 int sig_match_log(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2382 {
2383     if(!init_disasm_sig_ref(fw,is,rule)) {
2384         return 0;
2385     }
2386     const insn_match_t match_pop6[]={
2387         {MATCH_INS(POP, 6), {MATCH_OP_REST_ANY}},
2388         {ARM_INS_ENDING}
2389     };
2390     // skip forward through 3x pop     {r4, r5, r6, r7, r8, lr}
2391     if(!insn_match_find_nth(fw,is,38,3,match_pop6)) {
2392         return 0;
2393     }
2394     // third call
2395     if(!insn_match_find_nth(fw,is,24,3,match_bl_blximm)) {
2396         return 0;
2397     }
2398     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2399 }
2400 
2401 // this only works on DryOS r52 cams
2402 int sig_match_pow_dry_52(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2403 {
2404     if (fw->dryos_ver != 52) {
2405         return 0;
2406     }
2407     if(!init_disasm_sig_ref(fw,is,rule)) {
2408         return 0;
2409     }
2410     const insn_match_t match_ldrd_r0_r1[]={
2411         {MATCH_INS(LDRD,    3), {MATCH_OP_REG(R0), MATCH_OP_REG(R1),    MATCH_OP_ANY}},
2412         {ARM_INS_ENDING}
2413     };
2414     // skip forward to first ldrd    r0, r1, [r...]
2415     if(!insn_match_find_next(fw,is,50,match_ldrd_r0_r1)) {
2416         return 0;
2417     }
2418     // prevent false positive
2419     if(is->insn->detail->arm.operands[2].mem.base == ARM_REG_SP) {
2420         return 0;
2421     }
2422     if(!disasm_iter(fw,is)) {
2423         printf("sig_match_pow: disasm failed\n");
2424         return 0;
2425     }
2426     uint32_t adr=get_branch_call_insn_target(fw,is);
2427     if(!adr) {
2428         return 0;
2429     }
2430     return save_sig_with_j(fw,rule->name,adr);
2431 }
2432 
2433 // match for dryos > r52 cams
2434 int sig_match_pow_dry_gt_52(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2435 {
2436     if (fw->dryos_ver <= 52) {
2437         return 0;
2438     }
2439     if(!init_disasm_sig_ref(fw,is,rule)) {
2440         return 0;
2441     }
2442     const insn_match_t match1a[]={
2443         {MATCH_INS(LDRSH,   2), {MATCH_OP_REG(R0),  MATCH_OP_MEM(SP,INVALID,0x12)}},
2444         {MATCH_INS(LDRD,    3), {MATCH_OP_REG(R2),  MATCH_OP_REG(R3), MATCH_OP_MEM(SP,INVALID,0x20)}},
2445         {MATCH_INS(STR,     2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM(SP,INVALID,0)}},
2446         {MATCH_INS(BL,      MATCH_OPCOUNT_IGNORE)},
2447         {ARM_INS_ENDING}
2448     };
2449     const insn_match_t match1b[]={
2450         {MATCH_INS(MOV,     2), {MATCH_OP_REG(R2),  MATCH_OP_REG(R7)}},
2451         {MATCH_INS(LDRSH,   2), {MATCH_OP_REG(R0),  MATCH_OP_MEM(SP,INVALID,0x12)}},
2452         {MATCH_INS(MOV,     2), {MATCH_OP_REG(R3),  MATCH_OP_REG(R6)}},
2453         {MATCH_INS(STR,     2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM(SP,INVALID,0)}},
2454         {MATCH_INS(BL,      MATCH_OPCOUNT_IGNORE)},
2455         {ARM_INS_ENDING}
2456     };
2457     const insn_match_t* match1[]={ match1a, match1b };
2458     int idx;
2459     for (idx = 0; idx < 2; idx += 1)
2460     {
2461         // match above sequence
2462         if(insn_match_find_next_seq(fw,is,50,match1[idx]))
2463             break;
2464         init_disasm_sig_ref(fw,is,rule);
2465     }
2466     // check for match
2467     if (idx >= 2)
2468         return 0;
2469     // match above sequence
2470     uint32_t adr=get_branch_call_insn_target(fw,is);
2471     if(!adr) {
2472         return 0;
2473     }
2474     // follow bl
2475     disasm_iter_init(fw,is,adr);
2476     const insn_match_t match2a[]={
2477         {MATCH_INS(LDRD,3), {MATCH_OP_REG(R0),  MATCH_OP_REG(R1),   MATCH_OP_MEM_ANY}},
2478         {MATCH_INS(BLX, 1), {MATCH_OP_IMM_ANY}},
2479         {ARM_INS_ENDING}
2480     };
2481     const insn_match_t match2b[]={
2482         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R2),  MATCH_OP_REG(R0)}},
2483         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R3),  MATCH_OP_REG(R1)}},
2484         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R4),  MATCH_OP_IMM(0x40000000)}},
2485         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0),  MATCH_OP_IMM(0)}},
2486         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R1),  MATCH_OP_REG(R4)}},
2487         {MATCH_INS(BL,  1), {MATCH_OP_IMM_ANY}},
2488         {ARM_INS_ENDING}
2489     };
2490     const insn_match_t* match2[]={ match2a, match2b };
2491     // match above sequence
2492     if(!insn_match_find_next_seq(fw,is,15,match2[idx])) {
2493         return 0;
2494     }
2495     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2496 }
2497 
2498 int sig_match_sqrt(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2499 {
2500     if(!init_disasm_sig_ref(fw,is,rule)) {
2501         return 0;
2502     }
2503     // third call
2504     if(!insn_match_find_nth(fw,is,12,3,match_bl_blximm)) {
2505         return 0;
2506     }
2507     // follow
2508     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2509     if(!disasm_iter(fw,is)) {
2510         printf("sig_match_sqrt: disasm failed\n");
2511         return 0;
2512     }
2513     uint32_t j_tgt=get_direct_jump_target(fw,is);
2514     // veneer?
2515     if(j_tgt) {
2516         // follow
2517         disasm_iter_init(fw,is,j_tgt);
2518         if(!disasm_iter(fw,is)) {
2519             printf("sig_match_sqrt: disasm failed\n");
2520             return 0;
2521         }
2522     }
2523     // second call/branch (seems to be bhs)
2524     if(!insn_match_find_nth(fw,is,12,2,match_b_bl_blximm)) {
2525         return 0;
2526     }
2527     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2528 }
2529 int sig_match_get_drive_cluster_size(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2530 {
2531     if(!init_disasm_sig_ref(fw,is,rule)) {
2532         return 0;
2533     }
2534     // only handle first match, don't expect multiple refs to string
2535     if(fw_search_insn(fw,is,search_disasm_str_ref,0,"A/OpLogErr.txt",(uint32_t)is->adr+260)) {
2536         // find first call after string ref
2537         if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
2538             // printf("sig_match_get_drive_cluster_size: bl not found\n");
2539             return 0;
2540         }
2541         // follow
2542         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2543         // find second call
2544         if(!insn_match_find_nth(fw,is,13,2,match_bl_blximm)) {
2545             // printf("sig_match_get_drive_cluster_size: call 1 not found\n");
2546             return 0;
2547         }
2548         // follow
2549         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2550         disasm_iter(fw,is);
2551         if (B_target(fw, is->insn))
2552             disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2553         // find next call
2554         if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
2555             // printf("sig_match_get_drive_cluster_size: call 2 not found\n");
2556             return 0;
2557         }
2558         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2559     }
2560     return 0;
2561 }
2562 
2563 int sig_match_mktime_ext(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2564 {
2565     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2566     if(!str_adr) {
2567         printf("sig_match_mktime_ext: failed to find ref %s\n",rule->ref_name);
2568         return  0;
2569     }
2570     // TODO should handle multiple instances of string
2571     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
2572     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2573         // expect sscanf after str
2574         if(!find_next_sig_call(fw,is,12,"sscanf_FW")) {
2575             // printf("sig_match_mktime_ext: no sscanf\n");
2576             return 0;
2577         }
2578         // find next call
2579         if(!insn_match_find_next(fw,is,22,match_bl_blximm)) {
2580             // printf("sig_match_mktime_ext: no call\n");
2581             return 0;
2582         }
2583         // follow
2584         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2585         if(!disasm_iter(fw,is)) {
2586             printf("sig_match_mktime_ext: disasm failed\n");
2587             return 0;
2588         }
2589         uint32_t j_tgt=get_direct_jump_target(fw,is);
2590         // veneer?
2591         if(j_tgt) {
2592             // follow
2593             disasm_iter_init(fw,is,j_tgt);
2594             if(!disasm_iter(fw,is)) {
2595                 printf("sig_match_mktime_ext: disasm failed\n");
2596                 return 0;
2597             }
2598         }
2599         const insn_match_t match_pop4[]={
2600             {MATCH_INS(POP, 4), {MATCH_OP_REST_ANY}},
2601             {MATCH_INS(POP, 6), {MATCH_OP_REST_ANY}},
2602             {ARM_INS_ENDING}
2603         };
2604 
2605         // find pop
2606         if(!insn_match_find_next(fw,is,54,match_pop4)) {
2607             // printf("sig_match_mktime_ext: no pop\n");
2608             return 0;
2609         }
2610         if(!insn_match_find_next(fw,is,1,match_b)) {
2611             // printf("sig_match_mktime_ext: no b\n");
2612             return 0;
2613         }
2614         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2615     }
2616     return 0;
2617 }
2618 
2619 // match call after ref to "_EnrySRec" because "AC:Rec2PB" ref before push in function, hard to be sure of start
2620 int sig_match_rec2pb(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2621 {
2622     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2623     if(!str_adr) {
2624         printf("sig_match_mktime_ext: failed to find ref %s\n",rule->ref_name);
2625         return  0;
2626     }
2627     // TODO should handle multiple instances of string
2628     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
2629     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2630         const insn_match_t match_ldr_cbnz_r0[]={
2631             {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0), MATCH_OP_MEM_ANY}},
2632             {MATCH_INS(CBNZ, 2), {MATCH_OP_REG(R0), MATCH_OP_IMM_ANY}},
2633             {ARM_INS_ENDING}
2634         };
2635         if(!insn_match_find_next_seq(fw,is,10,match_ldr_cbnz_r0)) {
2636             // printf("sig_match_rec2pb: no cbnz\n");
2637             continue;
2638         }
2639         // follow
2640         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2641         if(!insn_match_find_next(fw,is,3,match_b_bl_blximm)) {
2642             // printf("sig_match_rec2pb: no call\n");
2643             // followed branch, doesn't make sense to keep searching
2644             return 0;
2645         }
2646         uint32_t adr = iter_state_adr(is);
2647         // follow for sanity check
2648         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2649         if(!find_next_sig_call(fw,is,16,"LogCameraEvent")) {
2650             // printf("sig_match_rec2pb: no LogCameraEvent call\n");
2651             return 0;
2652         }
2653         uint32_t regs[4];
2654         if((get_call_const_args(fw,is,4,regs)&3)!=3) {
2655             // printf("sig_match_rec2pb: failed to get args\n");
2656             return 0;
2657         }
2658         // sanity check starts with LogCameraEvent with expected number and string
2659         if(regs[0]==0x60 && adr2ptr(fw,regs[1]) && (strcmp((const char *)adr2ptr(fw,regs[1]),"AC:Rec2PB")==0)) {
2660             return save_sig_with_j(fw,rule->name,adr);
2661         } else {
2662             // printf("sig_match_rec2pb: bad args\n");
2663             return 0;
2664         }
2665     }
2666     return 0;
2667 }
2668 
2669 // could just do sig_match_named, 3rd b, but want more validation
2670 int sig_match_get_parameter_data(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2671 {
2672     if(!init_disasm_sig_ref(fw,is,rule)) {
2673         return 0;
2674     }
2675     const insn_match_t match_cmp_bhs[]={
2676         {MATCH_INS(CMP, 2), {MATCH_OP_REG_ANY, MATCH_OP_IMM_ANY}},
2677         {MATCH_INS_CC(B,HS,MATCH_OPCOUNT_IGNORE)},
2678         {ARM_INS_ENDING}
2679     };
2680     if(!insn_match_find_next_seq(fw,is,4,match_cmp_bhs)) {
2681         // printf("sig_match_get_parameter_data: no match cmp, bhs\n");
2682         return 0;
2683     }
2684     // follow
2685     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2686     if(!insn_match_find_next(fw,is,1,match_b)) {
2687         // printf("sig_match_get_parameter_data: no match b\n");
2688         return 0;
2689     }
2690     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2691 }
2692 
2693 // PrepareDirectory (via string ref) points at something like
2694 // mov r1, 1
2695 // b PrepareDirectory_x
2696 int sig_match_prepdir_x(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2697 {
2698     if(!init_disasm_sig_ref(fw,is,rule)) {
2699         return 0;
2700     }
2701     const insn_match_t match_mov_r1_1[]={
2702         {MATCH_INS(MOV,     2), {MATCH_OP_REG(R1),  MATCH_OP_IMM(1)}},
2703 #if CS_API_MAJOR < 4
2704         {MATCH_INS(MOVS,    2), {MATCH_OP_REG(R1),  MATCH_OP_IMM(1)}},
2705 #endif
2706         {ARM_INS_ENDING}
2707     };
2708     if(!insn_match_find_next(fw,is,1,match_mov_r1_1)) {
2709         //printf("sig_match_prepdir_x: no match mov\n");
2710         return 0;
2711     }
2712     if(!insn_match_find_next(fw,is,1,match_b)) {
2713         //printf("sig_match_prepdir_x: no match b\n");
2714         return 0;
2715     }
2716     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2717 }
2718 
2719 // PrepareDirectory (via string ref) points at something like
2720 // mov r1, 1
2721 // b PrepareDirectory_x
2722 int sig_match_prepdir_1(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2723 {
2724     uint32_t call_adr = find_call_near_str(fw,is,rule);
2725     if(call_adr) {
2726         disasm_iter_init(fw,is,call_adr);
2727         disasm_iter(fw,is);
2728         disasm_iter(fw,is);
2729         if (!CBx_target(fw,is->insn))
2730         {
2731             rule->param = SIG_NEAR_BEFORE(20,5);
2732             call_adr = find_call_near_str(fw,is,rule);
2733             if(!call_adr) {
2734                 return 0;
2735             }
2736             disasm_iter_init(fw,is,call_adr);
2737             disasm_iter(fw,is);
2738             return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2739         }
2740     }
2741 
2742     rule->param = SIG_NEAR_BEFORE(7,2);
2743     call_adr = find_call_near_str(fw,is,rule);
2744     if(!call_adr) {
2745         return 0;
2746     }
2747     return save_sig_match_call(fw, rule, call_adr);
2748 }
2749 // assume this function is directly after the 2 instructions of ref
2750 int sig_match_prepdir_0(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2751 {
2752     if(!init_disasm_sig_ref(fw,is,rule)) {
2753         return 0;
2754     }
2755     uint32_t ref_pdx=get_saved_sig_val("PrepareDirectory_x");
2756     if(!ref_pdx) {
2757         printf("sig_match_prepdir_0: missing PrepareDirectory_x\n");
2758         return 0;
2759     }
2760     // skip over, assume validated previously
2761     disasm_iter(fw,is);
2762     disasm_iter(fw,is);
2763     // this should be the start address of our function
2764     uint32_t adr=(uint32_t)is->adr|is->thumb;
2765     const insn_match_t match_mov_r1_1[]={
2766         {MATCH_INS(MOV,     2), {MATCH_OP_REG(R1),  MATCH_OP_IMM(0)}},
2767 #if CS_API_MAJOR < 4
2768         {MATCH_INS(MOVS,    2), {MATCH_OP_REG(R1),  MATCH_OP_IMM(0)}},
2769 #endif
2770         {ARM_INS_ENDING}
2771     };
2772     if(!insn_match_find_next(fw,is,1,match_mov_r1_1)) {
2773         //printf("sig_match_prepdir_0: no match mov\n");
2774         return 0;
2775     }
2776     if(!insn_match_find_next(fw,is,1,match_b)) {
2777         //printf("sig_match_prepdir_0: no match b\n");
2778         return 0;
2779     }
2780     uint32_t pdx=get_branch_call_insn_target(fw,is);
2781     if(pdx != ref_pdx) {
2782         //printf("sig_match_prepdir_0: target 0x%08x != 0x%08x\n",pdx,ref_pdx);
2783         return 0;
2784     }
2785     return save_sig_with_j(fw,rule->name,adr);
2786 }
2787 int sig_match_mkdir(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2788 {
2789     if(!init_disasm_sig_ref(fw,is,rule)) {
2790         return 0;
2791     }
2792     const insn_match_t match[]={
2793         {MATCH_INS(STRB,2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM_ANY}},
2794         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0),  MATCH_OP_REG(SP)}},
2795         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R1),  MATCH_OP_MEM_BASE(SP)}},
2796         {MATCH_INS(BL,  MATCH_OPCOUNT_IGNORE)},
2797         {ARM_INS_ENDING}
2798     };
2799     if(insn_match_find_next_seq(fw,is,148,match)) {
2800         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2801     }
2802 
2803     init_disasm_sig_ref(fw,is,rule);
2804     const insn_match_t match2[]={
2805         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R1),  MATCH_OP_REG_ANY}},
2806         {MATCH_INS(STRB,2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM_ANY}},
2807         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0),  MATCH_OP_REG(SP)}},
2808         {MATCH_INS(BL,  MATCH_OPCOUNT_IGNORE)},
2809         {ARM_INS_ENDING}
2810     };
2811     if(!insn_match_find_next_seq(fw,is,148,match2)) {
2812         //printf("sig_match_mkdir: no match\n");
2813         return 0;
2814     }
2815     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2816 }
2817 
2818 int sig_match_add_ptp_handler(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2819 {
2820     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2821     if(!str_adr) {
2822         printf("sig_match_add_ptp_handler: failed to find ref %s\n",rule->ref_name);
2823         return  0;
2824     }
2825     // TODO should handle multiple instances of string
2826     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
2827     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2828         // expect CreateTaskStrictly
2829         if(!find_next_sig_call(fw,is,8,"CreateTaskStrictly")) {
2830             // printf("sig_match_add_ptp_handler: no CreateTaskStrictly\n");
2831             continue;
2832         }
2833         // expect add_ptp_handler is 3rd call after CreateTask
2834         if(!insn_match_find_nth(fw,is,13,3,match_bl_blximm)) {
2835             // printf("sig_match_add_ptp_handler: no match bl\n");
2836             return 0;
2837         }
2838         // sanity check, expect opcode, func, 0
2839         uint32_t regs[4];
2840         if((get_call_const_args(fw,is,5,regs)&7)!=7) {
2841             // printf("sig_match_add_ptp_handler: failed to get args\n");
2842             return 0;
2843         }
2844         if(regs[0] < 0x9000 || regs[0] > 0x10000 || !adr2ptr(fw,regs[1]) || regs[2] != 0) {
2845             // printf("sig_match_add_ptp_handler: bad args 0x%08x 0x%08x 0x%08x\n",regs[0],regs[1],regs[2]);
2846             return 0;
2847         }
2848         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2849     }
2850     return 0;
2851 }
2852 int sig_match_qsort(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2853 {
2854     if(!init_disasm_sig_ref(fw,is,rule)) {
2855         return 0;
2856     }
2857     if(!find_next_sig_call(fw,is,90,"DebugAssert")) {
2858         // printf("sig_match_qsort: no DebugAssert\n");
2859         return 0;
2860     }
2861     if(!insn_match_find_nth(fw,is,38,3,match_bl_blximm)) {
2862         // printf("sig_match_qsort: no match bl\n");
2863         return 0;
2864     }
2865     // follow
2866     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2867     // if call in first 4 insn, follow again (newer cams have an extra sub)
2868     if(insn_match_find_next(fw,is,4,match_bl_blximm)) {
2869         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2870     }
2871     if(!insn_match_find_next(fw,is,14,match_bl_blximm)) {
2872         // printf("sig_match_qsort: no match bl (qsort)\n");
2873         return 0;
2874     }
2875     // sanity check, expect r1-r3 to be const
2876     uint32_t regs[4];
2877     if((get_call_const_args(fw,is,5,regs)&0xe)!=0xe) {
2878         // printf("sig_match_qsort: failed to get args\n");
2879         return 0;
2880     }
2881     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2882 }
2883 // looks for sequence of calls near ref string RedEyeController.c
2884 // DeleteFile_Fut
2885 // ...
2886 // strcpy
2887 // ...
2888 // strrchr
2889 // ...
2890 // DeleteDirectory_Fut
2891 int sig_match_deletedirectory_fut(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2892 {
2893     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2894     if(!str_adr) {
2895         printf("sig_match_deletedirectory_fut: failed to find ref %s\n",rule->ref_name);
2896         return  0;
2897     }
2898     // TODO using larger than default "near" range, needed for sx710
2899     // not looking for ref to string, just code near where the actual string is
2900     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - 2048) | fw->thumb_default); // reset to a bit before where the string was found
2901     uint32_t end_adr = ADR_ALIGN4(str_adr) + 2048;
2902     while(find_next_sig_call(fw,is,end_adr - (uint32_t)is->adr,"DeleteFile_Fut")) {
2903         if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
2904             // printf("sig_match_deletedirectory_fut: no match bl strcpy\n");
2905             continue;
2906         }
2907         if(!is_sig_call(fw,is,"strcpy")) {
2908             // printf("sig_match_deletedirectory_fut: bl not strcpy at 0x%"PRIx64"\n",is->insn->address);
2909             continue;
2910         }
2911         if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
2912             // printf("sig_match_deletedirectory_fut: no match bl strrchr at 0x%"PRIx64"\n",is->insn->address);
2913             continue;
2914         }
2915         if(!is_sig_call(fw,is,"strrchr")) {
2916             // printf("sig_match_deletedirectory_fut: bl not strrchr at 0x%"PRIx64"\n",is->insn->address);
2917             continue;
2918         }
2919         // verify that arg1 to strrch is /
2920         uint32_t regs[4];
2921         if((get_call_const_args(fw,is,2,regs)&0x2)!=0x2) {
2922             // printf("sig_match_deletedirectory_fut: failed to get strrchr r1 at 0x%"PRIx64"\n",is->insn->address);
2923             continue;
2924         }
2925         if(regs[1] != '/') {
2926             // printf("sig_match_deletedirectory_fut: strrchr r1 not '/' at 0x%"PRIx64"\n",is->insn->address);
2927             continue;
2928         }
2929         if(!insn_match_find_next(fw,is,5,match_bl_blximm)) {
2930             // printf("sig_match_deletedirectory_fut: no match bl at 0x%"PRIx64"\n",is->insn->address);
2931             continue;
2932         }
2933         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2934     }
2935     return 0;
2936 }
2937 
2938 /*
2939 match
2940    ref "LogicalEvent:0x%04x:adr:%p,Para:%ld" (or "LogicalEvent:0x%08x:adr:%p,Para:%ld")
2941    bl      LogCameraEvent
2942    mov     r0, rN
2943    bl      <some func>
2944    bl      set_control_event (or veneer)
2945 same string is used elsewhere, so match specific sequence
2946 */
2947 int sig_match_set_control_event(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2948 {
2949     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2950     if(!str_adr) {
2951         // not logged, two different ref strings so failing one is normal
2952         // printf("sig_match_set_control_event: failed to find ref %s\n",rule->ref_name);
2953         return  0;
2954     }
2955     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
2956     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2957         if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
2958             // printf("sig_match_set_control_event: no match bl at 0x%"PRIx64"\n",is->insn->address);
2959             continue;
2960         }
2961         if(!is_sig_call(fw,is,"LogCameraEvent")) {
2962             // printf("sig_match_set_control_event: not LogCameraEvent at 0x%"PRIx64"\n",is->insn->address);
2963             continue;
2964         }
2965         const insn_match_t match_seq[]={
2966             {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0),  MATCH_OP_REG_ANY,}},
2967             {MATCH_INS(BL, MATCH_OPCOUNT_IGNORE)},
2968             {MATCH_INS(BL, MATCH_OPCOUNT_IGNORE)},
2969             {ARM_INS_ENDING}
2970         };
2971         if(!insn_match_find_next_seq(fw,is,1,match_seq)) {
2972             // printf("sig_match_set_control_event: no match seq\n");
2973             continue;
2974         }
2975         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2976     }
2977     return 0;
2978 }
2979 // find displaybusyonscreen for r52 cams, later uses different code
2980 int sig_match_displaybusyonscreen_52(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2981 {
2982     if (fw->dryos_ver != 52) {
2983         return 0;
2984     }
2985     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2986     if(!str_adr) {
2987         printf("sig_match_displaybusyonscreen: failed to find ref %s\n",rule->ref_name);
2988         return  0;
2989     }
2990     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
2991     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2992         if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
2993             // printf("sig_match_displaybusyonscreen: no match bl at 0x%"PRIx64"\n",is->insn->address);
2994             continue;
2995         }
2996         if(!is_sig_call(fw,is,"LogCameraEvent")) {
2997             // printf("sig_match_displaybusyonscreen: not LogCameraEvent at 0x%"PRIx64"\n",is->insn->address);
2998             continue;
2999         }
3000         if(!find_next_sig_call(fw,is,4,"GUISrv_StartGUISystem_FW")) {
3001             // printf("sig_match_displaybusyonscreen: no match GUISrv_StartGUISystem_FW\n");
3002             continue;
3003         }
3004         if(!insn_match_find_nth(fw,is,5,2,match_bl_blximm)) {
3005             // printf("sig_match_displaybusyonscreen: no match bl 0x%"PRIx64"\n",is->insn->address);
3006             continue;
3007         }
3008         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3009     }
3010     return 0;
3011 }
3012 // find undisplaybusyonscreen for r52 cams, later uses different code
3013 int sig_match_undisplaybusyonscreen_52(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3014 {
3015     if (fw->dryos_ver != 52) {
3016         return 0;
3017     }
3018     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
3019     if(!str_adr) {
3020         printf("sig_match_undisplaybusyonscreen: failed to find ref %s\n",rule->ref_name);
3021         return  0;
3022     }
3023     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
3024     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
3025         // assume same function display* was found in, skip to that
3026         if(!find_next_sig_call(fw,is,24,"displaybusyonscreen")) {
3027             // printf("sig_match_undisplaybusyonscreen: no match displaybusyonscreen\n");
3028             continue;
3029         }
3030         if(!find_next_sig_call(fw,is,12,"GUISrv_StartGUISystem_FW")) {
3031             // printf("sig_match_undisplaybusyonscreen: no match GUISrv_StartGUISystem_FW\n");
3032             continue;
3033         }
3034         if(!insn_match_find_nth(fw,is,6,3,match_bl_blximm)) {
3035             // printf("sig_match_undisplaybusyonscreen: no match bl 0x%"PRIx64"\n",is->insn->address);
3036             continue;
3037         }
3038         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3039     }
3040     return 0;
3041 }
3042 
3043 int sig_match_try_take_sem_dry_gt_57(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3044 {
3045     if(!init_disasm_sig_ref(fw,is,rule)) {
3046         return 0;
3047     }
3048     if(!find_next_sig_call(fw,is,24,"ReceiveMessageQueue")) {
3049         printf("sig_match_try_take_sem_dry_gt_57: failed to find ReceiveMessageQueue\n");
3050         return 0;
3051     }
3052     if(!find_next_sig_call(fw,is,60,"bzero")) {
3053         printf("sig_match_try_take_sem_dry_gt_57: failed to find bzero\n");
3054         return 0;
3055     }
3056     if(insn_match_find_next(fw,is,3,match_bl_blximm)) {
3057         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3058     }
3059     printf("sig_match_try_take_sem_dry_gt_57: no match\n");
3060     return 0;
3061 }
3062 
3063 int sig_match_wait_all_eventflag_strict(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3064 {
3065     if(!init_disasm_sig_ref(fw,is,rule)) {
3066         return 0;
3067     }
3068     uint32_t str_adr = find_str_bytes_main_fw(fw,"EFTool.c");
3069     if(!str_adr) {
3070         printf("sig_match_wait_all_eventflag_strict: failed to find ref EFTool.c\n");
3071         return 0;
3072     }
3073     if(!find_next_sig_call(fw,is,60,"SleepTask")) {
3074         printf("sig_match_wait_all_eventflag_strict: failed to find SleepTask\n");
3075         return 0;
3076     }
3077 
3078     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,is->adr + 60)) {
3079         if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
3080             printf("sig_match_wait_all_eventflag_strict: no match bl 0x%"PRIx64"\n",is->insn->address);
3081             return 0;
3082         }
3083         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3084     }
3085     return 0;
3086 }
3087 
3088 int sig_match_get_num_posted_messages(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3089 {
3090     if(!init_disasm_sig_ref(fw,is,rule)) {
3091         return 0;
3092     }
3093     if(!find_next_sig_call(fw,is,50,"TakeSemaphore")) {
3094         printf("sig_match_get_num_posted_messages: failed to find TakeSemaphore\n");
3095         return 0;
3096     }
3097     // find next call
3098     if(!insn_match_find_next(fw,is,5,match_bl_blximm)) {
3099         printf("sig_match_get_num_posted_messages:  no match bl 0x%"PRIx64"\n",is->insn->address);
3100         return 0;
3101     }
3102     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3103 }
3104 
3105 int sig_match_set_hp_timer_after_now(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3106 {
3107     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
3108     if(!str_adr) {
3109         printf("sig_match_set_hp_timer_after_now: failed to find ref %s\n",rule->ref_name);
3110         return 0;
3111     }
3112     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
3113     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
3114         if(!find_next_sig_call(fw,is,20,"ClearEventFlag")) {
3115             // printf("sig_match_set_hp_timer_after_now: failed to find ClearEventFlag\n");
3116             continue;
3117         }
3118         // find 3rd call
3119         if(!insn_match_find_nth(fw,is,13,3,match_bl_blximm)) {
3120             // printf("sig_match_set_hp_timer_after_now: no match bl 0x%"PRIx64"\n",is->insn->address);
3121             continue;
3122         }
3123         // check call args, expect r0 = 70000
3124         uint32_t regs[4];
3125         uint32_t found_regs = get_call_const_args(fw,is,6,regs);
3126         if((found_regs&0x1)!=0x1) {
3127             // some cameras load r0 through a base reg, try alternate match
3128             // r3 == 3 and r2 or r1 found and in ROM
3129             if((found_regs & 0x8) && regs[3] == 4) {
3130                 if((found_regs & 0x2 && regs[1] > fw->rom_code_search_min_adr)
3131                     || (found_regs & 0x4 && regs[2] > fw->rom_code_search_min_adr)) {
3132                     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3133                 }
3134             }
3135             // printf("sig_match_set_hp_timer_after_now: failed to match args 0x%"PRIx64"\n",is->insn->address);
3136             continue;
3137         }
3138         // r1, r2 should be func pointers but may involve reg-reg moves that get_call_const_args doesn't track
3139         if(regs[0] != 70000) {
3140             // printf("sig_match_set_hp_timer_after_now: args mismatch 0x%08x 0x%08x 0x%"PRIx64"\n",regs[0],regs[1],is->insn->address);
3141             continue;
3142         }
3143         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3144     }
3145     return 0;
3146 }
3147 int sig_match_transfer_src_overlay(firmware *fw, iter_state_t *is, sig_rule_t *rule) {
3148     if(!init_disasm_sig_ref(fw,is,rule)) {
3149         return 0;
3150     }
3151     // skip to debugassert
3152     if(!find_next_sig_call(fw,is,32,"DebugAssert")) {
3153         printf("sig_match_transfer_src_overlay: no match DebugAssert\n");
3154         return 0;
3155     }
3156     var_ldr_desc_t desc;
3157     if(!find_and_get_var_ldr(fw, is, 20,4, ARM_REG_R0, &desc)) {
3158         printf("sig_match_transfer_src_overlay: no match ldr\n");
3159         return 0;
3160     }
3161     // following should be call
3162     if(!insn_match_find_next(fw,is,1,match_bl_blximm)) {
3163         printf("sig_match_transfer_src_overlay: no match bl 0x%"PRIx64"\n",is->insn->address);
3164         return 0;
3165     }
3166     // main sig value
3167     uint32_t fadr = get_branch_call_insn_target(fw,is);
3168     // adding active_bitmap_buffer here
3169     // note 4 bytes after value used on many ports, but the value normally sent to transfer_src_overlay
3170     save_misc_val("active_bitmap_buffer",desc.adr_adj,desc.off,(uint32_t)is->insn->address);
3171     // pick up bitmap_buffer
3172     // expect
3173     // ldr rx,[reg bitmap buffer]
3174     // add r0, <reg from bitmap buffer>, const
3175     const insn_match_t bm_buf_match[]={
3176         {MATCH_INS(LDR,   2),  {MATCH_OP_REG_ANY,  MATCH_OP_MEM_ANY}},
3177         {MATCH_INS(ADD,   3),  {MATCH_OP_REG(R0), MATCH_OP_REG_ANY, MATCH_OP_IMM_ANY}},
3178         {ARM_INS_ENDING}
3179     };
3180     if(insn_match_find_next_seq(fw,is,1,bm_buf_match)) {
3181         if((arm_reg)is->insn->detail->arm.operands[1].reg == desc.reg_base) {
3182             save_misc_val("bitmap_buffer",desc.adr_adj,is->insn->detail->arm.operands[2].imm,(uint32_t)is->insn->address);
3183         }
3184         /*
3185         else {
3186             printf("sig_match_transfer_src_overlay: no match bitmap_buffer add 0x%"PRIx64"\n",is->insn->address);
3187         }
3188         */
3189     }
3190     /*
3191     else {
3192         printf("sig_match_transfer_src_overlay: no match bitmap_buffer seq 0x%"PRIx64"\n",is->insn->address);
3193     }
3194     */
3195     return save_sig_with_j(fw,rule->name,fadr);
3196 }
3197 
3198 // find exmem related stuff
3199 int sig_match_exmem_vars(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3200 {
3201     uint32_t adr[2], fnd[2];
3202     if(!init_disasm_sig_ref(fw,is,rule)) {
3203         printf("sig_match_exmem_vars: missing ref\n");
3204         return 0;
3205     }
3206     // expect first LDR pc
3207     if(!insn_match_find_next(fw,is,15,match_ldr_pc)) {
3208         printf("sig_match_exmem_vars: match LDR PC failed\n");
3209         return 0;
3210     }
3211     adr[0]=LDR_PC2val(fw,is->insn);
3212     fnd[0]=(uint32_t)is->insn->address;
3213     if(!insn_match_find_next(fw,is,5,match_ldr_pc)) {
3214         printf("sig_match_exmem_vars: 2nd match LDR PC failed\n");
3215         return 0;
3216     }
3217     adr[1]=LDR_PC2val(fw,is->insn);
3218     fnd[1]=(uint32_t)is->insn->address;
3219     //printf("sig_match_exmem_vars: %x, %x\n",adr[0], adr[1]);
3220     int n;
3221     for (n=0; n<2; n++) {
3222         if (adr[n] < fw->data_start+fw->data_len) {
3223             uint32_t ladr = adr[n]-fw->data_start+fw->data_init_start;
3224             save_misc_val("exmem_types_table",ladr,0,fnd[n]);
3225             int m;
3226             int exm_typ_cnt = 0;
3227             for (m=0; m<42; m++) {
3228                 if ( (fw_u32(fw,ladr+m*4)!=0) && isASCIIstring(fw, fw_u32(fw,ladr+m*4)) )
3229                 {
3230                     char *extyp = (char*)adr2ptr(fw, fw_u32(fw,ladr+m*4));
3231                     if ( strncmp(extyp,"EXMEM",5)==0 )
3232                     {
3233                         exm_typ_cnt++;
3234                     }
3235                 }
3236                 else
3237                 {
3238                     break;
3239                 }
3240             }
3241             save_misc_val("exmem_type_count",exm_typ_cnt,0,ladr);
3242         }
3243         else if (adr[n] < fw->memisostart) {
3244             save_misc_val("exmem_alloc_table",adr[n],0,fnd[n]);
3245         }
3246     }
3247     return 1;
3248 }
3249 
3250 // find function that copies Zico Xtensa blobs to their destination (dryos 52)
3251 int sig_match_zicokick_52(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3252 {
3253     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
3254     if(!str_adr) {
3255         printf("sig_match_zicokick_52: failed to find ref %s\n",rule->ref_name);
3256         return  0;
3257     }
3258     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
3259 
3260     // search for string ref
3261     if(!fw_search_insn(fw,is,search_disasm_str_ref,0,rule->ref_name,(uint32_t)is->adr+SEARCH_NEAR_REF_RANGE)) {
3262         printf("sig_match_zicokick_52: failed to find insn ref %s\n",rule->ref_name);
3263         return 0;
3264     }
3265     // check preceding instruction
3266     if(!fw_disasm_iter_single(fw,adr_hist_get(&is->ah,1))) {
3267         printf("sig_match_zicokick_52: disasm failed\n");
3268         return 0;
3269     }
3270     if (!(isLDR_PC(fw->is->insn) && fw->is->insn->detail->arm.operands[0].reg == ARM_REG_R0)) {
3271         printf("sig_match_zicokick_52: match ldr r0 failed\n");
3272         return 0;
3273     }
3274     // save backtracked address
3275     uint32_t adr=(uint32_t)(fw->is->insn->address) | is->thumb;
3276     // step forward one from string ref
3277     if(!disasm_iter(fw,is)) {
3278         printf("sig_match_zicokick_52: disasm failed\n");
3279         return 0;
3280     }
3281     if (is->insn->id == ARM_INS_PUSH && is->insn->detail->arm.operands[0].reg == ARM_REG_R4) {
3282         return save_sig_with_j(fw,rule->name,adr);
3283     }
3284     return 0;
3285 }
3286 // find function that copies Zico Xtensa blobs to their destination (dryos >52)
3287 int sig_match_zicokick_gt52(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3288 {
3289     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
3290     if(!str_adr) {
3291         printf("sig_match_zicokick_gt52: failed to find ref %s\n",rule->ref_name);
3292         return  0;
3293     }
3294     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
3295 
3296     // search for string ref
3297     if(!fw_search_insn(fw,is,search_disasm_str_ref,0,rule->ref_name,(uint32_t)is->adr+SEARCH_NEAR_REF_RANGE)) {
3298         printf("sig_match_zicokick_gt52: failed to find insn ref %s\n",rule->ref_name);
3299         return 0;
3300     }
3301     int i;
3302     // search backward for
3303     // ldr r0,...
3304     // push r4,...
3305     for(i=1; i<=8; i++) {
3306         if (!fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i))) {
3307             printf("sig_match_zicokick_gt52: disasm failed\n");
3308             return 0;
3309         }
3310         if (fw->is->insn->id == ARM_INS_PUSH && fw->is->insn->detail->arm.operands[0].reg == ARM_REG_R4) {
3311             if (!fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i+1))) {
3312                 printf("sig_match_zicokick_gt52: disasm failed\n");
3313                 return 0;
3314             }
3315             if (isLDR_PC(fw->is->insn) && fw->is->insn->detail->arm.operands[0].reg == ARM_REG_R0) {
3316                 return save_sig_with_j(fw,rule->name,(uint32_t)(fw->is->insn->address) | is->thumb);
3317             }
3318             return 0;
3319         }
3320     }
3321     return 0;
3322 }
3323 int sig_match_zicokick_copy(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3324 {
3325     if(!init_disasm_sig_ref(fw,is,rule)) {
3326         return 0;
3327     }
3328     // TODO could be less strict on regs, 5 LDRs in a row is rare
3329     const insn_match_t match_ldrs_bl[]={
3330         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(PC)}},
3331         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R1),  MATCH_OP_MEM_BASE(PC)}},
3332         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R2),  MATCH_OP_MEM_BASE(R0)}},
3333         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(PC)}},
3334         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(R0)}},
3335         {MATCH_INS(BL,MATCH_OPCOUNT_IGNORE)},
3336         {ARM_INS_ENDING}
3337     };
3338     if(!insn_match_find_next_seq(fw,is,30,match_ldrs_bl)) {
3339         printf("sig_match_zicokick_copy no match ldr\n");
3340         return 0;
3341     }
3342     // TODO could sanity check bl target
3343     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3344 }
3345 
3346 int sig_match_zicokick_values(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3347 {
3348     if(!init_disasm_sig_ref(fw,is,rule)) {
3349         return 0;
3350     }
3351 // get_call_const_args doesn't currently handle ldr sequence
3352 #if 0
3353     // first call is further from function start
3354     if(!find_next_sig_call(fw,is,64,"zicokick_copy")) {
3355         printf("sig_match_zicokick_values: no zicokick_copy 1\n");
3356         return 0;
3357     }
3358     while(1) {
3359         uint32_t regs[4];
3360         if((get_call_const_args(fw,is,7,regs)&0x7)==0x7) {
3361             printf("xtensa blob @ 0x%08x, loads to 0x%08x, size 0x%08x\n",regs[1],regs[0],regs[2]);
3362         } else {
3363             printf("sig_match_zicokick_values: failed to get regs\n");
3364         }
3365         if(!find_next_sig_call(fw,is,8,"zicokick_copy")) {
3366             break;
3367         }
3368     }
3369     return 1;
3370 #endif
3371     int i;
3372     uint32_t uv[3] = {0,0,0};
3373     int uvi = 0;
3374     misc_blob_t *blobs=malloc((MISC_BLOB_XTENSA_MAX + 1)*sizeof(misc_blob_t));
3375     int n_blobs = 0;
3376 
3377     for(i=1; i<=64; i++) {
3378         if (!disasm_iter(fw,is)) {
3379             free(blobs);
3380             return 0;
3381         }
3382         if (is->insn->id == ARM_INS_LDR && is->insn->detail->arm.operands[1].type == ARM_OP_MEM) {
3383             uint32_t u = LDR_PC2val(fw,is->insn);
3384             if ((u<fw->base+fw->size8) && (u>fw->rom_code_search_max_adr)) {
3385                 // address outside the main fw
3386                 if (uvi<3) {
3387                     uv[uvi] = u;
3388                     uvi++;
3389                 }
3390             }
3391         }
3392         else if (is->insn->id == ARM_INS_BL) {
3393             if (uvi==3) {
3394                 // func call, all 3 addresses are in collection
3395                 uint32_t bsize, bloadedto, badr, u;
3396                 int j;
3397                 badr = MAX(MAX(uv[0],uv[1]),uv[2]);
3398                 for (j=0; j<3; j++) {
3399                     if (uv[j]!=badr) {
3400                         u = fw_u32(fw, uv[j]);
3401                         if (u<1024*1024*2) {
3402                             bsize = u;
3403                         }
3404                         else {
3405                             bloadedto = u;
3406                         }
3407                     }
3408                 }
3409                 if (bsize) {
3410                     if(n_blobs == MISC_BLOB_XTENSA_MAX) {
3411                         printf("sig_match_zicokick_values: ignoring xtensa blobs > %d\n",MISC_BLOB_XTENSA_MAX);
3412                         blobs[n_blobs].type = MISC_BLOB_TYPE_NONE;
3413                         break;
3414                     }
3415                     // printf("xtensa blob @ 0x%08x, loads to 0x%08x, size 0x%08x\n",badr,bloadedto,bsize);
3416                     blobs[n_blobs].type = MISC_BLOB_TYPE_XTENSA;
3417                     blobs[n_blobs].rom_adr = badr;
3418                     blobs[n_blobs].ram_adr = bloadedto;
3419                     blobs[n_blobs].size = bsize;
3420                     n_blobs++;
3421                 }
3422             }
3423             uvi = 0;
3424         }
3425         else if (is->insn->id == ARM_INS_POP) {
3426             break;
3427         }
3428     }
3429     if(n_blobs > 0) {
3430         blobs[n_blobs].type = MISC_BLOB_TYPE_NONE;
3431         save_misc_val_blobs("zicokick_values",blobs,0);
3432         return 1;
3433     } else {
3434         free(blobs);
3435         return 0;
3436     }
3437 }
3438 
3439 int sig_match_init_ex_drivers(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3440 {
3441     if(!init_disasm_sig_ref(fw,is,rule)) {
3442         return 0;
3443     }
3444     int i;
3445     int b_count;
3446     // search forward 32 instructions or 14 calls
3447     for(i=0, b_count = 0; i < 32 && b_count < 14; i++) {
3448         if (!disasm_iter(fw,is)) {
3449             printf("sig_match_init_ex_drivers: disasm failed 1\n");
3450             return 0;
3451         }
3452         uint32_t b_tgt = get_branch_call_insn_target(fw,is);
3453         if(!b_tgt) {
3454             continue;
3455         }
3456         b_count++;
3457         uint64_t next_adr = is->adr | is->thumb;
3458         disasm_iter_init(fw,is,b_tgt);
3459         if (!disasm_iter(fw,is)) {
3460             printf("sig_match_init_ex_drivers: disasm failed 2\n");
3461             return 0;
3462         }
3463         // expect the function we're looking for to start with a push
3464         if(is->insn->id == ARM_INS_PUSH) {
3465             if(find_next_sig_call(fw,is,30,"DebugAssert")) {
3466                 uint32_t regs[4];
3467                 if((get_call_const_args(fw,is,5,regs)&0x2)==0x2) {
3468                     const char *str=(char *)adr2ptr(fw,regs[1]);
3469                     if(str && strcmp(str,"InitExDrivers.c") == 0) {
3470                         return save_sig_with_j(fw,rule->name,b_tgt);
3471                     }
3472                 }
3473             }
3474         }
3475         disasm_iter_init(fw,is,next_adr);
3476     }
3477     return 0;
3478 }
3479 
3480 int sig_match_omar_init(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3481 {
3482     if(!init_disasm_sig_ref(fw,is,rule)) {
3483         return 0;
3484     }
3485     uint32_t fadr = find_last_call_from_func(fw,is,20,42);
3486     if(!fadr) {
3487         printf("sig_match_omar_init: no match call\n");
3488         return 0;
3489     }
3490     // follow
3491     disasm_iter_init(fw,is,fadr);
3492     if(!find_next_sig_call(fw,is,44,"dry_memcpy")) {
3493         printf("sig_match_omar_init: no match dry_memcpy\n");
3494         return 0;
3495     }
3496     uint32_t regs[4];
3497     // expect dry_memcpy(stack ptr,rom ptr, 0x18)
3498     if((get_call_const_args(fw,is,5,regs)&0x6)!=0x6) {
3499         printf("sig_match_omar_init: no match dry_memcpy args 1\n");
3500         return 0;
3501     }
3502     if(regs[2] != 0x18 || !adr2ptr(fw,regs[1])) {
3503         printf("sig_match_omar_init: no match dry_memcpy args 2\n");
3504         return 0;
3505     }
3506     uint32_t dadr = regs[1];
3507     save_misc_val("omar_init_data",dadr,0,(uint32_t)is->insn->address);
3508     misc_blob_t *blobs=malloc(3*sizeof(misc_blob_t));
3509     int i;
3510     for(i = 0; i<2; i++) {
3511         uint32_t dst = fw_u32(fw,dadr + i*12);
3512         uint32_t src = fw_u32(fw,dadr + i*12 + 4);
3513         uint32_t bsize = fw_u32(fw,dadr + i*12 + 8);
3514         if(src && dst && bsize) {
3515             blobs[i].type = MISC_BLOB_TYPE_OMAR;
3516             blobs[i].rom_adr = src;
3517             blobs[i].ram_adr = dst;
3518             blobs[i].size = bsize;
3519         } else {
3520             printf("sig_match_omar_init: invalid blobs\n");
3521             free(blobs);
3522             blobs = NULL;
3523             break;
3524         }
3525     }
3526     if(blobs) {
3527         blobs[2].type = MISC_BLOB_TYPE_NONE;
3528         save_misc_val_blobs("omar_init_values",blobs,0);
3529     }
3530 
3531     return save_sig_with_j(fw,rule->name,fadr);
3532 }
3533 
3534 int sig_match_init_error_handlers(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3535 {
3536     if(!init_disasm_sig_ref(fw,is,rule)) {
3537         return 0;
3538     }
3539     if(!find_next_sig_call(fw,is,64,"init_ex_drivers")) {
3540         printf("sig_match_init_error_handlers: no match init_ex_drivers\n");
3541         return 0;
3542     }
3543     if(!insn_match_find_nth(fw,is,4,2,match_bl_blximm)) {
3544         printf("sig_match_init_error_handlers: no match bl\n");
3545         return 0;
3546     }
3547     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3548 }
3549 
3550 int sig_match_default_assert_handler(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3551 {
3552     if(!init_disasm_sig_ref(fw,is,rule)) {
3553         return 0;
3554     }
3555     if(!find_next_sig_call(fw,is,14,"set_assert_handler")) {
3556         printf("sig_match_default_assert_handler: no match set_assert_handler\n");
3557         return 0;
3558     }
3559     // expect func r0
3560     uint32_t regs[4];
3561     if((get_call_const_args(fw,is,1,regs)&0x1)!=0x1) {
3562         printf("sig_match_default_assert_handler: no match arg\n");
3563         return 0;
3564     }
3565     return save_sig_with_j(fw,rule->name,regs[0]);
3566 }
3567 
3568 int sig_match_default_exception_handler(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3569 {
3570     if(!init_disasm_sig_ref(fw,is,rule)) {
3571         return 0;
3572     }
3573     if(!find_next_sig_call(fw,is,20,"set_exception_handler")) {
3574         printf("sig_match_default_exception_handler: no match set_exception_handler\n");
3575         return 0;
3576     }
3577     // expect func in r0
3578     uint32_t regs[4];
3579     if((get_call_const_args(fw,is,1,regs)&0x1)!=0x1) {
3580         printf("sig_match_default_exception_handler: no match arg\n");
3581         return 0;
3582     }
3583     return save_sig_with_j(fw,rule->name,regs[0]);
3584 }
3585 
3586 int sig_match_default_panic_handler(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3587 {
3588     if(!init_disasm_sig_ref(fw,is,rule)) {
3589         return 0;
3590     }
3591     if(!find_next_sig_call(fw,is,28,"set_panic_handler")) {
3592         printf("sig_match_default_panic_handler: no match set_panic_handler\n");
3593         return 0;
3594     }
3595     // expect func in r0
3596     uint32_t regs[4];
3597     if((get_call_const_args(fw,is,1,regs)&0x1)!=0x1) {
3598         printf("sig_match_default_panic_handler: no match arg\n");
3599         return 0;
3600     }
3601     return save_sig_with_j(fw,rule->name,regs[0]);
3602 }
3603 
3604 int sig_match_get_task_properties(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3605 {
3606     if(!init_disasm_sig_ref(fw,is,rule)) {
3607         return 0;
3608     }
3609     if(fw_search_insn(fw,is,search_disasm_str_ref,0,"Occured Time  %s\n",(uint32_t)is->adr+170)) {
3610         // expect printf function follow by call
3611         if(!find_next_sig_call(fw,is,16,"dry_error_printf")) {
3612             printf("get_task_properties: no match dry_error_printf 0x%"PRIx64"\n",is->insn->address);
3613             return 0;
3614         }
3615         if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
3616             printf("sig_match_get_task_properties: no match bl 0x%"PRIx64"\n",is->insn->address);
3617             return 0;
3618         }
3619         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3620     }
3621     printf("sig_match_get_task_properties: no match 'Occured Time' 0x%"PRIx64"\n",is->insn->address);
3622     return 0;
3623 }
3624 
3625 int sig_match_enable_hdmi_power(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3626 {
3627     if(!init_disasm_sig_ref(fw,is,rule)) {
3628         return 0;
3629     }
3630     if(!find_next_sig_call(fw,is,14,"CreateEventFlagStrictly")) {
3631         printf("sig_match_enable_hdmi_power: no match CreateEventFlagStrictly\n");
3632         return 0;
3633     }
3634     const insn_match_t match_seq[]={
3635         {MATCH_INS(BL,   MATCH_OPCOUNT_IGNORE)},
3636         {MATCH_INS(CBNZ, MATCH_OPCOUNT_IGNORE)},
3637         {ARM_INS_ENDING}
3638     };
3639     if(!insn_match_find_next_seq(fw,is,4,match_seq)) {
3640         printf("sig_match_enable_hdmi_power: no match bl seq cbnz 0x%"PRIx64"\n",is->insn->address);
3641         return 0;
3642     }
3643     // function should be next call
3644     if (!disasm_iter(fw,is)) {
3645         return 0;
3646     }
3647     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3648 }
3649 
3650 int sig_match_disable_hdmi_power(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3651 {
3652     if(!init_disasm_sig_ref(fw,is,rule)) {
3653         return 0;
3654     }
3655     if(!find_next_sig_call(fw,is,24,"EnableHDMIPower")) {
3656         printf("sig_match_disable_hdmi_power: no match EnableHDMIPower\n");
3657         return 0;
3658     }
3659     if(!find_next_sig_call(fw,is,22,"ClearEventFlag")) {
3660         printf("sig_match_disable_hdmi_power: no match ClearEventFlag\n");
3661         return 0;
3662     }
3663     const insn_match_t match_seq[]={
3664         {MATCH_INS(BL,   MATCH_OPCOUNT_IGNORE)},
3665         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0),  MATCH_OP_IMM(1)}},
3666         {MATCH_INS(POP, MATCH_OPCOUNT_IGNORE)},
3667         {ARM_INS_ENDING}
3668     };
3669     if(!insn_match_find_next_seq(fw,is,12,match_seq)) {
3670         printf("sig_match_disable_hdmi_power: no match seq bl movs pop 0x%"PRIx64"\n",is->insn->address);
3671         return 0;
3672     }
3673     // bl matched above should be func
3674     disasm_iter_init(fw,is,adr_hist_get(&is->ah,2));
3675     if (!disasm_iter(fw,is)) {
3676         return 0;
3677     }
3678     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3679 }
3680 
3681 int sig_match_levent_table(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3682 {
3683     if(!init_disasm_sig_ref(fw,is,rule)) {
3684         return 0;
3685     }
3686     if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
3687         // printf("sig_match_levent_table: no match bl 0x%"PRIx64"\n",is->insn->address);
3688         return 0;
3689     }
3690     // follow
3691     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3692 
3693     // find first call of next function
3694     if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
3695         // printf("sig_match_levent_table: no match bl 0x%"PRIx64"\n",is->insn->address);
3696         return 0;
3697     }
3698 
3699     // follow
3700     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3701 
3702     // first instruction should load address
3703     disasm_iter(fw,is);
3704     uint32_t adr=LDR_PC2val(fw,is->insn);
3705     if(!adr) {
3706         // printf("sig_match_levent_table: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
3707         return  0;
3708     }
3709     uint32_t *p=(uint32_t *)adr2ptr(fw,adr);
3710     if(!p) {
3711         printf("sig_match_levent_table: 0x%08x not a ROM adr 0x%"PRIx64"\n",adr,is->insn->address);
3712         return  0;
3713     }
3714     if(*(p+1) != 0x800) {
3715         printf("sig_match_levent_table: expected 0x800 not 0x%x at 0x%08x ref 0x%"PRIx64"\n",*(p+1),adr,is->insn->address);
3716         return  0;
3717     }
3718     // TODO saving the function might be useful for analysis
3719     save_misc_val(rule->name,adr,0,(uint32_t)is->insn->address);
3720     return 1;
3721 }
3722 int sig_match_flash_param_table(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3723 {
3724     if(!init_disasm_sig_ref(fw,is,rule)) {
3725         return 0;
3726     }
3727     // expect 3 asserts
3728     if(!insn_match_find_next(fw,is,14,match_bl_blximm)) {
3729         // printf("sig_match_flash_param_table: no match bl 1\n");
3730         return 0;
3731     }
3732     if(!is_sig_call(fw,is,"DebugAssert")) {
3733         // printf("sig_match_flash_param_table: bl 1 not DebugAssert at 0x%"PRIx64"\n",is->insn->address);
3734         return 0;
3735     }
3736     if(!insn_match_find_next(fw,is,7,match_bl_blximm)) {
3737         // printf("sig_match_flash_param_table: no match bl 2\n");
3738         return 0;
3739     }
3740     if(!is_sig_call(fw,is,"DebugAssert")) {
3741         // printf("sig_match_flash_param_table: bl 2 not DebugAssert at 0x%"PRIx64"\n",is->insn->address);
3742         return 0;
3743     }
3744     if(!insn_match_find_next(fw,is,8,match_bl_blximm)) {
3745         // printf("sig_match_flash_param_table: no match bl 3\n");
3746         return 0;
3747     }
3748     if(!is_sig_call(fw,is,"DebugAssert")) {
3749         // printf("sig_match_flash_param_table: bl 3 not DebugAssert at 0x%"PRIx64"\n",is->insn->address);
3750         return 0;
3751     }
3752     // expect AcquireRecursiveLockStrictly, func
3753     if(!insn_match_find_nth(fw,is,14,2,match_bl_blximm)) {
3754         // printf("sig_match_flash_param_table: no match sub 1\n");
3755         return 0;
3756     }
3757     // follow
3758     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3759 
3760     // first call
3761     if(!insn_match_find_next(fw,is,8,match_bl_blximm)) {
3762         // printf("sig_match_flash_param_table: no match sub 1 bl\n");
3763         return 0;
3764     }
3765 
3766     // follow
3767     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3768     // first instruction should load address
3769     disasm_iter(fw,is);
3770     uint32_t adr=LDR_PC2val(fw,is->insn);
3771     if(!adr) {
3772         // printf("sig_match_flash_param_table: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
3773         return  0;
3774     }
3775     save_misc_val(rule->name,adr,0,(uint32_t)is->insn->address);
3776     return 1;
3777 }
3778 int sig_match_jpeg_count_str(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3779 {
3780     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
3781     if(!str_adr) {
3782         printf("sig_match_jpeg_count_str: failed to find ref %s\n",rule->ref_name);
3783         return  0;
3784     }
3785     // TODO should handle multiple instances of string
3786     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
3787     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
3788         // printf("sig_match_jpeg_count_str: str match 0x%"PRIx64"\n",is->insn->address);
3789         if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
3790             // printf("sig_match_jpeg_count_str: no match bl\n");
3791             continue;
3792         }
3793         if(!is_sig_call(fw,is,"sprintf_FW")) {
3794             // printf("sig_match_jpeg_count_str: not sprintf_FW at 0x%"PRIx64"\n",is->insn->address);
3795             continue;
3796         }
3797         // expect ptr in r0, str in r1
3798         uint32_t regs[4];
3799         if((get_call_const_args(fw,is,5,regs)&0x3)!=0x3) {
3800             // printf("sig_match_jpeg_count_str: failed to get sprintf args 0x%"PRIx64"\n",is->insn->address);
3801             continue;
3802         }
3803         if(regs[1] != str_adr) {
3804             // printf("sig_match_jpeg_count_str: expected r1 == 0x%08x not 0x%08x at 0x%"PRIx64"\n",str_adr, regs[1],is->insn->address);
3805             return 0;
3806         }
3807         if(!adr_is_var(fw,regs[0])) {
3808             // printf("sig_match_jpeg_count_str: r0 == 0x%08x not var ptr at 0x%"PRIx64"\n",regs[0],is->insn->address);
3809             return 0;
3810         }
3811         save_misc_val(rule->name,regs[0],0,(uint32_t)is->insn->address);
3812         return 1;
3813     }
3814     return 0;
3815 }
3816 
3817 // set a boolean misc val if ref is present
3818 int sig_match_misc_flag_named(__attribute__ ((unused))firmware *fw, __attribute__ ((unused))iter_state_t *is, sig_rule_t *rule)
3819 {
3820     uint32_t ref=get_saved_sig_val(rule->ref_name);
3821     save_misc_val(rule->name,(ref)?1:0,0,ref);
3822     return 1;
3823 }
3824 
3825 int sig_match_dry_memset(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3826 {
3827     if(!init_disasm_sig_ref(fw,is,rule)) {
3828         return 0;
3829     }
3830     if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
3831         printf("sig_match_dry_memset: no bl 1\n");
3832         return 0;
3833     }
3834     // follow
3835     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3836     if(!insn_match_find_nth(fw,is,12,3,match_bl_blximm)) {
3837         printf("sig_match_dry_memset: no match bl 2\n");
3838         return 0;
3839     }
3840     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3841 }
3842 
3843 int sig_match_dry_memzero(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3844 {
3845     if(!init_disasm_sig_ref(fw,is,rule)) {
3846         return 0;
3847     }
3848     if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
3849         printf("sig_match_dry_memset: no bl 1\n");
3850         return 0;
3851     }
3852     // follow
3853     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3854     if(!insn_match_find_next(fw,is,7,match_bl_blximm)) {
3855         printf("sig_match_dry_memset: no match bl 2\n");
3856         return 0;
3857     }
3858     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3859 }
3860 
3861 #if 0
3862 // alt match from dry_memset, doesn't pick up veneer
3863 int sig_match_dry_memzero(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3864 {
3865     if(!init_disasm_sig_ref(fw,is,rule)) {
3866         return 0;
3867     }
3868     const insn_match_t match_start[]={
3869         {MATCH_INS(AND, 3), {MATCH_OP_REG(R3),  MATCH_OP_REG(R2),   MATCH_OP_IMM(0xff)}},
3870         {MATCH_INS(ORR, 3), {MATCH_OP_REG(R2),  MATCH_OP_REG(R3),   MATCH_OP_REG(R3)}},
3871         {MATCH_INS(ORR, 3), {MATCH_OP_REG(R2),  MATCH_OP_REG(R2),   MATCH_OP_REG(R2)}},
3872         {MATCH_INS(B, 1), {MATCH_OP_IMM_ANY}},
3873         {ARM_INS_ENDING}
3874     };
3875     if(!insn_match_find_next_seq(fw,is,1,match_start)) {
3876         printf("sig_match_dry_memzero: no match start\n");
3877         return 0;
3878     }
3879     // dry_memset jumps into this function after the mov r2,0 - assumed ARM
3880     uint32_t adr = get_branch_call_insn_target(fw,is) - 4;
3881     disasm_iter_init(fw,is,adr);
3882     const insn_match_t match_mov_r2_0[]={
3883         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R2), MATCH_OP_IMM(0x0)}},
3884         {ARM_INS_ENDING}
3885     };
3886     if(!insn_match_find_next(fw,is,1,match_mov_r2_0)) {
3887         printf("sig_match_dry_memzero: no match mov\n");
3888         return 0;
3889     }
3890     return save_sig_with_j(fw,rule->name,adr);
3891 }
3892 #endif
3893 
3894 int sig_match_dry_memcpy_bytes(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3895 {
3896     if(!init_disasm_sig_ref(fw,is,rule)) {
3897         return 0;
3898     }
3899     if(!insn_match_find_next(fw,is,7,match_bl_blximm)) {
3900         printf("sig_match_dry_memcpy_bytes: no bl 1\n");
3901         return 0;
3902     }
3903     // follow
3904     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3905     // expect tail call to dry_memcpy_bytes
3906     const insn_match_t match_end[]={
3907         {MATCH_INS(POP, MATCH_OPCOUNT_IGNORE)},
3908         {MATCH_INS_CC(B,AL,MATCH_OPCOUNT_IGNORE)},
3909         {ARM_INS_ENDING}
3910     };
3911 
3912     if(!insn_match_find_next_seq(fw,is,20,match_end)) {
3913         printf("sig_match_dry_memcpy_bytes: no match end\n");
3914         return 0;
3915     }
3916     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3917 }
3918 
3919 
3920 int sig_match_cam_has_iris_diaphragm(__attribute__ ((unused))firmware *fw, __attribute__ ((unused))iter_state_t *is, sig_rule_t *rule)
3921 {
3922     uint32_t v;
3923     uint32_t ref=0;get_saved_sig_val(rule->ref_name);
3924     // ILC assumed to have iris
3925     if(get_misc_val_value("CAM_IS_ILC")) {
3926         v=1;
3927     } else {
3928         ref=get_saved_sig_val(rule->ref_name);
3929         v=(ref)?1:0;
3930     }
3931     save_misc_val(rule->name,v,0,ref);
3932     return 1;
3933 }
3934 
3935 int sig_match_cam_uncached_bit(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3936 {
3937     if(!init_disasm_sig_ref(fw,is,rule)) {
3938         return 0;
3939     }
3940     const insn_match_t match_bic_r0[]={
3941         {MATCH_INS(BIC, 3), {MATCH_OP_REG(R0),  MATCH_OP_REG(R0),   MATCH_OP_IMM_ANY}},
3942         {ARM_INS_ENDING}
3943     };
3944     if(insn_match_find_next(fw,is,4,match_bic_r0)) {
3945         save_misc_val(rule->name,is->insn->detail->arm.operands[2].imm,0,(uint32_t)is->insn->address);
3946         return 1;
3947     }
3948     return 0;
3949 }
3950 
3951 int sig_match_umalloc_strictly(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3952 {
3953     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
3954     if(!str_adr) {
3955         printf("sig_umalloc_strictly: %s failed to find ref %s\n",rule->name,rule->ref_name);
3956         return  0;
3957     }
3958 
3959     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
3960     if(!fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
3961         printf("sig_match_umalloc_strictly: faild to find ref insn\n");
3962         return 0;
3963     }
3964     if(is->insn->detail->arm.operands[0].reg != ARM_REG_R0) {
3965         printf("sig_match_umalloc_strictly: reg mismatch\n");
3966         return 0;
3967     }
3968     if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
3969         printf("sig_match_umalloc_strictly: no bl 1\n");
3970         return 0;
3971     }
3972     if(!is_sig_call(fw,is,"CreateTaskStrictly")) {
3973         printf("sig_match_umalloc_strictly: no CreateTaskStrictly\n");
3974         return 0;
3975     }
3976     // b included because usually tail call
3977     if(!insn_match_find_next(fw,is,6,match_b_bl_blximm)) {
3978         printf("sig_match_umalloc_strictly: no bl 1\n");
3979         return 0;
3980     }
3981     // follow
3982     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3983     if(!insn_match_find_next(fw,is,10,match_bl_blximm)) {
3984         printf("sig_match_umalloc_strictly: no bl 2\n");
3985         return 0;
3986     }
3987     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3988 }
3989 
3990 int sig_match_dcache_clean_flush_and_disable(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3991 {
3992     if(!init_disasm_sig_ref(fw,is,rule)) {
3993         return 0;
3994     }
3995     if(!find_next_sig_call(fw,is,44,"GetSRAndDisableInterrupt")) {
3996         printf("sig_match_dcache_clean_flush_and_disable: no GetSRAndDisableInterrupt\n");
3997         return 0;
3998     }
3999     if(!insn_match_find_next(fw,is,2,match_bl_blximm)) {
4000         printf("sig_match_dcache_clean_flush_and_disable: no bl\n");
4001         return 0;
4002     }
4003     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
4004 }
4005 
4006 int sig_match_get_rom_id(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4007 {
4008     if(!init_disasm_sig_ref(fw,is,rule)) {
4009         return 0;
4010     }
4011     // two variants, overlapping dryos versions
4012     if(!disasm_iter(fw,is)) {
4013         printf("sig_match_get_rom_id: disasm failed\n");
4014         return 0;
4015     }
4016     if(is->insn->id == ARM_INS_MOV) {
4017         if(!disasm_iter(fw,is)) {
4018             printf("sig_match_get_rom_id: disasm failed\n");
4019             return 0;
4020         }
4021         if(is->insn->id != ARM_INS_B) {
4022             printf("sig_match_get_rom_id: no b\n");
4023             return 0;
4024         }
4025     } else if(is->insn->id == ARM_INS_PUSH) {
4026         const insn_match_t match_seq[]={
4027             {MATCH_INS(MOV, 2), {MATCH_OP_REG_ANY,  MATCH_OP_REG_ANY}},
4028             {MATCH_INS(BL, 1), {MATCH_OP_IMM_ANY}},
4029             {MATCH_INS(MOV, 2), {MATCH_OP_REG_ANY,  MATCH_OP_REG_ANY}},
4030             {MATCH_INS(POP, MATCH_OPCOUNT_IGNORE)},
4031             {MATCH_INS(B, MATCH_OPCOUNT_IGNORE)},
4032             {ARM_INS_ENDING}
4033         };
4034         if(!insn_match_find_next_seq(fw,is,1,match_seq)) {
4035             printf("sig_match_get_rom_id: no seq\n");
4036             return 0;
4037         }
4038     } else {
4039         printf("sig_match_get_rom_id: no match first insn\n");
4040         return 0;
4041     }
4042     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
4043 }
4044 
4045 int sig_match_dcache_flush_and_enable(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4046 {
4047     if(!init_disasm_sig_ref(fw,is,rule)) {
4048         return 0;
4049     }
4050     if(!find_next_sig_call(fw,is,12,"GetSRAndDisableInterrupt")) {
4051         printf("sig_match_dcache_flush_and_enable: no GetSRAndDisableInterrupt\n");
4052         return 0;
4053     }
4054     if(!find_next_sig_call(fw,is,8,"dcache_clean_flush_and_disable")) {
4055         printf("sig_match_dcache_flush_and_enable: no dcache_clean_flush_and_disable\n");
4056         return 0;
4057     }
4058     // some variants have a call in between, others are inline, not dry version specific
4059     // expect SetSR just after sig_match_dcache_flush_and_enable
4060     if(!find_next_sig_call(fw,is,112,"SetSR")) {
4061         printf("sig_match_dcache_flush_and_enable: no SetSR\n");
4062         return 0;
4063     }
4064     // call should be 2 insns before, rewind
4065     disasm_iter_init(fw,is,adr_hist_get(&is->ah,2));
4066     disasm_iter(fw,is);
4067     uint32_t adr = get_branch_call_insn_target(fw,is);
4068     if(!adr) {
4069         printf("sig_match_dcache_flush_and_enable: no match call\n");
4070         return 0;
4071     }
4072     return save_sig_with_j(fw,rule->name,adr);
4073 }
4074 
4075 
4076 int sig_match_physw_event_table(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4077 {
4078     if(!init_disasm_sig_ref(fw,is,rule)) {
4079         return 0;
4080     }
4081     // expect first LDR pc
4082     if(!insn_match_find_next(fw,is,5,match_ldr_pc)) {
4083         printf("sig_match_physw_event_table: match LDR PC failed\n");
4084         return 0;
4085     }
4086     uint32_t adr=LDR_PC2val(fw,is->insn);
4087     if(!adr) {
4088         printf("sig_match_physw_event_table: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
4089         return 0;
4090     }
4091     if(!adr2ptr(fw,adr)) {
4092         printf("sig_match_physw_event_table: adr not ROM 0x%08x at 0x%"PRIx64"\n",adr,is->insn->address);
4093         return 0;
4094     }
4095     save_misc_val(rule->name,adr,0,(uint32_t)is->insn->address);
4096     return 1;
4097 }
4098 int sig_match_uiprop_count(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4099 {
4100     if(!init_disasm_sig_ref(fw,is,rule)) {
4101         return 0;
4102     }
4103     if(!find_next_sig_call(fw,is,38,"DebugAssert")) {
4104         // printf("sig_match_uiprop_count: no DebugAssert 1\n");
4105         return 0;
4106     }
4107     if(!find_next_sig_call(fw,is,14,"DebugAssert")) {
4108         // printf("sig_match_uiprop_count: no DebugAssert 2\n");
4109         return 0;
4110     }
4111     const insn_match_t match_bic_cmp[]={
4112         {MATCH_INS(BIC, 3), {MATCH_OP_REG_ANY,  MATCH_OP_REG_ANY,   MATCH_OP_IMM(0x8000)}},
4113         {MATCH_INS(CMP, 2), {MATCH_OP_REG_ANY,  MATCH_OP_ANY}},
4114         {ARM_INS_ENDING}
4115     };
4116     if(!insn_match_find_next_seq(fw,is,3,match_bic_cmp)) {
4117         // printf("sig_match_uiprop_count: no bic,cmp\n");
4118         return 0;
4119     }
4120     save_misc_val(rule->name,is->insn->detail->arm.operands[1].imm,0,(uint32_t)is->insn->address);
4121     return 1;
4122 }
4123 
4124 int sig_match_get_canon_mode_list(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4125 {
4126     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
4127     if(!str_adr) {
4128         printf("sig_match_get_canon_mode_list: failed to find ref %s\n",rule->ref_name);
4129         return  0;
4130     }
4131     uint32_t adr=0;
4132     // TODO should handle multiple instances of string
4133     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
4134     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
4135         // printf("sig_match_get_canon_mode_list: str match 0x%"PRIx64"\n",is->insn->address);
4136         if(!find_next_sig_call(fw,is,4,"LogCameraEvent")) {
4137             // printf("sig_match_get_canon_mode_list: no LogCameraEvent\n");
4138             continue;
4139         }
4140         // some cameras have a mov and an extra call
4141         if(!disasm_iter(fw,is)) {
4142             // printf("sig_match_get_canon_mode_list: disasm failed\n");
4143             return 0;
4144         }
4145         const insn_match_t match_mov_r0_1[]={
4146 #if CS_API_MAJOR < 4
4147             {MATCH_INS(MOVS, 2), {MATCH_OP_REG(R0),  MATCH_OP_IMM(1)}},
4148 #endif
4149             {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0),  MATCH_OP_IMM(1)}},
4150             {ARM_INS_ENDING}
4151         };
4152         if(insn_match_any(is->insn,match_mov_r0_1)) {
4153             if(!insn_match_find_nth(fw,is,2,2,match_bl_blximm)) {
4154                 // printf("sig_match_get_canon_mode_list: no match bl 1x\n");
4155                 continue;
4156             }
4157         } else {
4158             if(!insn_match_any(is->insn,match_bl_blximm)) {
4159                 // printf("sig_match_get_canon_mode_list: no match bl 1\n");
4160                 continue;
4161             }
4162         }
4163         // found something to follow, break
4164         adr=get_branch_call_insn_target(fw,is);
4165         break;
4166     }
4167     if(!adr) {
4168         return 0;
4169     }
4170     // printf("sig_match_get_canon_mode_list: sub 1 0x%08x\n",adr);
4171     disasm_iter_init(fw,is,adr);
4172     if(!find_next_sig_call(fw,is,40,"TakeSemaphoreStrictly")) {
4173         // printf("sig_match_get_canon_mode_list: no TakeSemaphoreStrictly\n");
4174         return 0;
4175     }
4176     // match second call
4177     if(!insn_match_find_nth(fw,is,12,2,match_b_bl_blximm)) {
4178         // printf("sig_match_get_canon_mode_list: no match bl 2\n");
4179         return 0;
4180     }
4181     // follow
4182     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
4183     const insn_match_t match_loop[]={
4184         {MATCH_INS(ADD, 3), {MATCH_OP_REG_ANY,  MATCH_OP_REG_ANY,   MATCH_OP_IMM(1)}},
4185         {MATCH_INS(UXTH, 2), {MATCH_OP_REG_ANY,  MATCH_OP_REG_ANY}},
4186         {MATCH_INS(CMP, 2), {MATCH_OP_REG_ANY,  MATCH_OP_IMM_ANY}},
4187         {MATCH_INS_CC(B,LO,MATCH_OPCOUNT_IGNORE)},
4188         {ARM_INS_ENDING}
4189     };
4190     if(!insn_match_find_next_seq(fw,is,64,match_loop)) {
4191         // printf("sig_match_get_canon_mode_list: match 1 failed\n");
4192         return 0;
4193     }
4194     if(!insn_match_find_next(fw,is,2,match_bl_blximm)) {
4195         // printf("sig_match_get_canon_mode_list: no match bl 3\n");
4196         return 0;
4197     }
4198     // should be func
4199     adr=get_branch_call_insn_target(fw,is);
4200     // sanity check
4201     disasm_iter_init(fw,is,adr);
4202     const insn_match_t match_ldr_r0_ret[]={
4203         {MATCH_INS(LDR, 2),   {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(PC)}},
4204         {MATCH_INS(BX, 1),   {MATCH_OP_REG(LR)}},
4205         {ARM_INS_ENDING}
4206     };
4207     if(!insn_match_find_next_seq(fw,is,1,match_ldr_r0_ret)) {
4208         // printf("sig_match_get_canon_mode_list: match 2 failed\n");
4209         return 0;
4210     }
4211     return save_sig_with_j(fw,rule->name,adr);
4212 }
4213 
4214 int sig_match_zoom_busy(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4215 {
4216     if(!init_disasm_sig_ref(fw,is,rule)) {
4217         return 0;
4218     }
4219     // first call
4220     if(!insn_match_find_next(fw,is,5,match_bl_blximm)) {
4221         // printf("sig_match_zoom_busy: no match bl\n");
4222         return 0;
4223     }
4224     // follow
4225     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
4226     // get base address from first LDR PC
4227     if(!insn_match_find_next(fw,is,5,match_ldr_pc)) {
4228         // printf("sig_match_zoom_busy: match LDR PC failed\n");
4229         return 0;
4230     }
4231     uint32_t base=LDR_PC2val(fw,is->insn);
4232     arm_reg rb=is->insn->detail->arm.operands[0].reg;
4233 
4234     // look for first TakeSemaphoreStrictly
4235     if(!find_next_sig_call(fw,is,40,"TakeSemaphoreStrictly")) {
4236         // printf("sig_match_zoom_busy: no match TakeSemaphoreStrictly\n");
4237         return 0;
4238     }
4239     if(!disasm_iter(fw,is)) {
4240         // printf("sig_match_zoom_busy: disasm failed\n");
4241         return 0;
4242     }
4243     // assume next instruction is ldr
4244     if(is->insn->id != ARM_INS_LDR
4245         || is->insn->detail->arm.operands[0].reg != ARM_REG_R0
4246         || is->insn->detail->arm.operands[1].mem.base != rb) {
4247         // printf("sig_match_zoom_busy: no match LDR\n");
4248         return 0;
4249     }
4250     save_misc_val(rule->name,base,is->insn->detail->arm.operands[1].mem.disp,(uint32_t)is->insn->address);
4251     return 1;
4252 }
4253 
4254 int sig_match_focus_busy(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4255 {
4256     if(!init_disasm_sig_ref(fw,is,rule)) {
4257         return 0;
4258     }
4259     // look for first TakeSemaphore
4260     if(!find_next_sig_call(fw,is,40,"TakeSemaphore")) {
4261         // printf("sig_match_focus_busy: no match TakeSemaphore\n");
4262         return 0;
4263     }
4264     // next call
4265     if(!insn_match_find_next(fw,is,5,match_bl_blximm)) {
4266         // printf("sig_match_focus_busy: no match bl\n");
4267         return 0;
4268     }
4269     // follow
4270     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
4271     // get base address from first LDR PC
4272     if(!insn_match_find_next(fw,is,5,match_ldr_pc)) {
4273         // printf("sig_match_focus_busy: match LDR PC failed\n");
4274         return 0;
4275     }
4276     uint32_t base=LDR_PC2val(fw,is->insn);
4277     arm_reg rb=is->insn->detail->arm.operands[0].reg;
4278 
4279     // look for first TakeSemaphoreStrictly
4280     if(!find_next_sig_call(fw,is,50,"TakeSemaphoreStrictly")) {
4281         // printf("sig_match_focus_busy: no match TakeSemaphoreStrictly\n");
4282         return 0;
4283     }
4284     const insn_match_t match_ldr[]={
4285         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0), MATCH_OP_MEM_ANY}},
4286         {MATCH_INS(CBZ, 2), {MATCH_OP_REG(R0), MATCH_OP_IMM_ANY}},
4287         {ARM_INS_ENDING}
4288     };
4289     if(!insn_match_find_next_seq(fw,is,10,match_ldr)) {
4290         // printf("sig_match_focus_busy: no match LDR\n");
4291         return 0;
4292     }
4293     // rewind to LDR
4294     disasm_iter_init(fw,is,adr_hist_get(&is->ah,1));
4295     disasm_iter(fw,is);
4296     // check LDR
4297     if(is->insn->detail->arm.operands[1].mem.base != rb) {
4298         // printf("sig_match_focus_busy: no match LDR base\n");
4299         return 0;
4300     }
4301     save_misc_val(rule->name,base,is->insn->detail->arm.operands[1].mem.disp,(uint32_t)is->insn->address);
4302     return 1;
4303 }
4304 int sig_match_aram_size(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4305 {
4306     if(!init_disasm_sig_ref(fw,is,rule)) {
4307         printf("sig_match_aram_size: missing ref\n");
4308         return 0;
4309     }
4310     const insn_match_t match_ldr_r0_sp_cmp[]={
4311         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0),MATCH_OP_MEM(SP,INVALID,0xc)}},
4312         {MATCH_INS(CMP, 2), {MATCH_OP_REG(R0),MATCH_OP_IMM_ANY}},
4313         {ARM_INS_ENDING}
4314     };
4315     if(!insn_match_find_next_seq(fw,is,15,match_ldr_r0_sp_cmp)) {
4316         printf("sig_match_aram_size: no match LDR\n");
4317         return 0;
4318     }
4319     uint32_t val=is->insn->detail->arm.operands[1].imm;
4320     if(val != 0x22000 && val != 0x32000) {
4321         printf("sig_match_aram_size: unexpected ARAM size 0x%08x\n",val);
4322     }
4323     save_misc_val(rule->name,val,0,(uint32_t)is->insn->address);
4324     return 1;
4325 }
4326 
4327 int sig_match_aram_size_gt58(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4328 {
4329     if(!init_disasm_sig_ref(fw,is,rule)) {
4330         printf("sig_match_aram_size: missing ref\n");
4331         return 0;
4332     }
4333     const insn_match_t match_ldrd_r0r1_mov[]={
4334         {MATCH_INS(LDRD, 3), {MATCH_OP_REG(R0),MATCH_OP_REG(R1),MATCH_OP_MEM(SP,INVALID,0x10)}},
4335         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R2),MATCH_OP_IMM_ANY}},
4336         {ARM_INS_ENDING}
4337     };
4338     // d7? variant
4339     const insn_match_t match_ldrd_r2r1_mov[]={
4340         {MATCH_INS(LDRD, 3), {MATCH_OP_REG(R2),MATCH_OP_REG(R1),MATCH_OP_MEM(SP,INVALID,0x10)}},
4341         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R3),MATCH_OP_IMM_ANY}},
4342         {ARM_INS_ENDING}
4343     };
4344     if(!insn_match_find_next_seq(fw,is,15,match_ldrd_r0r1_mov)) {
4345         init_disasm_sig_ref(fw,is,rule); // reset to start
4346         if(!insn_match_find_next_seq(fw,is,15,match_ldrd_r2r1_mov)) {
4347             printf("sig_match_aram_size: no match LDR\n");
4348         }
4349         return 0;
4350     }
4351     uint32_t val=is->insn->detail->arm.operands[1].imm;
4352     if(val != 0x22000 && val != 0x32000) {
4353         printf("sig_match_aram_size: unexpected ARAM size 0x%08x\n",val);
4354     }
4355     save_misc_val(rule->name,val,0,(uint32_t)is->insn->address);
4356     return 1;
4357 }
4358 
4359 int sig_match_aram_start(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4360 {
4361     if(!init_disasm_sig_ref(fw,is,rule)) {
4362         printf("sig_match_aram_start: missing ref\n");
4363         return 0;
4364     }
4365     if(!find_next_sig_call(fw,is,50,"DebugAssert")) {
4366         printf("sig_aram_start: no match DebugAssert\n");
4367         return 0;
4368     }
4369     const insn_match_t match_cmp_bne_ldr[]={
4370         {MATCH_INS(CMP, 2), {MATCH_OP_REG(R1),MATCH_OP_IMM(0)}},
4371         {MATCH_INS_CC(B,NE,MATCH_OPCOUNT_IGNORE)},
4372         {MATCH_INS(LDR, 2), {MATCH_OP_REG_ANY,MATCH_OP_MEM_BASE(PC)}},
4373         {ARM_INS_ENDING}
4374     };
4375     if(!insn_match_find_next_seq(fw,is,15,match_cmp_bne_ldr)) {
4376         printf("sig_match_aram_start: no match CMP\n");
4377         return 0;
4378     }
4379     uint32_t adr=LDR_PC2val(fw,is->insn);
4380     if(!adr) {
4381         printf("sig_match_aram_start: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
4382         return 0;
4383     }
4384     // could sanity check that it looks like a RAM address
4385     save_misc_val(rule->name,adr,0,(uint32_t)is->insn->address);
4386     return 1;
4387 }
4388 
4389 int sig_match_aram_start2(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4390 {
4391     if (get_misc_val_value("ARAM_HEAP_START"))
4392         return 0;
4393 
4394     if(!init_disasm_sig_ref(fw,is,rule)) {
4395         printf("sig_match_aram_start: missing ref\n");
4396         return 0;
4397     }
4398     if(!find_next_sig_call(fw,is,60,"DebugAssert")) {
4399         printf("sig_aram_start2: no match DebugAssert\n");
4400         return 0;
4401     }
4402     const insn_match_t match_cmp_bne_ldr[]={
4403         {MATCH_INS(CMP, 2), {MATCH_OP_REG(R1),MATCH_OP_IMM(0)}},
4404         {MATCH_INS_CC(B,NE,MATCH_OPCOUNT_IGNORE)},
4405         {MATCH_INS(LDR, 2), {MATCH_OP_REG_ANY,MATCH_OP_MEM_BASE(SP)}},
4406         {MATCH_INS(LDR, 2), {MATCH_OP_REG_ANY,MATCH_OP_MEM_BASE(PC)}},
4407         {ARM_INS_ENDING}
4408     };
4409     if(!insn_match_find_next_seq(fw,is,15,match_cmp_bne_ldr)) {
4410         printf("sig_match_aram_start2: no match CMP\n");
4411         return 0;
4412     }
4413     uint32_t adr=LDR_PC2val(fw,is->insn);
4414     if(!adr) {
4415         printf("sig_match_aram_start2: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
4416         return 0;
4417     }
4418     // could sanity check that it looks like a RAM address
4419     save_misc_val(rule->name,adr,0,(uint32_t)is->insn->address);
4420     return 1;
4421 }
4422 
4423 int sig_match_icache_flush_range(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4424 {
4425     if(!init_disasm_sig_ref(fw,is,rule)) {
4426         printf("sig_match_icache_flush_range: missing ref\n");
4427         return 0;
4428     }
4429     if(!find_next_sig_call(fw,is,60,"DebugAssert")) {
4430         printf("sig_icache_flush_range: no match DebugAssert\n");
4431         return 0;
4432     }
4433     if(!find_next_sig_call(fw,is,44,"dcache_flush_range")) {
4434         printf("sig_icache_flush_range: no match DebugAssert\n");
4435         return 0;
4436     }
4437     if(!insn_match_find_next(fw,is,5,match_bl_blximm)) {
4438         printf("sig_icache_flush_range: bl match failed at 0x%"PRIx64"\n",is->insn->address);
4439         return 0;
4440     }
4441     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
4442 }
4443 
4444 int sig_match__nrflag(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4445 {
4446     if(!init_disasm_sig_ref(fw,is,rule)) {
4447         return 0;
4448     }
4449     uint32_t fadr=is->adr;
4450     // find range check on input arg
4451     const insn_match_t match_cmp_b[]={
4452         {MATCH_INS(CMP, 2), {MATCH_OP_REG(R0),MATCH_OP_IMM_ANY}},
4453         {MATCH_INS(B,MATCH_OPCOUNT_IGNORE)}, // blo or blt may be used, so don't include cond
4454         {ARM_INS_ENDING}
4455     };
4456     if(!insn_match_find_next_seq(fw,is,4,match_cmp_b) || is->insn->detail->arm.cc == ARM_CC_AL) {
4457         printf("sig_match__nrflag: no match CMP\n");
4458         return 0;
4459     }
4460     // follow
4461     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
4462     if(!disasm_iter(fw,is)) {
4463         printf("sig_match__nrflag: disasm failed\n");
4464         return 0;
4465     }
4466     // assume next is base addres
4467     uint32_t adr=LDR_PC2val(fw,is->insn);
4468     if(!adr) {
4469         printf("sig_match__nrflag: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
4470         return 0;
4471     }
4472     arm_reg reg_base = is->insn->detail->arm.operands[0].reg; // reg value was loaded into
4473     if(!disasm_iter(fw,is)) {
4474         printf("sig_match__nrflag: disasm failed\n");
4475         return 0;
4476     }
4477     // firmware may use add/sub to get actual firmware base address
4478     if(isADDx_imm(is->insn) || isSUBx_imm(is->insn)) {
4479         if((arm_reg)is->insn->detail->arm.operands[0].reg != reg_base) {
4480             printf("sig_match__nrflag: no match ADD/SUB\n");
4481             return 0;
4482         }
4483         if(isADDx_imm(is->insn)) {
4484             adr+=is->insn->detail->arm.operands[1].imm;
4485         } else {
4486             adr-=is->insn->detail->arm.operands[1].imm;
4487         }
4488         if(!disasm_iter(fw,is)) {
4489             printf("sig_match__nrflag: disasm failed\n");
4490             return 0;
4491         }
4492     }
4493     if(is->insn->id != ARM_INS_STR || (arm_reg)is->insn->detail->arm.operands[1].reg != reg_base) {
4494         printf("sig_match__nrflag: no match STR\n");
4495         return 0;
4496     }
4497     uint32_t disp = is->insn->detail->arm.operands[1].mem.disp;
4498     save_misc_val(rule->name,adr,disp,fadr);
4499     return 1;
4500 }
4501 // get the address used by a function that does something like
4502 // ldr rx =base
4503 // ldr r0 [rx, offset]
4504 // bx lr
4505 int sig_match_var_struct_get(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4506 {
4507     if(!init_disasm_sig_ref(fw,is,rule)) {
4508         return 0;
4509     }
4510     uint32_t fadr=is->adr;
4511     var_ldr_desc_t desc;
4512     if(!find_and_get_var_ldr(fw, is, 1, 4, ARM_REG_R0, &desc)) {
4513         printf("sig_match_var_struct_get: no match ldr\n");
4514         return 0;
4515     }
4516     if(!disasm_iter(fw,is)) {
4517         printf("sig_match_var_struct_get: disasm failed\n");
4518         return 0;
4519     }
4520     // TODO could check for other RET type instructions
4521     if(!insn_match(is->insn,match_bxlr)) {
4522         printf("sig_match_var_struct_get: no match BX LR\n");
4523         return 0;
4524     }
4525     save_misc_val(rule->name,desc.adr_adj,desc.off,fadr);
4526     return 1;
4527 }
4528 
4529 // get the address used by a function that does
4530 // ldr r1 =base
4531 // ldr r1 [rx, offset]
4532 // bx r1
4533 int sig_match_ui_mem_func_ptr(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4534 {
4535     if(!init_disasm_sig_ref(fw,is,rule)) {
4536         return 0;
4537     }
4538     uint32_t fadr=is->adr;
4539     var_ldr_desc_t desc;
4540     if(!find_and_get_var_ldr(fw, is, 1, 4, ARM_REG_R1, &desc)) {
4541         printf("sig_match_var_struct_get: no match ldr\n");
4542         return 0;
4543     }
4544     if(!disasm_iter(fw,is)) {
4545         printf("sig_match_var_struct_get: disasm failed\n");
4546         return 0;
4547     }
4548     const insn_match_t match_bx_r1[]={
4549         {MATCH_INS(BX,   1),  {MATCH_OP_REG(R1),}},
4550         {ARM_INS_ENDING}
4551     };
4552 
4553     // TODO could check for other RET type instructions
4554     if(!insn_match(is->insn,match_bx_r1)) {
4555         printf("sig_match_var_struct_get: no match BX R1\n");
4556         return 0;
4557     }
4558     save_misc_val(rule->name,desc.adr_adj,desc.off,fadr);
4559     return 1;
4560 }
4561 
4562 // get the sig from the memory addressed by specified stubs_misc
4563 int sig_match_func_ptr_val(firmware *fw, __attribute__ ((unused))iter_state_t *is, sig_rule_t *rule)
4564 {
4565     uint32_t adr = get_misc_val_value(rule->ref_name);
4566     if(!adr) {
4567         return 0;
4568     }
4569     uint32_t *vp = (uint32_t *)adr2ptr_with_data(fw,adr);
4570     if(!vp) {
4571         return 0;
4572     }
4573     return save_sig_with_j(fw,rule->name,*vp);
4574 }
4575 
4576 
4577 int sig_match_av_over_sem(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4578 {
4579     // don't bother on ND-only cams
4580     if(!get_misc_val_value("CAM_HAS_IRIS_DIAPHRAGM")) {
4581         return 0;
4582     }
4583 
4584     if(!init_disasm_sig_ref(fw,is,rule)) {
4585         return 0;
4586     }
4587     if(!find_next_sig_call(fw,is,30,"TakeSemaphore")) {
4588         printf("sig_match_av_over_sem: no match TakeSemaphore at 0x%"PRIx64"\n",is->insn->address);
4589         return 0;
4590     }
4591 
4592     // rewind 5 ins
4593     disasm_iter_init(fw,is,adr_hist_get(&is->ah,5));
4594     var_ldr_desc_t desc;
4595     if(!find_and_get_var_ldr(fw, is, 3, 4, ARM_REG_R0, &desc)) {
4596         printf("sig_match_av_over_sem: no match ldr at 0x%"PRIx64"\n",is->insn->address);
4597         return 0;
4598     }
4599 
4600     save_misc_val(rule->name,desc.adr_adj,desc.off,(uint32_t)is->insn->address);
4601     return 1;
4602 }
4603 
4604 int sig_match_canon_menu_active(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4605 {
4606     if(!init_disasm_sig_ref(fw,is,rule)) {
4607         return 0;
4608     }
4609     var_ldr_desc_t desc;
4610     if(!find_and_get_var_ldr(fw, is, 2, 4, ARM_REG_R0, &desc)) {
4611         printf("sig_match_canon_menu_active: no match ldr at 0x%"PRIx64"\n",is->insn->address);
4612         return 0;
4613     }
4614     if(!disasm_iter(fw,is)) {
4615         printf("sig_match_canon_menu_active: disasm failed\n");
4616         return 0;
4617     }
4618     if(is->insn->id != ARM_INS_CMP) {
4619         printf("sig_match_canon_menu_active: no match cmp at 0x%"PRIx64"\n",is->insn->address);
4620         return 0;
4621     }
4622     save_misc_val(rule->name,desc.adr_adj,desc.off,(uint32_t)is->insn->address);
4623     return 1;
4624 }
4625 
4626 int sig_match_file_counter_init(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4627 {
4628     if(!init_disasm_sig_ref(fw,is,rule)) {
4629         return 0;
4630     }
4631     // find first call
4632     if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
4633         // printf("sig_match_file_counter_init: bl match 1 failed at 0x%"PRIx64"\n",is->insn->address);
4634         return 0;
4635     }
4636     // some cameras (dry 58+?) have a nullsub before the function of interest
4637     if(check_simple_func(fw,get_branch_call_insn_target(fw,is),MATCH_SIMPLE_FUNC_NULLSUB,NULL)) {
4638         if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
4639             // printf("sig_match_file_counter_init: bl match 1a failed at 0x%"PRIx64"\n",is->insn->address);
4640             return 0;
4641         }
4642     }
4643     // follow
4644     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
4645     if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
4646         // printf("sig_match_file_counter_init: bl match 2 failed at 0x%"PRIx64"\n",is->insn->address);
4647         return 0;
4648     }
4649     uint32_t fadr = get_branch_call_insn_target(fw,is);
4650     // follow
4651     disasm_iter_init(fw,is,fadr);
4652     if(!disasm_iter(fw,is)) {
4653         // printf("sig_match_file_counter_init: disasm failed\n");
4654         return 0;
4655     }
4656     // sanity check
4657     if(!isLDR_PC(is->insn)) {
4658         // printf("sig_match_file_counter_init: no match LDR PC at 0x%"PRIx64"\n",is->insn->address);
4659         return 0;
4660     }
4661     // function we're looking for
4662     return save_sig_with_j(fw,rule->name,fadr);
4663 }
4664 int sig_match_file_counter_var(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4665 {
4666     if(!init_disasm_sig_ref(fw,is,rule)) {
4667         return 0;
4668     }
4669     uint32_t adr=LDR_PC2val(fw,is->insn);
4670     if(!adr) {
4671         // printf("sig_match_file_counter_var: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
4672         return 0;
4673     }
4674     if(is->insn->detail->arm.operands[0].reg != ARM_REG_R0) {
4675         // printf("sig_match_file_counter_var: not R0 0x%"PRIx64"\n",is->insn->address);
4676         return 0;
4677     }
4678     if(!adr_is_var(fw,adr)) {
4679         // printf("sig_match_file_counter_var: not a data address 0x%08x at 0x%"PRIx64"\n",adr,is->insn->address);
4680         return 0;
4681     }
4682     save_misc_val(rule->name,adr,0,(uint32_t)is->insn->address);
4683     return 1;
4684 }
4685 
4686 int sig_match_palette_vars(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4687 {
4688     if(!init_disasm_sig_ref(fw,is,rule)) {
4689         return 0;
4690     }
4691     if(!find_next_sig_call(fw,is,70,"transfer_src_overlay")) {
4692         printf("sig_match_palette_vars: no match transfer_src_overlay\n");
4693         return 0;
4694     }
4695     uint32_t fadr=0;
4696     int i;
4697     // search backwards for call before transfer_src_overlay
4698     for(i=1; i<=6; i++) {
4699         if(!fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i))) {
4700             printf("sig_match_palette_vars: disasm failed\n");
4701             return 0;
4702         }
4703         fadr=get_branch_call_insn_target(fw,fw->is);
4704         if(fadr) {
4705             break;
4706         }
4707    }
4708    if(!fadr) {
4709         printf("sig_match_palette_vars: no match bl 1 0x%"PRIx64"\n",fw->is->insn->address);
4710         return 0;
4711    }
4712     // follow
4713     disasm_iter_init(fw,is,fadr);
4714     // find first func call
4715     if(!insn_match_find_next(fw,is,3,match_bl)) {
4716         printf("sig_match_palette_vars: no match bl 2 0x%"PRIx64"\n",is->insn->address);
4717         return 0;
4718     }
4719     // follow
4720     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
4721 
4722     if(!insn_match_find_next(fw,is,3,match_ldr_pc)) {
4723         printf("sig_match_palette_vars: no match ldr pc 0x%"PRIx64"\n",is->insn->address);
4724         return 0;
4725     }
4726 
4727     uint32_t pal_base=LDR_PC2val(fw,is->insn);
4728     if(!pal_base || !adr_is_var(fw,pal_base)) {
4729         printf("sig_match_palette_vars: bad LDR PC 0x%"PRIx64"\n",is->insn->address);
4730         return 0;
4731     }
4732     // palette_control is at the start of struct, save register
4733     arm_reg ptr_reg = is->insn->detail->arm.operands[0].reg;
4734 
4735     save_misc_val(rule->name,pal_base,0,(uint32_t)is->insn->address);
4736 
4737     int found=0;
4738     // find LDR Rn  [ptr_reg +x]
4739     for(i=0; i<3; i++) {
4740         if(!disasm_iter(fw,is)) {
4741             printf("sig_match_palette_vars: disasm failed\n");
4742             return 0;
4743         }
4744         if (is->insn->id == ARM_INS_LDR && is->insn->detail->arm.operands[1].mem.base == ptr_reg) {
4745             save_misc_val("active_palette_buffer",
4746                         pal_base,
4747                         is->insn->detail->arm.operands[1].mem.disp,
4748                         (uint32_t)is->insn->address);
4749             found=1;
4750             break;
4751         }
4752     }
4753     if(!found) {
4754         printf("sig_match_palette_vars: no match active_palette_buffer 0x%"PRIx64"\n",is->insn->address);
4755         return 0;
4756     }
4757 
4758     if(!find_next_sig_call(fw,is,20,"PTM_RestoreUIProperty_FW")) {
4759         printf("sig_match_palette_vars: no match PTM_RestoreUIProperty_FW\n");
4760         return 0;
4761     }
4762     // find LDR Rn  [ptr_reg +x]
4763     for(i=0; i<6; i++) {
4764         if(!disasm_iter(fw,is)) {
4765             printf("sig_match_palette_vars: disasm failed\n");
4766             return 0;
4767         }
4768         if (is->insn->id == ARM_INS_LDR && is->insn->detail->arm.operands[1].mem.base == ptr_reg) {
4769             save_misc_val("palette_buffer_ptr",
4770                         pal_base,
4771                         is->insn->detail->arm.operands[1].mem.disp,
4772                         (uint32_t)is->insn->address);
4773             return 1;
4774         }
4775     }
4776     printf("sig_match_palette_vars: no match palette_buffer_ptr 0x%"PRIx64"\n",is->insn->address);
4777     return 0;
4778 }
4779 
4780 int sig_match_live_free_cluster_count(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4781 {
4782     if(!init_disasm_sig_ref(fw,is,rule)) {
4783         return 0;
4784     }
4785 
4786     // find third function call
4787     if(!insn_match_find_nth(fw,is,22,3,match_bl_blximm)) {
4788         printf("sig_match_live_free_cluster_count: no match bl1 0x%"PRIx64"\n",is->insn->address);
4789         return 0;
4790     }
4791     // follow
4792     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
4793 
4794     if(!find_next_sig_call(fw,is,20,"get_fstype")) {
4795         printf("sig_match_live_free_cluster_count: no get_fstype 0x%"PRIx64"\n",is->insn->address);
4796         return 0;
4797     }
4798 
4799     // find second function call
4800     if(!insn_match_find_nth(fw,is,12,2,match_bl_blximm)) {
4801         printf("sig_match_live_free_cluster_count: no match bl2 0x%"PRIx64"\n",is->insn->address);
4802         return 0;
4803     }
4804 
4805     // follow
4806     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
4807 
4808     // find second LDR [pc ..]
4809     if(!insn_match_find_next(fw,is,3,match_ldr_pc)) {
4810         printf("sig_match_live_free_cluster_count: no match ldr1 0x%"PRIx64"\n",is->insn->address);
4811         return 0;
4812     }
4813 
4814     if(!insn_match_find_next(fw,is,3,match_ldr_pc)) {
4815         printf("sig_match_live_free_cluster_count: no match ldr2 0x%"PRIx64"\n",is->insn->address);
4816         return 0;
4817     }
4818     uint32_t base = LDR_PC2val(fw,is->insn);
4819 
4820     if(!find_next_sig_call(fw,is,16,"takesemaphore_low")) {
4821         printf("sig_match_live_free_cluster_count: no takesemaphore_low 0x%"PRIx64"\n",is->insn->address);
4822         return 0;
4823     }
4824     const insn_match_t match_ldr_ldrd[]={
4825         {MATCH_INS(LDR,   2),  {MATCH_OP_REG_ANY, MATCH_OP_ANY}},
4826         {MATCH_INS(LDRD,   3),  {MATCH_OP_REG_ANY, MATCH_OP_REG_ANY, MATCH_OP_ANY}},
4827         {ARM_INS_ENDING}
4828     };
4829 
4830     if(!insn_match_find_next_seq(fw,is,50,match_ldr_ldrd)) {
4831         printf("sig_match_live_free_cluster_count: no match ldrd 0x%"PRIx64"\n",is->insn->address);
4832         return 0;
4833     }
4834     // +4 because var is 2nd word of ldrd load
4835     save_misc_val(rule->name,base,is->insn->detail->arm.operands[2].mem.disp + 4,(uint32_t)is->insn->address);
4836     return 1;
4837 
4838 }
4839 
4840 int sig_match_debug_logging_ptr(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4841 {
4842     uint32_t call_adr = find_str_arg_call(fw,is,rule);
4843     if(!call_adr) {
4844         printf("sig_match_debug_logging_ptr: no match call\n");
4845         return 0;
4846     }
4847     // is should be pointing at bx instruction, get the register being called
4848     arm_reg call_reg = is->insn->detail->arm.operands[0].reg;
4849 
4850     // backtrack until we find ldr into reg
4851     int i;
4852     for(i=1; i<10; i++) {
4853         fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i));
4854         cs_insn *insn=fw->is->insn;
4855         if((arm_reg)insn->detail->arm.operands[0].reg != call_reg || insn->id == ARM_INS_CMP ) {
4856             continue;
4857         }
4858         // LDR into target reg
4859         if(insn->id == ARM_INS_LDR && insn->detail->arm.operands[1].type == ARM_OP_MEM) {
4860             arm_reg base_reg = (arm_reg)insn->detail->arm.operands[1].reg;
4861             int disp = insn->detail->arm.operands[1].mem.disp;
4862             i++;
4863             // backtrack one more (assume no gap)
4864             fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i));
4865             uint32_t adr = LDR_PC2val(fw,fw->is->insn);
4866             if(!adr || (arm_reg)fw->is->insn->detail->arm.operands[0].reg != base_reg) {
4867                 printf("sig_match_debug_logging_ptr: no match ldr2 0x%x 0x%"PRIx64"\n",adr,fw->is->insn->address);
4868                 return 0;
4869             }
4870             save_misc_val(rule->name,adr + disp,disp,(uint32_t)fw->is->insn->address);
4871             return 1;
4872         }
4873         printf("sig_match_debug_logging_ptr: reg clobbered 0x%"PRIx64"\n",fw->is->insn->address);
4874         return 0;
4875     }
4876     printf("sig_match_debug_logging_ptr: no match ldr 0x%"PRIx64"\n",fw->is->insn->address);
4877     return 0;
4878 }
4879 
4880 int sig_match_debug_logging_flag(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4881 {
4882     if(!find_str_arg_call(fw,is,rule)) {
4883         printf("sig_match_debug_logging_flag: no match call\n");
4884         return 0;
4885     }
4886     if(!insn_match_find_next(fw,is,8,match_ldr_pc)) {
4887         printf("sig_match_debug_logging_flag: no match ldr pc 0x%"PRIx64"\n",is->insn->address);
4888         return 0;
4889     }
4890     uint32_t adr = LDR_PC2val(fw,is->insn);
4891     if(!disasm_iter(fw,is)) {
4892         printf("sig_match_debug_logging_flag: disasm failed\n");
4893         return 0;
4894     }
4895     arm_reg base_reg = (arm_reg)is->insn->detail->arm.operands[1].reg;
4896     uint32_t ref_adr = (uint32_t)is->insn->address;
4897     if (fw->arch_flags & FW_ARCH_FL_VMSA) {
4898         if(is->insn->id != ARM_INS_LDRB) {
4899             printf("sig_match_debug_logging_flag: no match ldrb 0x%"PRIx64"\n",is->insn->address);
4900             return 0;
4901         }
4902     } else {
4903         if(is->insn->id != ARM_INS_LDR) {
4904             printf("sig_match_debug_logging_flag: no match ldr 0x%"PRIx64"\n",is->insn->address);
4905             return 0;
4906         }
4907     }
4908     if((arm_reg)is->insn->detail->arm.operands[1].reg != base_reg) {
4909         printf("sig_match_debug_logging_flag: no match reg 0x%"PRIx64"\n",is->insn->address);
4910         return 0;
4911     }
4912     int disp = (arm_reg)is->insn->detail->arm.operands[1].mem.disp;
4913     if(!disasm_iter(fw,is)) {
4914         printf("sig_match_debug_logging_flag: disasm failed\n");
4915         return 0;
4916     }
4917     if(is->insn->id != ARM_INS_LSL) {
4918         printf("sig_match_debug_logging_flag: no match lsl\n");
4919         return 0;
4920     }
4921     save_misc_val(rule->name,adr + disp,disp,ref_adr);
4922     return 1;
4923 }
4924 int sig_match_mzrm_sendmsg_ret_adr(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4925 {
4926     if(!find_str_arg_call(fw,is,rule)) {
4927         printf("sig_match_mzrm_sendmsg_ret_adr: no match call\n");
4928         return 0;
4929     }
4930     if(!disasm_iter(fw,is)) {
4931         printf("sig_match_mzrm_sendmsg_ret_adr: disasm failed\n");
4932         return 0;
4933     }
4934     // address after blx, thumb bit set for current state
4935     save_misc_val(rule->name,(uint32_t)is->insn->address | is->thumb,0,0);
4936     return 1;
4937 }
4938 
4939 int sig_match_fw_yuv_layer_buf_52(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4940 {
4941     if(!init_disasm_sig_ref(fw,is,rule)) {
4942         return 0;
4943     }
4944     // code may have an unconditional branch which find_next_sig_call thinks is a veneer
4945     if(!find_next_sig_call_ex(fw,is,54,"get_displaytype",FIND_SIG_CALL_NO_UNK_VENEER)) {
4946         printf("sig_match_fw_yuv_layer_buf_52: no match get_displaytype\n");
4947         return 0;
4948     }
4949     printf("match get_displaytype 0x%"PRIx64"\n",is->insn->address);
4950     if(!insn_match_find_nth(fw,is,14,2,match_bl_blximm)) {
4951         printf("sig_match_fw_yuv_layer_buf_52: no match call\n");
4952         return 0;
4953     }
4954     printf("match 0x%"PRIx64"\n",is->insn->address);
4955     uint32_t regs[4];
4956     // get r1, backtracking up to 8 instructions
4957     if ((get_call_const_args(fw,is,8,regs)&2)!=2) {
4958         printf("sig_match_fw_yuv_layer_buf_52: no match const arg\n");
4959         return 0;
4960     }
4961     save_misc_val(rule->name,regs[1],0,(uint32_t)fw->is->insn->address); // fw is has backtracked address
4962     return 0;
4963 }
4964 
4965 int sig_match_fw_yuv_layer_buf_gt52(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4966 {
4967     if(!init_disasm_sig_ref(fw,is,rule)) {
4968         return 0;
4969     }
4970     if(!find_next_sig_call(fw,is,170,"DebugAssert")) {
4971         printf("sig_match_fw_yuv_layer_buf: no match DebugAssert\n");
4972         return 0;
4973     }
4974     if(!insn_match_find_next(fw,is,12,match_bl_blximm)) {
4975         printf("sig_match_fw_yuv_layer_buf: no match call\n");
4976         return 0;
4977     }
4978     uint32_t regs[4];
4979     // get r1, backtracking up to 8 instructions
4980     if ((get_call_const_args(fw,is,8,regs)&2)!=2) {
4981         printf("sig_match_fw_yuv_layer_buf: no match const arg\n");
4982         return 0;
4983     }
4984     save_misc_val(rule->name,regs[1],0,(uint32_t)fw->is->insn->address); // fw is has backtracked address
4985     return 0;
4986 }
4987 
4988 int sig_match_rom_ptr_get(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4989 {
4990     if(!init_disasm_sig_ref(fw,is,rule)) {
4991         return 0;
4992     }
4993     uint32_t fadr=is->adr;
4994     if(!disasm_iter(fw,is)) {
4995         printf("sig_match_rom_ptr_get: disasm failed\n");
4996         return 0;
4997     }
4998     uint32_t adr=LDR_PC2val(fw,is->insn);
4999     if(!adr) {
5000         printf("sig_match_rom_ptr_get: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
5001         return  0;
5002     }
5003     if(is->insn->detail->arm.operands[0].reg != ARM_REG_R0) {
5004         printf("sig_match_rom_ptr_get: not R0\n");
5005         return 0;
5006     }
5007     if(!disasm_iter(fw,is)) {
5008         printf("sig_match_rom_ptr_get: disasm failed\n");
5009         return 0;
5010     }
5011     // TODO could check for other RET type instructions
5012     if(!insn_match(is->insn,match_bxlr)) {
5013         printf("sig_match_rom_ptr_get: no match BX LR\n");
5014         return 0;
5015     }
5016     save_misc_val(rule->name,adr,0,fadr);
5017     return 1;
5018 }
5019 
5020 // find Nth function call within max_insns ins of string ref,
5021 // returns address w/thumb bit set according to current state of call instruction
5022 // modifies is and potentially fw->is
5023 uint32_t find_call_near_str(firmware *fw, iter_state_t *is, sig_rule_t *rule)
5024 {
5025     uint32_t str_adr;
5026     if(rule->param & SIG_NEAR_INDIRECT) {
5027         str_adr = find_str_bytes(fw,rule->ref_name); // indirect string could be in data area
5028     } else {
5029         str_adr = find_str_bytes_main_fw(fw,rule->ref_name); // direct string must be near actual code
5030     }
5031     if(!str_adr) {
5032         printf("find_call_near_str: %s failed to find ref %s\n",rule->name,rule->ref_name);
5033         return 0;
5034     }
5035     uint32_t search_adr = str_adr;
5036     // looking for ref to ptr to string, not ref to string
5037     // TODO only looks for first ptr
5038     if(rule->param & SIG_NEAR_INDIRECT) {
5039         // printf("find_call_near_str: %s str 0x%08x\n",rule->name,str_adr);
5040         search_adr=find_u32_adr_range(fw,str_adr,fw->rom_code_search_min_adr,fw->rom_code_search_max_adr);
5041         if(!search_adr) {
5042             printf("find_call_near_str: %s failed to find indirect ref %s\n",rule->name,rule->ref_name);
5043             return 0;
5044         }
5045         // printf("find_call_near_str: %s indirect 0x%08x\n",rule->name,search_adr);
5046     }
5047     const insn_match_t *insn_match;
5048     if(rule->param & SIG_NEAR_JMP_SUB) {
5049         insn_match = match_b_bl_blximm;
5050     } else {
5051         insn_match = match_bl_blximm;
5052     }
5053 
5054     int max_insns=rule->param&SIG_NEAR_OFFSET_MASK;
5055     int n=(rule->param&SIG_NEAR_COUNT_MASK)>>SIG_NEAR_COUNT_SHIFT;
5056     //printf("find_call_near_str: %s max_insns %d n %d %s\n",rule->name,max_insns,n,(rule->param & SIG_NEAR_REV)?"rev":"fwd");
5057     // TODO should handle multiple instances of string
5058     disasm_iter_init(fw,is,(ADR_ALIGN4(search_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
5059     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,search_adr+SEARCH_NEAR_REF_RANGE)) {
5060         // bactrack looking for preceding call
5061         if(rule->param & SIG_NEAR_REV) {
5062             int i;
5063             int n_calls=0;
5064             for(i=1; i<=max_insns; i++) {
5065                 fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i));
5066                 if(insn_match_any(fw->is->insn,insn_match)) {
5067                     n_calls++;
5068                 }
5069                 if(n_calls == n) {
5070                     return iter_state_adr(fw->is);
5071                 }
5072             }
5073         } else {
5074             if(insn_match_find_nth(fw,is,max_insns,n,insn_match)) {
5075                 return iter_state_adr(is);
5076             }
5077         }
5078     }
5079     printf("find_call_near_str: no match %s\n",rule->name);
5080     return 0;
5081 }
5082 
5083 // find Nth function call within max_insns ins of string ref
5084 int sig_match_near_str(firmware *fw, iter_state_t *is, sig_rule_t *rule)
5085 {
5086     if (!get_saved_sig_val(rule->name))
5087     {
5088         uint32_t call_adr = find_call_near_str(fw,is,rule);
5089         if(call_adr) {
5090             return save_sig_match_call(fw, rule, call_adr);
5091         }
5092     }
5093     return 0;
5094 }
5095 
5096 // find call that recieves string sig->ref_name in reg
5097 // returns address w/thumb bit set according to current state of call instruction
5098 // modifies is and potentially fw->is
5099 // does not currently handle indirect refs
5100 // handles multiple instances of string
5101 uint32_t find_str_arg_call(firmware *fw, iter_state_t *is, sig_rule_t *rule)
5102 {
5103     arm_reg reg = ARM_REG_R0 + (rule->param & SIG_STRCALL_ARG_MASK);
5104     int match_type = (rule->param & SIG_STRCALL_TYPE_MASK);
5105     const insn_match_t *match;
5106     if(match_type == SIG_STRCALL_CALL_IMM) {
5107         match = match_bl_blximm;
5108     } else if(match_type == SIG_STRCALL_JMP_REG) {
5109         match = match_bxreg;
5110     } else if(match_type == SIG_STRCALL_CALL_REG) {
5111         match = match_blxreg;
5112     } else {
5113         printf("find_str_arg_call: %s invalid match type %d\n",rule->name,match_type);
5114         return 0;
5115     }
5116 
5117     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name); // direct string must be near actual code
5118     if(!str_adr) {
5119         printf("find_str_arg_call: %s failed to find ref %s\n",rule->name,rule->ref_name);
5120         return 0;
5121     }
5122 
5123     do {
5124         disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - SEARCH_NEAR_REF_RANGE) | fw->thumb_default); // reset to a bit before where the string was found
5125         uint32_t call_adr = find_const_ref_match(fw, is, SEARCH_NEAR_REF_RANGE*2, 8, reg, str_adr, match, FIND_CONST_REF_MATCH_ANY);
5126         if(call_adr) {
5127             return call_adr;
5128         }
5129         str_adr = find_next_str_bytes_main_fw(fw,rule->ref_name, str_adr+strlen(rule->ref_name));
5130     } while (str_adr);
5131     printf("find_str_arg_call: no match %s r%d\n",rule->name,reg-ARM_REG_R0);
5132     return 0;
5133 }
5134 
5135 int sig_match_str_arg_call(firmware *fw, iter_state_t *is, sig_rule_t *rule)
5136 {
5137     uint32_t call_adr = find_str_arg_call(fw,is,rule);
5138     if(call_adr) {
5139         return save_sig_match_call(fw, rule, call_adr);
5140     }
5141     return 0;
5142 }
5143 
5144 int sig_match_prop_string(firmware *fw, iter_state_t *is, sig_rule_t *rule)
5145 {
5146     uint32_t call_adr = find_call_near_str(fw, is, rule);
5147 
5148     if (call_adr == 0)
5149         return 0;
5150 
5151     // initialize to found address
5152     disasm_iter_init(fw,is,call_adr);
5153     disasm_iter(fw,is);
5154 
5155     uint32_t myreg;
5156 
5157     if (is_sig_call(fw,is,"GetPropertyCase")) {
5158         // looking for r0
5159         myreg = 0;
5160     }
5161     else {
5162         // semaphore version of GetPropertyCase, looking for r1
5163         myreg = 1;
5164     }
5165 
5166     // re-init 'is' to current address minus at least 8 insts
5167     const int hl = 8;
5168     disasm_iter_init(fw,is,call_adr - hl*4);
5169     // history needs to be made
5170     while (is->adr < call_adr) {
5171         if (!disasm_iter(fw,is))
5172             disasm_iter_init(fw,is,(is->adr | is->thumb)+2);
5173     }
5174     uint32_t regs[4];
5175     // get r0 or r1, backtracking up to 8 instructions
5176     if ((get_call_const_args(fw,is,hl,regs)&(1<<myreg))==(1<<myreg)) {
5177         add_prop_hit(rule->name,(int)regs[myreg]);
5178         return 1;
5179     }
5180     return 0;
5181 }
5182 
5183 // check if func is a nullsub or mov r0, x ; ret
5184 // to prevent sig_named* matches from going off the end of dummy funcs
5185 int is_immediate_ret_sub(firmware *fw,iter_state_t *is_init)
5186 {
5187     fw_disasm_iter_single(fw,is_init->adr | is_init->thumb);
5188     const insn_match_t match_mov_r0_imm[]={
5189         {MATCH_INS(MOV,   2),  {MATCH_OP_REG(R0),  MATCH_OP_IMM_ANY}},
5190 #if CS_API_MAJOR < 4
5191         {MATCH_INS(MOVS,  2),  {MATCH_OP_REG(R0),  MATCH_OP_IMM_ANY}},
5192 #endif
5193         {ARM_INS_ENDING}
5194     };
5195     // if it's a MOV, check if next is ret
5196     if(insn_match_any(fw->is->insn,match_mov_r0_imm)) {
5197         fw_disasm_iter(fw);
5198     }
5199     if(isRETx(fw->is->insn)) {
5200         return 1;
5201     }
5202     return 0;
5203 }
5204 
5205 // match last function called by already matched sig,
5206 // either the last bl/blximmg before pop {... pc}
5207 // or b after pop {... lr}
5208 // param defines min and max number of insns
5209 // doesn't work on functions that don't push/pop since can't tell if unconditional branch is last
5210 #define SIG_NAMED_LAST_MAX_MASK     0x00000FFF
5211 #define SIG_NAMED_LAST_MIN_MASK     0x00FFF000
5212 #define SIG_NAMED_LAST_MIN_SHIFT    12
5213 #define SIG_NAMED_LAST_RANGE(min,max)   ((SIG_NAMED_LAST_MIN_MASK&((min)<<SIG_NAMED_LAST_MIN_SHIFT)) \
5214                                          | (SIG_NAMED_LAST_MAX_MASK&(max)))
5215 
5216 int sig_match_named_last(firmware *fw, iter_state_t *is, sig_rule_t *rule)
5217 {
5218     uint32_t ref_adr = get_saved_sig_val(rule->ref_name);
5219     int min = (rule->param&SIG_NAMED_LAST_MIN_MASK)>>SIG_NAMED_LAST_MIN_SHIFT;
5220     int max = (rule->param&SIG_NAMED_LAST_MAX_MASK);
5221     if(!ref_adr) {
5222         printf("sig_match_named_last: %s missing %s\n",rule->name,rule->ref_name);
5223         return 0;
5224     }
5225     disasm_iter_init(fw,is,ref_adr);
5226     if(is_immediate_ret_sub(fw,is)) {
5227         printf("sig_match_named_last: immediate return %s\n",rule->name);
5228         return 0;
5229     }
5230     uint32_t fadr = find_last_call_from_func(fw,is,min,max);
5231     if(fadr) {
5232         return save_sig_with_j(fw,rule->name,fadr);
5233     }
5234     return 0;
5235 }
5236 
5237 // default - use the named firmware function
5238 #define SIG_NAMED_ASIS          0x00000000
5239 // use the target of the first B, BX, BL, BLX etc
5240 #define SIG_NAMED_JMP_SUB       0x00000001
5241 // use the target of the first BL, BLX
5242 #define SIG_NAMED_SUB           0x00000002
5243 // match address of Nth instruction in named sub
5244 #define SIG_NAMED_INSN          0x00000003
5245 #define SIG_NAMED_TYPE_MASK     0x0000000F
5246 
5247 #define SIG_NAMED_CLEARTHUMB    0x00000010
5248 #define SIG_NAMED_FLAG_MASK     0x000000F0
5249 
5250 #define SIG_NAMED_NTH_MASK      0x00000F00
5251 #define SIG_NAMED_NTH_SHIFT     8
5252 
5253 // number of instructions to search for each Nth
5254 // default 5
5255 #define SIG_NAMED_NTH_RANGE_MASK  0x0003F000
5256 #define SIG_NAMED_NTH_RANGE_SHIFT 12
5257 
5258 //#define SIG_NAMED_NTH(n,type)   ((SIG_NAMED_NTH_MASK&((n)<<SIG_NAMED_NTH_SHIFT)) | ((SIG_NAMED_##type)&SIG_NAME_TYPE_MASK))
5259 #define SIG_NAMED_NTH(n,type)   ((SIG_NAMED_NTH_MASK&((n)<<SIG_NAMED_NTH_SHIFT)) | (SIG_NAMED_##type))
5260 
5261 #define SIG_NAMED_NTH_RANGE(n)   ((SIG_NAMED_NTH_RANGE_MASK&((n)<<SIG_NAMED_NTH_RANGE_SHIFT)))
5262 
5263 int sig_match_named_save_sig(firmware *fw,const char *name, uint32_t adr, uint32_t flags)
5264 {
5265     adr = save_sig_veneers(fw, name, adr);
5266     if(adr) {
5267         if(flags & SIG_NAMED_CLEARTHUMB) {
5268             adr = ADR_CLEAR_THUMB(adr);
5269         }
5270         save_sig(fw,name,adr);
5271         return 1;
5272     }
5273     return 0;
5274 }
5275 // match already identified function found by name
5276 // if offset is 1, match the first called function with 20 insn instead (e.g. to avoid eventproc arg handling)
5277 // veneers are added
5278 int sig_match_named(firmware *fw, iter_state_t *is, sig_rule_t *rule)
5279 {
5280     uint32_t ref_adr = get_saved_sig_val(rule->ref_name);
5281     if(!ref_adr) {
5282         printf("sig_match_named: missing %s\n",rule->ref_name);
5283         return 0;
5284     }
5285     uint32_t sig_type = rule->param & SIG_NAMED_TYPE_MASK;
5286     uint32_t sig_flags = rule->param & SIG_NAMED_FLAG_MASK;
5287     uint32_t sig_nth = (rule->param & SIG_NAMED_NTH_MASK)>>SIG_NAMED_NTH_SHIFT;
5288     uint32_t sig_nth_range = (rule->param & SIG_NAMED_NTH_RANGE_MASK)>>SIG_NAMED_NTH_RANGE_SHIFT;
5289     if(!sig_nth) {
5290         sig_nth=1;
5291     }
5292     if(!sig_nth_range) {
5293         sig_nth_range=5;
5294     }
5295     // no offset, just save match as is
5296     // TODO might want to validate anyway
5297     if(sig_type == SIG_NAMED_ASIS) {
5298         return sig_match_named_save_sig(fw,rule->name,ref_adr,sig_flags);
5299     }
5300     const insn_match_t *insn_match;
5301     if(sig_type == SIG_NAMED_JMP_SUB) {
5302         insn_match = match_b_bl_blximm;
5303     } else if(sig_type == SIG_NAMED_SUB) {
5304         insn_match = match_bl_blximm;
5305     } else if(sig_type == SIG_NAMED_INSN) {
5306         insn_match = NULL;
5307     } else {
5308         printf("sig_match_named: %s invalid type %d\n",rule->ref_name,sig_type);
5309         return 0;
5310     }
5311 
5312     disasm_iter_init(fw,is,ref_adr);
5313     // TODO for eventprocs, may just want to use the original
5314     if(is_immediate_ret_sub(fw,is)) {
5315         printf("sig_match_named: immediate return %s\n",rule->name);
5316         return 0;
5317     }
5318     if(sig_type == SIG_NAMED_INSN) {
5319         uint32_t i;
5320         // iter starts on the address given to init
5321         for(i=0;i<=sig_nth;i++) {
5322             if(!disasm_iter(fw,is)) {
5323                 printf("sig_match_named: disasm failed %s 0x%08x\n",rule->name,(uint32_t)is->insn->address);
5324                 return 0;
5325             }
5326         }
5327         return sig_match_named_save_sig(fw,rule->name,iter_state_adr(is),sig_flags);
5328     }
5329 
5330     // initial 15 is hard coded
5331     if(insn_match_find_nth(fw,is,15 + sig_nth_range*sig_nth,sig_nth,insn_match)) {
5332         uint32_t adr = B_BL_BLXimm_target(fw,is->insn);
5333         if(adr) {
5334             // BLX, set thumb bit
5335             if(is->insn->id == ARM_INS_BLX) {
5336                 // curently not thumb, set in target
5337                 if(!is->thumb) {
5338                     adr=ADR_SET_THUMB(adr);
5339                 }
5340             } else {
5341                 // preserve current state
5342                 adr |= is->thumb;
5343             }
5344             return sig_match_named_save_sig(fw,rule->name,adr,sig_flags);
5345         } else {
5346             printf("sig_match_named: %s invalid branch target 0x%08x\n",rule->ref_name,adr);
5347         }
5348     } else {
5349         printf("sig_match_named: %s branch not found 0x%08x\n",rule->ref_name,ref_adr);
5350     }
5351     return 0;
5352 }
5353 
5354 // bootstrap sigs:
5355 // Used to find the minimum needed to for find_generic_funcs to get generic task and eventproc matches
5356 // order is important
5357 sig_rule_t sig_rules_initial[]={
5358 // function         CHDK name                   ref name/string         func param          dry rel             match flags
5359 // NOTE _FW is in the CHDK column, because that's how it is in sig_names
5360 {sig_match_str_r0_call, "ExportToEventProcedure_FW","ExportToEventProcedure"},
5361 {sig_match_reg_evp,     "RegisterEventProcedure",},
5362 {sig_match_reg_evp_table, "RegisterEventProcTable","DispDev_EnableEventProc"},
5363 {sig_match_reg_evp_alt2, "RegisterEventProcedure_alt2","EngApp.Delete"},
5364 {sig_match_unreg_evp_table,"UnRegisterEventProcTable","MechaUnRegisterEventProcedure"},
5365 {sig_match_evp_table_veneer,"RegisterEventProcTable_alt","RegisterEventProcTable"},
5366 {sig_match_evp_table_veneer,"UnRegisterEventProcTable_alt","UnRegisterEventProcTable"},
5367 {sig_match_str_r0_call,"CreateTaskStrictly",    "LowConsole",},
5368 {sig_match_str_r0_call,"CreateTask",            "EvShel",},
5369 {sig_match_named,   "CreateTask_low",           "CreateTask",           (SIG_NAMED_NTH(2,SUB)|SIG_NAMED_NTH_RANGE(10)), SIG_DRY_MAX(52)},
5370 {sig_match_named,   "CreateTask_low",           "CreateTask",           (SIG_NAMED_NTH(3,SUB)|SIG_NAMED_NTH_RANGE(10)), SIG_DRY_MIN(54)},
5371 {sig_match_createtaskstrictly_alt,"CreateTaskStrictly_alt","HdmiCecTask",0,                 SIG_DRY_MIN(58)},
5372 {sig_match_createtask_alt,"CreateTask_alt",     "CreateTaskStrictly_alt",0,                 SIG_DRY_MIN(58)},
5373 {sig_match_near_str,   "dry_memcpy",            "EP Slot%d",            SIG_NEAR_BEFORE(4,1)},
5374 {sig_match_add_ptp_handler,"add_ptp_handler",   "PTPtoFAPI_EventProcTask_Try",},
5375 {NULL},
5376 };
5377 
5378 // main sigs:
5379 // Run after find_generic_funcs. Order is important, matches must come after any matches they depend on.
5380 // Matches that depend only on bootstrap sigs should be first
5381 sig_rule_t sig_rules_main[]={
5382 // function         CHDK name                   ref name/string         func param          dry rel             match flags
5383 {sig_match_named,   "SetParameterData",         "PTM_BackupUIProperty_FW", 0,               SIG_DRY_MIN(58)},
5384 {sig_match_named,   "ExitTask",                 "ExitTask_FW",},
5385 {sig_match_named,   "EngDrvRead",               "EngDrvRead_FW",        SIG_NAMED_JMP_SUB},
5386 {sig_match_named,   "CalcLog10",                "CalcLog10_FW",         SIG_NAMED_JMP_SUB},
5387 {sig_match_named,   "CalcSqrt",                 "CalcSqrt_FW",          SIG_NAMED_JMP_SUB},
5388 {sig_match_named,   "Close",                    "Close_FW",},
5389 {sig_match_named,   "Close_low",                "Close",                SIG_NAMED_NTH(3,SUB),SIG_DRY_MIN(58)},
5390 {sig_match_named,   "close",                    "Close",                SIG_NAMED_SUB,      SIG_DRY_MAX(57)},
5391 {sig_match_named,   "close",                    "Close_low",            SIG_NAMED_SUB,      SIG_DRY_MIN(58)},
5392 {sig_match_named,   "DoAELock",                 "SS.DoAELock_FW",       SIG_NAMED_JMP_SUB},
5393 {sig_match_named,   "DoAFLock",                 "SS.DoAFLock_FW",       SIG_NAMED_JMP_SUB},
5394 {sig_match_named,   "Fclose_Fut",               "Fclose_Fut_FW",},
5395 {sig_match_named,   "Fopen_Fut",                "Fopen_Fut_FW",},
5396 {sig_match_named,   "Fread_Fut",                "Fread_Fut_FW",},
5397 {sig_match_named,   "Fseek_Fut",                "Fseek_Fut_FW",},
5398 {sig_match_named,   "Fwrite_Fut",               "Fwrite_Fut_FW",},
5399 {sig_match_named,   "fopen_low",                "Fopen_Fut",            SIG_NAMED_NTH(3,SUB)},
5400 {sig_match_named,   "fut_prepare",              "Fopen_Fut",            SIG_NAMED_NTH(1,SUB)},
5401 {sig_match_named,   "fut_finish",               "Fopen_Fut",            SIG_NAMED_NTH(4,SUB)},
5402 // high level functions not yet matched
5403 //{sig_match_named,   "feof_low",                 "Feof_Fut",             SIG_NAMED_NTH(2,SUB)},
5404 //{sig_match_named,   "fflush_low",               "Fflush_Fut",           SIG_NAMED_NTH(2,SUB)},
5405 {sig_match_named,   "fread_low",                "Fread_Fut",            SIG_NAMED_NTH(2,SUB)},
5406 {sig_match_named,   "fseek_low",                "Fseek_Fut",            SIG_NAMED_NTH(2,SUB)},
5407 {sig_match_named,   "fwrite_low",               "Fwrite_Fut",           SIG_NAMED_NTH(2,SUB)},
5408 
5409 {sig_match_named,   "GetAdChValue",             "GetAdChValue_FW",},
5410 {sig_match_named,   "GetCurrentAvValue",        "GetCurrentAvValue_FW",},
5411 {sig_match_named,   "GetCurrentShutterSpeed",   "GetCurrentShutterSpeed_FW",},
5412 {sig_match_named,   "GetBatteryTemperature",    "GetBatteryTemperature_FW",},
5413 {sig_match_named,   "GetCCDTemperature",        "GetCCDTemperature_FW",},
5414 {sig_match_named,   "GetFocusLensSubjectDistance","GetFocusLensSubjectDistance_FW",SIG_NAMED_JMP_SUB},
5415 {sig_match_named,   "GetOpticalTemperature",    "GetOpticalTemperature_FW",},
5416 {sig_match_named,   "GetPropertyCase",          "GetPropertyCase_FW",   SIG_NAMED_SUB},
5417 {sig_match_named,   "GetSystemTime",            "GetSystemTime_FW",},
5418 {sig_match_named,   "_GetSystemTime",           "GetSystemTime",        SIG_NAMED_SUB},
5419 // d7 cams have an extra call in _GetSystemTime
5420 {sig_match_named,   "GetSRAndDisableInterrupt", "_GetSystemTime",       SIG_NAMED_SUB,      SIG_DRY_ANY,    SIG_NO_D7},
5421 {sig_match_named,   "GetSRAndDisableInterrupt", "_GetSystemTime",       SIG_NAMED_NTH(2,SUB),SIG_DRY_ANY,   SIG_NO_D6},
5422 {sig_match_named,   "SetSR",                    "_GetSystemTime",       SIG_NAMED_NTH(2,SUB),SIG_DRY_ANY,   SIG_NO_D7},
5423 {sig_match_named,   "SetSR",                    "_GetSystemTime",       SIG_NAMED_NTH(3,SUB),SIG_DRY_ANY,   SIG_NO_D6},
5424 {sig_match_named,   "GetUsableMaxAv",           "GetUsableMaxAv_FW",},
5425 {sig_match_named,   "GetUsableMinAv",           "GetUsableMinAv_FW",},
5426 // a different match would be needed for older, ND only cams maybe based on "AE Result Tv Setting "
5427 {sig_match_named,   "GetUsableAvRange",         "GetUsableMinAv",       SIG_NAMED_SUB},
5428 {sig_match_named,   "GetVRAMHPixelsSize",       "GetVRAMHPixelsSize_FW",},
5429 {sig_match_named,   "GetVRAMVPixelsSize",       "GetVRAMVPixelsSize_FW",},
5430 {sig_match_named,   "GetZoomLensCurrentPoint",  "GetZoomLensCurrentPoint_FW",},
5431 {sig_match_named,   "GetZoomLensCurrentPosition","GetZoomLensCurrentPosition_FW",},
5432 {sig_match_named,   "GiveSemaphore",            "GiveSemaphore_FW",},
5433 {sig_match_named,   "IsStrobeChargeCompleted",  "EF.IsChargeFull_FW",},
5434 {sig_match_named,   "Read",                     "Read_FW",},
5435 {sig_match_named,   "LEDDrive",                 "LEDDrive_FW",},
5436 {sig_match_named,   "LockMainPower",            "LockMainPower_FW",},
5437 {sig_match_named,   "MoveFocusLensToDistance",  "MoveFocusLensToDistance_FW",},
5438 {sig_match_named,   "MoveIrisWithAv",           "MoveIrisWithAv_FW",},
5439 {sig_match_named,   "MoveZoomLensWithPoint",    "MoveZoomLensWithPoint_FW",},
5440 {sig_match_named,   "Open",                     "Open_FW",},
5441 {sig_match_named,   "Open_low",                 "Open",                SIG_NAMED_NTH(3,SUB),SIG_DRY_MIN(58)},
5442 {sig_match_named,   "PostLogicalEventForNotPowerType",  "PostLogicalEventForNotPowerType_FW",},
5443 {sig_match_named,   "PostLogicalEventToUI",     "PostLogicalEventToUI_FW",},
5444 {sig_match_named,   "PT_MFOn",                  "SS.MFOn_FW",           SIG_NAMED_JMP_SUB},
5445 {sig_match_named,   "PT_MFOff",                 "SS.MFOff_FW",          SIG_NAMED_JMP_SUB},
5446 {sig_match_named,   "PT_MoveDigitalZoomToWide", "SS.MoveDigitalZoomToWide_FW", SIG_NAMED_JMP_SUB},
5447 {sig_match_named,   "PT_MoveOpticalZoomAt",     "SS.MoveOpticalZoomAt_FW",},
5448 {sig_match_named,   "PutInNdFilter",            "PutInNdFilter_FW",},
5449 {sig_match_named,   "PutOutNdFilter",           "PutOutNdFilter_FW",},
5450 {sig_match_named,   "SetAE_ShutterSpeed",       "SetAE_ShutterSpeed_FW",},
5451 {sig_match_named,   "SetAutoShutdownTime",      "SetAutoShutdownTime_FW",},
5452 {sig_match_named,   "SetCurrentCaptureModeType","SetCurrentCaptureModeType_FW",},
5453 {sig_match_named,   "SetDate",                  "SetDate_FW",},
5454 {sig_match_named,   "SetLogicalEventActive",    "UiEvnt_SetLogicalEventActive_FW",},
5455 {sig_match_named,   "SetScriptMode",            "SetScriptMode_FW",},
5456 {sig_match_named,   "SleepTask",                "SleepTask_FW",},
5457 {sig_match_named,   "SetPropertyCase",          "SetPropertyCase_FW",   SIG_NAMED_SUB},
5458 {sig_match_named,   "TakeSemaphore",            "TakeSemaphore_FW",},
5459 {sig_match_named,   "TurnOnDisplay",            "DispCon_TurnOnDisplay_FW",SIG_NAMED_SUB},
5460 {sig_match_named,   "TurnOffDisplay",           "DispCon_TurnOffDisplay_FW",SIG_NAMED_SUB},
5461 {sig_match_named,   "TurnOnBackLight",          "DispCon_TurnOnBackLight_FW",SIG_NAMED_SUB, SIG_DRY_MAX(57)},
5462 {sig_match_named,   "TurnOffBackLight",         "DispCon_TurnOffBackLight_FW",SIG_NAMED_SUB,SIG_DRY_MAX(57)},
5463 {sig_match_named,   "UIFS_WriteFirmInfoToFile", "UIFS_WriteFirmInfoToFile_FW",},
5464 {sig_match_named,   "UnlockAE",                 "SS.UnlockAE_FW",       SIG_NAMED_JMP_SUB},
5465 {sig_match_named,   "UnlockAF",                 "SS.UnlockAF_FW",       SIG_NAMED_JMP_SUB},
5466 {sig_match_named,   "UnlockMainPower",          "UnlockMainPower_FW",},
5467 {sig_match_named,   "UnRegisterEventProcedure", "UnRegisterEventProcTable", SIG_NAMED_SUB},
5468 //{sig_match_named,   "UnsetZoomForMovie",        "UnsetZoomForMovie_FW",},
5469 {sig_match_named,   "VbattGet",                 "VbattGet_FW",},
5470 {sig_match_named,   "Write",                    "Write_FW",},
5471 {sig_match_named,   "bzero",                    "exec_FW",              SIG_NAMED_SUB},
5472 {sig_match_named,   "exmem_free",               "ExMem.FreeCacheable_FW",SIG_NAMED_JMP_SUB, SIG_DRY_MAX(58)},
5473 {sig_match_named,   "exmem_alloc",              "ExMem.AllocCacheable_FW",SIG_NAMED_JMP_SUB,SIG_DRY_MAX(58)},
5474 {sig_match_named,   "exmem_ufree",              "ExMem.FreeUncacheable_FW",SIG_NAMED_JMP_SUB, SIG_DRY_MAX(58)},
5475 {sig_match_named,   "exmem_ualloc",             "ExMem.AllocUncacheable_FW",SIG_NAMED_JMP_SUB,SIG_DRY_MAX(58)},
5476 {sig_match_named,   "free",                     "FreeMemory_FW",        SIG_NAMED_JMP_SUB},
5477 {sig_match_named,   "heap_free",                "free",                 SIG_NAMED_NTH(2,SUB)},
5478 {sig_match_named,   "lseek",                    "Lseek_FW",},
5479 {sig_match_named,   "_log10",                   "CalcLog10",            SIG_NAMED_NTH(2,SUB)},
5480 {sig_match_named,   "malloc",                   "AllocateMemory_FW",    SIG_NAMED_JMP_SUB},
5481 {sig_match_named,   "heap_alloc",               "malloc",               SIG_NAMED_NTH(2,SUB)},
5482 {sig_match_named,   "memcmp",                   "memcmp_FW",},
5483 {sig_match_named,   "memcpy",                   "memcpy_FW",},
5484 {sig_match_named,   "memset",                   "memset_FW",},
5485 {sig_match_named,   "strcmp",                   "strcmp_FW",},
5486 {sig_match_named,   "strcpy",                   "strcpy_FW",},
5487 {sig_match_named,   "strlen",                   "strlen_FW",},
5488 {sig_match_named,   "task_CaptSeq",             "task_CaptSeqTask",},
5489 {sig_match_named,   "task_ExpDrv",              "task_ExpDrvTask",},
5490 {sig_match_named,   "task_FileWrite",           "task_FileWriteTask",},
5491 //{sig_match_named,   "task_MovieRecord",         "task_MovieRecord",},
5492 //{sig_match_named,   "task_PhySw",               "task_PhySw",},
5493 {sig_match_named,   "vsprintf",                 "sprintf_FW",           SIG_NAMED_SUB},
5494 {sig_match_named,   "PTM_GetCurrentItem",       "PTM_GetCurrentItem_FW",},
5495 {sig_match_named,   "DisableISDriveError",      "DisableISDriveError_FW",},
5496 {sig_match_named,   "hook_CreateTask",          "CreateTask",           SIG_NAMED_CLEARTHUMB},
5497 // alternate if CreateTask is in ROM
5498 {sig_match_named,   "hook_CreateTask_low",      "CreateTask_low",       SIG_NAMED_CLEARTHUMB},
5499 {sig_match_named,   "malloc_strictly",          "task_EvShel",          SIG_NAMED_NTH(2,SUB)},
5500 {sig_match_named,   "DebugAssert2",             "malloc_strictly",      SIG_NAMED_NTH(3,SUB)},
5501 // fails on d7 ILCs
5502 //{sig_match_named,   "AcquireRecursiveLockStrictly","StartWDT_FW",       SIG_NAMED_NTH(1,SUB)},
5503 {sig_match_named,   "AcquireRecursiveLockStrictly","PTM_AllReset_FW",   SIG_NAMED_SUB},
5504 {sig_match_named,   "CheckAllEventFlag",        "ChargeStrobeForFA_FW", SIG_NAMED_SUB},
5505 {sig_match_named,   "ClearEventFlag",           "GetAEIntegralValueWithFix_FW",SIG_NAMED_SUB},
5506 {sig_match_named,   "CheckAnyEventFlag",        "task_SynchTask",       SIG_NAMED_NTH(2,SUB)},
5507 {sig_match_named,   "taskcreate_LowConsole",    "task_EvShel",          SIG_NAMED_SUB},
5508 {sig_match_named,   "CreateMessageQueueStrictly","taskcreate_LowConsole",SIG_NAMED_SUB},
5509 {sig_match_named,   "CreateBinarySemaphoreStrictly","taskcreate_LowConsole",SIG_NAMED_NTH(2,SUB)},
5510 {sig_match_named,   "PostMessageQueue",         "GetCh_FW",             SIG_NAMED_NTH(2,SUB)},
5511 {sig_match_named,   "CreateEventFlagStrictly",  "InitializeDigicon_FW", SIG_NAMED_SUB},
5512 {sig_match_named,   "WaitForAnyEventFlag",      "task_DPOFTask",        SIG_NAMED_SUB},
5513 {sig_match_named,   "GetEventFlagValue",        "task_DPOFTask",        SIG_NAMED_NTH(2,SUB)},
5514 {sig_match_named,   "CreateBinarySemaphore",    "task_UartLog",         SIG_NAMED_SUB},
5515 {sig_match_named,   "PostMessageQueueStrictly", "EF.IsChargeFull_FW",   SIG_NAMED_SUB},
5516 {sig_match_named,   "SetEventFlag",             "StopStrobeChargeForFA_FW",SIG_NAMED_SUB},
5517 {sig_match_named,   "TryReceiveMessageQueue",   "task_DvlpSeqTask",     SIG_NAMED_NTH(3,SUB)},
5518 // Semaphore funcs found by eventproc match, but want veneers. Will warn if mismatched
5519 {sig_match_named,   "TakeSemaphore",            "task_Bye",             SIG_NAMED_SUB},
5520 {sig_match_named_last,"GiveSemaphore",          "TurnOnVideoOutMode_FW",SIG_NAMED_LAST_RANGE(10,24)},
5521 // TODO finding through veneers would be better for disassembly
5522 {sig_match_named,   "givesemaphore_low",        "GiveSemaphore",        SIG_NAMED_SUB,      SIG_DRY_MAX(52)}, // first call on dry <=52
5523 {sig_match_named,   "givesemaphore_low",        "GiveSemaphore",        SIG_NAMED_NTH(2,SUB),SIG_DRY_MIN(53)}, // 2nd call on dry >52
5524 
5525 // can't use last because func has early return POP
5526 {sig_match_named,   "ReleaseRecursiveLock",     "StartWDT_FW",          SIG_NAMED_NTH(2,SUB)},
5527 {sig_match_named,   "MoveOpticalZoomAt",        "SS.MoveOpticalZoomAt_FW",SIG_NAMED_SUB},
5528 {sig_match_named,   "SetVideoOutType",          "SetVideoOutType_FW",   SIG_NAMED_SUB},
5529 {sig_match_named,   "GetVideoOutType",          "GetVideoOutType_FW"},
5530 {sig_match_named,   "is_movie_recording",       "UIFS_StopMovieRecord_FW",SIG_NAMED_SUB},
5531 {sig_match_named,   "dry_con_printf",           "ShowCameraLogInfo_FW", SIG_NAMED_SUB},
5532 {sig_match_named,   "ui_malloc",                "CreateController_FW",  SIG_NAMED_SUB},
5533 {sig_match_ui_mem_func_ptr,"ui_malloc_ptr",     "ui_malloc", },
5534 {sig_match_func_ptr_val, "ui_malloc_default",   "ui_malloc_ptr", },
5535 {sig_match_named,   "pvm_malloc",               "ui_malloc_default",    SIG_NAMED_NTH(2,SUB)},
5536 {sig_match_named,   "pvm_get_largest_free_block_size_ptr","ui_malloc_default",SIG_NAMED_NTH(3,SUB)},
5537 {sig_match_named,   "pvm_get_largest_free_block_size","pvm_get_largest_free_block_size_ptr",SIG_NAMED_SUB},
5538 {sig_match_named,   "ui_free",                  "CreateController_FW",  SIG_NAMED_NTH(3,SUB)},
5539 {sig_match_ui_mem_func_ptr,"ui_free_ptr",       "ui_free",},
5540 {sig_match_func_ptr_val, "ui_free_default",     "ui_free_ptr", },
5541 {sig_match_named_last,"pvm_free",               "ui_free_default",      SIG_NAMED_LAST_RANGE(11,16)},
5542 {sig_match_near_str,"pvm_init_pool",            "\n%ld-byte from heap\n",SIG_NEAR_BEFORE(14,3)},
5543 
5544 {sig_match_near_str,"cameracon_set_state",      "AC:ChkCom2PB",         SIG_NEAR_BEFORE(4,1),},
5545 {sig_match_near_str,"cameracon_get_state",      "DlvrUSBCnct",          SIG_NEAR_AFTER(5,2)},
5546 {sig_match_near_str,"IsWirelessConnect",        "WiFiDisconnect",       SIG_NEAR_BEFORE(6,1),SIG_DRY_MAX(52)},
5547 {sig_match_near_str,"IsWirelessConnect",        "USBDisconnect",        SIG_NEAR_BEFORE(6,1),SIG_DRY_MIN(54)},
5548 {sig_match_var_struct_get,"cameracon_state",    "cameracon_get_state",},
5549 {sig_match_str_arg_call,"strstr",               "AUTPLAY",              SIG_STRCALL_ARG(1)},
5550 {sig_match_named_last,"strchr",                 "strstr",               SIG_NAMED_LAST_RANGE(14,22)},
5551 {sig_match_near_str,"init_task_error",          "USER_MEM size checking",SIG_NEAR_AFTER(3,1)},
5552 {sig_match_named_last,"dry_panic",              "init_task_error",      SIG_NAMED_LAST_RANGE(4,12)},
5553 {sig_match_named,   "dry_panic_low",            "dry_panic",            SIG_NAMED_NTH(3,SUB),SIG_DRY_ANY,   SIG_NO_D6},
5554 // not present in d7, inlined in d6 dry 58p9+
5555 {sig_match_near_str,"data_synchronization_barrier","ER DlphCntInv",     SIG_NEAR_AFTER(3,2),SIG_DRY_MAXP(58,8),    SIG_NO_D7},
5556 // alternate match because "exec" lands near a literal pool on some cams
5557 {sig_match_near_str,"bzero",                    "Canon Degital Camera"/*sic*/,SIG_NEAR_AFTER(8,2)|SIG_NEAR_INDIRECT},
5558 //{sig_match_near_str,"bzero",                    "FromDate",             SIG_NEAR_BEFORE(2,1)},
5559 // eventproc on most cams, but not EOS Ms
5560 {sig_match_named,   "GetCurrentDriveBaseSvValue","GetCurrentDriveBaseSvValue_FW",SIG_NAMED_NTH(1,SUB)},
5561 {sig_match_near_str,"GetCurrentDriveBaseSvValue","IsExecutePreConti",   SIG_NEAR_AFTER(7,2)},
5562 {sig_match_named,   "memset32",                 "bzero",                SIG_NAMED_NTH(1,INSN)},
5563 {sig_match_dry_memset,"dry_memset",             "ClearDefectTurnTable_FW",0,            SIG_DRY_MIN(53)},
5564 {sig_match_near_str,"dry_memset",               "[xWiSE] generateRandom Err.\n",SIG_NEAR_BEFORE(8,2),SIG_DRY_MAX(52)},
5565 {sig_match_dry_memzero,"dry_memzero",           "SetDefaultRecParameter_FW"},
5566 {sig_match_dry_memcpy_bytes,"dry_memcpy_bytes", "SaveDefectAdjTable_FW",},
5567 {sig_match_near_str,"dry_memmove_bytes",        "NoOperation BulkOut!Remain.Length = %lu",SIG_NEAR_AFTER(18,3)},
5568 {sig_match_misc_flag_named,"CAM_IS_ILC",        "task_EFLensComTask",},
5569 {sig_match_misc_flag_named,"CAM_HAS_ND_FILTER", "task_Nd",},
5570 {sig_match_misc_flag_named,"CAM_HAS_WIFI",      "task_ComWireless",},
5571 {sig_match_cam_has_iris_diaphragm,"CAM_HAS_IRIS_DIAPHRAGM","task_IrisEvent",},
5572 {sig_match_near_str,"ImagerActivate",           "Fail ImagerActivate(ErrorCode:%x)\r",SIG_NEAR_BEFORE(6,1)},
5573 {sig_match_screenlock_helper,"screenlock_helper","UIFS_DisplayFirmUpdateView_FW"},
5574 {sig_match_named,   "ScreenLock",               "screenlock_helper",SIG_NAMED_SUB},
5575 {sig_match_fclose_low,"fclose_low",             "Fclose_Fut"},
5576 {sig_match_named,   "fut_flush",                "fclose_low",          SIG_NAMED_NTH(1,SUB)},
5577 //{sig_match_screenlock,"ScreenLock",             "UIFS_DisplayFirmUpdateView_FW"},
5578 {sig_match_screenunlock,"ScreenUnlock",         "screenlock_helper",    0,SIG_DRY_MAX(55)},
5579 {sig_match_near_str,"ScreenUnlock",             "PB._ErrorRef",         SIG_NEAR_AFTER(8,2)|SIG_NEAR_JMP_SUB,SIG_DRY_RANGE(57,58)},
5580 {sig_match_near_str,"ScreenUnlock",             "PB._ErrorRef:SI",      SIG_NEAR_AFTER(8,2)|SIG_NEAR_JMP_SUB,SIG_DRY_MIN(59)},
5581 {sig_match_log_camera_event,"LogCameraEvent",   "task_StartupImage",},
5582 {sig_match_physw_misc, "physw_misc",            "task_PhySw"},
5583 {sig_match_kbd_read_keys, "kbd_read_keys",      "kbd_p1_f"},
5584 {sig_match_get_kbd_state, "GetKbdState",        "kbd_read_keys"},
5585 {sig_match_create_jumptable, "CreateJumptable", "InitializeAdjustmentSystem_FW"},
5586 // also finds DebugAssert
5587 {sig_match_take_semaphore_strict, "TakeSemaphoreStrictly","Fopen_Fut"},
5588 {sig_match_near_str,"dry_error_printf",         "\nSystem Panic: Module = %d, Panic = %d\n",SIG_NEAR_AFTER(2,1)},
5589 // string switched between Dry58p3 and Dry58p9
5590 {sig_match_get_semaphore_value,"GetSemaphoreValue","\tRaw[%i]",         0,              SIG_DRY_MAXP(58,8)},
5591 {sig_match_get_semaphore_value,"GetSemaphoreValue","BlankRaw(%d)",      0,              SIG_DRY_MINP(58,9)},
5592 {sig_match_stat,    "stat",                     "A/uartr.req"},
5593 {sig_match_open,    "open",                     "Open_FW",              0,              SIG_DRY_MAX(57)},
5594 {sig_match_open,    "open",                     "Open_low",             0,              SIG_DRY_MIN(58)},
5595 {sig_match_named,   "get_self_task_errno_pointer","open",               SIG_NAMED_NTH(2,SUB)},
5596 {sig_match_named,   "get_self_task_id",         "get_self_task_errno_pointer",SIG_NAMED_SUB},
5597 {sig_match_umalloc, "AllocateUncacheableMemory","Fopen_Fut_FW"},
5598 {sig_match_named,   "dcache_flush_range",       "AllocateUncacheableMemory",SIG_NAMED_NTH(2,SUB)},
5599 {sig_match_ufree,   "FreeUncacheableMemory",    "Fclose_Fut_FW"},
5600 {sig_match_cam_uncached_bit,"CAM_UNCACHED_BIT", "FreeUncacheableMemory"},
5601 {sig_match_umalloc_strictly,"umalloc_strictly", "DPOFTask"},
5602 {sig_match_dcache_clean_flush_and_disable,"dcache_clean_flush_and_disable", "MemoryChecker_FW"},
5603 {sig_match_get_rom_id,"GetRomID",               "GetRomID_FW",},
5604 {sig_match_dcache_flush_and_enable,"dcache_flush_and_enable", "GetRomID",0,             SIG_DRY_ANY,            SIG_NO_D7}, // d7 code is different
5605 {sig_match_deletefile_fut,"DeleteFile_Fut",     "Get Err TempPath"},
5606 {sig_match_near_str,"createsemaphore_low",      "termLock",             SIG_NEAR_AFTER(3,1)},
5607 // old match, malloc gets more cams and veneers
5608 //{sig_match_near_str,"takesemaphore_low",        "sem_test_callback",    SIG_NEAR_AFTER(12,2)},
5609 {sig_match_named,"takesemaphore_low",        "malloc",                  SIG_NAMED_SUB},
5610 // not using Strictly, to pick up veneers
5611 {sig_match_near_str,"AcquireRecursiveLock",     "not executed\n",SIG_NEAR_BEFORE(20,3),SIG_DRY_ANY,             SIG_NO_D7},
5612 {sig_match_near_str,"AcquireRecursiveLock",     "COCOA: ERR: QIF AcquireRecursiveLock QifPushmqif failure!!",SIG_NEAR_BEFORE(10,1),SIG_DRY_ANY,             SIG_NO_D6},
5613 {sig_match_near_str,"CreateCountingSemaphoreStrictly","DvlpSeqTask",    SIG_NEAR_BEFORE(18,3)},
5614 {sig_match_near_str,"CreateMessageQueue",       "CreateMessageQueue:%ld",SIG_NEAR_BEFORE(7,1)},
5615 {sig_match_near_str,"CreateEventFlag",          "CreateEventFlag:%ld",  SIG_NEAR_BEFORE(7,1),SIG_DRY_MAX(57)},
5616 {sig_match_near_str,"CreateEventFlag",          "CreateEventFlag:%ld",  SIG_NEAR_BEFORE(9,1),SIG_DRY_MIN(58)},
5617 {sig_match_near_str,"CreateRecursiveLock",      "WdtInt",               SIG_NEAR_BEFORE(9,1)},
5618 {sig_match_near_str,"CreateRecursiveLockStrictly","LoadedScript",       SIG_NEAR_AFTER(6,2)},
5619 {sig_match_near_str,"DeleteMessageQueue",       "DeleteMessageQueue(%d) is FAILURE",SIG_NEAR_BEFORE(10,1)},
5620 {sig_match_near_str,"DeleteEventFlag",          "DeleteEventFlag(%d) is FAILURE",SIG_NEAR_BEFORE(10,1)},
5621 {sig_match_near_str,"ReceiveMessageQueue",      "ReceiveMessageQue:%d", SIG_NEAR_BEFORE(9,1)},
5622 {sig_match_near_str,"RegisterInterruptHandler", "WdtInt",               SIG_NEAR_AFTER(3,1)},
5623 {sig_match_near_str,"TryPostMessageQueue",      "TryPostMessageQueue(%d)\n",SIG_NEAR_BEFORE(9,1),SIG_DRY_MAX(52)},
5624 // different string on cams newer than sx280
5625 {sig_match_near_str,"TryPostMessageQueue",      "[CWS]TryPostMessageQueue(%d) Failed\n",SIG_NEAR_BEFORE(9,1)},
5626 {sig_match_near_str,"TryTakeSemaphore",         "FileScheduleTask",     SIG_NEAR_AFTER(10,2),SIG_DRY_MAX(57)},
5627 {sig_match_try_take_sem_dry_gt_57,"TryTakeSemaphore","task_ImageStoreTask",0,SIG_DRY_MIN(58)},
5628 // pick up takesemaphore_low from TryTakeSemaphore in case not matched by earlier rule
5629 {sig_match_named,   "takesemaphore_low",        "TryTakeSemaphore",     SIG_NAMED_SUB},
5630 {sig_match_near_str,"WaitForAllEventFlag",      "Error WaitEvent PREPARE_TESTREC_EXECUTED.", SIG_NEAR_BEFORE(5,1)},
5631 {sig_match_near_str,"WaitForAnyEventFlagStrictly","_imageSensorTask",   SIG_NEAR_AFTER(10,2)},
5632 {sig_match_wait_all_eventflag_strict,"WaitForAllEventFlagStrictly","EF.StartInternalMainFlash_FW"},
5633 {sig_match_near_str,"DeleteSemaphore",          "DeleteSemaphore passed",SIG_NEAR_BEFORE(3,1)},
5634 {sig_match_get_num_posted_messages,"GetNumberOfPostedMessages","task_CtgTotalTask"},
5635 {sig_match_near_str,"LocalTime",                "%Y-%m-%dT%H:%M:%S",    SIG_NEAR_BEFORE(5,1),SIG_DRY_MAX(58)},
5636 {sig_match_near_str,"LocalTime",                "%Y.%m.%d %H:%M:%S",    SIG_NEAR_BEFORE(5,1)},
5637 {sig_match_near_str,"strftime",                 "%Y/%m/%d %H:%M:%S",    SIG_NEAR_AFTER(3,1)},
5638 {sig_match_near_str,"OpenFastDir",              "OpenFastDir_ERROR\n",  SIG_NEAR_BEFORE(5,1)},
5639 {sig_match_readfastdir,"ReadFastDir",           "ReadFast_ERROR\n",     SIG_NEAR_BEFORE(24,1)},
5640 {sig_match_near_str,"PT_PlaySound",             "BufAccBeep",           SIG_NEAR_AFTER(7,2)|SIG_NEAR_JMP_SUB,SIG_DRY_MAX(58)},
5641 // for dry 59+ the above match finds function that takes different params on some cameras (d7?)
5642 {sig_match_near_str,"PT_PlaySound",             "PB._PMenuCBR",         SIG_NEAR_BEFORE(7,3),SIG_DRY_MIN(59)},
5643 {sig_match_closedir,"closedir",                 "ReadFast_ERROR\n",     SIG_NEAR_AFTER(1,1)},
5644 {sig_match_strrchr,"strrchr",                   "ReadFast_ERROR\n",     SIG_NEAR_AFTER(9,2)},
5645 {sig_match_strrchr,"strrchr",                   "ReadFast_ERROR\n",     SIG_NEAR_BEFORE(18,4)},
5646 {sig_match_time,    "time",                     "<UseAreaSize> DataWidth : %d , DataHeight : %d\r\n",},
5647 {sig_match_near_str,"strcat",                   "String can't be displayed; no more space in buffer",SIG_NEAR_AFTER(5,2),SIG_DRY_MAX(52)},
5648 {sig_match_near_str,"strcat",                   "/api/getimagelist",    SIG_NEAR_AFTER(4,1),SIG_DRY_MIN(53)},
5649 //{sig_match_near_str,"strchr",                   "-._~",                 SIG_NEAR_AFTER(4,1)}, // ref not in d7 main fw
5650 {sig_match_strncpy, "strncpy",                  "UnRegisterEventProcedure",},
5651 {sig_match_strncmp, "strncmp",                  "EXFAT   ",},
5652 {sig_match_strtolx, "strtolx",                  "CheckSumAll_FW",},
5653 {sig_match_near_str,"strtol",                   "prio <task ID> <priority>\n",SIG_NEAR_AFTER(7,1)},
5654 {sig_match_exec_evp,"ExecuteEventProcedure",    "Can not Execute "},
5655 {sig_match_fgets_fut,"Fgets_Fut",               "CheckSumAll_FW",},
5656 {sig_match_named,   "fgets_low",                "Fgets_Fut",            SIG_NAMED_NTH(2,SUB)},
5657 {sig_match_log,     "_log",                     "_log10",},
5658 {sig_match_pow_dry_52,"_pow",                   "GetDefectTvAdj_FW",    0,                  SIG_DRY_MAX(52)},
5659 {sig_match_pow_dry_gt_52,"_pow",                "GetDefectTvAdj_FW",    0,                  SIG_DRY_RANGEP(53,0,59,3)},
5660 {sig_match_sqrt,    "_sqrt",                    "CalcSqrt",},
5661 {sig_match_named,   "get_fstype",               "OpenFastDir",          SIG_NAMED_NTH(2,SUB)},
5662 {sig_match_near_str,"GetMemInfo",               " -- refusing to print malloc information.\n",SIG_NEAR_AFTER(7,2)},
5663 {sig_match_get_drive_cluster_size,"GetDrive_ClusterSize","OpLog.WriteToSD_FW",},
5664 {sig_match_mktime_ext,"mktime_ext",             "%04d%02d%02dT%02d%02d%02d.%01d",},
5665 {sig_match_near_str,"PB2Rec",                   "AC:ActionP2R Fail",    SIG_NEAR_BEFORE(6,1)},
5666 {sig_match_rec2pb,  "Rec2PB",                   "_EnrySRec",},
5667 //{sig_match_named,   "GetParameterData",         "PTM_RestoreUIProperty_FW",          SIG_NAMED_NTH(3,JMP_SUB)},
5668 {sig_match_get_parameter_data,"GetParameterData","PTM_RestoreUIProperty_FW",},
5669 {sig_match_prepdir_1,"PrepareDirectory_1",      "<OpenFileWithDir> PrepareDirectory NG\r\n",SIG_NEAR_BEFORE(7,1)},
5670 {sig_match_prepdir_x,"PrepareDirectory_x",      "PrepareDirectory_1",},
5671 {sig_match_prepdir_0,"PrepareDirectory_0",      "PrepareDirectory_1",},
5672 {sig_match_mkdir,   "MakeDirectory_Fut",        "PrepareDirectory_x",},
5673 // moved to sig_rules_initial to allow auto-detecting handlers
5674 //{sig_match_add_ptp_handler,"add_ptp_handler",   "PTPtoFAPI_EventProcTask_Try",},
5675 {sig_match_qsort,   "qsort",                    "task_MetaCtg",},
5676 {sig_match_deletedirectory_fut,"DeleteDirectory_Fut","RedEyeController.c",},
5677 {sig_match_set_control_event,"set_control_event","LogicalEvent:0x%04x:adr:%p,Para:%ld",},
5678 // newer cams use %08x
5679 {sig_match_set_control_event,"set_control_event","LogicalEvent:0x%08x:adr:%p,Para:%ld",},
5680 {sig_match_displaybusyonscreen_52,"displaybusyonscreen","_PBBusyScrn",  0,                  SIG_DRY_MAX(52)},
5681 {sig_match_undisplaybusyonscreen_52,"undisplaybusyonscreen","_PBBusyScrn",0,                SIG_DRY_MAX(52)},
5682 {sig_match_near_str,"srand",                    "Canon Degital Camera"/*sic*/,SIG_NEAR_AFTER(14,4)|SIG_NEAR_INDIRECT},
5683 {sig_match_near_str,"rand",                     "Canon Degital Camera"/*sic*/,SIG_NEAR_AFTER(15,5)|SIG_NEAR_INDIRECT},
5684 {sig_match_set_hp_timer_after_now,"SetHPTimerAfterNow","MechaNC.c",},
5685 {sig_match_levent_table,"levent_table",         "ShowLogicalEventName_FW",},
5686 {sig_match_flash_param_table,"FlashParamsTable","GetParameterData",},
5687 {sig_match_named,   "get_playrec_mode",         "task_SsStartupTask",   SIG_NAMED_SUB},
5688 {sig_match_var_struct_get,"playrec_mode",       "get_playrec_mode",},
5689 {sig_match_jpeg_count_str,"jpeg_count_str",     "9999",},
5690 {sig_match_physw_event_table,"physw_event_table","kbd_read_keys_r2",},
5691 {sig_match_uiprop_count,"uiprop_count",         "PTM_SetCurrentItem_FW",},
5692 {sig_match_get_canon_mode_list,"get_canon_mode_list","AC:PTM_Init",},
5693 {sig_match_rom_ptr_get,"canon_mode_list",       "get_canon_mode_list",},
5694 {sig_match_zoom_busy,"zoom_busy",               "ResetZoomLens_FW",},
5695 {sig_match_focus_busy,"focus_busy",             "MoveFocusLensToTerminate_FW",},
5696 {sig_match_aram_size,"ARAM_HEAP_SIZE",          "AdditionAgentRAM_FW",  0,                  SIG_DRY_MAX(58)},
5697 {sig_match_aram_size_gt58,"ARAM_HEAP_SIZE",     "AdditionAgentRAM_FW",  0,                  SIG_DRY_MIN(59)},
5698 {sig_match_aram_start,"ARAM_HEAP_START",        "AdditionAgentRAM_FW",},
5699 {sig_match_aram_start2,"ARAM_HEAP_START",       "AdditionAgentRAM_FW",},
5700 {sig_match_icache_flush_range,"icache_flush_range","AdditionAgentRAM_FW",},
5701 {sig_match__nrflag,"_nrflag",                   "NRTBL.SetDarkSubType_FW",},
5702 {sig_match_near_str,"transfer_src_overlay_helper","Window_EmergencyRefreshPhysicalScreen",SIG_NEAR_BEFORE(6,1)},
5703 {sig_match_transfer_src_overlay,"transfer_src_overlay","transfer_src_overlay_helper",},
5704 {sig_match_named,"GraphicSystemCoreFinish_helper","transfer_src_overlay",SIG_NAMED_NTH(3,SUB),SIG_DRY_MAX(52)},
5705 {sig_match_named,"GraphicSystemCoreFinish_helper","transfer_src_overlay",SIG_NAMED_NTH(4,SUB),SIG_DRY_RANGE(53,57)},// VTMReduuce fails on M10
5706 {sig_match_named,"GraphicSystemCoreFinish_helper","transfer_src_overlay",SIG_NAMED_NTH(5,SUB),SIG_DRY_MIN(58)},// additional call
5707 //{sig_match_near_str,"GraphicSystemCoreFinish_helper","VTMReduuce"/*sic*/,SIG_NEAR_BEFORE(6,1),SIG_DRY_RANGE(58,58)},
5708 //{sig_match_near_str,"GraphicSystemCoreFinish_helper","VTMReduce",SIG_NEAR_BEFORE(6,1),SIG_DRY_MIN(59)},  // canon fixed the typo, works on sx730 but others have diff code
5709 {sig_match_named_last,"fw_yuv_layer_buf_helper","transfer_src_overlay",SIG_NAMED_LAST_RANGE(60,85)},
5710 {sig_match_named,"GraphicSystemCoreFinish","GraphicSystemCoreFinish_helper",SIG_NAMED_SUB},
5711 {sig_match_named,"mzrm_createmsg","GraphicSystemCoreFinish",SIG_NAMED_SUB},
5712 {sig_match_named_last,"mzrm_sendmsg","GraphicSystemCoreFinish",SIG_NAMED_LAST_RANGE(10,16)},
5713 {sig_match_zicokick_52,"zicokick_start",        "ZicoKick Start\n",0,SIG_DRY_MAX(52)},
5714 {sig_match_zicokick_gt52,"zicokick_start",      "ZicoKick Start\n",0,SIG_DRY_MIN(53)},
5715 {sig_match_zicokick_copy,"zicokick_copy",       "zicokick_start"},
5716 {sig_match_zicokick_values,"zicokick_values",   "zicokick_start"},
5717 {sig_match_named_last,"dcache_clean_range",     "zicokick_start",               SIG_NAMED_LAST_RANGE(40,58)},
5718 {sig_match_init_ex_drivers,"init_ex_drivers",   "task_Startup"},
5719 {sig_match_omar_init,"omar_init",               "init_ex_drivers",              0,          SIG_DRY_ANY,        SIG_NO_D7},
5720 {sig_match_init_error_handlers,"init_error_handlers","task_Startup"},
5721 {sig_match_named,   "set_assert_handler",       "init_error_handlers",          SIG_NAMED_NTH(2,SUB)},
5722 {sig_match_named,   "set_exception_handler",    "init_error_handlers",          SIG_NAMED_NTH(3,SUB)},
5723 {sig_match_named,   "set_panic_handler",        "init_error_handlers",          SIG_NAMED_NTH(4,JMP_SUB)},
5724 {sig_match_default_assert_handler,"default_assert_handler","init_error_handlers"},
5725 {sig_match_default_exception_handler,"default_exception_handler","init_error_handlers"},
5726 {sig_match_default_panic_handler,"default_panic_handler","init_error_handlers"},
5727 {sig_match_get_task_properties,"get_task_properties","default_assert_handler"},
5728 {sig_match_enable_hdmi_power,"EnableHDMIPower", "HecHdmiCecPhysicalCheckForScript_FW"},
5729 {sig_match_disable_hdmi_power,"DisableHDMIPower","HecHdmiCecPhysicalCheckForScript_FW"},
5730 {sig_match_get_nd_value,"get_nd_value",         "PutInNdFilter",},
5731 {sig_match_get_current_exp,"get_current_exp","ShowCurrentExp_FW",},
5732 {sig_match_get_current_nd_value,"get_current_nd_value","get_current_exp",},
5733 {sig_match_get_current_deltasv,"get_current_deltasv","get_current_exp",},
5734 {sig_match_imager_active_callback,"imager_active_callback","ImagerActivate",},
5735 {sig_match_imager_active,"imager_active","imager_active_callback",},
5736 {sig_match_get_dial_hw_position,"get_dial_hw_position","kbd_p1_f",},
5737 {sig_match_near_str,"get_displaytype","DisplayType : %d\r\n",SIG_NEAR_BEFORE(5,1)},
5738 {sig_match_prop_string,"PROPCASE_AFSTEP", "\n\rError : GetAFStepResult",SIG_NEAR_BEFORE(7,1)},
5739 {sig_match_prop_string,"PROPCASE_FOCUS_STATE", "\n\rError : GetAFResult",SIG_NEAR_BEFORE(7,1)},
5740 {sig_match_prop_string,"PROPCASE_AV", "\n\rError : GetAvResult",SIG_NEAR_BEFORE(7,1)},
5741 {sig_match_prop_string,"PROPCASE_BV", "\n\rError : GetBvResult",SIG_NEAR_BEFORE(7,1)},
5742 {sig_match_prop_string,"PROPCASE_DELTA_DIGITALGAIN", "\n\rError : GetDeltaDigitalResult",SIG_NEAR_BEFORE(7,1)},
5743 {sig_match_prop_string,"PROPCASE_DELTA_SV", "\n\rError : GetDeltaGainResult",SIG_NEAR_BEFORE(7,1)},
5744 {sig_match_prop_string,"PROPCASE_DELTA_ND", "\n\rError : GetDeltaNdResult",SIG_NEAR_BEFORE(7,1)},
5745 {sig_match_prop_string,"PROPCASE_EV_CORRECTION_2", "\n\rError : GetRealExposureCompensationResult",SIG_NEAR_BEFORE(7,1)},
5746 {sig_match_prop_string,"PROPCASE_ORIENTATION_SENSOR", "\n\rError : GetRotationAngleResult",SIG_NEAR_BEFORE(7,1)},
5747 {sig_match_prop_string,"PROPCASE_SV_MARKET", "\n\rError : GetSvResult",SIG_NEAR_BEFORE(7,1)},
5748 {sig_match_prop_string,"PROPCASE_SVFIX", "\n\rError : GetSvFixResult",SIG_NEAR_BEFORE(7,1)},
5749 {sig_match_prop_string,"PROPCASE_TV", "\n\rError : GetTvResult",SIG_NEAR_BEFORE(7,1)},
5750 {sig_match_prop_string,"PROPCASE_HSCAPTURE", "GetPropertyFromCase Error [HSCapture]",SIG_NEAR_BEFORE(7,1)},
5751 {sig_match_prop_string,"PROPCASE_FLASH_FIRE", "FlashDecision",SIG_NEAR_BEFORE(7,1)},
5752 {sig_match_prop_string,"PROPCASE_FELOCK", "GetPropertyFromCurrentCase Error [FELock]",SIG_NEAR_BEFORE(7,1)},
5753 {sig_match_prop_string,"PROPCASE_FLASH_ADJUST_MODE", "GetPropertyFromCurrentCase Error [FlashAdjust]",SIG_NEAR_BEFORE(7,1)},
5754 {sig_match_exmem_vars,"exmem_types_table", "ExMem.View_FW"},
5755 {sig_match_av_over_sem,"av_override_semaphore", "MoveIrisWithAv_FW"},
5756 {sig_match_canon_menu_active,"canon_menu_active", "StartRecModeMenu_FW"},
5757 {sig_match_file_counter_init,"file_counter_var_init","task_InitFileModules",},
5758 {sig_match_file_counter_var,"file_counter_var","file_counter_var_init",},
5759 {sig_match_var_struct_get,"displaytype",       "get_displaytype",},
5760 {sig_match_palette_vars,"palette_control",     "transfer_src_overlay_helper",0, SIG_DRY_MAX(58)},// Dry59 code is different
5761 {sig_match_live_free_cluster_count,"live_free_cluster_count","Close",0,         SIG_DRY_MAX(57)},
5762 {sig_match_live_free_cluster_count,"live_free_cluster_count","Close_low",0,     SIG_DRY_MIN(58)},
5763 {sig_match_debug_logging_ptr,"debug_logging_ptr","[GRYP]T: Terminate(Pri): Completed.\n",SIG_STRCALL_ARG(0)|SIG_STRCALL_JMP_REG},
5764 {sig_match_debug_logging_flag,"debug_logging_flag","[GRYP]E: Terminate(Pri): Event flag delete error.[0x%08x]\n",SIG_STRCALL_ARG(0)|SIG_STRCALL_CALL_REG},
5765 {sig_match_mzrm_sendmsg_ret_adr,"mzrm_sendmsg_ret_adr","SendMsg   : %d\n",      SIG_STRCALL_ARG(0)|SIG_STRCALL_CALL_REG},
5766 {sig_match_fw_yuv_layer_buf_52,"fw_yuv_layer_buf","fw_yuv_layer_buf_helper",0,SIG_DRY_MAX(52)}, // dry52 has different code
5767 {sig_match_fw_yuv_layer_buf_gt52,"fw_yuv_layer_buf","fw_yuv_layer_buf_helper",0,SIG_DRY_MIN(54)}, // dry52 has different code
5768 {NULL},
5769 };
5770 
5771 int sig_rule_applies(firmware *fw, sig_rule_t *rule)
5772 {
5773     // dryos version
5774     if((rule->dryos_min && fw->dryos_ver_full < rule->dryos_min) || (rule->dryos_max && fw->dryos_ver_full > rule->dryos_max)) {
5775         return 0;
5776     }
5777     // empty flags == all
5778     if(!rule->flags) {
5779         return 1;
5780     }
5781     // digic 7 excluded, VMSA
5782     if((rule->flags & SIG_NO_D7) && (fw->arch_flags & FW_ARCH_FL_VMSA)) {
5783         return 0;
5784     }
5785     // digic 6 excluded, not VMSA
5786     if((rule->flags & SIG_NO_D6) && !(fw->arch_flags & FW_ARCH_FL_VMSA)) {
5787         return 0;
5788     }
5789     return 1;
5790 }
5791 
5792 void run_sig_rules(firmware *fw, sig_rule_t *sig_rules)
5793 {
5794     sig_rule_t *rule=sig_rules;
5795     // for convenience, pass an iter_state to match fns so they don't have to manage
5796     iter_state_t *is=disasm_iter_new(fw,0);
5797     while(rule->match_fn) {
5798         if(!sig_rule_applies(fw,rule)) {
5799             rule++;
5800             continue;
5801         }
5802 //        printf("rule: %s ",rule->name);
5803         //int r=rule->match_fn(fw,is,rule);
5804         rule->match_fn(fw,is,rule);
5805 //        printf("%d\n",r);
5806         rule++;
5807     }
5808     disasm_iter_free(is);
5809 }
5810 
5811 void add_event_proc(firmware *fw, char *name, uint32_t adr)
5812 {
5813     // TODO - no ARM eventprocs seen so far, warn
5814     if(!ADR_IS_THUMB(adr)) {
5815         printf("add_event_proc: %s is ARM 0x%08x\n",name,adr);
5816     }
5817     // attempt to disassemble target
5818     if(!fw_disasm_iter_single(fw,adr)) {
5819         printf("add_event_proc: %s disassembly failed at 0x%08x\n",name,adr);
5820         return;
5821     }
5822     // handle functions that immediately jump
5823     // only one level of jump for now, doesn't check for conditionals, but first insn shouldn't be conditional
5824     //uint32_t b_adr=B_target(fw,fw->is->insn);
5825     uint32_t b_adr=get_direct_jump_target(fw,fw->is);
5826     if(b_adr) {
5827         char *buf=malloc(strlen(name)+6);
5828         sprintf(buf,"j_%s_FW",name);
5829         add_func_name(fw,buf,adr,NULL); // this is the orignal named address
5830 //        adr=b_adr | fw->is->thumb; // thumb bit from iter state
5831         adr=b_adr; // thumb bit already handled by get_direct...
5832     }
5833     add_func_name(fw,name,adr,"_FW");
5834 }
5835 
5836 // process a call to an 2 arg event proc registration function
5837 int process_reg_eventproc_call(firmware *fw, iter_state_t *is, __attribute__ ((unused))uint32_t unused) {
5838     uint32_t regs[4];
5839     // get r0, r1, backtracking up to 4 instructions
5840     if((get_call_const_args(fw,is,4,regs)&3)==3) {
5841         // TODO follow ptr to verify code, pick up underlying functions
5842         if(isASCIIstring(fw,regs[0])) {
5843             char *nm=(char *)adr2ptr(fw,regs[0]);
5844             add_event_proc(fw,nm,regs[1]);
5845             //add_func_name(fw,nm,regs[1],NULL);
5846             //printf("eventproc found %s 0x%08x at 0x%"PRIx64"\n",nm,regs[1],is->insn->address);
5847         } else {
5848             printf("eventproc name not string at 0x%"PRIx64"\n",is->insn->address);
5849         }
5850     } else {
5851         // check for special case: one of the 2 arg eventprocs is used in loop to register a table
5852 
5853         // using the existing 'is' iterator
5854         // first, address is backed up
5855         uint64_t adr = is->insn->address;
5856         uint32_t adr_thumb = is->thumb;
5857         uint32_t tbla = 0;
5858         int ar = -1;
5859         int found = 0;
5860         // go back a 10 instructions
5861         disasm_iter_init(fw,is,adr_hist_get(&is->ah,10));
5862         // search for ldr reg, =address where address is higher in ROM (supposed to be the eventproc table)
5863         while(1) {
5864             if (!disasm_iter(fw,is)) break;
5865             if (is->insn->address >= adr) break;
5866             if (is->insn->id == ARM_INS_LDR && is->insn->detail->arm.operands[1].type == ARM_OP_MEM) {
5867                 uint32_t u = LDR_PC2val(fw,is->insn);
5868                 if ((u<fw->base+fw->size8) && (u>adr) && (!isASCIIstring(fw,u))) {
5869                     ar = is->insn->detail->arm.operands[0].reg;
5870                     tbla = u;
5871                     break;
5872                 }
5873             }
5874         }
5875         // search for found register appearing later in an add instruction
5876         while(ar >= 0) {
5877             if (!disasm_iter(fw,is)) break;
5878             if (is->insn->address >= adr) break;
5879             if (is->insn->id == ARM_INS_ADD && is->insn->detail->arm.operands[1].reg == ar) {
5880                 found = 1;
5881                 //printf("found loop eventproc table at 0x%"PRIx64"\n",is->insn->address);
5882                 break;
5883             }
5884         }
5885         if (found) {
5886             // following is taken from process_eventproc_table_call
5887             uint32_t *p=(uint32_t*)adr2ptr_with_data(fw,tbla);
5888             if(p) {
5889                 while(*p) {
5890                     uint32_t nm_adr=*p;
5891                     // NULL name = end of table
5892                     if (!nm_adr) break;
5893                     if(!isASCIIstring(fw,nm_adr)) {
5894                         printf("eventproc name not string tbl2 0x%08x 0x%08x\n",tbla,nm_adr);
5895                         break;
5896                     }
5897                     char *nm=(char *)adr2ptr(fw,nm_adr);
5898                     p++;
5899                     uint32_t fn=*p;
5900                     p++;
5901                     add_event_proc(fw,nm,fn);
5902                 }
5903             } else {
5904                 printf("eventproc tbl2 not table 0x%08x\n",tbla);
5905             }
5906         }
5907         else {
5908             printf("failed to get export/register eventproc args at 0x%"PRIx64"\n",adr);
5909         }
5910         // restore address in 'is' to avoid infinite loop
5911         disasm_iter_init(fw,is,adr | adr_thumb);
5912         disasm_iter(fw,is);
5913     }
5914     return 0; // always keep looking
5915 }
5916 
5917 // process a call to event proc table registration
5918 int process_eventproc_table_call(firmware *fw, iter_state_t *is, __attribute__ ((unused))uint32_t unused) {
5919     uint32_t regs[4];
5920     int foundr0 = 0;
5921     // get r0, backtracking up to 4 instructions
5922     foundr0 = get_call_const_args(fw,is,4,regs) & 1;
5923     if (!foundr0) {
5924         // case 1: table memcpy'd onto stack
5925         uint32_t ca = iter_state_adr(is);
5926         uint32_t sa = adr_hist_get(&is->ah,2);
5927         uint32_t ta = adr_hist_get(&is->ah,8);
5928         disasm_iter_set(fw,is,ta);
5929         int n = 0;
5930         while(++n<=(8-2))
5931         {
5932             disasm_iter(fw,is);
5933         }
5934         fw_disasm_iter_single(fw,sa);
5935         uint32_t adr1 = get_saved_sig_val("j_dry_memcpy");
5936         uint32_t adr2 = get_branch_call_insn_target(fw,fw->is);
5937         if (fw->is->insn->id == ARM_INS_BLX && adr1 == adr2) {
5938             foundr0 = get_call_const_args(fw,is,8-2,regs) & 2;
5939             if (foundr0) {
5940                 regs[0] = regs[1];
5941                 // printf("eventproc table case1 0x%x found table 0x%x\n",ca,regs[1]);
5942             }
5943         }
5944         // restore iter address
5945         disasm_iter_init(fw,is,ca);
5946         disasm_iter(fw,is);
5947     }
5948     if(foundr0) {
5949         // include tables in RAM data
5950         uint32_t *p=(uint32_t*)adr2ptr_with_data(fw,regs[0]);
5951         //printf("found eventproc table 0x%08x\n",regs[0]);
5952         // if it was a valid address
5953         if(p) {
5954             while(*p) {
5955                 uint32_t nm_adr=*p;
5956                 if(!isASCIIstring(fw,nm_adr)) {
5957                     printf("eventproc name not string tbl 0x%08x 0x%08x\n",regs[0],nm_adr);
5958                     break;
5959                 }
5960                 char *nm=(char *)adr2ptr(fw,nm_adr);
5961                 p++;
5962                 uint32_t fn=*p;
5963                 p++;
5964                 //printf("found %s 0x%08x\n",nm,fn);
5965                 add_event_proc(fw,nm,fn);
5966                 //add_func_name(fw,nm,fn,NULL);
5967             }
5968         } else {
5969             printf("failed to get *EventProcTable arg 0x%08x at 0x%"PRIx64"\n",regs[0],is->insn->address);
5970         }
5971     } else {
5972         printf("failed to get *EventProcTable r0 at 0x%"PRIx64"\n",is->insn->address);
5973     }
5974     return 0;
5975 }
5976 
5977 int process_createtask_call(firmware *fw, iter_state_t *is, __attribute__ ((unused))uint32_t unused) {
5978     //printf("CreateTask call at %"PRIx64"\n",is->insn->address);
5979     uint32_t regs[4];
5980     // get r0 (name) and r3 (entry), backtracking up to 10 instructions
5981     if((get_call_const_args(fw,is,10,regs)&9)==9) {
5982         if(isASCIIstring(fw,regs[0])) {
5983             // TODO
5984             char *buf=malloc(64);
5985             char *nm=(char *)adr2ptr(fw,regs[0]);
5986             sprintf(buf,"task_%s",nm);
5987             //printf("found %s 0x%08x at 0x%"PRIx64"\n",buf,regs[3],is->insn->address);
5988             add_func_name(fw,buf,regs[3],NULL);
5989         } else {
5990             printf("task name name not string at 0x%"PRIx64"\n",is->insn->address);
5991         }
5992     } else {
5993         printf("failed to get CreateTask args at 0x%"PRIx64"\n",is->insn->address);
5994     }
5995     return 0;
5996 }
5997 
5998 int save_ptp_handler_func(firmware *fw,uint32_t op,uint32_t handler) {
5999     if((op >= 0x9000 && op < 0x10000) || (op >= 0x1000 && op < 0x2000)) {
6000         char *buf=malloc(64);
6001         const char *nm=get_ptp_op_name(op);
6002         if(nm) {
6003             sprintf(buf,"handle_%s",nm);
6004         } else {
6005             sprintf(buf,"handle_PTP_OC_0x%04x",op);
6006         }
6007         // TODO Canon sometimes uses the same handler for multiple opcodes
6008         add_func_name(fw,buf,handler,NULL);
6009     } else {
6010         return 0;
6011     }
6012     return 1;
6013 }
6014 int process_add_ptp_handler_call(firmware *fw, iter_state_t *is, __attribute__ ((unused))uint32_t unused) {
6015     uint32_t regs[4];
6016     // get r0 (opcode) and r1 (handler), backtracking up to 8 instructions
6017     if((get_call_const_args(fw,is,8,regs)&3)==3) {
6018         //uint32_t op=regs[0];
6019         if(!save_ptp_handler_func(fw,regs[0],regs[1])) {
6020             printf("add_ptp_handler op 0x%08x out of range 0x%"PRIx64"\n",regs[0],is->insn->address);
6021         }
6022         return 0;
6023     } else {
6024         // if above failed, check for opcode table
6025         arm_reg ptr_reg = ARM_REG_INVALID;
6026         int i;
6027         // backtrack until we get to ldrh r0, ...
6028         for(i=1; i<6; i++) {
6029             fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i));
6030             cs_insn *insn=fw->is->insn;
6031             if(insn->id != ARM_INS_LDRH) {
6032                 continue;
6033             }
6034             if(insn->detail->arm.operands[0].reg != ARM_REG_R0
6035                 || insn->detail->arm.operands[1].mem.base == ARM_REG_PC
6036                 // shift isn't set correctly under capstone 3, not required for current cams
6037                 /*|| insn->detail->arm.operands[1].shift.value != 3*/) {
6038                 continue;
6039             }
6040             ptr_reg = insn->detail->arm.operands[1].mem.base;
6041             //printf("add_ptp_handler ptr_reg %d at 0x%"PRIx64"\n",ptr_reg,insn->address);
6042             break;
6043         }
6044         // didn't find args or anything that looks like table load
6045         if(ptr_reg == ARM_REG_INVALID) {
6046             printf("failed to get add_ptp_handler args at 0x%"PRIx64"\n",is->insn->address);
6047             return 0;
6048         }
6049         uint32_t op_table=0;
6050         // backtrack looking for LDR into ptr_reg
6051         // starting from previous i
6052         for(; i<20; i++) {
6053             fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i));
6054             cs_insn *insn=fw->is->insn;
6055             if(!isLDR_PC(insn)) {
6056                 continue;
6057             }
6058             if((arm_reg)insn->detail->arm.operands[0].reg != ptr_reg) {
6059                 continue;
6060             }
6061             // printf("add_ptp_handler LDR PC 0x%08x at 0x%"PRIx64"\n",LDR_PC2val(fw,insn),insn->address);
6062             uint32_t adr=LDR_PC2val(fw,insn);
6063             // check loaded address points to expected value (OC GetStorageIDs)
6064             if(fw_u32(fw,adr) == 0x1004) {
6065                 op_table=adr;
6066             }
6067             break;
6068         }
6069         if(!op_table) {
6070             printf("failed to get ptp handler table adr at 0x%"PRIx64"\n",is->insn->address);
6071             return 0;
6072         }
6073         // TODO canon firmware has count in loop that calls add_ptp_handler,
6074         // but for simplicity just checking for valid opcode with hardcoded max
6075         for(i=0; i<64; i++) {
6076             uint32_t op=fw_u32(fw,op_table+i*8);
6077             uint32_t handler=fw_u32(fw,op_table+i*8+4);
6078             // fails on op out of range
6079             if(!save_ptp_handler_func(fw,op,handler)) {
6080                 break;
6081             }
6082         }
6083         return 0;
6084     }
6085 }
6086 
6087 int add_generic_func_match(search_calls_multi_data_t *match_fns,
6088                             int *match_fn_count,
6089                             int max_funcs,
6090                             search_calls_multi_fn fn,
6091                             uint32_t adr)
6092 {
6093     if(*match_fn_count >= max_funcs-1) {
6094         printf("add_generic_func_match: ERROR max_funcs %d reached\n",max_funcs);
6095         match_fns[max_funcs-1].adr=0;
6096         match_fns[max_funcs-1].fn=NULL;
6097         return 0;
6098     }
6099     match_fns[*match_fn_count].adr=adr;
6100     match_fns[*match_fn_count].fn=fn;
6101     (*match_fn_count)++;
6102     match_fns[*match_fn_count].adr=0;
6103     match_fns[*match_fn_count].fn=NULL;
6104     return 1;
6105 }
6106 #define MAX_GENERIC_FUNCS 16
6107 void add_generic_sig_match(search_calls_multi_data_t *match_fns,
6108                                 int *match_fn_count,
6109                                 search_calls_multi_fn fn,
6110                                 const char *name)
6111 {
6112     uint32_t adr=get_saved_sig_val(name);
6113     if(!adr) {
6114         printf("add_generic_sig_match: missing %s\n",name);
6115         return;
6116     }
6117     add_generic_func_match(match_fns,match_fn_count,MAX_GENERIC_FUNCS,fn,adr);
6118     char veneer[128];
6119     sprintf(veneer,"j_%s",name);
6120     adr=get_saved_sig_val(veneer);
6121     if(adr) {
6122         add_generic_func_match(match_fns,match_fn_count,MAX_GENERIC_FUNCS,fn,adr);
6123     }
6124 }
6125 
6126 void find_exception_handlers(firmware *fw, iter_state_t *is)
6127 {
6128     uint32_t ex_vec = 0;
6129     // somewhat duplicated from to firmware_load_ng, but it's simple
6130     if (fw->arch_flags & FW_ARCH_FL_VMSA) {
6131         const insn_match_t match_mcr_vbar[]={
6132             // Vector Base Address Register MCR p15, 0, <Rt>, c12, c0, 0 - not present on PMSA
6133             {MATCH_INS(MCR, 6), {MATCH_OP_PIMM(15),MATCH_OP_IMM(0),MATCH_OP_REG_ANY,MATCH_OP_CIMM(12),MATCH_OP_CIMM(0),MATCH_OP_IMM(0)}},
6134             {ARM_INS_ENDING}
6135         };
6136         // reset to main fw start
6137         disasm_iter_init(fw, is, fw->base + fw->main_offs + 12 + fw->thumb_default);
6138         if(!insn_match_find_next(fw,is,4,match_mcr_vbar)) {
6139             return;
6140         }
6141         // back up one
6142         disasm_iter_init(fw, is, adr_hist_get(&is->ah,1));
6143         disasm_iter(fw, is);
6144         // expect ldr to be exception vector address
6145         ex_vec  = LDR_PC2val(fw,is->insn);
6146         if(!ex_vec || adr_get_range_type(fw,ex_vec) != ADR_RANGE_ROM) {
6147             return;
6148         }
6149     }
6150     // both d6 and d7 appear to have an ARM instruction in reset, and thumb in the remaining
6151     // which appears contrary to arm documentation (ARM DDI 0406C.c (ID051414)
6152     // On digic 6, Reset appears to be an infinte loop, so must not be expected in any case
6153     disasm_iter_init(fw, is, ex_vec);
6154     disasm_iter(fw, is);
6155 
6156     char *names[]={
6157         "exception_handler_Reset",
6158         "exception_handler_UndefinedInstruction",
6159         "exception_handler_SupervisorCall",
6160         "exception_handler_PrefetchAbort",
6161         "exception_handler_DataAbort",
6162         "exception_handler_NotUsed",
6163         "exception_handler_IRQ",
6164         "exception_handler_FIQ",
6165     };
6166 
6167     uint32_t addr=LDR_PC2val(fw,is->insn);
6168     if(!addr && is->insn->id == ARM_INS_B) {
6169         addr=get_branch_call_insn_target(fw,is);
6170     }
6171     // addr may be 0 (= inf loop at reset vector) but stubs system won't recognize it anyway
6172     if(addr) {
6173         add_func_name(fw,names[0],addr,NULL);
6174     }
6175     disasm_iter_init(fw, is, ADR_SET_THUMB(ex_vec + 4));
6176     int i;
6177     for(i=1; i<8; i++) {
6178         disasm_iter(fw, is);
6179         // all seen so far use a thumb ldr.w pc,...
6180         // "NotUsed" is typically a NOP, which won't get picked up here, but would fall through to IRQ
6181         addr=LDR_PC2val(fw,is->insn);
6182         if(addr) {
6183             add_func_name(fw,names[i],addr,NULL);
6184         }
6185     }
6186 }
6187 
6188 /*
6189 collect as many calls as possible of functions identified by name, whether or not listed in funcs to find
6190 this does a full disassembly of the entire firmware, which is slow
6191 */
6192 void find_generic_funcs(firmware *fw) {
6193     search_calls_multi_data_t match_fns[MAX_GENERIC_FUNCS];
6194 
6195     int match_fn_count=0;
6196 
6197     add_generic_sig_match(match_fns,&match_fn_count,process_reg_eventproc_call,"ExportToEventProcedure_FW");
6198     add_generic_sig_match(match_fns,&match_fn_count,process_reg_eventproc_call,"RegisterEventProcedure_alt1");
6199     add_generic_sig_match(match_fns,&match_fn_count,process_reg_eventproc_call,"RegisterEventProcedure_alt2");
6200     add_generic_sig_match(match_fns,&match_fn_count,process_eventproc_table_call,"RegisterEventProcTable");
6201     add_generic_sig_match(match_fns,&match_fn_count,process_eventproc_table_call,"UnRegisterEventProcTable");
6202     add_generic_sig_match(match_fns,&match_fn_count,process_createtask_call,"CreateTaskStrictly");
6203     if(get_saved_sig_val("CreateTaskStrictly_alt")) {
6204         add_generic_sig_match(match_fns,&match_fn_count,process_createtask_call,"CreateTaskStrictly_alt");
6205     }
6206     add_generic_sig_match(match_fns,&match_fn_count,process_createtask_call,"CreateTask");
6207     if(get_saved_sig_val("CreateTask_alt")) {
6208         add_generic_sig_match(match_fns,&match_fn_count,process_createtask_call,"CreateTask_alt");
6209     }
6210     add_generic_sig_match(match_fns,&match_fn_count,process_eventproc_table_call,"RegisterEventProcTable_alt");
6211     add_generic_sig_match(match_fns,&match_fn_count,process_eventproc_table_call,"UnRegisterEventProcTable_alt");
6212     add_generic_sig_match(match_fns,&match_fn_count,process_add_ptp_handler_call,"add_ptp_handler");
6213 
6214     iter_state_t *is=disasm_iter_new(fw,0);
6215     disasm_iter_init(fw,is,fw->rom_code_search_min_adr | fw->thumb_default); // reset to start of fw
6216     fw_search_insn(fw,is,search_disasm_calls_multi,0,match_fns,0);
6217 
6218     int i;
6219     for(i=0;i<fw->adr_range_count;i++) {
6220         if(fw->adr_ranges[i].type != ADR_RANGE_RAM_CODE) {
6221             continue;
6222         }
6223         disasm_iter_init(fw,is,fw->adr_ranges[i].start | fw->thumb_default); // reset to start of range
6224         // check additional veneers, since regions are small and often need to jump back to ROM
6225         fw_search_insn(fw,is,search_disasm_calls_veneer_multi,0,match_fns,0);
6226     }
6227 
6228     find_exception_handlers(fw,is);
6229 
6230     disasm_iter_free(is);
6231 }
6232 
6233 void find_ctypes(firmware *fw)
6234 {
6235     static unsigned char ctypes[] =
6236     {
6237         0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60, 0x60, 0x60, 0x60, 0x60, 0x20, 0x20,
6238         0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
6239         0x48, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
6240         0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
6241         0x10, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6242         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x10, 0x10, 0x10, 0x10, 0x10,
6243         0x10, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6244         2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0x10, 0x10, 0x10, 0x20
6245     };
6246 
6247     uint32_t ctypes_matches[10];
6248     int match_count = find_bytes_all(fw,ctypes,sizeof(ctypes),fw->base,ctypes_matches,10);
6249     if(!match_count) {
6250         return;
6251     }
6252     if(match_count == 10) {
6253         fprintf(stderr,"WARNING found 10+ ctypes!\n");
6254     }
6255     int i;
6256     int match_i;
6257     uint32_t min_adr = 0xFFFFFFFF;
6258     for(i = 0; i< match_count; i++) {
6259         // ref should easily be in the first 1M
6260         uint32_t maxadr = (fw->rom_code_search_max_adr > fw->base + 0x400000)?fw->base + 0x100000:fw->rom_code_search_max_adr;
6261         uint32_t adr = find_u32_adr_range(fw,ctypes_matches[i],fw->rom_code_search_min_adr,maxadr);
6262         if(adr && adr < min_adr) {
6263             min_adr = adr;
6264             match_i = i;
6265         }
6266     }
6267     if(min_adr == 0xFFFFFFFF) {
6268         fprintf(stderr,"WARNING cytpes pointer not found, defaulting to first\n");
6269         match_i = 0;
6270     }
6271     save_misc_val("ctypes",ctypes_matches[match_i],0,min_adr);
6272 }
6273 
6274 void print_misc_val_makefile(const char *name)
6275 {
6276     misc_val_t *mv=get_misc_val(name);
6277     if(!mv) {
6278         return;
6279     }
6280     // TODO legitimate 0 values might be possible, if so can add found bit
6281     if(!mv->val) {
6282         bprintf("// %s not found\n",name);
6283         return;
6284     }
6285     bprintf("//   %s = 0x%08x# ",name,mv->val);
6286     if(mv->offset) {
6287         bprintf(" (0x%x+0x%x)",mv->base,mv->offset);
6288     }
6289     if(mv->ref_adr) {
6290         bprintf(" Found @0x%08x",mv->ref_adr);
6291     }
6292     bprintf("\n");
6293 }
6294 
6295 
6296 void output_firmware_vals(firmware *fw)
6297 {
6298     bprintf("// Camera info:\n");
6299     bprintf("//   Main firmware start: 0x%08x\n",fw->base+fw->main_offs);
6300     if (fw->dryos_ver == 0)
6301     {
6302         bprintf("//   Can't find DRYOS version !!!\n\n");
6303     } else {
6304         bprintf("//   DRYOS R%d (%s) @ 0x%08x ref @ 0x%08x\n",
6305                     fw->dryos_ver,
6306                     fw->dryos_ver_str,
6307                     fw->dryos_ver_adr,
6308                     fw->dryos_ver_ref_adr);
6309     }
6310     if (fw->firmware_ver_str == 0)
6311     {
6312         bprintf("//   Can't find firmware version !!!\n\n");
6313     }
6314     else
6315     {
6316         char *c = strrchr(fw->firmware_ver_str,' ') + 1; // points after the last space char
6317         uint32_t j = ptr2adr(fw,(uint8_t *)fw->firmware_ver_str);
6318         uint32_t k = j + c - fw->firmware_ver_str;
6319         if ( (k>=j) && (k<j+32) )
6320         {
6321             bprintf("//   %s   // Found @ 0x%08x, \"%s\" @ 0x%08x\n",fw->firmware_ver_str,j,c,k);
6322         }
6323         else
6324         {
6325             // no space found in string (shouldn't happen)
6326             bprintf("//   %s   // Found @ 0x%08x, \"%s\" @ 0x%08x\n",fw->firmware_ver_str,j,fw->firmware_ver_str,j);
6327         }
6328     }
6329     if (fw->arch_flags & FW_ARCH_FL_VMSA) {
6330         bprintf("//   VMSA detected, probably digic >= 7\n");
6331     }
6332 
6333     bprintf("\n// Values for makefile.inc\n");
6334     bprintf("//   PLATFORMOSVER = %d\n",fw->dryos_ver);
6335     if (fw->arch_flags & FW_ARCH_FL_VMSA) {
6336         bprintf("//   DIGIC = 70\n");
6337     } else {
6338         // 6+ exists, but not for known powershot firmware cams
6339         bprintf("//   DIGIC = 60\n");
6340     }
6341 
6342     if (fw->memisostart) {
6343         bprintf("//   MEMISOSTART = 0x%x\n",fw->memisostart);
6344     } else {
6345         bprintf("//   MEMISOSTART not found !!!\n");
6346     }
6347     if (fw->data_init_start)
6348     {
6349         bprintf("//   MEMBASEADDR = 0x%x\n",fw->data_start);
6350     }
6351     print_misc_val_makefile("ARAM_HEAP_START");
6352     print_misc_val_makefile("ARAM_HEAP_SIZE");
6353 
6354     bprintf("\n// Detected address ranges:\n");
6355     int i;
6356     for(i=0; i<fw->adr_range_count; i++) {
6357         if(fw->adr_ranges[i].type == ADR_RANGE_ROM) {
6358             bprintf("// %-8s 0x%08x - 0x%08x (%7d bytes)\n",
6359                     adr_range_desc_str(&fw->adr_ranges[i]),
6360                     fw->adr_ranges[i].start,
6361                     fw->adr_ranges[i].start+fw->adr_ranges[i].bytes,
6362                     fw->adr_ranges[i].bytes);
6363         } else {
6364             bprintf("// %-8s 0x%08x - 0x%08x copied from 0x%08x (%7d bytes)\n",
6365                     adr_range_desc_str(&fw->adr_ranges[i]),
6366                     fw->adr_ranges[i].start,
6367                     fw->adr_ranges[i].start+fw->adr_ranges[i].bytes,
6368                     fw->adr_ranges[i].src_start,
6369                     fw->adr_ranges[i].bytes);
6370         }
6371     }
6372     misc_val_t *mv=get_misc_val("zicokick_values");
6373     if(mv->blobs) {
6374         bprintf("\n// Zico Xtensa blobs:\n");
6375         for(i=0;mv->blobs[i].type != MISC_BLOB_TYPE_NONE;i++) {
6376             bprintf("// zico_%d 0x%08x - 0x%08x copied from 0x%08x (%7d bytes)\n",
6377                     i,
6378                     mv->blobs[i].ram_adr,
6379                     mv->blobs[i].ram_adr+mv->blobs[i].size,
6380                     mv->blobs[i].rom_adr,
6381                     mv->blobs[i].size);
6382         }
6383 
6384     }
6385     mv=get_misc_val("omar_init_values");
6386     if(mv->blobs) {
6387         bprintf("\n// Omar ARM blobs:\n");
6388         for(i=0;mv->blobs[i].type != MISC_BLOB_TYPE_NONE;i++) {
6389             bprintf("// omar_%d 0x%08x - 0x%08x copied from 0x%08x (%7d bytes)\n",
6390                     i,
6391                     mv->blobs[i].ram_adr,
6392                     mv->blobs[i].ram_adr+mv->blobs[i].size,
6393                     mv->blobs[i].rom_adr,
6394                     mv->blobs[i].size);
6395         }
6396     }
6397     if(fw->dryos_ver_count) {
6398         bprintf("\n// Found DryOS versions:\n");
6399         for(i=0;i<(int)fw->dryos_ver_count;i++) {
6400             bprintf("// 0x%08x %s \"%s\"\n",
6401                 fw->dryos_ver_list[i], (fw->dryos_ver_list[i] == fw->dryos_ver_adr) ? "main ":"other",
6402                 (char *)adr2ptr(fw,fw->dryos_ver_list[i]));
6403         }
6404         add_blankline();
6405     }
6406     add_blankline();
6407 
6408     // check if CreateTask is in ROM, offer CreateTask_low if it's in RAM
6409     sig_entry_t * ct = find_saved_sig("hook_CreateTask");
6410     if(ct && adr_get_range_type(fw,ct->val) != ADR_RANGE_RAM_CODE) {
6411         bprintf("// CreateTask is not in RAM code\n");
6412         ct->flags |= UNUSED;
6413         sig_entry_t * ctl = find_saved_sig("CreateTask_low");
6414         if(ctl && adr_get_range_type(fw,ctl->val) == ADR_RANGE_RAM_CODE) {
6415             bprintf("// use hook_CreateTask_low instead\n");
6416             ctl->flags &= ~UNUSED;
6417             sig_entry_t * hctl = find_saved_sig("hook_CreateTask_low");
6418             hctl->flags &= ~UNUSED;
6419         }
6420         add_blankline();
6421     }
6422 }
6423 
6424 // print platform.h define, if not default value
6425 void print_platform_misc_val_undef(const char *name, uint32_t def)
6426 {
6427     misc_val_t *mv=get_misc_val(name);
6428     if(mv && mv->val && mv->val != def) {
6429         bprintf("//#undef  %s\n",name);
6430         bprintf("//#define %s  0x%08x // Found @0x%08x\n",name,mv->val,mv->ref_adr);
6431     }
6432 }
6433 
6434 void output_platform_vals(firmware *fw) {
6435     bprintf("// Values below go in 'platform_camera.h':\n");
6436     bprintf("//#define CAM_DRYOS         1\n");
6437     if (fw->dryos_ver >= 39)
6438         bprintf("//#define CAM_DRYOS_2_3_R39 1 // Defined for cameras with DryOS version R39 or higher\n");
6439     if (fw->dryos_ver >= 47)
6440         bprintf("//#define CAM_DRYOS_2_3_R47 1 // Defined for cameras with DryOS version R47 or higher\n");
6441     if (fw->dryos_ver >= 59)
6442         bprintf("//#define CAM_DRYOS_2_3_R59 1 // Defined for cameras with DryOS version R59 or higher\n");
6443 
6444     if(get_misc_val_value("CAM_IS_ILC")) {
6445         bprintf("//#define CAM_ILC 1 // Camera is interchangeable lens\n");
6446     }
6447 
6448     if(get_misc_val_value("CAM_HAS_WIFI")) {
6449         bprintf("//#define CAM_HAS_WIFI 1 // Firmware has wifi support (only define if camera has hardware)\n");
6450     }
6451 
6452 
6453     print_platform_misc_val_undef("CAM_UNCACHED_BIT",0x10000000);
6454 
6455     if(get_misc_val_value("CAM_HAS_ND_FILTER")) {
6456         bprintf("//#define CAM_HAS_ND_FILTER 1 // Camera has ND filter\n");
6457     } else {
6458         bprintf("//#undef CAM_HAS_ND_FILTER // Camera does not have an ND filter\n");
6459     }
6460     if(get_misc_val_value("CAM_HAS_IRIS_DIAPHRAGM")) {
6461         bprintf("// Camera has an iris (CAM_HAS_IRIS_DIAPHRAGM default)\n");
6462     } else {
6463         bprintf("//#undef CAM_HAS_IRIS_DIAPHRAGM // Camera does not have an iris\n");
6464     }
6465 
6466     add_blankline();
6467 }
6468 
6469 void output_propcases(firmware *fw) {
6470 
6471     uint32_t used=0;
6472     uint32_t hits[KNOWN_PROPSET_COUNT];
6473     const uint32_t ps_offset = 6;
6474 
6475     memset(hits, 0, KNOWN_PROPSET_COUNT*sizeof(uint32_t));
6476 
6477     bprintf("// Known propcases\n");
6478 
6479     int n = 0;
6480     while (knownprops[n].name) {
6481         used += knownprops[n].use>0?1:0;
6482         if (knownprops[n].id >= 0)
6483         {
6484             if (knownprops[n].use)
6485             {
6486                 if (knownprops[n].id == knownprops[n].id_ps6) hits[6-ps_offset] += 1;
6487                 if (knownprops[n].id == knownprops[n].id_ps7) hits[7-ps_offset] += 1;
6488                 if (knownprops[n].id == knownprops[n].id_ps8) hits[8-ps_offset] += 1;
6489                 if (knownprops[n].id == knownprops[n].id_ps9) hits[9-ps_offset] += 1;
6490                 if (knownprops[n].id == knownprops[n].id_ps10) hits[10-ps_offset] += 1;
6491                 if (knownprops[n].id == knownprops[n].id_ps11) hits[11-ps_offset] += 1;
6492                 if (knownprops[n].id == knownprops[n].id_ps12) hits[12-ps_offset] += 1;
6493                 if (knownprops[n].id == knownprops[n].id_ps13) hits[13-ps_offset] += 1;
6494             }
6495             if (knownprops[n].use == 1)
6496             {
6497                 bprintf("// #define %s %i\n", knownprops[n].name, knownprops[n].id);
6498             }
6499             else
6500             {
6501                 // propcases not used by CHDK, name may be made up
6502                 bprintf("// //      %s %i\n", knownprops[n].name, knownprops[n].id);
6503             }
6504         }
6505         else
6506         {
6507             bprintf("//         %s not found\n", knownprops[n].name);
6508         }
6509         n++;
6510     }
6511 
6512     bprintf("// Guessed propset: ");
6513     int m = 0;
6514     uint32_t fmax = 0;
6515     int okay = 0;
6516     for (n=0; n<KNOWN_PROPSET_COUNT; n++)
6517     {
6518         if (hits[n] == used)
6519         {
6520             if (m) bprintf(", ");
6521             bprintf("%i", n+ps_offset);
6522             if (fw->sv->propset == n+ps_offset) okay = 1; // if the propset equals to (one of) the complete propset matches
6523             m += 1;
6524         }
6525         if (hits[n] > fmax) fmax = hits[n];
6526     }
6527     if (m == 0)
6528     {
6529         bprintf("uncertain (%i of %u match), closest to ",fmax,used);
6530         for (n=0; n<KNOWN_PROPSET_COUNT; n++)
6531         {
6532             if (hits[n] == fmax)
6533             {
6534                 if (m) bprintf(", ");
6535                 bprintf("%i", n+ps_offset);
6536                 if (fw->sv->propset == n+ps_offset) okay = 1; // if the propset equals to (one of) the most complete propset matches
6537                 m += 1;
6538             }
6539         }
6540     }
6541     bprintf("\n");
6542     if (!okay && fw->sv->propset>0)
6543     {
6544         // only shown when there's a clear mismatch
6545         bprintf("// Port's propset (%i) may be set incorrectly\n", fw->sv->propset);
6546     }
6547 
6548     add_blankline();
6549 }
6550 
6551 void output_exmem_types(firmware *fw)
6552 {
6553 
6554     misc_val_t *ett=get_misc_val("exmem_types_table");
6555     misc_val_t *etc=get_misc_val("exmem_type_count");
6556     if (ett->val == 0 || etc->val == 0) {
6557         return;
6558     }
6559     bprintf("// EXMEM types:\n");
6560     uint32_t n;
6561     for (n=0; n<etc->val; n++) {
6562         char *extyp = (char*)adr2ptr(fw, fw_u32(fw,ett->val+n*4));
6563         bprintf("// %s %i\n", extyp, n);
6564     }
6565     add_blankline();
6566 }
6567 
6568 void print_misc_val_comment(const char *name)
6569 {
6570     misc_val_t *mv=get_misc_val(name);
6571     if(!mv) {
6572         return;
6573     }
6574     // TODO legitimate 0 values might be possible, if so can add found bit
6575     if(!mv->val) {
6576         bprintf("// %s not found\n",name);
6577         return;
6578     }
6579     bprintf("// %s 0x%08x",name,mv->val);
6580     if(mv->offset) {
6581         bprintf(" (0x%x+0x%x)",mv->base,mv->offset);
6582     }
6583     if(mv->ref_adr) {
6584         bprintf(" Found @0x%08x",mv->ref_adr);
6585     }
6586     bprintf("\n");
6587 }
6588 
6589 typedef struct {
6590     int reg;
6591     uint32_t bit;
6592     uint32_t ev;
6593     uint32_t raw_info;
6594     int no_invert;
6595 } physw_table_entry_t;
6596 
6597 void get_physw_table_entry(firmware *fw, uint32_t adr, physw_table_entry_t *vals)
6598 {
6599     uint32_t info=fw_u32(fw,adr);
6600     vals->raw_info=info;
6601     vals->ev=fw_u32(fw,adr+4);
6602     // taken from finsig_dryos print_physw_raw_vals
6603     vals->reg=(info >>5) & 7;
6604     vals->bit=(1 << (info & 0x1f));
6605     // vals->no_invert=(info >> 16) & 1;
6606     vals->no_invert=((info&0xff0000)==0x10000)?1:0;
6607 }
6608 uint32_t find_physw_table_entry(firmware *fw, uint32_t tadr, int tcount, uint32_t ev)
6609 {
6610     int i;
6611     for(i=0; i<tcount; i++,tadr += 8) {
6612         if(fw_u32(fw,tadr+4) == ev) {
6613             return tadr;
6614         }
6615     }
6616     return 0;
6617 }
6618 // look for the first invalid looking entry
6619 uint32_t find_physw_table_max(firmware *fw, uint32_t tadr, int max_count)
6620 {
6621     int i;
6622     for(i=0; i<max_count; i++,tadr += 8) {
6623         physw_table_entry_t v;
6624         get_physw_table_entry(fw,tadr,&v);
6625         if(v.raw_info == 0 || v.raw_info == 0xFFFFFFFF || v.reg > 2) {
6626             return i;
6627         }
6628         // TODO could check that no event numbers (except -1) are repeated
6629     }
6630     return max_count;
6631 }
6632 void write_physw_event_table_dump(firmware *fw, uint32_t tadr, int tcount)
6633 {
6634     FILE *f=fopen("physw_bits.txt","w");
6635     if(!f) {
6636         return;
6637     }
6638     fprintf(f,"physw_event_table dump (%d entries printed, may not all be valid)\n",tcount);
6639     fprintf(f,"address    info       event      index bit        non-inverted\n");
6640     int i;
6641     physw_table_entry_t v;
6642 
6643     for(i=0; i<tcount; i++,tadr += 8) {
6644         get_physw_table_entry(fw,tadr,&v);
6645         fprintf(f,"0x%08x 0x%08x 0x%08x %-5d 0x%08x %d\n",tadr,v.raw_info,v.ev,v.reg,v.bit,v.no_invert);
6646     }
6647     fclose(f);
6648 }
6649 void print_kval(firmware *fw, uint32_t tadr, int tcount, uint32_t ev, const char *name, const char *sfx)
6650 {
6651     uint32_t adr=find_physw_table_entry(fw,tadr,tcount,ev);
6652     if(!adr) {
6653         return;
6654     }
6655     physw_table_entry_t v;
6656     get_physw_table_entry(fw,adr,&v);
6657 
6658     char fn[100], rn[100];
6659     strcpy(fn,name); strcat(fn,sfx);
6660     strcpy(rn,name); strcat(rn,"_IDX");
6661 
6662     bprintf("//#define %-20s0x%08x // Found @0x%08x, levent 0x%x%s\n",fn,v.bit,adr,v.ev,v.no_invert?" (non-inverted logic)":"");
6663     bprintf("//#define %-20s%d\n",rn,v.reg);
6664 
6665 }
6666 
6667 // key stuff copied from finsig_dryos.c
6668 typedef struct {
6669     int         reg;
6670     uint32_t    bits;
6671     char        nm[32];
6672     uint32_t    fadr;
6673     uint32_t    ev;
6674     int         inv;
6675 } kinfo;
6676 
6677 int     kmask[3];
6678 kinfo   key_info[100];
6679 int     kcount = 0;
6680 uint32_t kshutter_min_bits = 0xFFFFFFFF;
6681 
6682 void add_kinfo(int r, uint32_t b, const char *nm, uint32_t adr, uint32_t ev, int inv)
6683 {
6684     key_info[kcount].reg = r;
6685     key_info[kcount].bits = b;
6686     strcpy(key_info[kcount].nm, nm);
6687     key_info[kcount].fadr = adr;
6688     key_info[kcount].ev = ev;
6689     key_info[kcount].inv = inv;
6690     kcount++;
6691     kmask[r] |= b;
6692     if ((ev <= 1) && (b < kshutter_min_bits)) kshutter_min_bits = b;
6693 }
6694 
6695 uint32_t add_kmval(firmware *fw, uint32_t tadr, __attribute__ ((unused))int tsiz, int tlen, uint32_t ev, const char *name, uint32_t xtra)
6696 {
6697     uint32_t adr=find_physw_table_entry(fw,tadr,tlen,ev);
6698     if(!adr) {
6699         return 0;
6700     }
6701     physw_table_entry_t v;
6702     get_physw_table_entry(fw,adr,&v);
6703 
6704     add_kinfo(v.reg,v.bit|xtra,name,adr,v.ev,(v.no_invert)?0:1);
6705     return v.bit;
6706 }
6707 
6708 int kinfo_compare(const kinfo *p1, const kinfo *p2)
6709 {
6710     if (p1->reg > p2->reg)
6711     {
6712         return 1;
6713     }
6714     else if (p1->reg < p2->reg)
6715     {
6716         return -1;
6717     }
6718     if ((p1->ev <= 1) && (p2->ev <= 1))    // output shutter entries in reverse order
6719     {
6720         if (p1->bits > p2->bits)
6721         {
6722             return -1;
6723         }
6724         else if (p1->bits < p2->bits)
6725         {
6726             return 1;
6727         }
6728     }
6729     // if one entry is shutter then compare to min shutter bits
6730     if (p1->ev <= 1)
6731     {
6732         if (kshutter_min_bits > p2->bits)
6733         {
6734             return 1;
6735         }
6736         else if (kshutter_min_bits < p2->bits)
6737         {
6738             return -1;
6739         }
6740     }
6741     if (p2->ev <= 1)
6742     {
6743         if (p1->bits > kshutter_min_bits)
6744         {
6745             return 1;
6746         }
6747         else if (p1->bits < kshutter_min_bits)
6748         {
6749             return -1;
6750         }
6751     }
6752     if (p1->bits > p2->bits)
6753     {
6754         return 1;
6755     }
6756     else if (p1->bits < p2->bits)
6757     {
6758         return -1;
6759     }
6760 
6761     return 0;
6762 }
6763 
6764 void print_kmvals()
6765 {
6766     qsort(key_info, kcount, sizeof(kinfo), (void*)kinfo_compare);
6767 
6768     bprintf("//KeyMap keymap[] = {\n");
6769 
6770     int k;
6771     for (k=0; k<kcount; k++)
6772     {
6773         bprintf("//    { %d, %-20s,0x%08x }, // Found @0x%08x, levent 0x%02x%s\n",key_info[k].reg,key_info[k].nm,key_info[k].bits,key_info[k].fadr,key_info[k].ev,(key_info[k].inv==0)?"":" (uses inverted logic in physw_status)");
6774     }
6775 
6776     bprintf("//    { 0, 0, 0 }\n//};\n");
6777 }
6778 
6779 void do_km_vals(firmware *fw, uint32_t tadr,int tsiz,int tlen)
6780 {
6781     uint32_t key_half = add_kmval(fw,tadr,tsiz,tlen,0,"KEY_SHOOT_HALF",0);
6782     add_kmval(fw,tadr,tsiz,tlen,1,"KEY_SHOOT_FULL",key_half);
6783     add_kmval(fw,tadr,tsiz,tlen,1,"KEY_SHOOT_FULL_ONLY",0);
6784 
6785     add_kmval(fw,tadr,tsiz,tlen,0x101,"KEY_PLAYBACK",0);
6786     add_kmval(fw,tadr,tsiz,tlen,0x100,"KEY_POWER",0);
6787 
6788     // mostly copied from finsig_dryos, with < r52 stuff removed
6789     if (fw->dryos_ver == 52)  // unclear if this applies any other ver
6790     {
6791         add_kmval(fw,tadr,tsiz,tlen,3,"KEY_ZOOM_IN",0);
6792         add_kmval(fw,tadr,tsiz,tlen,4,"KEY_ZOOM_OUT",0);
6793         add_kmval(fw,tadr,tsiz,tlen,6,"KEY_UP",0);
6794         add_kmval(fw,tadr,tsiz,tlen,7,"KEY_DOWN",0);
6795         add_kmval(fw,tadr,tsiz,tlen,8,"KEY_LEFT",0);
6796         add_kmval(fw,tadr,tsiz,tlen,9,"KEY_RIGHT",0);
6797         add_kmval(fw,tadr,tsiz,tlen,0xA,"KEY_SET",0);
6798         add_kmval(fw,tadr,tsiz,tlen,0xB,"KEY_MENU",0);
6799         add_kmval(fw,tadr,tsiz,tlen,0xC,"KEY_DISPLAY",0);
6800         add_kmval(fw,tadr,tsiz,tlen,0x12,"KEY_HELP",0);
6801         add_kmval(fw,tadr,tsiz,tlen,0x19,"KEY_ERASE",0);
6802         add_kmval(fw,tadr,tsiz,tlen,2,"KEY_VIDEO",0);
6803 //        add_kmval(fw,tadr,tsiz,tlen,18,"KEY_SHORTCUT",0);
6804     }
6805     else if (fw->dryos_ver < 54)
6806     {
6807         add_kmval(fw,tadr,tsiz,tlen,2,"KEY_ZOOM_IN",0);
6808         add_kmval(fw,tadr,tsiz,tlen,3,"KEY_ZOOM_OUT",0);
6809         add_kmval(fw,tadr,tsiz,tlen,4,"KEY_UP",0);
6810         add_kmval(fw,tadr,tsiz,tlen,5,"KEY_DOWN",0);
6811         add_kmval(fw,tadr,tsiz,tlen,6,"KEY_LEFT",0);
6812         add_kmval(fw,tadr,tsiz,tlen,7,"KEY_RIGHT",0);
6813         add_kmval(fw,tadr,tsiz,tlen,8,"KEY_SET",0);
6814         add_kmval(fw,tadr,tsiz,tlen,9,"KEY_MENU",0);
6815         add_kmval(fw,tadr,tsiz,tlen,0xA,"KEY_DISPLAY",0);
6816     }
6817     else if (fw->dryos_ver < 55)
6818     {
6819         add_kmval(fw,tadr,tsiz,tlen,3,"KEY_ZOOM_IN",0);
6820         add_kmval(fw,tadr,tsiz,tlen,4,"KEY_ZOOM_OUT",0);
6821         add_kmval(fw,tadr,tsiz,tlen,6,"KEY_UP",0);
6822         add_kmval(fw,tadr,tsiz,tlen,7,"KEY_DOWN",0);
6823         add_kmval(fw,tadr,tsiz,tlen,8,"KEY_LEFT",0);
6824         add_kmval(fw,tadr,tsiz,tlen,9,"KEY_RIGHT",0);
6825         add_kmval(fw,tadr,tsiz,tlen,0xA,"KEY_SET",0);
6826         add_kmval(fw,tadr,tsiz,tlen,0xE,"KEY_MENU",0);
6827         add_kmval(fw,tadr,tsiz,tlen,2,"KEY_VIDEO",0);
6828         add_kmval(fw,tadr,tsiz,tlen,0xD,"KEY_DISPLAY",0);
6829         add_kmval(fw,tadr,tsiz,tlen,0x103,"KEY_WIFI",0);
6830 // framing assist / shortuct
6831 //        add_kmval(fw,tadr,tsiz,tlen,0xF,"KEY_",0);
6832     }
6833     else if (fw->dryos_ver < 59)
6834     {
6835         add_kmval(fw,tadr,tsiz,tlen,3,"KEY_ZOOM_IN",0);
6836         add_kmval(fw,tadr,tsiz,tlen,4,"KEY_ZOOM_OUT",0);
6837         add_kmval(fw,tadr,tsiz,tlen,6,"KEY_UP",0);
6838         add_kmval(fw,tadr,tsiz,tlen,7,"KEY_DOWN",0);
6839         add_kmval(fw,tadr,tsiz,tlen,8,"KEY_LEFT",0);
6840         add_kmval(fw,tadr,tsiz,tlen,9,"KEY_RIGHT",0);
6841         add_kmval(fw,tadr,tsiz,tlen,0xA,"KEY_SET",0);
6842         add_kmval(fw,tadr,tsiz,tlen,0x14,"KEY_MENU",0);
6843         add_kmval(fw,tadr,tsiz,tlen,2,"KEY_VIDEO",0);
6844         add_kmval(fw,tadr,tsiz,tlen,0xD,"KEY_DISPLAY",0);
6845         add_kmval(fw,tadr,tsiz,tlen,0x103,"KEY_WIFI",0);
6846 // framing assist, shortcut
6847 //        add_kmval(fw,tadr,tsiz,tlen,0xF,"KEY_",0);
6848     }
6849     else
6850     {
6851         add_kmval(fw,tadr,tsiz,tlen,3,"KEY_ZOOM_IN",0);
6852         add_kmval(fw,tadr,tsiz,tlen,4,"KEY_ZOOM_OUT",0);
6853         add_kmval(fw,tadr,tsiz,tlen,6,"KEY_UP",0);
6854         add_kmval(fw,tadr,tsiz,tlen,7,"KEY_DOWN",0);
6855         add_kmval(fw,tadr,tsiz,tlen,8,"KEY_LEFT",0);
6856         add_kmval(fw,tadr,tsiz,tlen,9,"KEY_RIGHT",0);
6857         add_kmval(fw,tadr,tsiz,tlen,0xA,"KEY_SET",0);
6858         add_kmval(fw,tadr,tsiz,tlen,0x15,"KEY_MENU",0);
6859         add_kmval(fw,tadr,tsiz,tlen,2,"KEY_VIDEO",0);
6860         add_kmval(fw,tadr,tsiz,tlen,0xB,"KEY_ERASE",0); // also framing assist etc
6861         add_kmval(fw,tadr,tsiz,tlen,0x103,"KEY_WIFI",0);
6862     }
6863 
6864     bprintf("\n// Keymap values for kbd.c. Additional keys may be present, only common values included here.\n");
6865     bprintf("// WARNING: Key name / function may vary! Values for unknown DryOS versions should not be trusted!\n");
6866     print_kmvals();
6867 }
6868 void output_physw_vals(firmware *fw) {
6869     print_misc_val_comment("physw_event_table");
6870     uint32_t physw_tbl=get_misc_val_value("physw_event_table");
6871     if(!physw_tbl) {
6872         return;
6873     }
6874     int physw_tbl_len=find_physw_table_max(fw,physw_tbl,50);
6875     write_physw_event_table_dump(fw,physw_tbl,physw_tbl_len);
6876 
6877     bprintf("// Values below go in 'platform_kbd.h':\n");
6878     if (fw->dryos_ver >= 58)
6879     {
6880         // Event ID's have changed in DryOS 58 **********
6881         print_kval(fw,physw_tbl,physw_tbl_len,0x30A,"SD_READONLY","_FLAG");
6882         print_kval(fw,physw_tbl,physw_tbl_len,0x302,"USB","_MASK");
6883         print_kval(fw,physw_tbl,physw_tbl_len,0x305,"BATTCOVER","_FLAG");
6884         print_kval(fw,physw_tbl,physw_tbl_len,0x304,"HOTSHOE","_FLAG");
6885         print_kval(fw,physw_tbl,physw_tbl_len,0x300,"ANALOG_AV","_FLAG");
6886     }
6887     else
6888     {
6889         print_kval(fw,physw_tbl,physw_tbl_len,0x20A,"SD_READONLY","_FLAG");
6890         print_kval(fw,physw_tbl,physw_tbl_len,0x202,"USB","_MASK");
6891         print_kval(fw,physw_tbl,physw_tbl_len,0x205,"BATTCOVER","_FLAG");
6892         print_kval(fw,physw_tbl,physw_tbl_len,0x204,"HOTSHOE","_FLAG");
6893         print_kval(fw,physw_tbl,physw_tbl_len,0x200,"ANALOG_AV","_FLAG");
6894     }
6895     do_km_vals(fw,physw_tbl,2,physw_tbl_len);
6896 
6897     add_blankline();
6898 }
6899 
6900 /*
6901 typedef struct
6902 {
6903     uint16_t mode;
6904     char *nm;
6905 } ModeMapName;
6906 
6907 
6908 // TODO numbers changed after g1xmk2
6909 // M=32770
6910 ModeMapName mmnames[] = {
6911     { 32768,"MODE_AUTO" },
6912     { 32769,"MODE_M" },
6913     { 32770,"MODE_AV" },
6914     { 32771,"MODE_TV" },
6915     { 32772,"MODE_P" },
6916 
6917     { 65535,"" }
6918 };
6919 
6920 char* mode_name(uint16_t v)
6921 {
6922     int i;
6923     for (i=0; mmnames[i].mode != 65535; i++)
6924     {
6925         if (mmnames[i].mode == v)
6926             return mmnames[i].nm;
6927     }
6928 
6929     return "";
6930 }
6931 */
6932 
6933 
6934 void output_modemap(firmware *fw) {
6935     print_misc_val_comment("canon_mode_list");
6936     bprintf("// Check modemap values from 'platform/CAMERA/shooting.c':\n");
6937     misc_val_t *mv=get_misc_val("canon_mode_list");
6938     if(!mv) {
6939         add_blankline();
6940         return;
6941     }
6942     int i;
6943     uint32_t adr=mv->val;
6944     int bad=0;
6945     for(i=0; i<50; i++,adr+=2) {
6946         uint16_t *pv=(uint16_t*)adr2ptr(fw,adr);
6947         if(!pv) {
6948             break;
6949         }
6950         if(*pv==0xFFFF) {
6951             break;
6952         }
6953         osig *m = find_sig_val(fw->sv->modemap, *pv);
6954         if (!m) {
6955             bprintf("// %5hu  0x%04hx In firmware but not in current modemap",*pv,*pv);
6956             /*
6957             char *s = mode_name(*pv);
6958             if (strcmp(s,"") != 0) {
6959                 bprintf(" (%s)",s);
6960             }
6961             */
6962             bprintf("\n");
6963             bad++;
6964         } else {
6965 //            bprintf("// %5hu  0x%04hx %s\n", *pv,*pv,m->nm);
6966             m->pct = 100;
6967         }
6968     }
6969     osig *m = fw->sv->modemap;
6970     while (m)
6971     {
6972         if (m->pct != 100)    // not matched above?
6973         {
6974             bprintf("// Current modemap entry not found in firmware - %-24s %5d\n",m->nm,m->val);
6975             bad++;
6976         }
6977         m = m->nxt;
6978     }
6979     if (bad == 0)
6980     {
6981         bprintf("// No problems found with modemap table.\n");
6982     }
6983 
6984     add_blankline();
6985 }
6986 
6987 // copied from finsig_dryos
6988 int compare_sig_names(const sig_entry_t **p1, const sig_entry_t **p2)
6989 {
6990     int rv = strcasecmp((*p1)->name, (*p2)->name);     // Case insensitive
6991     if (rv != 0)
6992         return rv;
6993     rv = strcmp((*p1)->name, (*p2)->name);          // Case sensitive (if equal with insensitive test)
6994     if (rv != 0)
6995         return rv;
6996     if ((*p1)->val < (*p2)->val)
6997         return -1;
6998     else if ((*p1)->val > (*p2)->val)
6999         return 1;
7000     return 0;
7001 }
7002 
7003 int compare_func_addresses(const sig_entry_t **p1, const sig_entry_t **p2)
7004 {
7005     if ((*p1)->val < (*p2)->val)
7006         return -1;
7007     else if ((*p1)->val > (*p2)->val)
7008         return 1;
7009     return compare_sig_names(p1,p2);
7010 }
7011 
7012 void write_funcs(firmware *fw, char *filename, sig_entry_t *fns[], int (*compare)(const sig_entry_t **p1, const sig_entry_t **p2))
7013 {
7014     int k;
7015 
7016     qsort(fns, next_sig_entry, sizeof(sig_entry_t*), (void*)compare);
7017 
7018     FILE *out_fp = fopen(filename, "w");
7019     for (k=0; k<next_sig_entry; k++)
7020     {
7021         if (strncmp(fns[k]->name,"hook_",5) == 0) {
7022             continue;
7023         }
7024         if (fns[k]->val != 0)
7025         {
7026             if (fns[k]->flags & BAD_MATCH)
7027             {
7028                 osig* ostub2 = find_sig(fw->sv->stubs,fns[k]->name);
7029                 if (ostub2 && ostub2->val)
7030                     fprintf(out_fp, "0x%08x,%s,(stubs_entry_2.s)\n", ostub2->val, fns[k]->name);
7031             }
7032             else
7033                 fprintf(out_fp, "0x%08x,%s\n", fns[k]->val, fns[k]->name);
7034         }
7035 #ifdef LIST_IMPORTANT_FUNCTIONS
7036         else if (fns[k]->flags & LIST_ALWAYS)
7037         {
7038             // helps development by listing important functions even when not found
7039             fprintf(out_fp, "0,%s,(NOT FOUND)\n", fns[k]->name);
7040         }
7041 #endif
7042     }
7043     fclose(out_fp);
7044 }
7045 // end copy finsig_dryos
7046 void write_func_lists(firmware *fw) {
7047     sig_entry_t *fns[MAX_SIG_ENTRY];
7048     int k;
7049     for (k=0; k<next_sig_entry; k++)
7050         fns[k] = &sig_names[k];
7051 
7052     write_funcs(fw, "funcs_by_name.csv", fns, compare_sig_names);
7053     write_funcs(fw, "funcs_by_address.csv", fns, compare_func_addresses);
7054 }
7055 
7056 void print_other_stubs_min(firmware *fw, const char *name, uint32_t fadr, uint32_t atadr)
7057 {
7058     osig *o = find_sig(fw->sv->stubs_min,name);
7059     if (o)
7060     {
7061         bprintf("//DEF(%-40s,0x%08x) // Found @0x%08x",name,fadr,atadr);
7062         if (fadr != o->val)
7063         {
7064             bprintf(", ** != ** stubs_min = 0x%08x (%s)",o->val,o->sval);
7065         }
7066         else
7067         {
7068             bprintf(",          stubs_min = 0x%08x (%s)",o->val,o->sval);
7069         }
7070     }
7071     else
7072     {
7073         bprintf("DEF(%-40s,0x%08x) // Found @0x%08x",name,fadr,atadr);
7074     }
7075     bprintf("\n");
7076 }
7077 
7078 void print_stubs_min_def(firmware *fw, misc_val_t *sig)
7079 {
7080     if(sig->flags & MISC_VAL_NO_STUB) {
7081         return;
7082     }
7083     // find best match and report results
7084     osig* ostub2=find_sig(fw->sv->stubs_min,sig->name);
7085     const char *ostub_src = "stubs_min";
7086 
7087     if(!ostub2) {
7088         ostub2=find_sig(fw->sv->stubs,sig->name);
7089         ostub_src="stubs_entry_2";
7090     }
7091 
7092     const char *macro = "DEF";
7093     if(sig->flags & MISC_VAL_DEF_CONST) {
7094         macro="DEF_CONST";
7095     }
7096 
7097     if (ostub2)
7098     {
7099         bprintf("//%s(%-34s,0x%08x)",macro,sig->name,sig->val);
7100         if (sig->val != ostub2->val)
7101         {
7102             bprintf(", ** != ** %s = 0x%08x (%s)",ostub_src,ostub2->val,ostub2->sval);
7103         }
7104         else
7105         {
7106             bprintf(",          %s = 0x%08x (%s)",ostub_src,ostub2->val,ostub2->sval);
7107         }
7108     }
7109     else if(sig->base || sig->offset)
7110     {
7111         bprintf("%s(%-34s,0x%08x)",macro,sig->name,sig->val);
7112         if(sig->offset || sig->ref_adr) {
7113             bprintf(" //");
7114             if(sig->offset) {
7115                 bprintf(" (0x%x+0x%x)",sig->base,sig->offset);
7116             }
7117             if(sig->ref_adr) {
7118                 bprintf(" Found @0x%08x",sig->ref_adr);
7119             }
7120         }
7121     }
7122     else
7123     {
7124         if (sig->flags & MISC_VAL_OPTIONAL) return;
7125         bprintf("// %s not found",sig->name);
7126     }
7127     bprintf("\n");
7128 }
7129 
7130 // Search for other things that go in 'stubs_min.S'
7131 void find_other_stubs_min(firmware *fw)
7132 {
7133     int k,k1;
7134 
7135     out_hdr = 1;
7136 
7137     // focus_len_table
7138     if (fw->sv->min_focus_len != 0)
7139     {
7140         int found = 0, pos = 0, len = 0, size = 0;
7141         for (k=0; k<fw->size32; k++)
7142         {
7143             if (fw->buf32[k] == fw->sv->min_focus_len)
7144             {
7145                 int mul = 1;
7146                 if ((fw->buf32[k+1] == 100) && (fw->buf32[k+2] == 0)) mul = 3;
7147                 if ((fw->buf32[k+1] == 100) && (fw->buf32[k+2] != 0)) mul = 2;
7148                 if ((fw->buf32[k+1] ==   0) && (fw->buf32[k+2] != 0)) mul = 2;
7149                 for (k1 = k + mul; (k1 < fw->size32) && (fw->buf32[k1] > fw->buf32[k1-mul]) && (fw->buf32[k1] > fw->sv->min_focus_len) && (fw->buf32[k1] < fw->sv->max_focus_len); k1 += mul) ;
7150                 if (fw->buf32[k1] == fw->sv->max_focus_len)
7151                 {
7152                     if ((found == 0) || ((size < mul) && (len < ((k1 - k) / mul) + 1)))
7153                     {
7154                         found = 1;
7155                         pos = k;
7156                         len = ((k1 - k) / mul) + 1;
7157                         size = mul;
7158                     }
7159                 }
7160             }
7161         }
7162         if (found == 1)
7163         {
7164             uint32_t adr = fw->base + (pos << 2);
7165             bprintf("// focus_len_table contains zoom focus lengths for use in 'get_focal_length' (main.c).\n");
7166             if (size == 1)
7167                 bprintf("// each entry contains 1 int value, which is the the zoom focus length.\n",size);
7168             else
7169                 bprintf("// each entry contains %d int value(s), the first is the zoom focus length.\n",size);
7170             bprintf("// there are %d entries in the table - set NUM_FL to %d\n",len,len);
7171             print_other_stubs_min(fw,"focus_len_table",adr,adr);
7172         }
7173     }
7174 }
7175 
7176 // Output match results for function
7177 // matches stuff butchered out for now, just using value in sig_names table
7178 void print_results(firmware *fw, sig_entry_t *sig)
7179 {
7180     int i;
7181     int err = 0;
7182     char line[500] = "";
7183 
7184     if (sig->flags & DONT_EXPORT) {
7185         return;
7186     }
7187 
7188     if ((sig->flags & DONT_EXPORT_ILC) && get_misc_val_value("CAM_IS_ILC")) {
7189         return;
7190     }
7191 
7192     // find best match and report results
7193     osig* ostub2 = find_sig(fw->sv->stubs,sig->name);
7194 
7195     if (ostub2 && (sig->val != ostub2->val))
7196     {
7197         if (ostub2->type != TYPE_IGNORE)
7198         {
7199             err = 1;
7200             sig->flags |= BAD_MATCH;
7201         }
7202     }
7203     else
7204     {
7205         if (sig->flags & UNUSED) return;
7206     }
7207 
7208     // write to header (if error) or body buffer (no error)
7209     out_hdr = err;
7210 
7211     char *macro = "NHSTUB";
7212     if (sig->flags & ARM_STUB) {
7213         macro = "NHSTUB2";
7214     }
7215     if (strncmp(sig->name,"task_",5) == 0 ||
7216         strncmp(sig->name,"hook_",5) == 0) macro = "   DEF";
7217 
7218     if (!sig->val && !ostub2)
7219     {
7220         if (sig->flags & OPTIONAL) return;
7221         char fmt[51] = "";
7222         sprintf(fmt, "// ERROR: %%s is not found. %%%ds//--- --- ", (int)(34-strlen(sig->name)));
7223         sprintf(line+strlen(line), fmt, sig->name, "");
7224     }
7225     else
7226     {
7227         if (ostub2 || (sig->flags & UNUSED))
7228             sprintf(line+strlen(line),"//%s(%-37s,0x%08x) //%3d ", macro, sig->name, sig->val, 0);
7229         else
7230             sprintf(line+strlen(line),"%s(%-39s,0x%08x) //%3d ", macro, sig->name, sig->val, 0);
7231 
7232         /*
7233         if (matches->fail > 0)
7234             sprintf(line+strlen(line),"%2d%% ", matches->success*100/(matches->success+matches->fail));
7235         else
7236             */
7237             sprintf(line+strlen(line),"    ");
7238     }
7239 
7240     if (ostub2)
7241     {
7242         if (ostub2->type == TYPE_IGNORE)
7243             sprintf(line+strlen(line),"       Overridden");
7244         else if (sig->val == ostub2->val)
7245             sprintf(line+strlen(line),"       == 0x%08x    ",ostub2->val);
7246         else {
7247             // if both have same value check if differs only by veneer
7248             if(sig->val && ostub2->val) {
7249                 fw_disasm_iter_single(fw,ostub2->val);
7250                 if(get_direct_jump_target(fw,fw->is) == sig->val) {
7251                     sprintf(line+strlen(line)," <-veneer 0x%08x    ",ostub2->val);
7252                 } else {
7253                     fw_disasm_iter_single(fw,sig->val);
7254                     if(get_direct_jump_target(fw,fw->is) == ostub2->val) {
7255                         sprintf(line+strlen(line)," veneer-> 0x%08x    ",ostub2->val);
7256                     } else {
7257                         sprintf(line+strlen(line),"   *** != 0x%08x    ",ostub2->val);
7258                     }
7259                 }
7260             } else {
7261                 sprintf(line+strlen(line),"   *** != 0x%08x    ",ostub2->val);
7262             }
7263         }
7264     }
7265     else
7266         sprintf(line+strlen(line),"                        ");
7267 
7268     for (i=strlen(line)-1; i>=0 && line[i]==' '; i--) line[i] = 0;
7269     bprintf("%s\n",line);
7270 
7271     /*
7272     for (i=1;i<count && matches[i].fail==matches[0].fail;i++)
7273     {
7274         if (matches[i].ptr != matches->ptr)
7275         {
7276             bprintf("// ALT: %s(%s, 0x%x) // %d %d/%d\n", macro, curr_name, matches[i].ptr, matches[i].sig, matches[i].success, matches[i].fail);
7277         }
7278     }
7279     */
7280 }
7281 
7282 void write_stubs(firmware *fw,int max_find_func) {
7283     int k;
7284     bprintf("// Values below can be overridden in 'stubs_min.S':\n");
7285     misc_val_t *stub_min=misc_vals;
7286     while(stub_min->name) {
7287         print_stubs_min_def(fw,stub_min);
7288         stub_min++;
7289     }
7290 
7291     find_other_stubs_min(fw);
7292 
7293     add_blankline();
7294 
7295     for (k = 0; k < max_find_func; k++)
7296     {
7297         print_results(fw,&sig_names[k]);
7298     }
7299 }
7300 
7301 int main(int argc, char **argv)
7302 {
7303     clock_t t1 = clock();
7304 
7305     firmware fw;
7306     memset(&fw,0,sizeof(firmware));
7307     if (argc < 4) {
7308         fprintf(stderr,"finsig_thumb2 <primary> <base> <outputfilename>\n");
7309         exit(1);
7310     }
7311 
7312     for (next_sig_entry = 0; sig_names[next_sig_entry].name != 0; next_sig_entry++);
7313     int max_find_sig = next_sig_entry;
7314 
7315     fw.sv = new_stub_values();
7316     load_stubs(fw.sv, "stubs_entry_2.S", 1);
7317     load_stubs_min(fw.sv);
7318     load_modemap(fw.sv);
7319     load_platform(fw.sv);
7320 
7321     bprintf("// !!! THIS FILE IS GENERATED. DO NOT EDIT. !!!\n");
7322     bprintf("#include \"stubs_asm.h\"\n\n");
7323 
7324     firmware_load(&fw,argv[1],strtoul(argv[2], NULL, 0),FW_ARCH_ARMv7);
7325     if(!firmware_init_capstone(&fw)) {
7326         exit(1);
7327     }
7328     firmware_init_data_ranges(&fw);
7329 
7330     out_fp = fopen(argv[3],"w");
7331     if (out_fp == NULL) {
7332         fprintf(stderr,"Error opening output file %s\n",argv[3]);
7333         exit(1);
7334     }
7335 
7336 
7337     // find ctypes - previously separate from regular sig matches to set code search limit
7338     find_ctypes(&fw);
7339 
7340     run_sig_rules(&fw,sig_rules_initial);
7341     find_generic_funcs(&fw);
7342     run_sig_rules(&fw,sig_rules_main);
7343 
7344     output_firmware_vals(&fw);
7345 
7346     output_platform_vals(&fw);
7347     output_physw_vals(&fw);
7348     output_modemap(&fw);
7349 
7350     output_propcases(&fw);
7351     output_exmem_types(&fw);
7352 
7353     write_stubs(&fw,max_find_sig);
7354 
7355     write_output();
7356     fclose(out_fp);
7357 
7358     write_func_lists(&fw);
7359 
7360     firmware_unload(&fw);
7361 
7362     clock_t t2 = clock();
7363 
7364     printf("Time to generate stubs %.2f seconds\n",(double)(t2-t1)/(double)CLOCKS_PER_SEC);
7365 
7366     return 0;
7367 }

/* [<][>][^][v][top][bottom][index][help] */