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_with_j
  17. find_next_sig_call
  18. is_sig_call
  19. init_disasm_sig_ref
  20. sig_match_str_r0_call
  21. sig_match_reg_evp
  22. sig_match_reg_evp_table
  23. sig_match_reg_evp_alt2
  24. sig_match_unreg_evp_table
  25. sig_match_evp_table_veneer
  26. sig_match_get_nd_value
  27. sig_match_get_current_exp
  28. sig_match_get_current_nd_value
  29. sig_match_imager_active_callback
  30. sig_match_imager_active
  31. sig_match_screenlock_helper
  32. sig_match_screenunlock
  33. sig_match_log_camera_event
  34. sig_match_physw_misc
  35. sig_match_kbd_read_keys
  36. sig_match_get_kbd_state
  37. sig_match_get_dial_hw_position
  38. sig_match_create_jumptable
  39. sig_match_take_semaphore_strict
  40. sig_match_get_semaphore_value
  41. sig_match_stat
  42. sig_match_open
  43. sig_match_open_gt_57
  44. sig_match_close_gt_57
  45. sig_match_umalloc
  46. sig_match_ufree
  47. sig_match_deletefile_fut
  48. sig_match_closedir
  49. save_sig_match_call
  50. sig_match_readfastdir
  51. sig_match_strrchr
  52. sig_match_time
  53. sig_match_strncpy
  54. sig_match_strncmp
  55. sig_match_strtolx
  56. sig_match_exec_evp
  57. sig_match_fgets_fut
  58. sig_match_log
  59. sig_match_pow_dry_52
  60. sig_match_pow_dry_gt_52
  61. sig_match_sqrt
  62. sig_match_get_drive_cluster_size
  63. sig_match_mktime_ext
  64. sig_match_rec2pb
  65. sig_match_get_parameter_data
  66. sig_match_prepdir_x
  67. sig_match_prepdir_1
  68. sig_match_prepdir_0
  69. sig_match_mkdir
  70. sig_match_add_ptp_handler
  71. sig_match_qsort
  72. sig_match_deletedirectory_fut
  73. sig_match_set_control_event
  74. sig_match_displaybusyonscreen_52
  75. sig_match_undisplaybusyonscreen_52
  76. sig_match_try_take_sem_dry_gt_58
  77. sig_match_wait_all_eventflag_strict
  78. sig_match_get_num_posted_messages
  79. sig_match_set_hp_timer_after_now
  80. sig_match_transfer_src_overlay
  81. sig_match_exmem_vars
  82. sig_match_zicokick_52
  83. sig_match_zicokick_gt52
  84. sig_match_zicokick_copy
  85. sig_match_zicokick_values
  86. sig_match_init_ex_drivers
  87. sig_match_omar_init
  88. sig_match_enable_hdmi_power
  89. sig_match_disable_hdmi_power
  90. sig_match_levent_table
  91. sig_match_flash_param_table
  92. sig_match_jpeg_count_str
  93. sig_match_misc_flag_named
  94. sig_match_cam_has_iris_diaphragm
  95. sig_match_cam_uncached_bit
  96. sig_match_physw_event_table
  97. sig_match_uiprop_count
  98. sig_match_get_canon_mode_list
  99. sig_match_zoom_busy
  100. sig_match_focus_busy
  101. sig_match_aram_size
  102. sig_match_aram_size_gt58
  103. sig_match_aram_start
  104. sig_match_aram_start2
  105. sig_match__nrflag
  106. sig_match_var_struct_get
  107. sig_match_av_over_sem
  108. sig_match_canon_menu_active
  109. sig_match_file_counter_init
  110. sig_match_file_counter_var
  111. sig_match_palette_vars
  112. sig_match_rom_ptr_get
  113. find_call_near_str
  114. sig_match_near_str
  115. sig_match_prop_string
  116. is_immediate_ret_sub
  117. sig_match_named_last
  118. sig_match_named_save_sig
  119. sig_match_named
  120. run_sig_rules
  121. add_event_proc
  122. process_reg_eventproc_call
  123. process_eventproc_table_call
  124. process_createtask_call
  125. save_ptp_handler_func
  126. process_add_ptp_handler_call
  127. add_generic_func_match
  128. add_generic_sig_match
  129. find_exception_handlers
  130. find_generic_funcs
  131. find_ctypes
  132. print_misc_val_makefile
  133. output_firmware_vals
  134. print_platform_misc_val_undef
  135. output_platform_vals
  136. output_propcases
  137. output_exmem_types
  138. print_misc_val_comment
  139. get_physw_table_entry
  140. find_physw_table_entry
  141. find_physw_table_max
  142. write_physw_event_table_dump
  143. print_kval
  144. add_kinfo
  145. add_kmval
  146. kinfo_compare
  147. print_kmvals
  148. do_km_vals
  149. output_physw_vals
  150. output_modemap
  151. compare_sig_names
  152. compare_func_addresses
  153. write_funcs
  154. write_func_lists
  155. print_other_stubs_min
  156. print_stubs_min_def
  157. find_other_stubs_min
  158. print_results
  159. write_stubs
  160. 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 /* copied from finsig_dryos.c */
  32 char    out_buf[32*1024] = "";
  33 int     out_len = 0;
  34 char    hdr_buf[32*1024] = "";
  35 int     hdr_len = 0;
  36 int     out_hdr = 1;
  37 
  38 FILE *out_fp;
  39 
  40 void bprintf(char *fmt, ...)
  41 {
  42     va_list argp;
  43     va_start(argp, fmt);
  44 
  45     if (out_hdr)
  46         hdr_len += vsprintf(hdr_buf+hdr_len,fmt,argp);
  47     else
  48         out_len += vsprintf(out_buf+out_len,fmt,argp);
  49 
  50     va_end(argp);
  51 }
  52 
  53 void add_blankline()
  54 {
  55     if (strcmp(hdr_buf+hdr_len-2,"\n\n") != 0)
  56     {
  57         hdr_buf[hdr_len++] = '\n';
  58         hdr_buf[hdr_len] = 0;
  59     }
  60 }
  61 
  62 void write_output()
  63 {
  64     add_blankline();
  65     if (out_fp)
  66     {
  67         fprintf(out_fp,"%s",hdr_buf);
  68         fprintf(out_fp,"%s",out_buf);
  69     }
  70 }
  71 
  72 // Master list of functions / addresses to find
  73 
  74 #define DONT_EXPORT    0x01
  75 #define OPTIONAL       0x02
  76 #define UNUSED         0x04
  77 #define BAD_MATCH      0x08
  78 #define EV_MATCH       0x10
  79 #define LIST_ALWAYS    0x20
  80 // force an arm veneer (NHSTUB2)
  81 #define ARM_STUB       0x80
  82 #define DONT_EXPORT_ILC 0x100
  83 
  84 typedef struct {
  85     char        *name;
  86     int         flags;
  87     uint32_t    val;
  88 } sig_entry_t;
  89 
  90 int next_sig_entry = 0;
  91 
  92 #define MAX_SIG_ENTRY  5000
  93 
  94 sig_entry_t  sig_names[MAX_SIG_ENTRY] =
  95 {
  96     // Order here currently has no effect on search order, but mostly copied from finsig_dryos which did
  97     { "ExportToEventProcedure_FW", UNUSED|DONT_EXPORT },
  98     { "RegisterEventProcedure", UNUSED|DONT_EXPORT },
  99     { "RegisterEventProcedure_alt1", UNUSED|DONT_EXPORT },
 100     { "RegisterEventProcedure_alt2", UNUSED|DONT_EXPORT },
 101     { "RegisterEventProcTable", UNUSED|DONT_EXPORT },
 102     { "UnRegisterEventProcTable", UNUSED|DONT_EXPORT },
 103     { "UnRegisterEventProcedure", UNUSED|DONT_EXPORT },
 104     { "PrepareDirectory_1", UNUSED|DONT_EXPORT },
 105     { "PrepareDirectory_x", UNUSED|DONT_EXPORT },
 106     { "PrepareDirectory_0", UNUSED|DONT_EXPORT },
 107     { "CreateTaskStrictly", UNUSED|DONT_EXPORT },
 108     { "CreateTaskStrictly_alt", UNUSED|DONT_EXPORT },
 109     { "CreateTask_alt", UNUSED|DONT_EXPORT },
 110     { "CreateTask_low", UNUSED | OPTIONAL },
 111     { "CreateJumptable", UNUSED },
 112     { "_uartr_req", UNUSED },
 113     { "StartRecModeMenu", UNUSED },
 114     { "LogCameraEvent", UNUSED|DONT_EXPORT },
 115     { "getImageDirName", UNUSED|DONT_EXPORT },
 116 
 117     { "AllocateMemory", UNUSED|LIST_ALWAYS },
 118     { "AllocateUncacheableMemory" },
 119     { "Close" },
 120     { "CreateBinarySemaphore" },
 121     { "CreateCountingSemaphore", UNUSED|LIST_ALWAYS },
 122     { "CreateTask" },
 123     { "DebugAssert", OPTIONAL|LIST_ALWAYS },
 124     { "DeleteDirectory_Fut" },
 125     { "DeleteFile_Fut" },
 126     { "DeleteSemaphore", UNUSED|LIST_ALWAYS },
 127     { "DoAELock" },
 128     { "DoAFLock" },
 129     { "EnterToCompensationEVF" },
 130     { "ExecuteEventProcedure", ARM_STUB },
 131     { "ExitFromCompensationEVF" },
 132     { "ExitTask" },
 133     { "ExpCtrlTool_StartContiAE" },
 134     { "ExpCtrlTool_StopContiAE" },
 135     { "Fclose_Fut" },
 136     { "Feof_Fut" },
 137     { "Fflush_Fut" },
 138     { "Fgets_Fut" },
 139     { "Fopen_Fut" },
 140     { "Fread_Fut" },
 141     { "FreeMemory", UNUSED|LIST_ALWAYS },
 142     { "FreeUncacheableMemory" },
 143     { "Fseek_Fut" },
 144     { "Fwrite_Fut" },
 145     { "GetBatteryTemperature" },
 146     { "GetCCDTemperature" },
 147 
 148     { "GetCurrentAvValue" },
 149     { "GetCurrentShutterSpeed" },
 150     { "GetUsableMaxAv", OPTIONAL },
 151     { "GetUsableMinAv", OPTIONAL },
 152     { "GetUsableAvRange", UNUSED |OPTIONAL },
 153     { "get_nd_value", OPTIONAL },
 154     { "get_current_exp", UNUSED | OPTIONAL }, // helper, underlying function of ShowCurrentExp
 155     { "get_current_nd_value", OPTIONAL },
 156     { "GetDrive_ClusterSize" },
 157     { "GetDrive_FreeClusters" },
 158     { "GetDrive_TotalClusters" },
 159     { "GetFocusLensSubjectDistance" },
 160     { "GetFocusLensSubjectDistanceFromLens" },
 161     { "GetImageFolder", OPTIONAL },
 162     { "GetKbdState" },
 163     { "GetMemInfo" },
 164     { "GetOpticalTemperature" },
 165     { "GetParameterData" },
 166     { "GetPropertyCase" },
 167     { "GetSystemTime" },
 168     { "GetVRAMHPixelsSize" },
 169     { "GetVRAMVPixelsSize" },
 170     { "GetZoomLensCurrentPoint" },
 171     { "GetZoomLensCurrentPosition" },
 172     { "GiveSemaphore", OPTIONAL|LIST_ALWAYS },
 173     { "IsStrobeChargeCompleted" },
 174     { "LEDDrive", OPTIONAL },
 175     { "LocalTime" },
 176     { "LockMainPower" },
 177     { "Lseek", UNUSED|LIST_ALWAYS },
 178     { "MakeDirectory_Fut" },
 179     { "MakeSDCardBootable", OPTIONAL },
 180     { "MoveFocusLensToDistance" },
 181     { "MoveIrisWithAv", OPTIONAL },
 182     { "MoveZoomLensWithPoint", DONT_EXPORT_ILC},
 183     { "NewTaskShell", UNUSED },
 184     { "Open" },
 185     { "PB2Rec" },
 186     { "PT_MoveDigitalZoomToWide", OPTIONAL | DONT_EXPORT_ILC},
 187     { "PT_MoveOpticalZoomAt", OPTIONAL | DONT_EXPORT_ILC },
 188     { "MoveOpticalZoomAt", OPTIONAL | DONT_EXPORT_ILC },
 189     { "PT_PlaySound" },
 190     { "PostLogicalEventForNotPowerType" },
 191     { "PostLogicalEventToUI" },
 192     { "PutInNdFilter", OPTIONAL },
 193     { "PutOutNdFilter", OPTIONAL },
 194     { "Read" },
 195     { "ReadFastDir" },
 196     { "Rec2PB" },
 197     { "Remove", OPTIONAL|UNUSED },
 198     { "RenameFile_Fut" },
 199     { "Restart" },
 200     { "screenlock_helper", UNUSED|DONT_EXPORT },
 201     { "ScreenLock" },
 202     { "ScreenUnlock" },
 203     { "SetAE_ShutterSpeed" },
 204     { "SetAutoShutdownTime" },
 205     { "SetCurrentCaptureModeType" },
 206     { "SetDate" },
 207     { "SetFileAttributes" },
 208     { "SetFileTimeStamp" },
 209     { "SetLogicalEventActive" },
 210     { "SetParameterData" },
 211     { "SetPropertyCase" },
 212     { "SetScriptMode" },
 213     { "SleepTask" },
 214     { "TakeSemaphore" },
 215     { "TurnOffBackLight" },
 216     { "TurnOnBackLight" },
 217     { "TurnOnDisplay" },
 218     { "TurnOffDisplay" },
 219     { "UIFS_WriteFirmInfoToFile", OPTIONAL|UNUSED},
 220     { "UnlockAE" },
 221     { "UnlockAF" },
 222     { "UnlockMainPower" },
 223     { "UnsetZoomForMovie", OPTIONAL | DONT_EXPORT_ILC },
 224 //    { "UpdateMBROnFlash" },
 225     { "VbattGet" },
 226     { "Write" },
 227     { "WriteSDCard" },
 228 
 229     { "_log" },
 230     { "_log10" },
 231     { "_pow" },
 232     { "_sqrt" },
 233     { "add_ptp_handler" },
 234     { "apex2us" },
 235     { "close" },
 236     { "displaybusyonscreen", OPTIONAL },
 237     { "err_init_task", OPTIONAL },
 238     { "exmem_alloc", OPTIONAL },
 239     { "exmem_free", OPTIONAL|UNUSED },
 240     { "exmem_ualloc" },
 241     { "exmem_ufree" },
 242     { "free" },
 243 
 244     { "kbd_p1_f" },
 245     { "kbd_p1_f_cont" },
 246     { "kbd_p2_f" },
 247     { "kbd_read_keys" },
 248     { "kbd_read_keys_r2" },
 249 
 250     { "kbd_pwr_off", OPTIONAL },
 251     { "kbd_pwr_on", OPTIONAL },
 252     { "lseek" },
 253     { "malloc" },
 254     { "memcmp" },
 255     { "memcpy" },
 256     { "memset" },
 257 // identical to MakeDirectory_Fut for recent cams
 258 //    { "mkdir" },
 259     { "mktime_ext" },
 260     { "open" },
 261     { "OpenFastDir" },
 262     { "closedir" },
 263     { "get_fstype", OPTIONAL|LIST_ALWAYS },
 264     { "qsort" },
 265     { "rand" },
 266     { "read", UNUSED|OPTIONAL },
 267     { "realloc", OPTIONAL|LIST_ALWAYS },
 268     { "reboot_fw_update" },
 269     { "set_control_event" },
 270     { "srand" },
 271     { "stat" },
 272     { "strcat" },
 273     { "strchr" },
 274     { "strcmp" },
 275     { "strcpy" },
 276     { "strftime" },
 277     { "strlen" },
 278     { "strncmp" },
 279     { "strncpy" },
 280     { "strrchr" },
 281     { "strtol" },
 282     { "strtolx" },
 283 
 284     { "task_CaptSeq" },
 285     { "task_DvlpSeqTask", OPTIONAL },
 286     { "task_ExpDrv" },
 287     { "task_FileWrite", OPTIONAL },
 288     { "task_InitFileModules" },
 289     { "task_MovieRecord" },
 290     { "task_PhySw", OPTIONAL },
 291     { "task_RotaryEncoder", OPTIONAL },
 292     { "task_TouchPanel", OPTIONAL },
 293     { "task_TricInitTask", OPTIONAL },
 294 
 295     { "hook_CreateTask" },
 296     { "hook_CreateTask_low", UNUSED}, // unused changed at runtime if CreateTask in ROM
 297 
 298     { "time" },
 299     { "vsprintf" },
 300     { "write", UNUSED|OPTIONAL },
 301     { "undisplaybusyonscreen", OPTIONAL },
 302 
 303     { "EngDrvIn", OPTIONAL|UNUSED|LIST_ALWAYS },
 304     { "EngDrvOut", OPTIONAL|UNUSED|LIST_ALWAYS },
 305     { "EngDrvRead" },
 306     { "EngDrvBits", OPTIONAL|UNUSED|LIST_ALWAYS },
 307 
 308     { "PTM_GetCurrentItem" },
 309     { "PTM_SetCurrentItem", UNUSED|LIST_ALWAYS },
 310     { "PTM_NextItem", OPTIONAL|UNUSED|LIST_ALWAYS },
 311     { "PTM_PrevItem", OPTIONAL|UNUSED|LIST_ALWAYS },
 312     { "PTM_SetPropertyEnable", OPTIONAL|UNUSED|LIST_ALWAYS },
 313 
 314     { "DisableISDriveError", OPTIONAL },
 315 
 316     // OS functions, mostly to aid firmware analysis. Order is important!
 317     { "_GetSystemTime", OPTIONAL|UNUSED|LIST_ALWAYS }, // only for locating timer functions
 318     { "SetTimerAfter", OPTIONAL|UNUSED|LIST_ALWAYS },
 319     { "SetTimerWhen", OPTIONAL|UNUSED|LIST_ALWAYS },
 320     { "CancelTimer", OPTIONAL|UNUSED|LIST_ALWAYS },
 321     { "CancelHPTimer" },
 322     { "SetHPTimerAfterTimeout", OPTIONAL|UNUSED|LIST_ALWAYS },
 323     { "SetHPTimerAfterNow" },
 324     { "CreateTaskStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 325     { "CreateMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 326     { "CreateRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 327     { "GetSemaphoreValue", OPTIONAL|UNUSED|LIST_ALWAYS },
 328     { "TryTakeSemaphore", OPTIONAL|UNUSED|LIST_ALWAYS },
 329     { "CreateMessageQueueStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 330     { "CreateEventFlagStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 331     { "CreateBinarySemaphoreStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 332     { "CreateCountingSemaphoreStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 333     { "CreateRecursiveLockStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 334     { "TakeSemaphoreStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 335     { "ReceiveMessageQueueStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 336     { "PostMessageQueueStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },    // r23+
 337     { "WaitForAnyEventFlagStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 338     { "WaitForAllEventFlagStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 339     { "AcquireRecursiveLockStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 340     { "DeleteMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 341     { "PostMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 342     { "ReceiveMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 343     { "TryReceiveMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 344     { "TryPostMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 345     { "GetNumberOfPostedMessages", OPTIONAL|UNUSED|LIST_ALWAYS },
 346     { "DeleteRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 347     { "AcquireRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 348     { "ReleaseRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 349     { "WaitForAnyEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 350     { "WaitForAllEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 351     { "ClearEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 352     { "SetEventFlag", OPTIONAL|LIST_ALWAYS },
 353     { "GetEventFlagValue", OPTIONAL|UNUSED|LIST_ALWAYS },
 354     { "CreateEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 355     { "DeleteEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 356     { "CheckAnyEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 357     { "CheckAllEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 358     { "RegisterInterruptHandler", OPTIONAL|UNUSED|LIST_ALWAYS },
 359     { "UnregisterInterruptHandler", OPTIONAL|UNUSED|LIST_ALWAYS },
 360     { "GetSRAndDisableInterrupt", OPTIONAL|UNUSED|LIST_ALWAYS }, // disables IRQ, returns a value
 361     { "SetSR", OPTIONAL|UNUSED|LIST_ALWAYS }, // enables IRQ, puts back value returned by GetSR
 362     { "EnableInterrupt", OPTIONAL|UNUSED|LIST_ALWAYS }, // enables IRQ
 363     { "_divmod_signed_int", OPTIONAL|UNUSED|LIST_ALWAYS}, // division for signed integers, remainder is returned in r1
 364     { "_divmod_unsigned_int", OPTIONAL|UNUSED|LIST_ALWAYS}, // division for unsigned integers, remainder is returned in r1
 365     { "_dflt", OPTIONAL|UNUSED|LIST_ALWAYS}, // int -> double
 366     { "_dfltu", OPTIONAL|UNUSED|LIST_ALWAYS}, // uint -> double
 367     { "_dfix", OPTIONAL|UNUSED|LIST_ALWAYS}, // double -> int
 368     { "_dfixu", OPTIONAL|UNUSED|LIST_ALWAYS}, // double -> uint
 369     { "_dmul", OPTIONAL|UNUSED|LIST_ALWAYS}, // double precision float multiplication
 370     { "_ddiv", OPTIONAL|UNUSED|LIST_ALWAYS}, // double precision float division
 371     { "_dadd", OPTIONAL|UNUSED|LIST_ALWAYS}, // addition for doubles
 372     { "_dsub", OPTIONAL|UNUSED|LIST_ALWAYS}, // subtraction for doubles
 373     { "_drsb", OPTIONAL|UNUSED|LIST_ALWAYS}, // reverse subtraction for doubles (?)
 374     { "_dcmp", OPTIONAL|UNUSED|LIST_ALWAYS}, // comparison of 2 doubles, only updates condition flags
 375     { "_dcmp_reverse", OPTIONAL|UNUSED|LIST_ALWAYS}, // like _dcmp, but operands in reverse order, only updates condition flags
 376     { "_safe_sqrt", OPTIONAL|UNUSED|LIST_ALWAYS}, // only calls _sqrt for numbers >= 0
 377     { "_scalbn", OPTIONAL|UNUSED|LIST_ALWAYS}, // double scalbn (double x, long exp), returns x * FLT_RADIX ** exp
 378     { "_fflt", OPTIONAL|UNUSED|LIST_ALWAYS}, // int -> float
 379     { "_ffltu", OPTIONAL|UNUSED|LIST_ALWAYS}, // uint -> float
 380     { "_ffix", OPTIONAL|UNUSED|LIST_ALWAYS}, // float -> int
 381     { "_ffixu", OPTIONAL|UNUSED|LIST_ALWAYS}, // float -> uint
 382     { "_fmul", OPTIONAL|UNUSED|LIST_ALWAYS}, // single precision float multiplication
 383     { "_fdiv", OPTIONAL|UNUSED|LIST_ALWAYS}, // single precision float division
 384     { "_f2d", OPTIONAL|UNUSED|LIST_ALWAYS}, // float -> double
 385     { "DisplayBusyOnScreen", OPTIONAL|UNUSED|LIST_ALWAYS}, // displays full screen "busy" message
 386     { "UndisplayBusyOnScreen", OPTIONAL|UNUSED|LIST_ALWAYS},
 387     { "CreateDialogBox", OPTIONAL|UNUSED|LIST_ALWAYS},
 388     { "DisplayDialogBox", OPTIONAL|UNUSED|LIST_ALWAYS},
 389     { "add_ui_to_dialog", OPTIONAL|UNUSED|LIST_ALWAYS}, // name made up, assigns resources to a dialog
 390     { "get_string_by_id", OPTIONAL|UNUSED|LIST_ALWAYS}, // name made up, retrieves a localised or unlocalised string by its ID
 391     { "malloc_strictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // name made up
 392     { "GetCurrentMachineTime", OPTIONAL|UNUSED|LIST_ALWAYS }, // reads usec counter, name from ixus30
 393     { "HwOcReadICAPCounter", OPTIONAL|UNUSED|LIST_ALWAYS }, // reads usec counter, name from ixus30
 394     { "transfer_src_overlay_helper",UNUSED}, // helper for other related functions
 395     { "transfer_src_overlay" },
 396     { "GraphicSystemCoreFinish_helper", OPTIONAL|UNUSED }, // function that calls GraphicSystemCoreFinish
 397     { "GraphicSystemCoreFinish", OPTIONAL|UNUSED }, // used to identify mzrm message functions
 398     { "mzrm_createmsg", OPTIONAL|UNUSED },
 399     { "mzrm_sendmsg", OPTIONAL|UNUSED },
 400     { "zicokick_start", OPTIONAL|UNUSED }, // used to identify Zico core Xtensa blobs
 401     { "zicokick_copy", OPTIONAL|UNUSED }, // used to identify Zico core Xtensa blobs
 402     { "init_ex_drivers", OPTIONAL|UNUSED }, // used to identify Omar core ARM blobs
 403     { "omar_init", OPTIONAL|UNUSED }, // used to identify Omar core ARM blobs
 404 
 405     { "createsemaphore_low", OPTIONAL|UNUSED },
 406 //    { "deletesemaphore_low", UNUSED },
 407     { "givesemaphore_low", OPTIONAL|UNUSED}, // OPT_CONSOLE_REDIR_ENABLED
 408     { "takesemaphore_low", OPTIONAL|UNUSED },
 409     { "bzero" }, // 
 410     { "memset32" }, // actually jump to 2nd instruction of bzero 
 411     { "get_dial_hw_position", OPTIONAL },
 412 
 413     // Other stuff needed for finding misc variables - don't export to stubs_entry.S
 414     { "GetSDProtect", UNUSED },
 415     { "DispCon_ShowBitmapColorBar", UNUSED },
 416     { "ResetZoomLens", OPTIONAL|UNUSED },
 417     { "ResetFocusLens", OPTIONAL|UNUSED },
 418     { "NR_GetDarkSubType", OPTIONAL|UNUSED },
 419     { "NR_SetDarkSubType", OPTIONAL|UNUSED },
 420     { "SavePaletteData", OPTIONAL|UNUSED },
 421     { "GUISrv_StartGUISystem", OPTIONAL|UNUSED|LIST_ALWAYS },
 422     { "get_resource_pointer", OPTIONAL|UNUSED|LIST_ALWAYS }, // name made up, gets a pointer to a certain resource (font, dialog, icon)
 423     { "CalcLog10", OPTIONAL|UNUSED|LIST_ALWAYS }, // helper
 424     { "CalcSqrt", OPTIONAL|UNUSED }, // helper
 425     { "dry_memcpy", OPTIONAL|UNUSED }, // helper, memcpy-like function in dryos kernel code
 426     { "get_playrec_mode", OPTIONAL|UNUSED }, // helper, made up name
 427     { "DebugAssert2", OPTIONAL|UNUSED }, // helper, made up name, two arg form of DebugAssert
 428     { "get_canon_mode_list", OPTIONAL|UNUSED }, // helper, made up name
 429     { "taskcreate_LowConsole", OPTIONAL|UNUSED }, // helper, made up name
 430     { "ImagerActivate", OPTIONAL|UNUSED }, // helper
 431     { "imager_active_callback", OPTIONAL|UNUSED }, // helper
 432     { "file_counter_var_init", OPTIONAL|UNUSED }, // helper
 433     { "get_displaytype", OPTIONAL|UNUSED }, // for camera bitmap res change
 434 
 435     { "MFOn", OPTIONAL },
 436     { "MFOff", OPTIONAL },
 437     { "PT_MFOn", OPTIONAL },
 438     { "PT_MFOff", OPTIONAL },
 439     { "SS_MFOn", OPTIONAL },
 440     { "SS_MFOff", OPTIONAL },
 441 
 442     { "GetAdChValue", OPTIONAL },
 443 
 444     // for HDMI remote support - optional, probably only present on cameras with HDMI
 445     { "EnableHDMIPower", OPTIONAL },
 446     { "DisableHDMIPower", OPTIONAL },
 447 
 448     { "SetVideoOutType", OPTIONAL },
 449     { "GetVideoOutType", OPTIONAL },
 450 
 451     {0,0,0},
 452 };
 453 
 454 typedef struct {
 455     char*   name;   // name
 456     int     id;     // propcase id, as found
 457     int     use;    // 0: informational only; 1: use for propset guess AND print as #define; 2: use for propset guess
 458     
 459     int     id_ps6; // id in propset 6
 460     int     id_ps7; // id in propset 7
 461     int     id_ps8; // id in propset 8
 462     int     id_ps9; // id in propset 9
 463     int     id_ps10;// id in propset 10
 464     int     id_ps11;// id in propset 11
 465     int     id_ps12;// id in propset 12
 466     int     id_ps13;// id in propset 13
 467 } known_prop_t;
 468 
 469 #define KNOWN_PROPSET_COUNT (13-5)
 470 
 471 known_prop_t knownprops[] =
 472 {   // name                          id  u ps6 ps7 ps8 ps9 ps10 ps11 ps12 ps13
 473     {"PROPCASE_AFSTEP"             , -1, 2, 13, 13, 13, 13,  13,  13,  13,  13},
 474     {"PROPCASE_FOCUS_STATE"        , -1, 1, 18, 18, 18, 18,  18,  18,  18,  18},
 475     {"PROPCASE_AV"                 , -1, 1, 23, 23, 23, 23,  23,  23,  23,  23},
 476     {"PROPCASE_BV"                 , -1, 1, 34, 38, 35, 38,  40,  40,  40,  40},
 477     {"PROPCASE_DELTA_DIGITALGAIN"  , -1, 2, 77, 82, 79, 82,  84,  85,  85,  84},
 478     {"PROPCASE_DELTA_SV"           , -1, 1, 79, 84, 81, 84,  86,  87,  87,  86},
 479     {"PROPCASE_DELTA_ND"           , -1, 2, 80, 85, 82, 85,  87,  88,  88,  87},
 480     {"PROPCASE_FELOCK"             , -1, 2,114,120,117,120, 122, 123, 123, 122},
 481     {"PROPCASE_FLASH_ADJUST_MODE"  , -1, 1,121,127,124,127, 129, 130, 130, 129},
 482     {"PROPCASE_FLASH_FIRE"         , -1, 1,122,128,125,128, 130, 131, 131, 130},
 483     {"PROPCASE_HSCAPTURE"          , -1, 2,138,144,141,144, 146, 147, 147, 146},
 484     {"PROPCASE_EV_CORRECTION_2"    , -1, 1,210,216,213,216, 218, 219, 220, 218},
 485     {"PROPCASE_ORIENTATION_SENSOR" , -1, 1,222,228,225,228, 230, 231, 232, 230},
 486     {"PROPCASE_SV_MARKET"          , -1, 1,249,255,252,255, 257, 259, 260, 258},
 487     {"PROPCASE_SVFIX"              , -1, 0,  0,  0,  0,  0,   0,   0,   0, 259},
 488     {"PROPCASE_TV"                 , -1, 1,265,272,269,272, 274, 276, 277, 275},
 489     {0,}
 490 };
 491 
 492 void add_prop_hit(char *name, int id)
 493 {
 494     int n = 0;
 495     while (knownprops[n].name) {
 496         if (strcmp(knownprops[n].name,name) == 0) {
 497             knownprops[n].id = id;
 498             break;
 499         }
 500         n++;
 501     }
 502 }
 503 
 504 #define MISC_BLOB_XTENSA_MAX    5
 505 #define MISC_BLOB_TYPE_NONE     0
 506 #define MISC_BLOB_TYPE_XTENSA   1
 507 #define MISC_BLOB_TYPE_OMAR     2
 508 typedef struct {
 509     int         type;
 510     uint32_t    rom_adr; // location of data in ROM, if copied
 511     uint32_t    ram_adr; // location of data in RAM
 512     uint32_t    size;
 513 } misc_blob_t;
 514 
 515 // for values that don't get a DEF etc
 516 #define MISC_VAL_NO_STUB    1
 517 // DEF_CONST instead of DEF
 518 #define MISC_VAL_DEF_CONST  2
 519 #define MISC_VAL_OPTIONAL   4
 520 // variables and constants
 521 typedef struct {
 522     char        *name;
 523     int         flags;
 524     uint32_t    val;
 525     // informational values
 526     uint32_t    base; // if stub is found as ptr + offset, record
 527     uint32_t    offset;
 528     uint32_t    ref_adr; // code address near where value found (TODO may want list)
 529     misc_blob_t *blobs; // malloc'd array of blobs if this is a blob type value, terminated with flags = 0
 530 } misc_val_t;
 531 
 532 misc_val_t misc_vals[]={
 533     // stubs_min variables / constants
 534     { "ctypes",             },
 535     { "physw_run",          },
 536     { "physw_sleep_delay",  },
 537     { "physw_status",       },
 538     { "fileio_semaphore",   },
 539     { "levent_table",       },
 540     { "FlashParamsTable",   },
 541     { "playrec_mode",       },
 542     { "jpeg_count_str",     },
 543     { "zoom_busy",          },
 544     { "focus_busy",         },
 545     { "imager_active",      },
 546     { "canon_menu_active",  },
 547     { "file_counter_var",   },
 548     { "_nrflag",            MISC_VAL_OPTIONAL},
 549     { "av_override_semaphore",MISC_VAL_OPTIONAL},
 550     { "active_bitmap_buffer",MISC_VAL_OPTIONAL},
 551     { "displaytype",        MISC_VAL_OPTIONAL},
 552     { "bitmap_buffer",      MISC_VAL_OPTIONAL},
 553     { "palette_control",    MISC_VAL_OPTIONAL},
 554     { "palette_buffer_ptr", MISC_VAL_OPTIONAL},
 555     { "active_palette_buffer",MISC_VAL_OPTIONAL},
 556     { "CAM_UNCACHED_BIT",   MISC_VAL_NO_STUB},
 557     { "physw_event_table",  MISC_VAL_NO_STUB},
 558     { "uiprop_count",       MISC_VAL_DEF_CONST},
 559     { "canon_mode_list",    MISC_VAL_NO_STUB},
 560     { "ARAM_HEAP_START",    MISC_VAL_NO_STUB},
 561     { "ARAM_HEAP_SIZE",     MISC_VAL_NO_STUB},
 562     { "zicokick_values",    MISC_VAL_NO_STUB}, // used to identify Zico core Xtensa blobs (dummy for now)
 563     { "omar_init_data",     MISC_VAL_NO_STUB}, // structure containing pointers to Omar blogs
 564     { "omar_init_values",   MISC_VAL_NO_STUB}, // Omar blobs
 565     { "CAM_HAS_ND_FILTER",  MISC_VAL_NO_STUB},
 566     { "CAM_IS_ILC",         MISC_VAL_NO_STUB}, // used for finsig code that wants to check for interchangeable lens
 567     { "CAM_HAS_IRIS_DIAPHRAGM",MISC_VAL_NO_STUB},
 568     { "exmem_alloc_table",  },
 569     { "exmem_types_table",  },
 570     { "exmem_type_count",   MISC_VAL_DEF_CONST},
 571     {0,0,0},
 572 };
 573 
 574 misc_val_t *get_misc_val(const char *name)
 575 {
 576     misc_val_t *p=misc_vals;
 577     while(p->name) {
 578         if(strcmp(name,p->name) == 0) {
 579             return p;
 580         }
 581         p++;
 582     }
 583     return NULL;
 584 }
 585 
 586 // get value of misc val, if set. Name :<
 587 uint32_t get_misc_val_value(const char *name)
 588 {
 589     misc_val_t *p=get_misc_val(name);
 590     if(!p) {
 591         printf("get_misc_val_value: invalid name %s\n",name);
 592         return 0;
 593     }
 594     return p->val;
 595 }
 596 void save_misc_val(const char *name, uint32_t base, uint32_t offset, uint32_t ref_adr)
 597 {
 598     misc_val_t *p=get_misc_val(name);
 599     if(!p) {
 600         printf("save_misc_val: invalid name %s\n",name);
 601         return;
 602     }
 603     p->val = base + offset;
 604     p->base = base;
 605     p->offset = offset;
 606     p->ref_adr = ref_adr;
 607     p->blobs = NULL;
 608 }
 609 void save_misc_val_blobs(const char *name, misc_blob_t *blobs, uint32_t ref_adr)
 610 {
 611     misc_val_t *p=get_misc_val(name);
 612     if(!p) {
 613         printf("save_misc_val: invalid name %s\n",name);
 614         return;
 615     }
 616     p->val = p->base = p->offset = 0;
 617     p->ref_adr = ref_adr;
 618     p->blobs = blobs;
 619 }
 620 
 621 // Return the array index of a named function in the array above
 622 #if 0
 623 int find_saved_sig_index(const char *name)
 624 {
 625     int i;
 626     for (i=0; sig_names[i].name != 0; i++)
 627     {
 628         if (strcmp(name,sig_names[i].name) == 0)
 629         {
 630             return i;
 631         }
 632     }
 633     return -1;
 634 }
 635 #endif
 636 
 637 sig_entry_t * find_saved_sig(const char *name)
 638 {
 639     int i;
 640     for (i=0; sig_names[i].name != 0; i++)
 641     {
 642         if (strcmp(name,sig_names[i].name) == 0)
 643         {
 644             return &sig_names[i];
 645         }
 646     }
 647     return NULL;
 648 }
 649 
 650 // return value of saved sig, or 0 if not found / doesn't exist
 651 uint32_t get_saved_sig_val(const char *name)
 652 {
 653     sig_entry_t *sig=find_saved_sig(name);
 654     if(!sig) {
 655         // printf("get_saved_sig_val: missing %s\n",name);
 656         return 0;
 657     }
 658     return sig->val;
 659 }
 660 
 661 // unused for now
 662 // Return the array index of of function with given address
 663 #if 0
 664 int find_saved_sig_index_by_adr(uint32_t adr)
 665 {
 666     if(!adr) {
 667         return  -1;
 668     }
 669     int i;
 670     for (i=0; sig_names[i].name != 0; i++)
 671     {
 672         if (sig_names[i].val == adr)
 673         {
 674             return i;
 675         }
 676     }
 677     return -1;
 678 }
 679 #endif
 680 #if 0
 681 sig_entry_t* find_saved_sig_by_val(uint32_t val)
 682 {
 683     if(!val) {
 684         return NULL;
 685     }
 686     int i;
 687     for (i=0; sig_names[i].name != 0; i++)
 688     {
 689         if (sig_names[i].val == val)
 690         {
 691             return &sig_names[i];
 692         }
 693     }
 694     return NULL;
 695 }
 696 #endif
 697 
 698 // Save the address value found for a function in the above array
 699 void save_sig(firmware *fw, const char *name, uint32_t val)
 700 {
 701     sig_entry_t *sig = find_saved_sig(name);
 702     if (!sig)
 703     {
 704         printf("save_sig: refusing to save unknown name %s\n",name);
 705         return;
 706     }
 707     // if we end up needed these, can add a flag
 708     if(!adr_is_main_fw_code(fw,val)) {
 709         printf("save_sig: refusing to save %s with out of range address 0x%08x\n",name,val);
 710         return;
 711     }
 712     if(sig->val && sig->val != val) {
 713         printf("save_sig: duplicate name %s existing 0x%08x != new 0x%08x\n",name,sig->val,val);
 714     }
 715     sig->val = val;
 716 }
 717 
 718 void add_func_name(firmware *fw, char *n, uint32_t eadr, char *suffix)
 719 {
 720     int k;
 721 
 722     char *s = n;
 723     int mallocd = 0;
 724     if (suffix != 0)
 725     {
 726         s = malloc(strlen(n) + strlen(suffix) + 1);
 727         sprintf(s, "%s%s", n, suffix);
 728         mallocd = 1;
 729     }
 730 
 731     // if we end up needed these, can add a flag
 732     if(!adr_is_main_fw_code(fw,eadr)) {
 733         printf("save_sig: refusing to save %s with out of range address 0x%08x\n",s,eadr);
 734         if(mallocd) {
 735             free(s);
 736         }
 737         return;
 738     }
 739 
 740     for (k=0; sig_names[k].name != 0; k++)
 741     {
 742         if (strcmp(sig_names[k].name, s) == 0)
 743         {
 744             if (sig_names[k].val == 0)             // same name, no address
 745             {
 746                 sig_names[k].val = eadr;
 747                 sig_names[k].flags |= EV_MATCH;
 748                 if (mallocd)
 749                     free(s);
 750                 return;
 751             }
 752             else if (sig_names[k].val == eadr)     // same name, same address
 753             {
 754                 if (mallocd)
 755                     free(s);
 756                 return;
 757             }
 758             else // same name, different address
 759             {
 760                 printf("add_func_name: duplicate name %s existing 0x%08x != new 0x%08x\n",s, sig_names[k].val, eadr);
 761             }
 762         }
 763     }
 764 
 765     sig_names[next_sig_entry].name = s;
 766     sig_names[next_sig_entry].flags = OPTIONAL|UNUSED;
 767     sig_names[next_sig_entry].val = eadr;
 768     next_sig_entry++;
 769     sig_names[next_sig_entry].name = 0;
 770 }
 771 
 772 // save sig, with up to one level veneer added as j_...
 773 int save_sig_with_j(firmware *fw, char *name, uint32_t adr)
 774 {
 775     if(!adr) {
 776         printf("save_sig_with_j: %s null adr\n",name);
 777         return 0;
 778     }
 779     // attempt to disassemble target
 780     if(!fw_disasm_iter_single(fw,adr)) {
 781         printf("save_sig_with_j: %s disassembly failed at 0x%08x\n",name,adr);
 782         return 0;
 783     }
 784     // handle functions that immediately jump
 785     // only one level of jump for now, doesn't check for conditionals, but first insn shouldn't be conditional
 786     //uint32_t b_adr=B_target(fw,fw->is->insn);
 787     uint32_t b_adr=get_direct_jump_target(fw,fw->is);
 788     if(b_adr) {
 789         char *buf=malloc(strlen(name)+6);
 790         sprintf(buf,"j_%s",name);
 791         add_func_name(fw,buf,adr,NULL); // this is the orignal named address
 792 //        adr=b_adr | fw->is->thumb; // thumb bit from iter state
 793         adr=b_adr; // thumb bit already handled by get_direct...
 794     }
 795     save_sig(fw,name,adr);
 796     return 1;
 797 }
 798 
 799 // find next call to func named "name" or j_name, up to max_offset form the current is address
 800 // TODO should have a way of dealing with more than one veneer
 801 // TODO max_offset is in bytes, unlike insn search functions that use insn counts
 802 int find_next_sig_call(firmware *fw, iter_state_t *is, uint32_t max_offset, const char *name)
 803 {
 804     uint32_t adr=get_saved_sig_val(name);
 805 
 806     if(!adr) {
 807         printf("find_next_sig_call: missing %s\n",name);
 808         return 0;
 809     }
 810 
 811     search_calls_multi_data_t match_fns[3];
 812 
 813     match_fns[0].adr=adr;
 814     match_fns[0].fn=search_calls_multi_end;
 815     char veneer[128];
 816     sprintf(veneer,"j_%s",name);
 817     adr=get_saved_sig_val(veneer);
 818     if(!adr) {
 819         match_fns[1].adr=0;
 820     } else {
 821         match_fns[1].adr=adr;
 822         match_fns[1].fn=search_calls_multi_end;
 823         match_fns[2].adr=0;
 824     }
 825     return fw_search_insn(fw,is,search_disasm_calls_multi,0,match_fns,is->adr + max_offset);
 826 }
 827 // is the insn pointed to by is a call to "name" or one of it's veneers?
 828 // note: inefficient, should not be used for large searches
 829 int is_sig_call(firmware *fw, iter_state_t *is, const char *name)
 830 {
 831     uint32_t adr=get_branch_call_insn_target(fw,is);
 832     // not a call at all
 833     // TODO could check if unknown veneer
 834     if(!adr) {
 835         return 0;
 836     }
 837     uint32_t sig_adr=get_saved_sig_val(name);
 838     osig* ostub2 = find_sig(fw->sv->stubs,name);
 839     if (ostub2 && ostub2->val)
 840         sig_adr = ostub2->val;
 841     if(!sig_adr) {
 842         printf("is_sig_call: missing %s\n",name);
 843         return 0;
 844     }
 845     if(adr == sig_adr) {
 846         return 1;
 847     }
 848     char veneer[128];
 849     sprintf(veneer,"j_%s",name);
 850     sig_adr=get_saved_sig_val(veneer);
 851     if(!sig_adr) {
 852         return 0;
 853     }
 854     return (adr == sig_adr);
 855 }
 856 
 857 typedef struct sig_rule_s sig_rule_t;
 858 typedef int (*sig_match_fn)(firmware *fw, iter_state_t *is, sig_rule_t *rule);
 859 // signature matching structure
 860 struct sig_rule_s {
 861     sig_match_fn    match_fn;       // function to locate function
 862     char        *name;              // function name used in CHDK
 863     char        *ref_name;          // event / other name to match in the firmware
 864     int         param;              // function specific param/offset
 865     int         dryos_min;          // minimum dryos rel (0 = any)
 866     int         dryos_max;          // max dryos rel to apply this sig to (0 = any)
 867     // DryOS version specific params / offsets - not used yet
 868     /*
 869     int         dryos52_param; // ***** UPDATE for new DryOS version *****
 870     int         dryos54_param;
 871     int         dryos55_param;
 872     int         dryos57_param;
 873     int         dryos58_param;
 874     */
 875 };
 876 
 877 // Get DryOS version specific param
 878 /*
 879 int dryos_param(firmware *fw, sig_rule_t *sig)
 880 {
 881     switch (fw->dryos_ver)
 882     {
 883     case 52:    return sig->dryos52_param;
 884     case 54:    return sig->dryos54_param;
 885     case 55:    return sig->dryos55_param;
 886     case 57:    return sig->dryos57_param;
 887     case 58:    return sig->dryos58_param;
 888     }
 889     return 0;
 890 }
 891 */
 892 
 893 // initialize iter state using address from ref_name, print error and return 0 if not found
 894 int init_disasm_sig_ref(firmware *fw, iter_state_t *is, sig_rule_t *rule)
 895 {
 896     if(!rule->ref_name) {
 897         printf("init_disasm_sig_ref: %s missing ref_name\n",rule->name);
 898         return 0;
 899     }
 900     uint32_t adr=get_saved_sig_val(rule->ref_name);
 901     if(!adr) {
 902         printf("init_disasm_sig_ref: %s missing %s\n",rule->name,rule->ref_name);
 903         return 0;
 904     }
 905     if(!disasm_iter_init(fw,is,adr)) {
 906         printf("init_disasm_sig_ref: %s bad address 0x%08x for %s\n",rule->name,adr,rule->ref_name);
 907         return 0;
 908     }
 909     return 1;
 910 }
 911 
 912 int sig_match_near_str(firmware *fw, iter_state_t *is, sig_rule_t *rule);
 913 
 914 // match 
 915 // r0=ref value
 916 //...
 917 // bl=<our func>
 918 int sig_match_str_r0_call(firmware *fw, iter_state_t *is, sig_rule_t *rule)
 919 {
 920     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
 921     if(!str_adr) {
 922         printf("sig_match_str_r0_call: %s failed to find ref %s\n",rule->name,rule->ref_name);
 923         return  0;
 924     }
 925 
 926 //    printf("sig_match_str_r0_call: %s ref str %s 0x%08x\n",rule->name,rule->ref_name,str_adr);
 927 
 928     // TODO should handle multiple instances of string
 929     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
 930     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
 931         if(is->insn->detail->arm.operands[0].reg == ARM_REG_R0) {
 932             // printf("sig_match_str_r0_call: %s ref str %s ref 0x%"PRIx64"\n",rule->name,rule->ref_name,is->insn->address);
 933             // TODO should check if intervening insn nuke r0
 934             if(insn_match_find_next(fw,is,4,match_b_bl_blximm)) {
 935                 uint32_t adr=get_branch_call_insn_target(fw,is);
 936                 // printf("sig_match_str_r0_call: thumb %s call 0x%08x\n",rule->name,adr);
 937                 return save_sig_with_j(fw,rule->name,adr);
 938             }
 939         }
 940     }
 941     return 0;
 942 }
 943 
 944 // find RegisterEventProcedure
 945 int sig_match_reg_evp(firmware *fw, iter_state_t *is, sig_rule_t *rule)
 946 {
 947     const insn_match_t reg_evp_match[]={
 948         {MATCH_INS(MOV,   2),  {MATCH_OP_REG(R2),  MATCH_OP_REG(R1)}},
 949         {MATCH_INS(LDR,   2),  {MATCH_OP_REG(R1),  MATCH_OP_MEM_ANY}},
 950         {MATCH_INS(B,     MATCH_OPCOUNT_IGNORE)},
 951         {ARM_INS_ENDING}
 952     };
 953 
 954     uint32_t e_to_evp=get_saved_sig_val("ExportToEventProcedure_FW");
 955     if(!e_to_evp) {
 956         printf("sig_match_reg_evp: failed to find ExportToEventProcedure, giving up\n");
 957         return 0;
 958     }
 959 
 960     //look for the underlying RegisterEventProcedure function (not currently used)
 961     uint32_t reg_evp=0;
 962     // start at identified Export..
 963     disasm_iter_init(fw,is,e_to_evp);
 964     if(insn_match_seq(fw,is,reg_evp_match)) {
 965         reg_evp=ADR_SET_THUMB(is->insn->detail->arm.operands[0].imm);
 966         //printf("RegisterEventProcedure found 0x%08x at %"PRIx64"\n",reg_evp,is->insn->address);
 967         save_sig(fw,"RegisterEventProcedure",reg_evp);
 968     }
 969     return (reg_evp != 0);
 970 }
 971 
 972 // find event proc table registration, and some other stuff
 973 // TODO this should be broken up to some generic parts
 974 int sig_match_reg_evp_table(firmware *fw, iter_state_t *is, sig_rule_t *rule)
 975 {
 976     // ref to find RegisterEventProcTable
 977     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name); // note this string may appear more than once, assuming want first
 978     if(!str_adr) {
 979         printf("sig_match_reg_evp_table: failed to find %s\n",rule->ref_name);
 980         return 0;
 981     }
 982     //printf("sig_match_reg_evp_table: DispDev_EnableEventProc 0x%08x\n",str_adr);
 983     uint32_t reg_evp_alt1=0;
 984     uint32_t reg_evp_tbl=0;
 985     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
 986     uint32_t dd_enable_p=0;
 987     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
 988         if(is->insn->detail->arm.operands[0].reg != ARM_REG_R0) {
 989             continue;
 990         }
 991         if(!insn_match_find_next(fw,is,2,match_b_bl)) {
 992             continue;
 993         }
 994         reg_evp_alt1=ADR_SET_THUMB(is->insn->detail->arm.operands[0].imm);
 995         //printf("RegisterEventProcedure_alt1 found 0x%08x at %"PRIx64"\n",reg_evp_alt1,is->insn->address);
 996         save_sig(fw,"RegisterEventProcedure_alt1",reg_evp_alt1);
 997 
 998         uint32_t regs[4];
 999 
1000         // get r0 and r1, backtracking up to 4 instructions
1001         if((get_call_const_args(fw,is,4,regs)&3)==3) {
1002             // sanity check, arg0 was the original thing we were looking for
1003             if(regs[0]==str_adr) {
1004                 dd_enable_p=regs[1]; // constant value should already have correct ARM/THUMB bit
1005                 //printf("DispDev_EnableEventProc found 0x%08x at %"PRIx64"\n",dd_enable_p,is->insn->address);
1006                 add_func_name(fw,"DispDev_EnableEventProc",dd_enable_p,NULL);
1007                 break;
1008             }
1009         }
1010     } 
1011     // found candidate function
1012     if(dd_enable_p) {
1013         disasm_iter_init(fw,is,dd_enable_p); // start at found func
1014         if(insn_match_find_next(fw,is,4,match_b_bl)) { // find the first bl
1015             // sanity check, make sure we get a const in r0
1016             uint32_t regs[4];
1017             if(get_call_const_args(fw,is,4,regs)&1) {
1018                 reg_evp_tbl=ADR_SET_THUMB(is->insn->detail->arm.operands[0].imm);
1019                 // printf("RegisterEventProcTable found 0x%08x at %"PRIx64"\n",reg_evp_tbl,is->insn->address);
1020                 save_sig(fw,"RegisterEventProcTable",reg_evp_tbl);
1021             }
1022         }
1023     }
1024     return (reg_evp_tbl != 0);
1025 }
1026 
1027 // find an alternate eventproc registration call
1028 int sig_match_reg_evp_alt2(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1029 {
1030     uint32_t reg_evp_alt2=0;
1031     // TODO could make this a param for different fw variants
1032     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
1033     if(!str_adr) {
1034         printf("sig_match_reg_evp_alt2: failed to find %s\n",rule->ref_name);
1035         return 0;
1036     }
1037     //printf("sig_match_reg_evp_alt2: EngApp.Delete 0x%08x\n",str_adr);
1038     uint32_t reg_evp_alt1=get_saved_sig_val("RegisterEventProcedure_alt1");
1039 
1040     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
1041     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
1042         if(is->insn->detail->arm.operands[0].reg != ARM_REG_R0) {
1043             continue;
1044         }
1045         if(!insn_match_find_next(fw,is,3,match_b_bl)) {
1046             continue;
1047         }
1048         uint32_t regs[4];
1049         // sanity check, constants in r0, r1 and r0 was the original thing we were looking for
1050         if((get_call_const_args(fw,is,4,regs)&3)==3) {
1051             if(regs[0]==str_adr) {
1052                 reg_evp_alt2=ADR_SET_THUMB(is->insn->detail->arm.operands[0].imm);
1053                 // TODO could keep looking
1054                 if(reg_evp_alt2 == reg_evp_alt1) {
1055                     printf("RegisterEventProcedure_alt2 == _alt1 at %"PRIx64"\n",is->insn->address);
1056                     reg_evp_alt2=0;
1057                 } else {
1058                     save_sig(fw,"RegisterEventProcedure_alt2",reg_evp_alt2);
1059                    // printf("RegisterEventProcedure_alt2 found 0x%08x at %"PRIx64"\n",reg_evp_alt2,is->insn->address);
1060                     // TODO could follow alt2 and make sure it matches expected mov r2,0, bl register..
1061                 }
1062                 break;
1063             }
1064         }
1065     }
1066     return (reg_evp_alt2 != 0);
1067 }
1068 
1069 // find UnRegisterEventProc (made up name) for reference, finding tables missed by reg_event_proc_table
1070 int sig_match_unreg_evp_table(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1071 {
1072     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
1073     if(!str_adr) {
1074         printf("sig_match_unreg_evp_table: failed to find %s\n",rule->ref_name);
1075         return 0;
1076     }
1077     // for checks
1078     uint32_t reg_evp_alt1=get_saved_sig_val("RegisterEventProcedure_alt1");
1079     uint32_t reg_evp_alt2=get_saved_sig_val("RegisterEventProcedure_alt2");
1080 
1081     uint32_t mecha_unreg=0;
1082     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
1083     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
1084         //printf("sig_match_unreg_evp_table: found ref 0x%"PRIx64"\n",is->insn->address);
1085         if(is->insn->detail->arm.operands[0].reg != ARM_REG_R0) {
1086             continue;
1087         }
1088         if(!insn_match_find_next(fw,is,3,match_b_bl)) {
1089             continue;
1090         }
1091         uint32_t reg_call=get_branch_call_insn_target(fw,is);
1092         // wasn't a registration call (could be unreg)
1093         // TODO could check veneers
1094         if(!reg_call || (reg_call != reg_evp_alt1 && reg_call != reg_evp_alt2)) {
1095             continue;
1096         }
1097         uint32_t regs[4];
1098         if((get_call_const_args(fw,is,4,regs)&3)==3) {
1099             // sanity check we got the right string
1100             if(regs[0]==str_adr) {
1101                 mecha_unreg=ADR_SET_THUMB(regs[1]);
1102                 break;
1103             }
1104         }
1105     }
1106     if(!mecha_unreg) {
1107         return 0;
1108     }
1109     // follow
1110     disasm_iter_init(fw,is,mecha_unreg);
1111     // find first func call
1112     if(!insn_match_find_next(fw,is,7,match_b_bl)) {
1113         return 0;
1114     }
1115     // now find next ldr pc. Could follow above func, but this way picks up veneer on many fw
1116     const insn_match_t match_ldr_r0[]={
1117         {MATCH_INS(LDR, 2),   {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(PC)}},
1118         {ARM_INS_ENDING}
1119     };
1120     if(!insn_match_find_next(fw,is,18,match_ldr_r0)) {
1121         return 0;
1122     }
1123     uint32_t tbl=LDR_PC2val(fw,is->insn);
1124     if(!tbl) {
1125         return 0;
1126     }
1127     if(!disasm_iter(fw,is)) {
1128         printf("sig_match_unreg_evp_table: disasm failed\n");
1129         return 0;
1130     }
1131     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1132 }
1133 // find some veneers of RegisterEventProcTable/UnRegisterEventProcTable
1134 // expects b <something else>, b <ref_name>
1135 // TODO should be a generic find veneer near?
1136 int sig_match_evp_table_veneer(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1137 {
1138     uint32_t ref_adr = get_saved_sig_val(rule->ref_name);
1139     int prevb = 0;
1140     uint32_t cadr;
1141     // following should probably be done using fw_search_insn
1142     // both veneers consist of a single b instruction, always preceded by another b instruction
1143     disasm_iter_init(fw,is,ref_adr); // start at our known function
1144     while (is->adr < (ref_adr+0x800)) {
1145         cadr = is->adr;
1146         if (!disasm_iter(fw,is)) {
1147             disasm_iter_set(fw,is,(is->adr+2) | fw->thumb_default);
1148         }
1149         else {
1150             if (is->insn->id == ARM_INS_B) {
1151                 uint32_t b_adr = get_branch_call_insn_target(fw,is);
1152                 if (prevb && (b_adr == ref_adr)) {
1153                     // this doesn't use _with_j since we want identify the veneer
1154                     add_func_name(fw,rule->name,cadr | is->thumb,NULL);
1155                     return 1;
1156                 }
1157                 prevb = 1;
1158             }
1159         }
1160     }
1161     return 0;
1162 }
1163 
1164 int sig_match_get_nd_value(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1165 {
1166     // this match is only valid for cameras with both ND and Iris
1167     if(!get_misc_val_value("CAM_HAS_ND_FILTER") || !get_misc_val_value("CAM_HAS_IRIS_DIAPHRAGM")) {
1168         return 0;
1169     }
1170 
1171     if(!init_disasm_sig_ref(fw,is,rule)) {
1172         return 0;
1173     }
1174     if(!find_next_sig_call(fw,is,16,"ClearEventFlag")) {
1175         printf("sig_match_get_nd_value: no match ClearEventFlag\n");
1176         return 0;
1177     }
1178     if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
1179         printf("sig_match_get_nd_value: bl match 1 failed\n");
1180         return 0;
1181     }
1182     // follow
1183     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1184     disasm_iter(fw,is);
1185     if (B_target(fw,is->insn))
1186         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1187     // first call should be either get_nd_value or GetUsableAvRange
1188     if(!insn_match_find_next(fw,is,5,match_bl_blximm)) {
1189         printf("sig_match_get_nd_value: bl match 2 failed\n");
1190         return 0;
1191     }
1192     uint32_t addr=get_branch_call_insn_target(fw,is);
1193     if(addr == get_saved_sig_val("GetUsableAvRange")) {
1194         printf("sig_match_get_nd_value: found GetUsableAvRange, iris or ND only?\n");
1195         return 0;
1196     }
1197     return save_sig_with_j(fw,rule->name,addr);
1198 }
1199 
1200 int sig_match_get_current_exp(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1201 {
1202     if(!init_disasm_sig_ref(fw,is,rule)) {
1203         return 0;
1204     }
1205     if(!insn_match_find_next(fw,is,2,match_bl_blximm)) {
1206         printf("sig_match_get_current_exp: bl match 1 failed\n");
1207         return 0;
1208     }
1209     // follow
1210     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1211     if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
1212         printf("sig_match_get_current_exp: bl match 2 failed\n");
1213         return 0;
1214     }
1215     // follow
1216     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1217     if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
1218         printf("sig_match_get_current_exp: bl match 3 failed\n");
1219         return 0;
1220     }
1221     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1222 }
1223 
1224 int sig_match_get_current_nd_value(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1225 {
1226     // this match is only valid for cameras with both ND and Iris
1227     if(!get_misc_val_value("CAM_HAS_ND_FILTER") || !get_misc_val_value("CAM_HAS_IRIS_DIAPHRAGM")) {
1228         return 0;
1229     }
1230     if(!init_disasm_sig_ref(fw,is,rule)) {
1231         return 0;
1232     }
1233     if(!find_next_sig_call(fw,is,36,"GetCurrentShutterSpeed_FW")) {
1234         printf("sig_match_get_current_nd_value: no match GetCurrentShutterSpeed_FW\n");
1235         return 0;
1236     }
1237     // bl <func we want>
1238     // strh r0, [rN,8]
1239     const insn_match_t match_bl_strh[]={
1240         {MATCH_INS(BL,MATCH_OPCOUNT_IGNORE)},
1241         {MATCH_INS(STRH,2), {MATCH_OP_REG(R0),  MATCH_OP_MEM(INVALID,INVALID,0x8)}},
1242         {ARM_INS_ENDING}
1243     };
1244     if(!insn_match_find_next_seq(fw,is,10,match_bl_strh)) {
1245         printf("sig_match_get_current_nd_value: match failed\n");
1246         return 0;
1247     }
1248     // rewind one for call
1249     disasm_iter_init(fw,is,adr_hist_get(&is->ah,1));
1250     disasm_iter(fw,is);
1251     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1252 }
1253 
1254 int sig_match_imager_active_callback(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1255 {
1256     if(!init_disasm_sig_ref(fw,is,rule)) {
1257         return 0;
1258     }
1259     const insn_match_t match_ldr_bl_mov_pop[]={
1260         {MATCH_INS(LDR, 2),   {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(PC)}},
1261         {MATCH_INS(BL, MATCH_OPCOUNT_IGNORE)},
1262         {MATCH_INS(MOV,2),  {MATCH_OP_REG(R0),  MATCH_OP_IMM(0)}},
1263         {MATCH_INS(POP, MATCH_OPCOUNT_IGNORE)},
1264         {ARM_INS_ENDING}
1265     };
1266 
1267     if(!insn_match_find_next_seq(fw,is,28,match_ldr_bl_mov_pop)) {
1268         printf("sig_match_imager_active_callback: match failed\n");
1269         return 0;
1270     }
1271     // rewind to LDR r0,...
1272     disasm_iter_init(fw,is,adr_hist_get(&is->ah,3));
1273     // get LDR value
1274     disasm_iter(fw,is);
1275     uint32_t f1=LDR_PC2val(fw,is->insn);
1276 //    printf("f1 0x%08x\n",f1);
1277     // thumb bit should be set correctly
1278     return save_sig_with_j(fw,rule->name,f1);
1279 }
1280 int sig_match_imager_active(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1281 {
1282     if(!init_disasm_sig_ref(fw,is,rule)) {
1283         return 0;
1284     }
1285 
1286     const insn_match_t match_ldr_mov_str_pop[]={
1287         {MATCH_INS(LDR, 2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM_BASE(PC)}},
1288         {MATCH_INS(MOV,2), {MATCH_OP_REG_ANY,  MATCH_OP_IMM(1)}},
1289         {MATCH_INS(STR, 2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM_ANY}},
1290         {MATCH_INS(POP, MATCH_OPCOUNT_IGNORE)},
1291         {ARM_INS_ENDING}
1292     };
1293 
1294     int backtrack=3;
1295     if(!insn_match_find_next_seq(fw,is,10,match_ldr_mov_str_pop)) {
1296         // re-init and try reverse mov/ldr order
1297         init_disasm_sig_ref(fw,is,rule);
1298         const insn_match_t match_mov_ldr_str_pop[]={
1299             {MATCH_INS(MOV,2), {MATCH_OP_REG_ANY,  MATCH_OP_IMM(1)}},
1300             {MATCH_INS(LDR, 2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM_BASE(PC)}},
1301             {MATCH_INS(STR, 2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM_ANY}},
1302             {MATCH_INS(POP, MATCH_OPCOUNT_IGNORE)},
1303             {ARM_INS_ENDING}
1304         };
1305         if(!insn_match_find_next_seq(fw,is,10,match_mov_ldr_str_pop)) {
1306             printf("sig_match_imager_active: match failed\n");
1307             return 0;
1308         }
1309         backtrack=2;
1310     }
1311     // rewind to LDR
1312     disasm_iter_init(fw,is,adr_hist_get(&is->ah,backtrack));
1313     disasm_iter(fw,is);
1314     uint32_t base=LDR_PC2val(fw,is->insn);
1315     uint32_t reg=is->insn->detail->arm.operands[0].reg;
1316 //    printf("base 0x%08x @0x%08x\n",base,(uint32_t)is->insn->address);
1317     // skip mov if after LDR
1318     if(backtrack == 3) {
1319         disasm_iter(fw,is);
1320     }
1321     disasm_iter(fw,is);
1322     // sanity check base is the same as LDR'd to
1323     if(is->insn->detail->arm.operands[1].mem.base != reg) {
1324         printf("sig_match_imager_active: reg mismatch\n");
1325         return 0;
1326     }
1327     uint32_t off=is->insn->detail->arm.operands[1].mem.disp;
1328 //    printf("off 0x%08x @0x%08x\n",off,(uint32_t)is->insn->address);
1329     save_misc_val("imager_active",base,off,(uint32_t)is->insn->address);
1330     return 1;
1331 }
1332 
1333 int sig_match_screenlock_helper(firmware *fw, iter_state_t *is, sig_rule_t *rule) {
1334     if(!init_disasm_sig_ref(fw,is,rule)) {
1335         return 0;
1336     }
1337     uint32_t init_adr = (uint32_t)is->adr | is->thumb;
1338     // match specific instruction sequence instead of first call because g3x, g5x have different code
1339     // not by dryos rev, sx710 has same code as earlier cams
1340     const insn_match_t match_cmp_bne_bl[]={
1341         {MATCH_INS(CMP, 2), {MATCH_OP_REG(R0),  MATCH_OP_IMM(0)}},
1342         {MATCH_INS_CC(B,NE,MATCH_OPCOUNT_IGNORE)},
1343         {MATCH_INS(BL,MATCH_OPCOUNT_IGNORE)},
1344         {ARM_INS_ENDING}
1345     };
1346     const insn_match_t match_ldrpc_mov_b[]={
1347         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(PC)}},
1348         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R1),  MATCH_OP_IMM(0)}},
1349         {MATCH_INS_CC(B,AL,MATCH_OPCOUNT_IGNORE)},
1350         {ARM_INS_ENDING}
1351     };
1352     // match first seq, this is the func we want
1353     if(insn_match_find_next_seq(fw,is,6,match_cmp_bne_bl)) {
1354         return save_sig_with_j(fw,rule->name,init_adr);
1355 
1356     }
1357     // try alternate match on newer cameras (around r57, but some variation)
1358     // this version puts a pointer to the function used in normal match in r0, 0 in R1, and jumps
1359     // go back to start
1360     disasm_iter_init(fw,is,init_adr);
1361     if(!insn_match_find_next_seq(fw,is,1,match_ldrpc_mov_b)) {
1362         printf("sig_match_screenlock_helper: match 2 failed 0x%"PRIx64"\n",is->insn->address);
1363         return 0;
1364     }
1365     disasm_iter_init(fw,is,init_adr);
1366     disasm_iter(fw,is);
1367     uint32_t adr = LDR_PC2val(fw,is->insn);
1368     if(!adr) {
1369         printf("sig_match_screenlock_helper: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
1370         return 0;
1371     }
1372     disasm_iter_init(fw,is,adr);
1373     // retry original match on pointer
1374     if(!insn_match_find_next_seq(fw,is,6,match_cmp_bne_bl)) {
1375         printf("sig_match_screenlock_helper: match failed 0x%8x\n",init_adr);
1376         return 0;
1377     }
1378     return save_sig_with_j(fw,rule->name,adr);
1379 }
1380 
1381 int sig_match_screenunlock(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1382 {
1383     if(!init_disasm_sig_ref(fw,is,rule)) {
1384         return 0;
1385     }
1386     // look for ScreenLock call to verify right version of UIFS_DisplayFirmUpdateView
1387     if(!find_next_sig_call(fw,is,14,"ScreenLock")) {
1388         // printf("sig_match_screenunlock: no ScreenLock\n");
1389         return 0;
1390     }
1391     
1392     // expect tail call to ScreenUnlock
1393     const insn_match_t match_end[]={
1394         {MATCH_INS(POP, MATCH_OPCOUNT_IGNORE)},
1395         {MATCH_INS_CC(B,AL,MATCH_OPCOUNT_IGNORE)},
1396         {ARM_INS_ENDING}
1397     };
1398     if(!insn_match_find_next_seq(fw,is,38,match_end)) {
1399         // printf("sig_match_screenunlock: match failed\n");
1400         return 0;
1401     }
1402     // TODO would be nice to have some validation
1403     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1404 }
1405 
1406 // look for f(0x60,"_Simage") at start of task_StartupImage
1407 int sig_match_log_camera_event(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1408 {
1409     if(!init_disasm_sig_ref(fw,is,rule)) {
1410         return 0;
1411     }
1412     if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
1413         // printf("sig_match_log_camera_event: bl match failed\n");
1414         return 0;
1415     }
1416     uint32_t regs[4];
1417     if((get_call_const_args(fw,is,4,regs)&3)!=3) {
1418         // printf("sig_match_log_camera_event: get args failed\n");
1419         return 0;
1420     }
1421     if(regs[0] != 0x60) {
1422         // printf("sig_match_log_camera_event: bad r0 0x%x\n",regs[0]);
1423         return 0;
1424     }
1425     const char *str=(char *)adr2ptr(fw,regs[1]);
1426     if(!str || strcmp(str,"_SImage") != 0) {
1427         // printf("sig_match_log_camera_event: bad r1 0x%x\n",regs[1]);
1428         return 0;
1429     }
1430     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1431 }
1432 
1433 // TODO this finds multiple values in PhySwTask main function
1434 int sig_match_physw_misc(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1435 {
1436     if(!init_disasm_sig_ref(fw,is,rule)) {
1437         osig* ostub2 = find_sig(fw->sv->stubs,rule->ref_name);
1438         if (ostub2 && ostub2->val)
1439         {
1440             disasm_iter_init(fw,is,ostub2->val);
1441         }
1442         else
1443         {
1444             return 0;
1445         }
1446     }
1447     int i;
1448     uint32_t physw_run=0;
1449     for(i=0; i<3; i++) {
1450         if(!disasm_iter(fw,is)) {
1451             printf("sig_match_physw_misc: disasm failed\n");
1452             return 0;
1453         }
1454         physw_run=LDR_PC2val(fw,is->insn);
1455         if(physw_run) {
1456             if(adr_is_var(fw,physw_run)) {
1457                 save_misc_val("physw_run",physw_run,0,(uint32_t)is->insn->address);
1458                 break;
1459             } else {
1460                 printf("sig_match_physw_misc: adr not data? 0x%08x\n",physw_run);
1461                 return 0;
1462             }
1463         }
1464     }
1465     if(!physw_run) {
1466         return 0;
1467     }
1468 
1469     // look for physw_sleep_delay, offset from physw_run, loaded before SleepTask
1470     if(!insn_match_find_next(fw,is,7,match_bl_blximm)) {
1471         return 0;
1472     }
1473     uint32_t sleeptask=get_saved_sig_val("SleepTask");
1474     if(!sleeptask) {
1475         printf("sig_match_physw_misc: missing SleepTask\n");
1476         return 0;
1477     }
1478     uint32_t f=get_branch_call_insn_target(fw,is);
1479 
1480     // call wasn't direct, check for veneer
1481     if(f != sleeptask) {
1482         fw_disasm_iter_single(fw,f);
1483         uint32_t f2=get_direct_jump_target(fw,fw->is);
1484         if(f2 != sleeptask) {
1485             return 0;
1486         }
1487         // sleeptask veneer is useful for xref
1488         // re-adding existing won't hurt
1489         save_sig_with_j(fw,"SleepTask",f);
1490     }
1491     // rewind 1 for r0
1492     disasm_iter_init(fw,is,adr_hist_get(&is->ah,1));
1493     if(!disasm_iter(fw,is)) {
1494         printf("sig_match_physw_misc: disasm failed\n");
1495         return 0;
1496     }
1497     // TODO could check base is same reg physw_run was loaded into
1498     if(is->insn->id != ARM_INS_LDR
1499         || is->insn->detail->arm.operands[0].reg != ARM_REG_R0) {
1500         return 0;
1501     }
1502     save_misc_val("physw_sleep_delay",physw_run,is->insn->detail->arm.operands[1].mem.disp,(uint32_t)is->insn->address);
1503     // skip over sleeptask to next insn
1504     if(!disasm_iter(fw,is)) {
1505         printf("sig_match_physw_misc: disasm failed\n");
1506         return 0;
1507     }
1508     
1509     // look for kbd_p1_f
1510     if(!insn_match_find_next(fw,is,2,match_bl_blximm)) {
1511         return 0;
1512     }
1513     save_sig(fw,"kbd_p1_f",get_branch_call_insn_target(fw,is));
1514 
1515     // look for kbd_p2_f
1516     if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
1517         return 0;
1518     }
1519     save_sig(fw,"kbd_p2_f",get_branch_call_insn_target(fw,is));
1520     return 1;
1521 }
1522 // TODO also finds p1_f_cont, physw_status
1523 int sig_match_kbd_read_keys(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1524 {
1525     if(!init_disasm_sig_ref(fw,is,rule)) {
1526         return 0;
1527     }
1528     // look for kbd_read_keys
1529     if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
1530         return 0;
1531     }
1532     save_sig(fw,"kbd_read_keys",get_branch_call_insn_target(fw,is));
1533     if(!disasm_iter(fw,is)) {
1534         printf("sig_match_kbd_read_keys: disasm failed\n");
1535         return 0;
1536     }
1537     uint32_t physw_status=LDR_PC2val(fw,is->insn);
1538     if(physw_status) {
1539         save_misc_val("physw_status",physw_status,0,(uint32_t)is->insn->address);
1540         save_sig(fw,"kbd_p1_f_cont",(uint32_t)(is->insn->address) | is->thumb);
1541         return 1;
1542     }
1543     return 0;
1544 }
1545 
1546 // TODO also finds kbd_read_keys_r2
1547 int sig_match_get_kbd_state(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1548 {
1549     if(!init_disasm_sig_ref(fw,is,rule)) {
1550         return 0;
1551     }
1552     // instructions that zero out physw_status
1553     insn_match_t match[]={
1554         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(PC)}},
1555         {MATCH_INS(BL,  MATCH_OPCOUNT_IGNORE)},
1556         {ARM_INS_ENDING}
1557     };
1558 
1559     if(!insn_match_find_next_seq(fw,is,11,match)) {
1560         return 0;
1561     }
1562     save_sig_with_j(fw,"GetKbdState",get_branch_call_insn_target(fw,is));
1563     // look for kbd_read_keys_r2
1564     if(!insn_match_find_next(fw,is,5,match_b_bl_blximm)) {
1565         return 0;
1566     }
1567     save_sig_with_j(fw,"kbd_read_keys_r2",get_branch_call_insn_target(fw,is));
1568     return 1;
1569 }
1570 
1571 int sig_match_get_dial_hw_position(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1572 {
1573     if(!init_disasm_sig_ref(fw,is,rule)) {
1574         return 0;
1575     }
1576     uint32_t adr = find_last_call_from_func(fw,is,18,50);
1577     if(!adr) {
1578         // printf("sig_match_get_dial_hw_position: no match call 1 at 0x%"PRIx64"\n",is->insn->address);
1579         return 0;
1580     }
1581     // follow
1582     disasm_iter_init(fw,is,adr);
1583     adr = find_last_call_from_func(fw,is,16,32);
1584     if(!adr) {
1585         // printf("sig_match_get_dial_hw_position: no match call 2 at 0x%"PRIx64"\n",is->insn->address);
1586         return 0;
1587     }
1588     // follow
1589     disasm_iter_init(fw,is,adr);
1590     // find next function call
1591     if(!insn_match_find_next(fw,is,30,match_bl_blximm)) {
1592         // printf("sig_match_get_dial_hw_position: no match call 3 at 0x%"PRIx64"\n",is->insn->address);
1593         return 0;
1594     }
1595     uint32_t fadr = get_branch_call_insn_target(fw,is);
1596     // rewind and match instructions for sanity check
1597     disasm_iter_init(fw,is,adr_hist_get(&is->ah,4));
1598     const insn_match_t match_hw_dial_call[]={
1599         {MATCH_INS(ADD,MATCH_OPCOUNT_ANY), {MATCH_OP_REG(R0)}},
1600         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0),MATCH_OP_MEM_BASE(PC)}},
1601         {MATCH_INS(BL,MATCH_OPCOUNT_IGNORE)},
1602         {ARM_INS_ENDING}
1603     };
1604     if(!insn_match_find_next(fw,is,4,match_hw_dial_call)) {
1605         // printf("sig_match_get_dial_hw_position: no match seq 0x%"PRIx64"\n",is->insn->address);
1606         return 0;
1607     }
1608     return save_sig_with_j(fw,rule->name,fadr);
1609 }
1610 
1611 int sig_match_create_jumptable(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1612 {
1613     if(!init_disasm_sig_ref(fw,is,rule)) {
1614         return 0;
1615     }
1616     // find second function call
1617     if(!insn_match_find_nth(fw,is,20,2,match_bl_blximm)) {
1618         return 0;
1619     }
1620     // follow
1621     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1622     if(!insn_match_find_next(fw,is,15,match_bl_blximm)) {
1623         return 0;
1624     }
1625     // TODO could verify it looks right (version string)
1626     save_sig(fw,"CreateJumptable",get_branch_call_insn_target(fw,is));
1627     return 1;
1628 }
1629 
1630 // TODO this actually finds a bunch of different stuff
1631 int sig_match_take_semaphore_strict(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1632 {
1633     if(!init_disasm_sig_ref(fw,is,rule)) {
1634         return 0;
1635     }
1636     // find first function call
1637     if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
1638         return 0;
1639     }
1640     // follow
1641     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1642     // find second call
1643     if(!insn_match_find_nth(fw,is,10,2,match_bl_blximm)) {
1644         return 0;
1645     }
1646     // follow
1647     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1648     // skip two calls, next should be DebugAssert
1649     if(!insn_match_find_nth(fw,is,20,3,match_bl_blximm)) {
1650         return 0;
1651     }
1652     save_sig_with_j(fw,"DebugAssert",get_branch_call_insn_target(fw,is));
1653 
1654     // next should be TakeSemaphoreStrictly
1655     if(!insn_match_find_next(fw,is,7,match_bl_blximm)) {
1656         return 0;
1657     }
1658     save_sig_with_j(fw,"TakeSemaphoreStrictly",get_branch_call_insn_target(fw,is));
1659     arm_reg ptr_reg = ARM_REG_INVALID;
1660     uint32_t sem_adr=0;
1661     int i;
1662     // iterate backwards looking for the value put in r0
1663     for(i=1; i<7; i++) {
1664         fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i));
1665         cs_insn *insn=fw->is->insn;
1666         if(insn->id != ARM_INS_LDR) {
1667             continue;
1668         }
1669         if(ptr_reg == ARM_REG_INVALID
1670             && insn->detail->arm.operands[0].reg == ARM_REG_R0
1671             && insn->detail->arm.operands[1].mem.base != ARM_REG_PC) {
1672             ptr_reg = insn->detail->arm.operands[1].mem.base;
1673             continue;
1674         }
1675         if(ptr_reg == ARM_REG_INVALID || !isLDR_PC(insn) || insn->detail->arm.operands[0].reg != ptr_reg) {
1676             continue;
1677         }
1678         sem_adr=LDR_PC2val(fw,insn);
1679         if(sem_adr) {
1680             break;
1681         }
1682     }
1683     if(!sem_adr) {
1684         return 0;
1685     }
1686     save_misc_val("fileio_semaphore",sem_adr,0,(uint32_t)is->insn->address);
1687     // look for next call: GetDrive_FreeClusters
1688     if(!insn_match_find_next(fw,is,10,match_bl_blximm)) {
1689         return 0;
1690     }
1691     return save_sig_with_j(fw,"GetDrive_FreeClusters",get_branch_call_insn_target(fw,is));
1692 }
1693 
1694 int sig_match_get_semaphore_value(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1695 {
1696     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
1697     if(!str_adr) {
1698         printf("sig_get_semaphore_value: failed to find ref %s\n",rule->ref_name);
1699         return 0;
1700     }
1701 
1702     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
1703     // assume first / only ref
1704     if(!fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
1705         // printf("sig_get_semaphore_value: failed to find code ref to %s\n",rule->ref_name);
1706         return 0;
1707     }
1708     // search backwards for func call
1709     uint32_t fadr=0;
1710     int i;
1711     for(i=1; i<=5; i++) {
1712         if(!fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i))) {
1713             // printf("sig_get_semaphore_value: disasm failed\n");
1714             return 0;
1715         }
1716         if(insn_match_any(fw->is->insn,match_bl_blximm)){
1717             fadr=get_branch_call_insn_target(fw,fw->is);
1718             break;
1719         }
1720     }
1721     if(!fadr) {
1722         // printf("sig_get_semaphore_value: failed to find bl 1\n");
1723         return 0;
1724     }
1725     // follow
1726     disasm_iter_init(fw,is,fadr);
1727     // look for first call
1728     if(!insn_match_find_next(fw,is,9,match_bl_blximm)) {
1729         // printf("sig_get_semaphore_value: failed to find bl 2\n");
1730         return 0;
1731     }
1732     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1733 }
1734 // similar to sig_match_str_r0_call, but string also appears with Fopen_Fut
1735 int sig_match_stat(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1736 {
1737     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
1738     if(!str_adr) {
1739         printf("sig_match_stat: %s failed to find ref %s\n",rule->name,rule->ref_name);
1740         return  0;
1741     }
1742 
1743     // TODO should handle multiple instances of string
1744     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
1745     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
1746         if(is->insn->detail->arm.operands[0].reg == ARM_REG_R0) {
1747             if(insn_match_find_next(fw,is,2,match_bl_blximm)) {
1748                 uint32_t adr=get_branch_call_insn_target(fw,is);
1749                 // same string ref'd by Fopen
1750                 if(is_sig_call(fw,is,"Fopen_Fut_FW")) {
1751                     continue;
1752                 }
1753                 // TODO could check r1 not a const
1754                 return save_sig_with_j(fw,rule->name,adr);
1755             }
1756         }
1757     }
1758     return 0;
1759 }
1760 static const insn_match_t match_open_mov_call[]={
1761     // 3 reg / reg movs, followed by a call
1762     {MATCH_INS(MOV, 2), {MATCH_OP_REG_ANY,  MATCH_OP_REG_ANY}},
1763     {MATCH_INS(MOV, 2), {MATCH_OP_REG_ANY,  MATCH_OP_REG_ANY}},
1764     {MATCH_INS(MOV, 2), {MATCH_OP_REG_ANY,  MATCH_OP_REG_ANY}},
1765     {MATCH_INS(BL,  MATCH_OPCOUNT_IGNORE)},
1766     {ARM_INS_ENDING}
1767 };
1768 
1769 
1770 // find low level open
1771 int sig_match_open(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1772 {
1773     if(!init_disasm_sig_ref(fw,is,rule)) {
1774         return 0;
1775     }
1776     if(!insn_match_find_next_seq(fw,is,48,match_open_mov_call)) {
1777         return 0;
1778     }
1779     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1780 }
1781 // find low level open for dryos >= 58
1782 // TODO not verified it works as expected
1783 int sig_match_open_gt_57(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1784 {
1785     if(!init_disasm_sig_ref(fw,is,rule)) {
1786         return 0;
1787     }
1788     if(!find_next_sig_call(fw,is,38,"TakeSemaphoreStrictly")) {
1789         return 0;
1790     }
1791     // looking for next call
1792     // this should be equivalent to previous versions Open, without the extra semaphore wrapper
1793     if(!insn_match_find_next(fw,is,5,match_bl_blximm)) {
1794         return 0;
1795     }
1796     // follow
1797     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1798     // match same pattern as normal
1799     if(!insn_match_find_next_seq(fw,is,48,match_open_mov_call)) {
1800         return 0;
1801     }
1802     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1803 }
1804 
1805 // find low level close for dryos >= 58
1806 // TODO not verified it works as expected
1807 int sig_match_close_gt_57(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1808 {
1809     if(!init_disasm_sig_ref(fw,is,rule)) {
1810         return 0;
1811     }
1812     if(!find_next_sig_call(fw,is,34,"TakeSemaphoreStrictly")) {
1813         return 0;
1814     }
1815     // looking for next call
1816     // this should be equivalent to previous versions Close, without the extra semaphore wrapper
1817     if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
1818         return 0;
1819     }
1820     // follow
1821     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1822     // first call
1823     if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
1824         return 0;
1825     }
1826     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1827 }
1828 
1829 
1830 // AllocateUncacheableMemory
1831 int sig_match_umalloc(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1832 {
1833     if(!init_disasm_sig_ref(fw,is,rule)) {
1834         return 0;
1835     }
1836     // looking for 3rd call
1837     if(!insn_match_find_nth(fw,is,15,3,match_bl_blximm)) {
1838         return 0;
1839     }
1840     //follow
1841     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1842     // looking for 3rd call again
1843     if(!insn_match_find_nth(fw,is,14,3,match_bl_blximm)) {
1844         return 0;
1845     }
1846     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1847 }
1848 
1849 // FreeUncacheableMemory
1850 int sig_match_ufree(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1851 {
1852     if(!init_disasm_sig_ref(fw,is,rule)) {
1853         return 0;
1854     }
1855     // find the first call to strcpy
1856     if(!find_next_sig_call(fw,is,60,"strcpy_FW")) {
1857         return 0;
1858     }
1859     // find 3rd call
1860     if(!insn_match_find_nth(fw,is,12,3,match_bl_blximm)) {
1861         return 0;
1862     }
1863     // follow
1864     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
1865     // Look for Close call
1866     if(!find_next_sig_call(fw,is,40,"Close_FW")) {
1867         return 0;
1868     }
1869     // next call should be FreeUncacheableMemory
1870     if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
1871         return 0;
1872     }
1873     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1874 }
1875 
1876 int sig_match_deletefile_fut(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1877 {
1878     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
1879     if(!str_adr) {
1880         printf("sig_match_deletefile_fut: %s failed to find ref %s\n",rule->name,rule->ref_name);
1881         return  0;
1882     }
1883     // TODO should handle multiple instances of string
1884     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
1885     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
1886         // next call should be DeleteFile_Fut
1887         if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
1888             continue;
1889         }
1890         // follow
1891         uint32_t adr=get_branch_call_insn_target(fw,is);
1892         if(!fw_disasm_iter_single(fw,adr)) {
1893             printf("sig_match_deletefile_fut: disasm failed\n");
1894             return 0;
1895         }
1896         const insn_match_t match_mov_r1[]={
1897             {MATCH_INS(MOV,     2), {MATCH_OP_REG(R1),  MATCH_OP_IMM_ANY}},
1898 #if CS_API_MAJOR < 4
1899             {MATCH_INS(MOVS,    2), {MATCH_OP_REG(R1),  MATCH_OP_IMM_ANY}},
1900 #endif
1901             {ARM_INS_ENDING}
1902         };
1903 
1904         if(!insn_match_any(fw->is->insn,match_mov_r1)){
1905             continue;
1906         }
1907         return save_sig_with_j(fw,rule->name,adr);
1908     }
1909     return 0;
1910 }
1911 
1912 uint32_t find_call_near_str(firmware *fw, iter_state_t *is, sig_rule_t *rule);
1913 
1914 int sig_match_closedir(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1915 {
1916     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
1917     if(!str_adr) {
1918         printf("sig_match_closedir: %s failed to find ref %s\n",rule->name,rule->ref_name);
1919         return  0;
1920     }
1921     // TODO should handle multiple instances of string
1922     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
1923     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
1924         if(!find_next_sig_call(fw,is,60,"sprintf_FW")) {
1925             continue;
1926         }
1927         if(insn_match_find_nth(fw,is,7,2,match_bl_blximm)) {
1928             return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1929         }
1930     }
1931 
1932     uint32_t call_adr = find_call_near_str(fw,is,rule);
1933     if(call_adr) {
1934         disasm_iter_init(fw,is,call_adr); // reset to a bit before where the string was found
1935         const insn_match_t match_closedir[]={
1936             {MATCH_INS(BL,MATCH_OPCOUNT_IGNORE)},
1937             {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0),  MATCH_OP_REG_ANY}},
1938             {MATCH_INS(BL,MATCH_OPCOUNT_IGNORE)},
1939             {ARM_INS_ENDING}
1940         };
1941         if(insn_match_seq(fw,is,match_closedir)){
1942             return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
1943         }
1944     }
1945 
1946     return 0;
1947 }
1948 
1949 // Save sig for function call (BL/BLX) at current instruction
1950 int save_sig_match_call(firmware* fw, sig_rule_t *rule, uint32_t call_adr)
1951 {
1952     disasm_iter_init(fw,fw->is,call_adr); // reset to a bit before where the string was found
1953     disasm_iter(fw,fw->is);
1954     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,fw->is));
1955 }
1956 
1957 int sig_match_readfastdir(firmware *fw, iter_state_t *is, sig_rule_t *rule)
1958 {
1959     uint32_t str_adr;
1960     str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
1961     if(!str_adr) {
1962         printf("sig_match_readfastdir: %s failed to find ref %s\n",rule->name,rule->ref_name);
1963         return 0;
1964     }
1965     const insn_match_t match_cbnz_r0[]={
1966         {MATCH_INS(CBNZ, 2), {MATCH_OP_REG(R0), MATCH_OP_IMM_ANY}},
1967         {ARM_INS_ENDING}
1968     };
1969     const insn_match_t match_cbz_r0[]={
1970         {MATCH_INS(CBZ, 2), {MATCH_OP_REG(R0), MATCH_OP_IMM_ANY}},
1971         {ARM_INS_ENDING}
1972     };
1973     int max_insns=rule->param&SIG_NEAR_OFFSET_MASK;
1974     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
1975     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
1976         uint32_t ref_adr = iter_state_adr(is);
1977         // Check for bl followed by cbnz in previous 2 instructions
1978         fw_disasm_iter_single(fw,adr_hist_get(&is->ah,2));
1979         if(insn_match_any(fw->is->insn,match_bl_blximm)) {
1980             uint32_t call_adr = iter_state_adr(fw->is);
1981             fw_disasm_iter_single(fw,adr_hist_get(&is->ah,1));
1982             if(insn_match_any(fw->is->insn,match_cbnz_r0)) {
1983                 return save_sig_match_call(fw, rule, call_adr);
1984             }
1985         }
1986         int i;
1987         for(i=3; i<=max_insns; i++) {
1988             // Check for bl followed by cbz branching to ref_adr
1989             fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i));
1990             if(insn_match_any(fw->is->insn,match_bl_blximm)) {
1991                 uint32_t call_adr = iter_state_adr(fw->is);
1992                 fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i-1));
1993                 if(insn_match_any(fw->is->insn,match_cbz_r0)) {
1994                     uint32_t b_adr = get_branch_call_insn_target(fw,fw->is);
1995                     if (ref_adr == b_adr) {
1996                         return save_sig_match_call(fw, rule, call_adr);
1997                     }
1998                 }
1999             }
2000         }
2001     }
2002     printf("sig_match_readfastdir: no match %s\n",rule->name);
2003     return 0;
2004 }
2005 
2006 int sig_match_strrchr(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2007 {
2008     uint32_t sig_adr=get_saved_sig_val(rule->name);
2009     if (sig_adr == 0)
2010     {
2011         uint32_t call_adr = find_call_near_str(fw,is,rule);
2012         if(call_adr) {
2013             disasm_iter_init(fw,is,call_adr-4); // reset to a bit before where the string was found
2014             const insn_match_t match_mov_r1_imm[]={
2015                 {MATCH_INS(MOV, 2), {MATCH_OP_REG(R1),  MATCH_OP_IMM_ANY}},
2016                 {ARM_INS_ENDING}
2017             };
2018             if(insn_match_find_next(fw,is,2,match_mov_r1_imm)){
2019                 return save_sig_match_call(fw, rule, call_adr);
2020             }
2021         }
2022     }
2023     return 0;
2024 }
2025 
2026 int sig_match_time(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2027 {
2028     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2029     if(!str_adr) {
2030         printf("sig_match_time: %s failed to find ref %s\n",rule->name,rule->ref_name);
2031         return  0;
2032     }
2033     uint32_t fadr=0;
2034     // TODO should handle multiple instances of string
2035     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
2036     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2037         // find second func after str ref
2038         if(insn_match_find_nth(fw,is,6,2,match_bl_blximm)) {
2039             fadr=get_branch_call_insn_target(fw,is);
2040             break;
2041         }
2042     }
2043     if(!fadr) {
2044         return 0;
2045     }
2046     // follow found func
2047     disasm_iter_init(fw,is,fadr);
2048     // find second call
2049     if(insn_match_find_nth(fw,is,11,2,match_bl_blximm)) {
2050         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2051     }
2052     return 0;
2053 }
2054 
2055 int sig_match_strncpy(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2056 {
2057     if(!init_disasm_sig_ref(fw,is,rule)) {
2058         return 0;
2059     }
2060     if(!find_next_sig_call(fw,is,60,"strcpy_FW")) {
2061         return 0;
2062     }
2063     if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
2064         return 0;
2065     }
2066     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2067 }
2068 
2069 int sig_match_strncmp(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2070 {
2071     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2072     if(!str_adr) {
2073         printf("sig_match_strncmp: failed to find ref %s\n",rule->ref_name);
2074         return  0;
2075     }
2076     // TODO should handle multiple instances of string
2077     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
2078     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2079         if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
2080             continue;
2081         }
2082         uint32_t regs[4];
2083         if((get_call_const_args(fw,is,4,regs)&6)==6) {
2084             // sanity check we got the right string
2085             if(regs[1]==str_adr &&  regs[2] == strlen(rule->ref_name)) {
2086                 return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2087             }
2088         }
2089     }
2090     return 0;
2091 }
2092 
2093 int sig_match_strtolx(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2094 {
2095     if(!init_disasm_sig_ref(fw,is,rule)) {
2096         return 0;
2097     }
2098     if(!find_next_sig_call(fw,is,130,"strncpy")) {
2099         return 0;
2100     }
2101     // find first call after strncpy
2102     if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
2103         return 0;
2104     }
2105     uint32_t adr=get_branch_call_insn_target(fw,is);
2106     if(!adr) {
2107         return 0;
2108     }
2109     // follow
2110     disasm_iter_init(fw,is,adr);
2111     if(!disasm_iter(fw,is)) {
2112         printf("sig_match_strtolx: disasm failed\n");
2113         return 0;
2114     }
2115     // expect
2116     // mov r3, #0
2117     // b ...
2118     const insn_match_t match_mov_r3_imm[]={
2119         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R3),  MATCH_OP_IMM_ANY}},
2120         {ARM_INS_ENDING}
2121     };
2122     if(!insn_match(is->insn,match_mov_r3_imm)){
2123         return 0;
2124     }
2125     if(!disasm_iter(fw,is)) {
2126         printf("sig_match_strtolx: disasm failed\n");
2127         return 0;
2128     }
2129     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2130 }
2131 
2132 // find the version of ExecuteEventProcedure that doesn't assert evp isn't reg'd
2133 int sig_match_exec_evp(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2134 {
2135     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2136     if(!str_adr) {
2137         printf("sig_match_exec_evp: failed to find ref %s\n",rule->ref_name);
2138         return  0;
2139     }
2140     // TODO should handle multiple instances of string
2141     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
2142     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2143         // search backwards for push {r0,...}
2144         int i;
2145         for(i=1; i<=18; i++) {
2146             if(!fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i))) {
2147                 break;
2148             }
2149             if(fw->is->insn->id == ARM_INS_PUSH && fw->is->insn->detail->arm.operands[0].reg == ARM_REG_R0) {
2150                 // push should be start of func
2151                 uint32_t adr=(uint32_t)(fw->is->insn->address) | is->thumb;
2152                 // search forward in original iter_state for DebugAssert. If found, in the wrong ExecuteEventProcedure
2153                 if(find_next_sig_call(fw,is,28,"DebugAssert")) {
2154                     break;
2155                 }
2156                 return save_sig_with_j(fw,rule->name,adr);
2157             }
2158         }
2159     }
2160     return 0;
2161 }
2162 
2163 int sig_match_fgets_fut(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2164 {
2165     if(!init_disasm_sig_ref(fw,is,rule)) {
2166         return 0;
2167     }
2168     if(!find_next_sig_call(fw,is,16,"Fopen_Fut_FW")) {
2169         return 0;
2170     }
2171     disasm_iter(fw,is);
2172     disasm_iter(fw,is);
2173     if (B_target(fw,is->insn) && (is->insn->detail->arm.cc == ARM_CC_NE)) {
2174         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2175     } else {
2176         if (B_target(fw,is->insn) && (is->insn->detail->arm.cc == ARM_CC_NE)) {
2177             disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2178         }
2179     }
2180     if(!insn_match_find_nth(fw,is,20,1,match_bl_blximm)) {
2181         return 0;
2182     }
2183     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2184 }
2185 
2186 int sig_match_log(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2187 {
2188     if(!init_disasm_sig_ref(fw,is,rule)) {
2189         return 0;
2190     }
2191     const insn_match_t match_pop6[]={
2192         {MATCH_INS(POP, 6), {MATCH_OP_REST_ANY}},
2193         {ARM_INS_ENDING}
2194     };
2195     // skip forward through 3x pop     {r4, r5, r6, r7, r8, lr}
2196     if(!insn_match_find_nth(fw,is,38,3,match_pop6)) {
2197         return 0;
2198     }
2199     // third call
2200     if(!insn_match_find_nth(fw,is,24,3,match_bl_blximm)) {
2201         return 0;
2202     }
2203     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2204 }
2205 
2206 // this only works on DryOS r52 cams
2207 int sig_match_pow_dry_52(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2208 {
2209     if (fw->dryos_ver != 52) {
2210         return 0;
2211     }
2212     if(!init_disasm_sig_ref(fw,is,rule)) {
2213         return 0;
2214     }
2215     const insn_match_t match_ldrd_r0_r1[]={
2216         {MATCH_INS(LDRD,    3), {MATCH_OP_REG(R0), MATCH_OP_REG(R1),    MATCH_OP_ANY}},
2217         {ARM_INS_ENDING}
2218     };
2219     // skip forward to first ldrd    r0, r1, [r...]
2220     if(!insn_match_find_next(fw,is,50,match_ldrd_r0_r1)) {
2221         return 0;
2222     }
2223     // prevent false positive
2224     if(is->insn->detail->arm.operands[2].mem.base == ARM_REG_SP) {
2225         return 0;
2226     }
2227     if(!disasm_iter(fw,is)) {
2228         printf("sig_match_pow: disasm failed\n");
2229         return 0;
2230     }
2231     uint32_t adr=get_branch_call_insn_target(fw,is);
2232     if(!adr) {
2233         return 0;
2234     }
2235     return save_sig_with_j(fw,rule->name,adr);
2236 }
2237 
2238 // match for dryos > r52 cams
2239 int sig_match_pow_dry_gt_52(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2240 {
2241     if (fw->dryos_ver <= 52) {
2242         return 0;
2243     }
2244     if(!init_disasm_sig_ref(fw,is,rule)) {
2245         return 0;
2246     }
2247     const insn_match_t match1a[]={
2248         {MATCH_INS(LDRSH,   2), {MATCH_OP_REG(R0),  MATCH_OP_MEM(SP,INVALID,0x12)}},
2249         {MATCH_INS(LDRD,    3), {MATCH_OP_REG(R2),  MATCH_OP_REG(R3), MATCH_OP_MEM(SP,INVALID,0x20)}},
2250         {MATCH_INS(STR,     2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM(SP,INVALID,0)}},
2251         {MATCH_INS(BL,      MATCH_OPCOUNT_IGNORE)},
2252         {ARM_INS_ENDING}
2253     };
2254     const insn_match_t match1b[]={
2255         {MATCH_INS(MOV,     2), {MATCH_OP_REG(R2),  MATCH_OP_REG(R7)}},
2256         {MATCH_INS(LDRSH,   2), {MATCH_OP_REG(R0),  MATCH_OP_MEM(SP,INVALID,0x12)}},
2257         {MATCH_INS(MOV,     2), {MATCH_OP_REG(R3),  MATCH_OP_REG(R6)}},
2258         {MATCH_INS(STR,     2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM(SP,INVALID,0)}},
2259         {MATCH_INS(BL,      MATCH_OPCOUNT_IGNORE)},
2260         {ARM_INS_ENDING}
2261     };
2262     const insn_match_t* match1[]={ match1a, match1b };
2263     int idx;
2264     for (idx = 0; idx < 2; idx += 1)
2265     {
2266         // match above sequence
2267         if(insn_match_find_next_seq(fw,is,50,match1[idx]))
2268             break;
2269         init_disasm_sig_ref(fw,is,rule);
2270     }
2271     // check for match
2272     if (idx >= 2)
2273         return 0;
2274     // match above sequence
2275     uint32_t adr=get_branch_call_insn_target(fw,is);
2276     if(!adr) {
2277         return 0;
2278     }
2279     // follow bl
2280     disasm_iter_init(fw,is,adr);
2281     const insn_match_t match2a[]={
2282         {MATCH_INS(LDRD,3), {MATCH_OP_REG(R0),  MATCH_OP_REG(R1),   MATCH_OP_MEM_ANY}},
2283         {MATCH_INS(BLX, 1), {MATCH_OP_IMM_ANY}},
2284         {ARM_INS_ENDING}
2285     };
2286     const insn_match_t match2b[]={
2287         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R2),  MATCH_OP_REG(R0)}},
2288         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R3),  MATCH_OP_REG(R1)}},
2289         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R4),  MATCH_OP_IMM(0x40000000)}},
2290         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0),  MATCH_OP_IMM(0)}},
2291         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R1),  MATCH_OP_REG(R4)}},
2292         {MATCH_INS(BL,  1), {MATCH_OP_IMM_ANY}},
2293         {ARM_INS_ENDING}
2294     };
2295     const insn_match_t* match2[]={ match2a, match2b };
2296     // match above sequence
2297     if(!insn_match_find_next_seq(fw,is,15,match2[idx])) {
2298         return 0;
2299     }
2300     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2301 }
2302 
2303 int sig_match_sqrt(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2304 {
2305     if(!init_disasm_sig_ref(fw,is,rule)) {
2306         return 0;
2307     }
2308     // third call
2309     if(!insn_match_find_nth(fw,is,12,3,match_bl_blximm)) {
2310         return 0;
2311     }
2312     // follow
2313     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2314     if(!disasm_iter(fw,is)) {
2315         printf("sig_match_sqrt: disasm failed\n");
2316         return 0;
2317     }
2318     uint32_t j_tgt=get_direct_jump_target(fw,is);
2319     // veneer?
2320     if(j_tgt) {
2321         // follow
2322         disasm_iter_init(fw,is,j_tgt);
2323         if(!disasm_iter(fw,is)) {
2324             printf("sig_match_sqrt: disasm failed\n");
2325             return 0;
2326         }
2327     }
2328     // second call/branch (seems to be bhs)
2329     if(!insn_match_find_nth(fw,is,12,2,match_b_bl_blximm)) {
2330         return 0;
2331     }
2332     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2333 }
2334 int sig_match_get_drive_cluster_size(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2335 {
2336     if(!init_disasm_sig_ref(fw,is,rule)) {
2337         return 0;
2338     }
2339     // only handle first match, don't expect multiple refs to string
2340     if(fw_search_insn(fw,is,search_disasm_str_ref,0,"A/OpLogErr.txt",(uint32_t)is->adr+260)) {
2341         // find first call after string ref
2342         if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
2343             // printf("sig_match_get_drive_cluster_size: bl not found\n");
2344             return 0;
2345         }
2346         // follow
2347         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2348         // find second call
2349         if(!insn_match_find_nth(fw,is,13,2,match_bl_blximm)) {
2350             // printf("sig_match_get_drive_cluster_size: call 1 not found\n");
2351             return 0;
2352         }
2353         // follow
2354         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2355         disasm_iter(fw,is);
2356         if (B_target(fw, is->insn))
2357             disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2358         // find next call
2359         if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
2360             // printf("sig_match_get_drive_cluster_size: call 2 not found\n");
2361             return 0;
2362         }
2363         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2364     }
2365     return 0;
2366 }
2367 
2368 int sig_match_mktime_ext(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2369 {
2370     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2371     if(!str_adr) {
2372         printf("sig_match_mktime_ext: failed to find ref %s\n",rule->ref_name);
2373         return  0;
2374     }
2375     // TODO should handle multiple instances of string
2376     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
2377     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2378         // expect sscanf after str
2379         if(!find_next_sig_call(fw,is,12,"sscanf_FW")) {
2380             // printf("sig_match_mktime_ext: no sscanf\n");
2381             return 0;
2382         }
2383         // find next call
2384         if(!insn_match_find_next(fw,is,22,match_bl_blximm)) {
2385             // printf("sig_match_mktime_ext: no call\n");
2386             return 0;
2387         }
2388         // follow
2389         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2390         if(!disasm_iter(fw,is)) {
2391             printf("sig_match_mktime_ext: disasm failed\n");
2392             return 0;
2393         }
2394         uint32_t j_tgt=get_direct_jump_target(fw,is);
2395         // veneer?
2396         if(j_tgt) {
2397             // follow
2398             disasm_iter_init(fw,is,j_tgt);
2399             if(!disasm_iter(fw,is)) {
2400                 printf("sig_match_mktime_ext: disasm failed\n");
2401                 return 0;
2402             }
2403         }
2404         const insn_match_t match_pop4[]={
2405             {MATCH_INS(POP, 4), {MATCH_OP_REST_ANY}},
2406             {MATCH_INS(POP, 6), {MATCH_OP_REST_ANY}},
2407             {ARM_INS_ENDING}
2408         };
2409 
2410         // find pop
2411         if(!insn_match_find_next(fw,is,54,match_pop4)) {
2412             // printf("sig_match_mktime_ext: no pop\n");
2413             return 0;
2414         }
2415         if(!insn_match_find_next(fw,is,1,match_b)) {
2416             // printf("sig_match_mktime_ext: no b\n");
2417             return 0;
2418         }
2419         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2420     }
2421     return 0;
2422 }
2423 
2424 // match call after ref to "_EnrySRec" because "AC:Rec2PB" ref before push in function, hard to be sure of start
2425 int sig_match_rec2pb(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2426 {
2427     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2428     if(!str_adr) {
2429         printf("sig_match_mktime_ext: failed to find ref %s\n",rule->ref_name);
2430         return  0;
2431     }
2432     // TODO should handle multiple instances of string
2433     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
2434     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2435         const insn_match_t match_ldr_cbnz_r0[]={
2436             {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0), MATCH_OP_MEM_ANY}},
2437             {MATCH_INS(CBNZ, 2), {MATCH_OP_REG(R0), MATCH_OP_IMM_ANY}},
2438             {ARM_INS_ENDING}
2439         };
2440         if(!insn_match_find_next_seq(fw,is,10,match_ldr_cbnz_r0)) {
2441             // printf("sig_match_rec2pb: no cbnz\n");
2442             continue;
2443         }
2444         // follow
2445         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2446         if(!insn_match_find_next(fw,is,3,match_b_bl_blximm)) {
2447             // printf("sig_match_rec2pb: no call\n");
2448             // followed branch, doesn't make sense to keep searching
2449             return 0;
2450         }
2451         uint32_t adr = iter_state_adr(is);
2452         // follow for sanity check
2453         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2454         if(!find_next_sig_call(fw,is,16,"LogCameraEvent")) {
2455             // printf("sig_match_rec2pb: no LogCameraEvent call\n");
2456             return 0;
2457         }
2458         uint32_t regs[4];
2459         if((get_call_const_args(fw,is,4,regs)&3)!=3) {
2460             // printf("sig_match_rec2pb: failed to get args\n");
2461             return 0;
2462         }
2463         // sanity check starts with LogCameraEvent with expected number and string
2464         if(regs[0]==0x60 && adr2ptr(fw,regs[1]) && (strcmp((const char *)adr2ptr(fw,regs[1]),"AC:Rec2PB")==0)) {
2465             return save_sig_with_j(fw,rule->name,adr);
2466         } else {
2467             // printf("sig_match_rec2pb: bad args\n");
2468             return 0;
2469         }
2470     }
2471     return 0;
2472 }
2473 
2474 // could just do sig_match_named, 3rd b, but want more validation
2475 int sig_match_get_parameter_data(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2476 {
2477     if(!init_disasm_sig_ref(fw,is,rule)) {
2478         return 0;
2479     }
2480     const insn_match_t match_cmp_bhs[]={
2481         {MATCH_INS(CMP, 2), {MATCH_OP_REG_ANY, MATCH_OP_IMM_ANY}},
2482         {MATCH_INS_CC(B,HS,MATCH_OPCOUNT_IGNORE)},
2483         {ARM_INS_ENDING}
2484     };
2485     if(!insn_match_find_next_seq(fw,is,4,match_cmp_bhs)) {
2486         // printf("sig_match_get_parameter_data: no match cmp, bhs\n");
2487         return 0;
2488     }
2489     // follow
2490     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2491     if(!insn_match_find_next(fw,is,1,match_b)) {
2492         // printf("sig_match_get_parameter_data: no match b\n");
2493         return 0;
2494     }
2495     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2496 }
2497 
2498 // PrepareDirectory (via string ref) points at something like
2499 // mov r1, 1
2500 // b PrepareDirectory_x
2501 int sig_match_prepdir_x(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2502 {
2503     if(!init_disasm_sig_ref(fw,is,rule)) {
2504         return 0;
2505     }
2506     const insn_match_t match_mov_r1_1[]={
2507         {MATCH_INS(MOV,     2), {MATCH_OP_REG(R1),  MATCH_OP_IMM(1)}},
2508 #if CS_API_MAJOR < 4
2509         {MATCH_INS(MOVS,    2), {MATCH_OP_REG(R1),  MATCH_OP_IMM(1)}},
2510 #endif
2511         {ARM_INS_ENDING}
2512     };
2513     if(!insn_match_find_next(fw,is,1,match_mov_r1_1)) {
2514         //printf("sig_match_prepdir_x: no match mov\n");
2515         return 0;
2516     }
2517     if(!insn_match_find_next(fw,is,1,match_b)) {
2518         //printf("sig_match_prepdir_x: no match b\n");
2519         return 0;
2520     }
2521     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2522 }
2523 
2524 // PrepareDirectory (via string ref) points at something like
2525 // mov r1, 1
2526 // b PrepareDirectory_x
2527 int sig_match_prepdir_1(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2528 {
2529     uint32_t call_adr = find_call_near_str(fw,is,rule);
2530     if(call_adr) {
2531         disasm_iter_init(fw,is,call_adr);
2532         disasm_iter(fw,is);
2533         disasm_iter(fw,is);
2534         if (!CBx_target(fw,is->insn))
2535         {
2536             rule->param = SIG_NEAR_BEFORE(20,5);
2537             call_adr = find_call_near_str(fw,is,rule);
2538             if(!call_adr) {
2539                 return 0;
2540             }
2541             disasm_iter_init(fw,is,call_adr);
2542             disasm_iter(fw,is);
2543             return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2544         }
2545     }
2546 
2547     rule->param = SIG_NEAR_BEFORE(7,2);
2548     call_adr = find_call_near_str(fw,is,rule);
2549     if(!call_adr) {
2550         return 0;
2551     }
2552     return save_sig_match_call(fw, rule, call_adr);
2553 }
2554 // assume this function is directly after the 2 instructions of ref
2555 int sig_match_prepdir_0(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2556 {
2557     if(!init_disasm_sig_ref(fw,is,rule)) {
2558         return 0;
2559     }
2560     uint32_t ref_pdx=get_saved_sig_val("PrepareDirectory_x");
2561     if(!ref_pdx) {
2562         printf("sig_match_prepdir_0: missing PrepareDirectory_x\n");
2563         return 0;
2564     }
2565     // skip over, assume validated previously
2566     disasm_iter(fw,is);
2567     disasm_iter(fw,is);
2568     // this should be the start address of our function
2569     uint32_t adr=(uint32_t)is->adr|is->thumb;
2570     const insn_match_t match_mov_r1_1[]={
2571         {MATCH_INS(MOV,     2), {MATCH_OP_REG(R1),  MATCH_OP_IMM(0)}},
2572 #if CS_API_MAJOR < 4
2573         {MATCH_INS(MOVS,    2), {MATCH_OP_REG(R1),  MATCH_OP_IMM(0)}},
2574 #endif
2575         {ARM_INS_ENDING}
2576     };
2577     if(!insn_match_find_next(fw,is,1,match_mov_r1_1)) {
2578         //printf("sig_match_prepdir_0: no match mov\n");
2579         return 0;
2580     }
2581     if(!insn_match_find_next(fw,is,1,match_b)) {
2582         //printf("sig_match_prepdir_0: no match b\n");
2583         return 0;
2584     }
2585     uint32_t pdx=get_branch_call_insn_target(fw,is);
2586     if(pdx != ref_pdx) {
2587         //printf("sig_match_prepdir_0: target 0x%08x != 0x%08x\n",pdx,ref_pdx);
2588         return 0;
2589     }
2590     return save_sig_with_j(fw,rule->name,adr);
2591 }
2592 int sig_match_mkdir(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2593 {
2594     if(!init_disasm_sig_ref(fw,is,rule)) {
2595         return 0;
2596     }
2597     const insn_match_t match[]={
2598         {MATCH_INS(STRB,2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM_ANY}},
2599         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0),  MATCH_OP_REG(SP)}},
2600         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R1),  MATCH_OP_MEM_BASE(SP)}},
2601         {MATCH_INS(BL,  MATCH_OPCOUNT_IGNORE)},
2602         {ARM_INS_ENDING}
2603     };
2604     if(insn_match_find_next_seq(fw,is,148,match)) {
2605         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2606     }
2607 
2608     init_disasm_sig_ref(fw,is,rule);
2609     const insn_match_t match2[]={
2610         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R1),  MATCH_OP_REG_ANY}},
2611         {MATCH_INS(STRB,2), {MATCH_OP_REG_ANY,  MATCH_OP_MEM_ANY}},
2612         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0),  MATCH_OP_REG(SP)}},
2613         {MATCH_INS(BL,  MATCH_OPCOUNT_IGNORE)},
2614         {ARM_INS_ENDING}
2615     };
2616     if(!insn_match_find_next_seq(fw,is,148,match2)) {
2617         //printf("sig_match_mkdir: no match\n");
2618         return 0;
2619     }
2620     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2621 }
2622 
2623 int sig_match_add_ptp_handler(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2624 {
2625     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2626     if(!str_adr) {
2627         printf("sig_match_add_ptp_handler: failed to find ref %s\n",rule->ref_name);
2628         return  0;
2629     }
2630     // TODO should handle multiple instances of string
2631     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
2632     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2633         // expect CreateTaskStrictly
2634         if(!find_next_sig_call(fw,is,8,"CreateTaskStrictly")) {
2635             // printf("sig_match_add_ptp_handler: no CreateTaskStrictly\n");
2636             continue;
2637         }
2638         // expect add_ptp_handler is 3rd call after CreateTask
2639         if(!insn_match_find_nth(fw,is,13,3,match_bl_blximm)) {
2640             // printf("sig_match_add_ptp_handler: no match bl\n");
2641             return 0;
2642         }
2643         // sanity check, expect opcode, func, 0
2644         uint32_t regs[4];
2645         if((get_call_const_args(fw,is,5,regs)&7)!=7) {
2646             // printf("sig_match_add_ptp_handler: failed to get args\n");
2647             return 0;
2648         }
2649         if(regs[0] < 0x9000 || regs[0] > 0x10000 || !adr2ptr(fw,regs[1]) || regs[2] != 0) {
2650             // printf("sig_match_add_ptp_handler: bad args 0x%08x 0x%08x 0x%08x\n",regs[0],regs[1],regs[2]);
2651             return 0;
2652         }
2653         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2654     }
2655     return 0;
2656 }
2657 int sig_match_qsort(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2658 {
2659     if(!init_disasm_sig_ref(fw,is,rule)) {
2660         return 0;
2661     }
2662     if(!find_next_sig_call(fw,is,90,"DebugAssert")) {
2663         // printf("sig_match_qsort: no DebugAssert\n");
2664         return 0;
2665     }
2666     if(!insn_match_find_nth(fw,is,38,3,match_bl_blximm)) {
2667         // printf("sig_match_qsort: no match bl\n");
2668         return 0;
2669     }
2670     // follow
2671     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2672     // if call in first 4 insn, follow again (newer cams have an extra sub)
2673     if(insn_match_find_next(fw,is,4,match_bl_blximm)) {
2674         disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
2675     }
2676     if(!insn_match_find_next(fw,is,14,match_bl_blximm)) {
2677         // printf("sig_match_qsort: no match bl (qsort)\n");
2678         return 0;
2679     }
2680     // sanity check, expect r1-r3 to be const
2681     uint32_t regs[4];
2682     if((get_call_const_args(fw,is,5,regs)&0xe)!=0xe) {
2683         // printf("sig_match_qsort: failed to get args\n");
2684         return 0;
2685     }
2686     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2687 }
2688 // looks for sequence of calls near ref string RedEyeController.c
2689 // DeleteFile_Fut
2690 // ...
2691 // strcpy
2692 // ...
2693 // strchr
2694 // ...
2695 // DeleteDirectory_Fut
2696 int sig_match_deletedirectory_fut(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2697 {
2698     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2699     if(!str_adr) {
2700         printf("sig_match_deletedirectory_fut: failed to find ref %s\n",rule->ref_name);
2701         return  0;
2702     }
2703     // TODO using larger than default "near" range, needed for sx710
2704     // not looking for ref to string, just code near where the actual string is
2705     disasm_iter_init(fw,is,(ADR_ALIGN4(str_adr) - 2048) | fw->thumb_default); // reset to a bit before where the string was found
2706     uint32_t end_adr = ADR_ALIGN4(str_adr) + 2048;
2707     while(find_next_sig_call(fw,is,end_adr - (uint32_t)is->adr,"DeleteFile_Fut")) {
2708         if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
2709             // printf("sig_match_deletedirectory_fut: no match bl strcpy\n");
2710             continue;
2711         }
2712         if(!is_sig_call(fw,is,"strcpy")) {
2713             // printf("sig_match_deletedirectory_fut: bl not strcpy at 0x%"PRIx64"\n",is->insn->address);
2714             continue;
2715         }
2716         if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
2717             // printf("sig_match_deletedirectory_fut: no match bl strrchr at 0x%"PRIx64"\n",is->insn->address);
2718             continue;
2719         }
2720         if(!is_sig_call(fw,is,"strrchr")) {
2721             // printf("sig_match_deletedirectory_fut: bl not strrchr at 0x%"PRIx64"\n",is->insn->address);
2722             continue;
2723         }
2724         // verify that arg1 to strrch is /
2725         uint32_t regs[4];
2726         if((get_call_const_args(fw,is,2,regs)&0x2)!=0x2) {
2727             // printf("sig_match_deletedirectory_fut: failed to get strrchr r1 at 0x%"PRIx64"\n",is->insn->address);
2728             continue;
2729         }
2730         if(regs[1] != '/') {
2731             // printf("sig_match_deletedirectory_fut: strrchr r1 not '/' at 0x%"PRIx64"\n",is->insn->address);
2732             continue;
2733         }
2734         if(!insn_match_find_next(fw,is,5,match_bl_blximm)) {
2735             // printf("sig_match_deletedirectory_fut: no match bl at 0x%"PRIx64"\n",is->insn->address);
2736             continue;
2737         }
2738         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2739     }
2740     return 0;
2741 }
2742 
2743 /*
2744 match
2745    ref "LogicalEvent:0x%04x:adr:%p,Para:%ld" (or "LogicalEvent:0x%08x:adr:%p,Para:%ld")
2746    bl      LogCameraEvent
2747    mov     r0, rN
2748    bl      <some func>
2749    bl      set_control_event (or veneer)
2750 same string is used elsewhere, so match specific sequence
2751 */
2752 int sig_match_set_control_event(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2753 {
2754     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2755     if(!str_adr) {
2756         // not logged, two different ref strings so failing one is normal
2757         // printf("sig_match_set_control_event: failed to find ref %s\n",rule->ref_name);
2758         return  0;
2759     }
2760     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
2761     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2762         if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
2763             // printf("sig_match_set_control_event: no match bl at 0x%"PRIx64"\n",is->insn->address);
2764             continue;
2765         }
2766         if(!is_sig_call(fw,is,"LogCameraEvent")) {
2767             // printf("sig_match_set_control_event: not LogCameraEvent at 0x%"PRIx64"\n",is->insn->address);
2768             continue;
2769         }
2770         const insn_match_t match_seq[]={
2771             {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0),  MATCH_OP_REG_ANY,}},
2772             {MATCH_INS(BL, MATCH_OPCOUNT_IGNORE)},
2773             {MATCH_INS(BL, MATCH_OPCOUNT_IGNORE)},
2774             {ARM_INS_ENDING}
2775         };
2776         if(!insn_match_find_next_seq(fw,is,1,match_seq)) {
2777             // printf("sig_match_set_control_event: no match seq\n");
2778             continue;
2779         }
2780         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2781     }
2782     return 0;
2783 }
2784 // find displaybusyonscreen for r52 cams, later uses different code
2785 int sig_match_displaybusyonscreen_52(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2786 {
2787     if (fw->dryos_ver != 52) {
2788         return 0;
2789     }
2790     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2791     if(!str_adr) {
2792         printf("sig_match_displaybusyonscreen: failed to find ref %s\n",rule->ref_name);
2793         return  0;
2794     }
2795     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
2796     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2797         if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
2798             // printf("sig_match_displaybusyonscreen: no match bl at 0x%"PRIx64"\n",is->insn->address);
2799             continue;
2800         }
2801         if(!is_sig_call(fw,is,"LogCameraEvent")) {
2802             // printf("sig_match_displaybusyonscreen: not LogCameraEvent at 0x%"PRIx64"\n",is->insn->address);
2803             continue;
2804         }
2805         if(!find_next_sig_call(fw,is,4,"GUISrv_StartGUISystem_FW")) {
2806             // printf("sig_match_displaybusyonscreen: no match GUISrv_StartGUISystem_FW\n");
2807             continue;
2808         }
2809         if(!insn_match_find_nth(fw,is,5,2,match_bl_blximm)) {
2810             // printf("sig_match_displaybusyonscreen: no match bl 0x%"PRIx64"\n",is->insn->address);
2811             continue;
2812         }
2813         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2814     }
2815     return 0;
2816 }
2817 // find undisplaybusyonscreen for r52 cams, later uses different code
2818 int sig_match_undisplaybusyonscreen_52(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2819 {
2820     if (fw->dryos_ver != 52) {
2821         return 0;
2822     }
2823     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2824     if(!str_adr) {
2825         printf("sig_match_undisplaybusyonscreen: failed to find ref %s\n",rule->ref_name);
2826         return  0;
2827     }
2828     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
2829     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2830         // assume same function display* was found in, skip to that
2831         if(!find_next_sig_call(fw,is,24,"displaybusyonscreen")) {
2832             // printf("sig_match_undisplaybusyonscreen: no match displaybusyonscreen\n");
2833             continue;
2834         }
2835         if(!find_next_sig_call(fw,is,12,"GUISrv_StartGUISystem_FW")) {
2836             // printf("sig_match_undisplaybusyonscreen: no match GUISrv_StartGUISystem_FW\n");
2837             continue;
2838         }
2839         if(!insn_match_find_nth(fw,is,6,3,match_bl_blximm)) {
2840             // printf("sig_match_undisplaybusyonscreen: no match bl 0x%"PRIx64"\n",is->insn->address);
2841             continue;
2842         }
2843         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2844     }
2845     return 0;
2846 }
2847 
2848 int sig_match_try_take_sem_dry_gt_58(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2849 {
2850     if(!init_disasm_sig_ref(fw,is,rule)) {
2851         return 0;
2852     }
2853     if(!find_next_sig_call(fw,is,24,"ReceiveMessageQueue")) {
2854         printf("sig_match_try_take_sem_dry_gt_58: failed to find ReceiveMessageQueue\n");
2855         return 0;
2856     }
2857     if(!find_next_sig_call(fw,is,60,"bzero")) {
2858         printf("sig_match_try_take_sem_dry_gt_58: failed to find bzero\n");
2859         return 0;
2860     }
2861     if(insn_match_find_next(fw,is,3,match_bl_blximm)) {
2862         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2863     }
2864     printf("sig_match_try_take_sem_dry_gt_58: no match\n");
2865     return 0;
2866 }
2867 
2868 int sig_match_wait_all_eventflag_strict(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2869 {
2870     if(!init_disasm_sig_ref(fw,is,rule)) {
2871         return 0;
2872     }
2873     uint32_t str_adr = find_str_bytes_main_fw(fw,"EFTool.c");
2874     if(!str_adr) {
2875         printf("sig_match_wait_all_eventflag_strict: failed to find ref EFTool.c\n");
2876         return 0;
2877     }
2878     if(!find_next_sig_call(fw,is,60,"SleepTask")) {
2879         printf("sig_match_wait_all_eventflag_strict: failed to find SleepTask\n");
2880         return 0;
2881     }
2882 
2883     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,is->adr + 60)) {
2884         if(!insn_match_find_next(fw,is,6,match_bl_blximm)) {
2885             printf("sig_match_wait_all_eventflag_strict: no match bl 0x%"PRIx64"\n",is->insn->address);
2886             return 0;
2887         }
2888         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2889     }
2890     return 0;
2891 }
2892 
2893 int sig_match_get_num_posted_messages(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2894 {
2895     if(!init_disasm_sig_ref(fw,is,rule)) {
2896         return 0;
2897     }
2898     if(!find_next_sig_call(fw,is,50,"TakeSemaphore")) {
2899         printf("sig_match_get_num_posted_messages: failed to find TakeSemaphore\n");
2900         return 0;
2901     }
2902     // find next call
2903     if(!insn_match_find_next(fw,is,5,match_bl_blximm)) {
2904         printf("sig_match_get_num_posted_messages:  no match bl 0x%"PRIx64"\n",is->insn->address);
2905         return 0;
2906     }
2907     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2908 }
2909 
2910 int sig_match_set_hp_timer_after_now(firmware *fw, iter_state_t *is, sig_rule_t *rule)
2911 {
2912     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
2913     if(!str_adr) {
2914         printf("sig_match_set_hp_timer_after_now: failed to find ref %s\n",rule->ref_name);
2915         return 0;
2916     }
2917     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
2918     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
2919         if(!find_next_sig_call(fw,is,20,"ClearEventFlag")) {
2920             // printf("sig_match_set_hp_timer_after_now: failed to find ClearEventFlag\n");
2921             continue;
2922         }
2923         // find 3rd call
2924         if(!insn_match_find_nth(fw,is,13,3,match_bl_blximm)) {
2925             // printf("sig_match_set_hp_timer_after_now: no match bl 0x%"PRIx64"\n",is->insn->address);
2926             continue;
2927         }
2928         // check call args, expect r0 = 70000
2929         uint32_t regs[4];
2930         uint32_t found_regs = get_call_const_args(fw,is,6,regs);
2931         if((found_regs&0x1)!=0x1) {
2932             // some cameras load r0 through a base reg, try alternate match
2933             // r3 == 3 and r2 or r1 found and in ROM
2934             if((found_regs & 0x8) && regs[3] == 4) {
2935                 if((found_regs & 0x2 && regs[1] > fw->rom_code_search_min_adr) 
2936                     || (found_regs & 0x4 && regs[2] > fw->rom_code_search_min_adr)) {
2937                     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2938                 }
2939             }
2940             // printf("sig_match_set_hp_timer_after_now: failed to match args 0x%"PRIx64"\n",is->insn->address);
2941             continue;
2942         }
2943         // r1, r2 should be func pointers but may involve reg-reg moves that get_call_const_args doesn't track
2944         if(regs[0] != 70000) {
2945             // printf("sig_match_set_hp_timer_after_now: args mismatch 0x%08x 0x%08x 0x%"PRIx64"\n",regs[0],regs[1],is->insn->address);
2946             continue;
2947         }
2948         return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
2949     }
2950     return 0;
2951 }
2952 int sig_match_transfer_src_overlay(firmware *fw, iter_state_t *is, sig_rule_t *rule) {
2953     if(!init_disasm_sig_ref(fw,is,rule)) {
2954         return 0;
2955     }
2956     // skip to debugassert
2957     if(!find_next_sig_call(fw,is,32,"DebugAssert")) {
2958         printf("sig_match_transfer_src_overlay: no match DebugAssert\n");
2959         return 0;
2960     }
2961     var_ldr_desc_t desc;
2962     if(!find_and_get_var_ldr(fw, is, 20,4, ARM_REG_R0, &desc)) {
2963         printf("sig_match_transfer_src_overlay: no match ldr\n");
2964         return 0;
2965     }
2966     // following should be call
2967     if(!insn_match_find_next(fw,is,1,match_bl_blximm)) {
2968         printf("sig_match_transfer_src_overlay: no match bl 0x%"PRIx64"\n",is->insn->address);
2969         return 0;
2970     }
2971     // main sig value
2972     uint32_t fadr = get_branch_call_insn_target(fw,is);
2973     // adding active_bitmap_buffer here
2974     // note 4 bytes after value used on many ports, but the value normally sent to transfer_src_overlay
2975     save_misc_val("active_bitmap_buffer",desc.adr_adj,desc.off,(uint32_t)is->insn->address);
2976     // pick up bitmap_buffer 
2977     // expect
2978     // ldr rx,[reg bitmap buffer]
2979     // add r0, <reg from bitmap buffer>, const
2980     const insn_match_t bm_buf_match[]={
2981         {MATCH_INS(LDR,   2),  {MATCH_OP_REG_ANY,  MATCH_OP_MEM_ANY}},
2982         {MATCH_INS(ADD,   3),  {MATCH_OP_REG(R0), MATCH_OP_REG_ANY, MATCH_OP_IMM_ANY}},
2983         {ARM_INS_ENDING}
2984     };
2985     if(insn_match_find_next_seq(fw,is,1,bm_buf_match)) {
2986         if(is->insn->detail->arm.operands[1].reg == desc.reg_base) {
2987             save_misc_val("bitmap_buffer",desc.adr_adj,is->insn->detail->arm.operands[2].imm,(uint32_t)is->insn->address);
2988         }
2989         /*
2990         else {
2991             printf("sig_match_transfer_src_overlay: no match bitmap_buffer add 0x%"PRIx64"\n",is->insn->address);
2992         }
2993         */
2994     }
2995     /*
2996     else {
2997         printf("sig_match_transfer_src_overlay: no match bitmap_buffer seq 0x%"PRIx64"\n",is->insn->address);
2998     }
2999     */
3000     return save_sig_with_j(fw,rule->name,fadr);
3001 }
3002 
3003 // find exmem related stuff
3004 int sig_match_exmem_vars(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3005 {
3006     uint32_t adr[2], fnd[2];
3007     if(!init_disasm_sig_ref(fw,is,rule)) {
3008         printf("sig_match_exmem_vars: missing ref\n");
3009         return 0;
3010     }
3011     // expect first LDR pc
3012     if(!insn_match_find_next(fw,is,15,match_ldr_pc)) {
3013         printf("sig_match_exmem_vars: match LDR PC failed\n");
3014         return 0;
3015     }
3016     adr[0]=LDR_PC2val(fw,is->insn);
3017     fnd[0]=(uint32_t)is->insn->address;
3018     if(!insn_match_find_next(fw,is,5,match_ldr_pc)) {
3019         printf("sig_match_exmem_vars: 2nd match LDR PC failed\n");
3020         return 0;
3021     }
3022     adr[1]=LDR_PC2val(fw,is->insn);
3023     fnd[1]=(uint32_t)is->insn->address;
3024     //printf("sig_match_exmem_vars: %x, %x\n",adr[0], adr[1]);
3025     int n;
3026     for (n=0; n<2; n++) {
3027         if (adr[n] < fw->data_start+fw->data_len) {
3028             uint32_t ladr = adr[n]-fw->data_start+fw->data_init_start;
3029             save_misc_val("exmem_types_table",ladr,0,fnd[n]);
3030             int m;
3031             int exm_typ_cnt = 0;
3032             for (m=0; m<42; m++) {
3033                 if ( (fw_u32(fw,ladr+m*4)!=0) && isASCIIstring(fw, fw_u32(fw,ladr+m*4)) )
3034                 {
3035                     char *extyp = (char*)adr2ptr(fw, fw_u32(fw,ladr+m*4));
3036                     if ( strncmp(extyp,"EXMEM",5)==0 )
3037                     {
3038                         exm_typ_cnt++;
3039                     }
3040                 }
3041                 else
3042                 {
3043                     break;
3044                 }
3045             }
3046             save_misc_val("exmem_type_count",exm_typ_cnt,0,ladr);
3047         }
3048         else if (adr[n] < fw->memisostart) {
3049             save_misc_val("exmem_alloc_table",adr[n],0,fnd[n]);
3050         }
3051     }
3052     return 1;
3053 }
3054 
3055 // find function that copies Zico Xtensa blobs to their destination (dryos 52)
3056 int sig_match_zicokick_52(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3057 {
3058     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
3059     if(!str_adr) {
3060         printf("sig_match_zicokick_52: failed to find ref %s\n",rule->ref_name);
3061         return  0;
3062     }
3063     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
3064     
3065     // search for string ref
3066     if(!fw_search_insn(fw,is,search_disasm_str_ref,0,rule->ref_name,(uint32_t)is->adr+SEARCH_NEAR_REF_RANGE)) {
3067         printf("sig_match_zicokick_52: failed to find insn ref %s\n",rule->ref_name);
3068         return 0;
3069     }
3070     // check preceding instruction
3071     if(!fw_disasm_iter_single(fw,adr_hist_get(&is->ah,1))) {
3072         printf("sig_match_zicokick_52: disasm failed\n");
3073         return 0;
3074     }
3075     if (!(isLDR_PC(fw->is->insn) && fw->is->insn->detail->arm.operands[0].reg == ARM_REG_R0)) {
3076         printf("sig_match_zicokick_52: match ldr r0 failed\n");
3077         return 0;
3078     }
3079     // save backtracked address
3080     uint32_t adr=(uint32_t)(fw->is->insn->address) | is->thumb;
3081     // step forward one from string ref
3082     if(!disasm_iter(fw,is)) {
3083         printf("sig_match_zicokick_52: disasm failed\n");
3084         return 0;
3085     }
3086     if (is->insn->id == ARM_INS_PUSH && is->insn->detail->arm.operands[0].reg == ARM_REG_R4) {
3087         return save_sig_with_j(fw,rule->name,adr);
3088     }
3089     return 0;
3090 }
3091 // find function that copies Zico Xtensa blobs to their destination (dryos >52)
3092 int sig_match_zicokick_gt52(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3093 {
3094     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
3095     if(!str_adr) {
3096         printf("sig_match_zicokick_gt52: failed to find ref %s\n",rule->ref_name);
3097         return  0;
3098     }
3099     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
3100     
3101     // search for string ref
3102     if(!fw_search_insn(fw,is,search_disasm_str_ref,0,rule->ref_name,(uint32_t)is->adr+SEARCH_NEAR_REF_RANGE)) {
3103         printf("sig_match_zicokick_gt52: failed to find insn ref %s\n",rule->ref_name);
3104         return 0;
3105     }
3106     int i;
3107     // search backward for
3108     // ldr r0,...
3109     // push r4,...
3110     for(i=1; i<=8; i++) {
3111         if (!fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i))) {
3112             printf("sig_match_zicokick_gt52: disasm failed\n");
3113             return 0;
3114         }
3115         if (fw->is->insn->id == ARM_INS_PUSH && fw->is->insn->detail->arm.operands[0].reg == ARM_REG_R4) {
3116             if (!fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i+1))) {
3117                 printf("sig_match_zicokick_gt52: disasm failed\n");
3118                 return 0;
3119             }
3120             if (isLDR_PC(fw->is->insn) && fw->is->insn->detail->arm.operands[0].reg == ARM_REG_R0) {
3121                 return save_sig_with_j(fw,rule->name,(uint32_t)(fw->is->insn->address) | is->thumb);
3122             }
3123             return 0;
3124         }
3125     }
3126     return 0;
3127 }
3128 int sig_match_zicokick_copy(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3129 {
3130     if(!init_disasm_sig_ref(fw,is,rule)) {
3131         return 0;
3132     }
3133     // TODO could be less strict on regs, 5 LDRs in a row is rare
3134     const insn_match_t match_ldrs_bl[]={
3135         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(PC)}},
3136         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R1),  MATCH_OP_MEM_BASE(PC)}},
3137         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R2),  MATCH_OP_MEM_BASE(R0)}},
3138         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(PC)}},
3139         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(R0)}},
3140         {MATCH_INS(BL,MATCH_OPCOUNT_IGNORE)},
3141         {ARM_INS_ENDING}
3142     };
3143     if(!insn_match_find_next_seq(fw,is,30,match_ldrs_bl)) {
3144         printf("sig_match_zicokick_copy no match ldr\n");
3145         return 0;
3146     }
3147     // TODO could sanity check bl target
3148     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3149 }
3150 
3151 int sig_match_zicokick_values(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3152 {
3153     if(!init_disasm_sig_ref(fw,is,rule)) {
3154         return 0;
3155     }
3156 // get_call_const_args doesn't currently handle ldr sequence
3157 #if 0
3158     // first call is further from function start
3159     if(!find_next_sig_call(fw,is,64,"zicokick_copy")) {
3160         printf("sig_match_zicokick_values: no zicokick_copy 1\n");
3161         return 0;
3162     }
3163     while(1) {
3164         uint32_t regs[4];
3165         if((get_call_const_args(fw,is,7,regs)&0x7)==0x7) {
3166             printf("xtensa blob @ 0x%08x, loads to 0x%08x, size 0x%08x\n",regs[1],regs[0],regs[2]);
3167         } else {
3168             printf("sig_match_zicokick_values: failed to get regs\n");
3169         }
3170         if(!find_next_sig_call(fw,is,8,"zicokick_copy")) {
3171             break;
3172         }
3173     }
3174     return 1;
3175 #endif
3176     int i;
3177     uint32_t uv[3] = {0,0,0};
3178     int uvi = 0;
3179     misc_blob_t *blobs=malloc((MISC_BLOB_XTENSA_MAX + 1)*sizeof(misc_blob_t));
3180     int n_blobs = 0;
3181 
3182     for(i=1; i<=64; i++) {
3183         if (!disasm_iter(fw,is)) {
3184             free(blobs);
3185             return 0;
3186         }
3187         if (is->insn->id == ARM_INS_LDR && is->insn->detail->arm.operands[1].type == ARM_OP_MEM) {
3188             uint32_t u = LDR_PC2val(fw,is->insn);
3189             if ((u<fw->base+fw->size8) && (u>fw->rom_code_search_max_adr)) {
3190                 // address outside the main fw
3191                 if (uvi<3) {
3192                     uv[uvi] = u;
3193                     uvi++;
3194                 }
3195             }
3196         }
3197         else if (is->insn->id == ARM_INS_BL) {
3198             if (uvi==3) {
3199                 // func call, all 3 addresses are in collection
3200                 uint32_t bsize, bloadedto, badr, u;
3201                 int j;
3202                 badr = MAX(MAX(uv[0],uv[1]),uv[2]);
3203                 for (j=0; j<3; j++) {
3204                     if (uv[j]!=badr) {
3205                         u = fw_u32(fw, uv[j]);
3206                         if (u<1024*1024*2) {
3207                             bsize = u;
3208                         }
3209                         else {
3210                             bloadedto = u;
3211                         }
3212                     }
3213                 }
3214                 if (bsize) {
3215                     if(n_blobs == MISC_BLOB_XTENSA_MAX) {
3216                         printf("sig_match_zicokick_values: ignoring xtensa blobs > %d\n",MISC_BLOB_XTENSA_MAX);
3217                         blobs[n_blobs].type = MISC_BLOB_TYPE_NONE;
3218                         break;
3219                     }
3220                     // printf("xtensa blob @ 0x%08x, loads to 0x%08x, size 0x%08x\n",badr,bloadedto,bsize);
3221                     blobs[n_blobs].type = MISC_BLOB_TYPE_XTENSA;
3222                     blobs[n_blobs].rom_adr = badr;
3223                     blobs[n_blobs].ram_adr = bloadedto;
3224                     blobs[n_blobs].size = bsize;
3225                     n_blobs++;
3226                 }
3227             }
3228             uvi = 0;
3229         }
3230         else if (is->insn->id == ARM_INS_POP) {
3231             break;
3232         }
3233     }
3234     if(n_blobs > 0) {
3235         blobs[n_blobs].type = MISC_BLOB_TYPE_NONE;
3236         save_misc_val_blobs("zicokick_values",blobs,0);
3237         return 1;
3238     } else {
3239         free(blobs);
3240         return 0;
3241     }
3242 }
3243 
3244 int sig_match_init_ex_drivers(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3245 {
3246     if(!init_disasm_sig_ref(fw,is,rule)) {
3247         return 0;
3248     }
3249     int i;
3250     int b_count;
3251     // search forward 32 instructions or 14 calls
3252     for(i=0, b_count = 0; i < 32 && b_count < 14; i++) {
3253         if (!disasm_iter(fw,is)) {
3254             printf("sig_match_init_ex_drivers: disasm failed 1\n");
3255             return 0;
3256         }
3257         uint32_t b_tgt = get_branch_call_insn_target(fw,is);
3258         if(!b_tgt) {
3259             continue;
3260         }
3261         b_count++;
3262         uint64_t next_adr = is->adr | is->thumb;
3263         disasm_iter_init(fw,is,b_tgt);
3264         if (!disasm_iter(fw,is)) {
3265             printf("sig_match_init_ex_drivers: disasm failed 2\n");
3266             return 0;
3267         }
3268         // expect the function we're looking for to start with a push
3269         if(is->insn->id == ARM_INS_PUSH) {
3270             if(find_next_sig_call(fw,is,30,"DebugAssert")) {
3271                 uint32_t regs[4];
3272                 if((get_call_const_args(fw,is,5,regs)&0x2)==0x2) {
3273                     const char *str=(char *)adr2ptr(fw,regs[1]);
3274                     if(str && strcmp(str,"InitExDrivers.c") == 0) {
3275                         return save_sig_with_j(fw,rule->name,b_tgt);
3276                     }
3277                 }
3278             }
3279         }
3280         disasm_iter_init(fw,is,next_adr);
3281     }
3282     return 0;
3283 }
3284 
3285 int sig_match_omar_init(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3286 {
3287     // not present on digic 7
3288     if (fw->arch_flags & FW_ARCH_FL_VMSA) {
3289         return 0;
3290     }
3291     if(!init_disasm_sig_ref(fw,is,rule)) {
3292         return 0;
3293     }
3294     uint32_t fadr = find_last_call_from_func(fw,is,20,42);
3295     if(!fadr) {
3296         printf("sig_match_omar_init: no match call\n");
3297         return 0;
3298     }
3299     // follow
3300     disasm_iter_init(fw,is,fadr);
3301     if(!find_next_sig_call(fw,is,44,"dry_memcpy")) {
3302         printf("sig_match_omar_init: no match dry_memcpy\n");
3303         return 0;
3304     }
3305     uint32_t regs[4];
3306     // expect dry_memcpy(stack ptr,rom ptr, 0x18)
3307     if((get_call_const_args(fw,is,5,regs)&0x6)!=0x6) {
3308         printf("sig_match_omar_init: no match dry_memcpy args 1\n");
3309         return 0;
3310     }
3311     if(regs[2] != 0x18 || !adr2ptr(fw,regs[1])) {
3312         printf("sig_match_omar_init: no match dry_memcpy args 2\n");
3313         return 0;
3314     }
3315     uint32_t dadr = regs[1];
3316     save_misc_val("omar_init_data",dadr,0,(uint32_t)is->insn->address);
3317     misc_blob_t *blobs=malloc(3*sizeof(misc_blob_t));
3318     int i;
3319     for(i = 0; i<2; i++) {
3320         uint32_t dst = fw_u32(fw,dadr + i*12);
3321         uint32_t src = fw_u32(fw,dadr + i*12 + 4);
3322         uint32_t bsize = fw_u32(fw,dadr + i*12 + 8);
3323         if(src && dst && bsize) {
3324             blobs[i].type = MISC_BLOB_TYPE_OMAR;
3325             blobs[i].rom_adr = src;
3326             blobs[i].ram_adr = dst;
3327             blobs[i].size = bsize;
3328         } else {
3329             printf("sig_match_omar_init: invalid blobs\n");
3330             free(blobs);
3331             blobs = NULL;
3332             break;
3333         }
3334     }
3335     if(blobs) {
3336         blobs[2].type = MISC_BLOB_TYPE_NONE;
3337         save_misc_val_blobs("omar_init_values",blobs,0);
3338     }
3339 
3340     return save_sig_with_j(fw,rule->name,fadr);
3341 }
3342 
3343 int sig_match_enable_hdmi_power(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3344 {
3345     if(!init_disasm_sig_ref(fw,is,rule)) {
3346         return 0;
3347     }
3348     if(!find_next_sig_call(fw,is,14,"CreateEventFlagStrictly")) {
3349         printf("sig_match_enable_hdmi_power: no match CreateEventFlagStrictly\n");
3350         return 0;
3351     }
3352     const insn_match_t match_seq[]={
3353         {MATCH_INS(BL,   MATCH_OPCOUNT_IGNORE)},
3354         {MATCH_INS(CBNZ, MATCH_OPCOUNT_IGNORE)},
3355         {ARM_INS_ENDING}
3356     };
3357     if(!insn_match_find_next_seq(fw,is,4,match_seq)) {
3358         printf("sig_match_enable_hdmi_power: no match bl seq cbnz 0x%"PRIx64"\n",is->insn->address);
3359         return 0;
3360     }
3361     // function should be next call
3362     if (!disasm_iter(fw,is)) {
3363         return 0;
3364     }
3365     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3366 }
3367 
3368 int sig_match_disable_hdmi_power(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3369 {
3370     if(!init_disasm_sig_ref(fw,is,rule)) {
3371         return 0;
3372     }
3373     if(!find_next_sig_call(fw,is,24,"EnableHDMIPower")) {
3374         printf("sig_match_disable_hdmi_power: no match EnableHDMIPower\n");
3375         return 0;
3376     }
3377     if(!find_next_sig_call(fw,is,22,"ClearEventFlag")) {
3378         printf("sig_match_disable_hdmi_power: no match ClearEventFlag\n");
3379         return 0;
3380     }
3381     const insn_match_t match_seq[]={
3382         {MATCH_INS(BL,   MATCH_OPCOUNT_IGNORE)},
3383         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0),  MATCH_OP_IMM(1)}},
3384         {MATCH_INS(POP, MATCH_OPCOUNT_IGNORE)},
3385         {ARM_INS_ENDING}
3386     };
3387     if(!insn_match_find_next_seq(fw,is,12,match_seq)) {
3388         printf("sig_match_disable_hdmi_power: no match seq bl movs pop 0x%"PRIx64"\n",is->insn->address);
3389         return 0;
3390     }
3391     // bl matched above should be func
3392     disasm_iter_init(fw,is,adr_hist_get(&is->ah,2));
3393     if (!disasm_iter(fw,is)) {
3394         return 0;
3395     }
3396     return save_sig_with_j(fw,rule->name,get_branch_call_insn_target(fw,is));
3397 }
3398 
3399 int sig_match_levent_table(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3400 {
3401     if(!init_disasm_sig_ref(fw,is,rule)) {
3402         return 0;
3403     }
3404     if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
3405         // printf("sig_match_levent_table: no match bl 0x%"PRIx64"\n",is->insn->address);
3406         return 0;
3407     }
3408     // follow
3409     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3410 
3411     // find first call of next function
3412     if(!insn_match_find_next(fw,is,4,match_bl_blximm)) {
3413         // printf("sig_match_levent_table: no match bl 0x%"PRIx64"\n",is->insn->address);
3414         return 0;
3415     }
3416     
3417     // follow
3418     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3419 
3420     // first instruction should load address
3421     disasm_iter(fw,is);
3422     uint32_t adr=LDR_PC2val(fw,is->insn);
3423     if(!adr) {
3424         // printf("sig_match_levent_table: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
3425         return  0;
3426     }
3427     uint32_t *p=(uint32_t *)adr2ptr(fw,adr);
3428     if(!p) {
3429         printf("sig_match_levent_table: 0x%08x not a ROM adr 0x%"PRIx64"\n",adr,is->insn->address);
3430         return  0;
3431     }
3432     if(*(p+1) != 0x800) {
3433         printf("sig_match_levent_table: expected 0x800 not 0x%x at 0x%08x ref 0x%"PRIx64"\n",*(p+1),adr,is->insn->address);
3434         return  0;
3435     }
3436     // TODO saving the function might be useful for analysis
3437     save_misc_val(rule->name,adr,0,(uint32_t)is->insn->address);
3438     return 1;
3439 }
3440 int sig_match_flash_param_table(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3441 {
3442     if(!init_disasm_sig_ref(fw,is,rule)) {
3443         return 0;
3444     }
3445     // expect 3 asserts
3446     if(!insn_match_find_next(fw,is,14,match_bl_blximm)) {
3447         // printf("sig_match_flash_param_table: no match bl 1\n");
3448         return 0;
3449     }
3450     if(!is_sig_call(fw,is,"DebugAssert")) {
3451         // printf("sig_match_flash_param_table: bl 1 not DebugAssert at 0x%"PRIx64"\n",is->insn->address);
3452         return 0;
3453     }
3454     if(!insn_match_find_next(fw,is,7,match_bl_blximm)) {
3455         // printf("sig_match_flash_param_table: no match bl 2\n");
3456         return 0;
3457     }
3458     if(!is_sig_call(fw,is,"DebugAssert")) {
3459         // printf("sig_match_flash_param_table: bl 2 not DebugAssert at 0x%"PRIx64"\n",is->insn->address);
3460         return 0;
3461     }
3462     if(!insn_match_find_next(fw,is,8,match_bl_blximm)) {
3463         // printf("sig_match_flash_param_table: no match bl 3\n");
3464         return 0;
3465     }
3466     if(!is_sig_call(fw,is,"DebugAssert")) {
3467         // printf("sig_match_flash_param_table: bl 3 not DebugAssert at 0x%"PRIx64"\n",is->insn->address);
3468         return 0;
3469     }
3470     // expect AcquireRecursiveLockStrictly, func
3471     if(!insn_match_find_nth(fw,is,14,2,match_bl_blximm)) {
3472         // printf("sig_match_flash_param_table: no match sub 1\n");
3473         return 0;
3474     }
3475     // follow
3476     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3477 
3478     // first call
3479     if(!insn_match_find_next(fw,is,8,match_bl_blximm)) {
3480         // printf("sig_match_flash_param_table: no match sub 1 bl\n");
3481         return 0;
3482     }
3483     
3484     // follow
3485     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3486     // first instruction should load address
3487     disasm_iter(fw,is);
3488     uint32_t adr=LDR_PC2val(fw,is->insn);
3489     if(!adr) {
3490         // printf("sig_match_flash_param_table: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
3491         return  0;
3492     }
3493     save_misc_val(rule->name,adr,0,(uint32_t)is->insn->address);
3494     return 1;
3495 }
3496 int sig_match_jpeg_count_str(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3497 {
3498     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
3499     if(!str_adr) {
3500         printf("sig_match_jpeg_count_str: failed to find ref %s\n",rule->ref_name);
3501         return  0;
3502     }
3503     // TODO should handle multiple instances of string
3504     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
3505     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
3506         // printf("sig_match_jpeg_count_str: str match 0x%"PRIx64"\n",is->insn->address);
3507         if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
3508             // printf("sig_match_jpeg_count_str: no match bl\n");
3509             continue;
3510         }
3511         if(!is_sig_call(fw,is,"sprintf_FW")) {
3512             // printf("sig_match_jpeg_count_str: not sprintf_FW at 0x%"PRIx64"\n",is->insn->address);
3513             continue;
3514         }
3515         // expect ptr in r0, str in r1
3516         uint32_t regs[4];
3517         if((get_call_const_args(fw,is,5,regs)&0x3)!=0x3) {
3518             // printf("sig_match_jpeg_count_str: failed to get sprintf args 0x%"PRIx64"\n",is->insn->address);
3519             continue;
3520         }
3521         if(regs[1] != str_adr) {
3522             // printf("sig_match_jpeg_count_str: expected r1 == 0x%08x not 0x%08x at 0x%"PRIx64"\n",str_adr, regs[1],is->insn->address);
3523             return 0;
3524         }
3525         if(!adr_is_var(fw,regs[0])) {
3526             // printf("sig_match_jpeg_count_str: r0 == 0x%08x not var ptr at 0x%"PRIx64"\n",regs[0],is->insn->address);
3527             return 0;
3528         }
3529         save_misc_val(rule->name,regs[0],0,(uint32_t)is->insn->address);
3530         return 1;
3531     }
3532     return 0;
3533 }
3534 
3535 // set a boolean misc val if ref is present
3536 int sig_match_misc_flag_named(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3537 {
3538     uint32_t ref=get_saved_sig_val(rule->ref_name);
3539     save_misc_val(rule->name,(ref)?1:0,0,ref);
3540     return 1;
3541 }
3542 
3543 int sig_match_cam_has_iris_diaphragm(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3544 {
3545     uint32_t v;
3546     uint32_t ref=0;get_saved_sig_val(rule->ref_name);
3547     // ILC assumed to have iris
3548     if(get_misc_val_value("CAM_IS_ILC")) {
3549         v=1;
3550     } else {
3551         ref=get_saved_sig_val(rule->ref_name);
3552         v=(ref)?1:0;
3553     }
3554     save_misc_val(rule->name,v,0,ref);
3555     return 1;
3556 }
3557 
3558 int sig_match_cam_uncached_bit(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3559 {
3560     if(!init_disasm_sig_ref(fw,is,rule)) {
3561         return 0;
3562     }
3563     const insn_match_t match_bic_r0[]={
3564         {MATCH_INS(BIC, 3), {MATCH_OP_REG(R0),  MATCH_OP_REG(R0),   MATCH_OP_IMM_ANY}},
3565         {ARM_INS_ENDING}
3566     };
3567     if(insn_match_find_next(fw,is,4,match_bic_r0)) {
3568         save_misc_val(rule->name,is->insn->detail->arm.operands[2].imm,0,(uint32_t)is->insn->address);
3569         return 1;
3570     }
3571     return 0;
3572 }
3573 
3574 int sig_match_physw_event_table(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3575 {
3576     if(!init_disasm_sig_ref(fw,is,rule)) {
3577         return 0;
3578     }
3579     // expect first LDR pc
3580     if(!insn_match_find_next(fw,is,5,match_ldr_pc)) {
3581         printf("sig_match_physw_event_table: match LDR PC failed\n");
3582         return 0;
3583     }
3584     uint32_t adr=LDR_PC2val(fw,is->insn);
3585     if(!adr) {
3586         printf("sig_match_physw_event_table: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
3587         return 0;
3588     }
3589     if(!adr2ptr(fw,adr)) {
3590         printf("sig_match_physw_event_table: adr not ROM 0x%08x at 0x%"PRIx64"\n",adr,is->insn->address);
3591         return 0;
3592     }
3593     save_misc_val(rule->name,adr,0,(uint32_t)is->insn->address);
3594     return 1;
3595 }
3596 int sig_match_uiprop_count(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3597 {
3598     if(!init_disasm_sig_ref(fw,is,rule)) {
3599         return 0;
3600     }
3601     if(!find_next_sig_call(fw,is,38,"DebugAssert")) {
3602         // printf("sig_match_uiprop_count: no DebugAssert 1\n");
3603         return 0;
3604     }
3605     if(!find_next_sig_call(fw,is,14,"DebugAssert")) {
3606         // printf("sig_match_uiprop_count: no DebugAssert 2\n");
3607         return 0;
3608     }
3609     const insn_match_t match_bic_cmp[]={
3610         {MATCH_INS(BIC, 3), {MATCH_OP_REG_ANY,  MATCH_OP_REG_ANY,   MATCH_OP_IMM(0x8000)}},
3611         {MATCH_INS(CMP, 2), {MATCH_OP_REG_ANY,  MATCH_OP_ANY}},
3612         {ARM_INS_ENDING}
3613     };
3614     if(!insn_match_find_next_seq(fw,is,3,match_bic_cmp)) {
3615         // printf("sig_match_uiprop_count: no bic,cmp\n");
3616         return 0;
3617     }
3618     save_misc_val(rule->name,is->insn->detail->arm.operands[1].imm,0,(uint32_t)is->insn->address);
3619     return 1;
3620 }
3621 
3622 int sig_match_get_canon_mode_list(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3623 {
3624     uint32_t str_adr = find_str_bytes_main_fw(fw,rule->ref_name);
3625     if(!str_adr) {
3626         printf("sig_match_get_canon_mode_list: failed to find ref %s\n",rule->ref_name);
3627         return  0;
3628     }
3629     uint32_t adr=0;
3630     // TODO should handle multiple instances of string
3631     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
3632     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,str_adr+SEARCH_NEAR_REF_RANGE)) {
3633         // printf("sig_match_get_canon_mode_list: str match 0x%"PRIx64"\n",is->insn->address);
3634         if(!find_next_sig_call(fw,is,4,"LogCameraEvent")) {
3635             // printf("sig_match_get_canon_mode_list: no LogCameraEvent\n");
3636             continue;
3637         }
3638         // some cameras have a mov and an extra call
3639         if(!disasm_iter(fw,is)) {
3640             // printf("sig_match_get_canon_mode_list: disasm failed\n");
3641             return 0;
3642         }
3643         const insn_match_t match_mov_r0_1[]={
3644 #if CS_API_MAJOR < 4
3645             {MATCH_INS(MOVS, 2), {MATCH_OP_REG(R0),  MATCH_OP_IMM(1)}},
3646 #endif
3647             {MATCH_INS(MOV, 2), {MATCH_OP_REG(R0),  MATCH_OP_IMM(1)}},
3648             {ARM_INS_ENDING}
3649         };
3650         if(insn_match_any(is->insn,match_mov_r0_1)) {
3651             if(!insn_match_find_nth(fw,is,2,2,match_bl_blximm)) {
3652                 // printf("sig_match_get_canon_mode_list: no match bl 1x\n");
3653                 continue;
3654             }
3655         } else {
3656             if(!insn_match_any(is->insn,match_bl_blximm)) {
3657                 // printf("sig_match_get_canon_mode_list: no match bl 1\n");
3658                 continue;
3659             }
3660         }
3661         // found something to follow, break
3662         adr=get_branch_call_insn_target(fw,is);
3663         break;
3664     }
3665     if(!adr) {
3666         return 0;
3667     }
3668     // printf("sig_match_get_canon_mode_list: sub 1 0x%08x\n",adr);
3669     disasm_iter_init(fw,is,adr);
3670     if(!find_next_sig_call(fw,is,40,"TakeSemaphoreStrictly")) {
3671         // printf("sig_match_get_canon_mode_list: no TakeSemaphoreStrictly\n");
3672         return 0;
3673     }
3674     // match second call
3675     if(!insn_match_find_nth(fw,is,12,2,match_b_bl_blximm)) {
3676         // printf("sig_match_get_canon_mode_list: no match bl 2\n");
3677         return 0;
3678     }
3679     // follow
3680     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3681     const insn_match_t match_loop[]={
3682         {MATCH_INS(ADD, 3), {MATCH_OP_REG_ANY,  MATCH_OP_REG_ANY,   MATCH_OP_IMM(1)}},
3683         {MATCH_INS(UXTH, 2), {MATCH_OP_REG_ANY,  MATCH_OP_REG_ANY}},
3684         {MATCH_INS(CMP, 2), {MATCH_OP_REG_ANY,  MATCH_OP_IMM_ANY}},
3685         {MATCH_INS_CC(B,LO,MATCH_OPCOUNT_IGNORE)},
3686         {ARM_INS_ENDING}
3687     };
3688     if(!insn_match_find_next_seq(fw,is,64,match_loop)) {
3689         // printf("sig_match_get_canon_mode_list: match 1 failed\n");
3690         return 0;
3691     }
3692     if(!insn_match_find_next(fw,is,2,match_bl_blximm)) {
3693         // printf("sig_match_get_canon_mode_list: no match bl 3\n");
3694         return 0;
3695     }
3696     // should be func
3697     adr=get_branch_call_insn_target(fw,is);
3698     // sanity check
3699     disasm_iter_init(fw,is,adr);
3700     const insn_match_t match_ldr_r0_ret[]={
3701         {MATCH_INS(LDR, 2),   {MATCH_OP_REG(R0),  MATCH_OP_MEM_BASE(PC)}},
3702         {MATCH_INS(BX, 1),   {MATCH_OP_REG(LR)}},
3703         {ARM_INS_ENDING}
3704     };
3705     if(!insn_match_find_next_seq(fw,is,1,match_ldr_r0_ret)) {
3706         // printf("sig_match_get_canon_mode_list: match 2 failed\n");
3707         return 0;
3708     }
3709     return save_sig_with_j(fw,rule->name,adr);
3710 } 
3711 
3712 int sig_match_zoom_busy(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3713 {
3714     if(!init_disasm_sig_ref(fw,is,rule)) {
3715         return 0;
3716     }
3717     // first call
3718     if(!insn_match_find_next(fw,is,5,match_bl_blximm)) {
3719         // printf("sig_match_zoom_busy: no match bl\n");
3720         return 0;
3721     }
3722     // follow
3723     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3724     // get base address from first LDR PC
3725     if(!insn_match_find_next(fw,is,5,match_ldr_pc)) {
3726         // printf("sig_match_zoom_busy: match LDR PC failed\n");
3727         return 0;
3728     }
3729     uint32_t base=LDR_PC2val(fw,is->insn);
3730     arm_reg rb=is->insn->detail->arm.operands[0].reg;
3731     
3732     // look for first TakeSemaphoreStrictly
3733     if(!find_next_sig_call(fw,is,40,"TakeSemaphoreStrictly")) {
3734         // printf("sig_match_zoom_busy: no match TakeSemaphoreStrictly\n");
3735         return 0;
3736     }
3737     if(!disasm_iter(fw,is)) {
3738         // printf("sig_match_zoom_busy: disasm failed\n");
3739         return 0;
3740     }
3741     // assume next instruction is ldr
3742     if(is->insn->id != ARM_INS_LDR 
3743         || is->insn->detail->arm.operands[0].reg != ARM_REG_R0
3744         || is->insn->detail->arm.operands[1].mem.base != rb) {
3745         // printf("sig_match_zoom_busy: no match LDR\n");
3746         return 0;
3747     }
3748     save_misc_val(rule->name,base,is->insn->detail->arm.operands[1].mem.disp,(uint32_t)is->insn->address);
3749     return 1;
3750 }
3751 
3752 int sig_match_focus_busy(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3753 {
3754     if(!init_disasm_sig_ref(fw,is,rule)) {
3755         return 0;
3756     }
3757     // look for first TakeSemaphore
3758     if(!find_next_sig_call(fw,is,40,"TakeSemaphore")) {
3759         // printf("sig_match_focus_busy: no match TakeSemaphore\n");
3760         return 0;
3761     }
3762     // next call
3763     if(!insn_match_find_next(fw,is,5,match_bl_blximm)) {
3764         // printf("sig_match_focus_busy: no match bl\n");
3765         return 0;
3766     }
3767     // follow
3768     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3769     // get base address from first LDR PC
3770     if(!insn_match_find_next(fw,is,5,match_ldr_pc)) {
3771         // printf("sig_match_focus_busy: match LDR PC failed\n");
3772         return 0;
3773     }
3774     uint32_t base=LDR_PC2val(fw,is->insn);
3775     arm_reg rb=is->insn->detail->arm.operands[0].reg;
3776     
3777     // look for first TakeSemaphoreStrictly
3778     if(!find_next_sig_call(fw,is,50,"TakeSemaphoreStrictly")) {
3779         // printf("sig_match_focus_busy: no match TakeSemaphoreStrictly\n");
3780         return 0;
3781     }
3782     const insn_match_t match_ldr[]={
3783         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0), MATCH_OP_MEM_ANY}},
3784         {MATCH_INS(CBZ, 2), {MATCH_OP_REG(R0), MATCH_OP_IMM_ANY}},
3785         {ARM_INS_ENDING}
3786     };
3787     if(!insn_match_find_next_seq(fw,is,10,match_ldr)) {
3788         // printf("sig_match_focus_busy: no match LDR\n");
3789         return 0;
3790     }
3791     // rewind to LDR
3792     disasm_iter_init(fw,is,adr_hist_get(&is->ah,1));
3793     disasm_iter(fw,is);
3794     // check LDR 
3795     if(is->insn->detail->arm.operands[1].mem.base != rb) {
3796         // printf("sig_match_focus_busy: no match LDR base\n");
3797         return 0;
3798     }
3799     save_misc_val(rule->name,base,is->insn->detail->arm.operands[1].mem.disp,(uint32_t)is->insn->address);
3800     return 1;
3801 }
3802 int sig_match_aram_size(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3803 {
3804     if(!init_disasm_sig_ref(fw,is,rule)) {
3805         printf("sig_match_aram_size: missing ref\n");
3806         return 0;
3807     }
3808     const insn_match_t match_ldr_r0_sp_cmp[]={
3809         {MATCH_INS(LDR, 2), {MATCH_OP_REG(R0),MATCH_OP_MEM(SP,INVALID,0xc)}},
3810         {MATCH_INS(CMP, 2), {MATCH_OP_REG(R0),MATCH_OP_IMM_ANY}},
3811         {ARM_INS_ENDING}
3812     };
3813     if(!insn_match_find_next_seq(fw,is,15,match_ldr_r0_sp_cmp)) {
3814         printf("sig_match_aram_size: no match LDR\n");
3815         return 0;
3816     }
3817     uint32_t val=is->insn->detail->arm.operands[1].imm;
3818     if(val != 0x22000 && val != 0x32000) {
3819         printf("sig_match_aram_size: unexpected ARAM size 0x%08x\n",val);
3820     }
3821     save_misc_val(rule->name,val,0,(uint32_t)is->insn->address);
3822     return 1;
3823 }
3824 
3825 int sig_match_aram_size_gt58(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3826 {
3827     if(!init_disasm_sig_ref(fw,is,rule)) {
3828         printf("sig_match_aram_size: missing ref\n");
3829         return 0;
3830     }
3831     const insn_match_t match_ldrd_r0r1_mov[]={
3832         {MATCH_INS(LDRD, 3), {MATCH_OP_REG(R0),MATCH_OP_REG(R1),MATCH_OP_MEM(SP,INVALID,0x10)}},
3833         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R2),MATCH_OP_IMM_ANY}},
3834         {ARM_INS_ENDING}
3835     };
3836     // d7? variant
3837     const insn_match_t match_ldrd_r2r1_mov[]={
3838         {MATCH_INS(LDRD, 3), {MATCH_OP_REG(R2),MATCH_OP_REG(R1),MATCH_OP_MEM(SP,INVALID,0x10)}},
3839         {MATCH_INS(MOV, 2), {MATCH_OP_REG(R3),MATCH_OP_IMM_ANY}},
3840         {ARM_INS_ENDING}
3841     };
3842     if(!insn_match_find_next_seq(fw,is,15,match_ldrd_r0r1_mov)) {
3843         init_disasm_sig_ref(fw,is,rule); // reset to start
3844         if(!insn_match_find_next_seq(fw,is,15,match_ldrd_r2r1_mov)) {
3845             printf("sig_match_aram_size: no match LDR\n");
3846         }
3847         return 0;
3848     }
3849     uint32_t val=is->insn->detail->arm.operands[1].imm;
3850     if(val != 0x22000 && val != 0x32000) {
3851         printf("sig_match_aram_size: unexpected ARAM size 0x%08x\n",val);
3852     }
3853     save_misc_val(rule->name,val,0,(uint32_t)is->insn->address);
3854     return 1;
3855 }
3856 
3857 int sig_match_aram_start(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3858 {
3859     if(!init_disasm_sig_ref(fw,is,rule)) {
3860         printf("sig_match_aram_start: missing ref\n");
3861         return 0;
3862     }
3863     if(!find_next_sig_call(fw,is,50,"DebugAssert")) {
3864         printf("sig_aram_start: no match DebugAssert\n");
3865         return 0;
3866     }
3867     const insn_match_t match_cmp_bne_ldr[]={
3868         {MATCH_INS(CMP, 2), {MATCH_OP_REG(R1),MATCH_OP_IMM(0)}},
3869         {MATCH_INS_CC(B,NE,MATCH_OPCOUNT_IGNORE)},
3870         {MATCH_INS(LDR, 2), {MATCH_OP_REG_ANY,MATCH_OP_MEM_BASE(PC)}},
3871         {ARM_INS_ENDING}
3872     };
3873     if(!insn_match_find_next_seq(fw,is,15,match_cmp_bne_ldr)) {
3874         printf("sig_match_aram_start: no match CMP\n");
3875         return 0;
3876     }
3877     uint32_t adr=LDR_PC2val(fw,is->insn);
3878     if(!adr) {
3879         printf("sig_match_aram_start: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
3880         return 0;
3881     }
3882     // could sanity check that it looks like a RAM address
3883     save_misc_val(rule->name,adr,0,(uint32_t)is->insn->address);
3884     return 1;
3885 }
3886 
3887 int sig_match_aram_start2(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3888 {
3889     if (get_misc_val_value("ARAM_HEAP_START"))
3890         return 0;
3891 
3892     if(!init_disasm_sig_ref(fw,is,rule)) {
3893         printf("sig_match_aram_start: missing ref\n");
3894         return 0;
3895     }
3896     if(!find_next_sig_call(fw,is,60,"DebugAssert")) {
3897         printf("sig_aram_start2: no match DebugAssert\n");
3898         return 0;
3899     }
3900     const insn_match_t match_cmp_bne_ldr[]={
3901         {MATCH_INS(CMP, 2), {MATCH_OP_REG(R1),MATCH_OP_IMM(0)}},
3902         {MATCH_INS_CC(B,NE,MATCH_OPCOUNT_IGNORE)},
3903         {MATCH_INS(LDR, 2), {MATCH_OP_REG_ANY,MATCH_OP_MEM_BASE(SP)}},
3904         {MATCH_INS(LDR, 2), {MATCH_OP_REG_ANY,MATCH_OP_MEM_BASE(PC)}},
3905         {ARM_INS_ENDING}
3906     };
3907     if(!insn_match_find_next_seq(fw,is,15,match_cmp_bne_ldr)) {
3908         printf("sig_match_aram_start2: no match CMP\n");
3909         return 0;
3910     }
3911     uint32_t adr=LDR_PC2val(fw,is->insn);
3912     if(!adr) {
3913         printf("sig_match_aram_start2: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
3914         return 0;
3915     }
3916     // could sanity check that it looks like a RAM address
3917     save_misc_val(rule->name,adr,0,(uint32_t)is->insn->address);
3918     return 1;
3919 }
3920 
3921 int sig_match__nrflag(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3922 {
3923     if(!init_disasm_sig_ref(fw,is,rule)) {
3924         return 0;
3925     }
3926     uint32_t fadr=is->adr;
3927     // find range check on input arg
3928     const insn_match_t match_cmp_b[]={
3929         {MATCH_INS(CMP, 2), {MATCH_OP_REG(R0),MATCH_OP_IMM_ANY}},
3930         {MATCH_INS(B,MATCH_OPCOUNT_IGNORE)}, // blo or blt may be used, so don't include cond
3931         {ARM_INS_ENDING}
3932     };
3933     if(!insn_match_find_next_seq(fw,is,4,match_cmp_b) || is->insn->detail->arm.cc == ARM_CC_AL) {
3934         printf("sig_match__nrflag: no match CMP\n");
3935         return 0;
3936     }
3937     // follow
3938     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
3939     if(!disasm_iter(fw,is)) {
3940         printf("sig_match__nrflag: disasm failed\n");
3941         return 0;
3942     }
3943     // assume next is base addres
3944     uint32_t adr=LDR_PC2val(fw,is->insn);
3945     if(!adr) {
3946         printf("sig_match__nrflag: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
3947         return 0;
3948     }
3949     arm_reg reg_base = is->insn->detail->arm.operands[0].reg; // reg value was loaded into
3950     if(!disasm_iter(fw,is)) {
3951         printf("sig_match__nrflag: disasm failed\n");
3952         return 0;
3953     }
3954     // firmware may use add/sub to get actual firmware base address
3955     if(isADDx_imm(is->insn) || isSUBx_imm(is->insn)) {
3956         if(is->insn->detail->arm.operands[0].reg != reg_base) {
3957             printf("sig_match__nrflag: no match ADD/SUB\n");
3958             return 0;
3959         }
3960         if(isADDx_imm(is->insn)) {
3961             adr+=is->insn->detail->arm.operands[1].imm;
3962         } else {
3963             adr-=is->insn->detail->arm.operands[1].imm;
3964         }
3965         if(!disasm_iter(fw,is)) {
3966             printf("sig_match__nrflag: disasm failed\n");
3967             return 0;
3968         }
3969     }
3970     if(is->insn->id != ARM_INS_STR || is->insn->detail->arm.operands[1].reg != reg_base) {
3971         printf("sig_match__nrflag: no match STR\n");
3972         return 0;
3973     }
3974     uint32_t disp = is->insn->detail->arm.operands[1].mem.disp;
3975     save_misc_val(rule->name,adr,disp,fadr);
3976     return 1;
3977 }
3978 // get the address used by a function that does something like
3979 // ldr rx =base
3980 // ldr r0 [rx, offset]
3981 // bx lr
3982 int sig_match_var_struct_get(firmware *fw, iter_state_t *is, sig_rule_t *rule)
3983 {
3984     if(!init_disasm_sig_ref(fw,is,rule)) {
3985         return 0;
3986     }
3987     uint32_t fadr=is->adr;
3988     var_ldr_desc_t desc;
3989     if(!find_and_get_var_ldr(fw, is, 1, 4, ARM_REG_R0, &desc)) {
3990         printf("sig_match_var_struct_get: no match ldr\n");
3991         return 0;
3992     }
3993     if(!disasm_iter(fw,is)) {
3994         printf("sig_match_var_struct_get: disasm failed\n");
3995         return 0;
3996     }
3997     // TODO could check for other RET type instructions
3998     if(!insn_match(is->insn,match_bxlr)) {
3999         printf("sig_match_var_struct_get: no match BX LR\n");
4000         return 0;
4001     }
4002     save_misc_val(rule->name,desc.adr_adj,desc.off,fadr);
4003     return 1;
4004 }
4005 
4006 int sig_match_av_over_sem(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4007 {
4008     // don't bother on ND-only cams
4009     if(!get_misc_val_value("CAM_HAS_IRIS_DIAPHRAGM")) {
4010         return 0;
4011     }
4012 
4013     if(!init_disasm_sig_ref(fw,is,rule)) {
4014         return 0;
4015     }
4016     if(!find_next_sig_call(fw,is,30,"TakeSemaphore")) {
4017         printf("sig_match_av_over_sem: no match TakeSemaphore at 0x%"PRIx64"\n",is->insn->address);
4018         return 0;
4019     }
4020 
4021     // rewind 5 ins
4022     disasm_iter_init(fw,is,adr_hist_get(&is->ah,5));
4023     var_ldr_desc_t desc;
4024     if(!find_and_get_var_ldr(fw, is, 3, 4, ARM_REG_R0, &desc)) {
4025         printf("sig_match_av_over_sem: no match ldr at 0x%"PRIx64"\n",is->insn->address);
4026         return 0;
4027     }
4028 
4029     save_misc_val(rule->name,desc.adr_adj,desc.off,(uint32_t)is->insn->address);
4030     return 1;
4031 }
4032 
4033 int sig_match_canon_menu_active(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4034 {
4035     if(!init_disasm_sig_ref(fw,is,rule)) {
4036         return 0;
4037     }
4038     var_ldr_desc_t desc;
4039     if(!find_and_get_var_ldr(fw, is, 2, 4, ARM_REG_R0, &desc)) {
4040         printf("sig_match_canon_menu_active: no match ldr at 0x%"PRIx64"\n",is->insn->address);
4041         return 0;
4042     }
4043     if(!disasm_iter(fw,is)) {
4044         printf("sig_match_canon_menu_active: disasm failed\n");
4045         return 0;
4046     }
4047     if(is->insn->id != ARM_INS_CMP) {
4048         printf("sig_match_canon_menu_active: no match cmp at 0x%"PRIx64"\n",is->insn->address);
4049         return 0;
4050     }
4051     save_misc_val(rule->name,desc.adr_adj,desc.off,(uint32_t)is->insn->address);
4052     return 1;
4053 }
4054 
4055 int sig_match_file_counter_init(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4056 {
4057     if(!init_disasm_sig_ref(fw,is,rule)) {
4058         return 0;
4059     }
4060     // find first call
4061     if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
4062         // printf("sig_match_file_counter_init: bl match 1 failed at 0x%"PRIx64"\n",is->insn->address);
4063         return 0;
4064     }
4065     // some cameras (dry 58+?) have a nullsub before the function of interest
4066     if(check_simple_func(fw,get_branch_call_insn_target(fw,is),MATCH_SIMPLE_FUNC_NULLSUB,NULL)) {
4067         if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
4068             // printf("sig_match_file_counter_init: bl match 1a failed at 0x%"PRIx64"\n",is->insn->address);
4069             return 0;
4070         }
4071     }
4072     // follow
4073     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
4074     if(!insn_match_find_next(fw,is,3,match_bl_blximm)) {
4075         // printf("sig_match_file_counter_init: bl match 2 failed at 0x%"PRIx64"\n",is->insn->address);
4076         return 0;
4077     }
4078     uint32_t fadr = get_branch_call_insn_target(fw,is);
4079     // follow
4080     disasm_iter_init(fw,is,fadr);
4081     if(!disasm_iter(fw,is)) {
4082         // printf("sig_match_file_counter_init: disasm failed\n");
4083         return 0;
4084     }
4085     // sanity check
4086     if(!isLDR_PC(is->insn)) {
4087         // printf("sig_match_file_counter_init: no match LDR PC at 0x%"PRIx64"\n",is->insn->address);
4088         return 0;
4089     }
4090     // function we're looking for
4091     return save_sig_with_j(fw,rule->name,fadr);
4092 }
4093 int sig_match_file_counter_var(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4094 {
4095     if(!init_disasm_sig_ref(fw,is,rule)) {
4096         return 0;
4097     }
4098     uint32_t adr=LDR_PC2val(fw,is->insn);
4099     if(!adr) {
4100         // printf("sig_match_file_counter_var: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
4101         return 0;
4102     }
4103     if(is->insn->detail->arm.operands[0].reg != ARM_REG_R0) {
4104         // printf("sig_match_file_counter_var: not R0 0x%"PRIx64"\n",is->insn->address);
4105         return 0;
4106     }
4107     if(!adr_is_var(fw,adr)) {
4108         // printf("sig_match_file_counter_var: not a data address 0x%08x at 0x%"PRIx64"\n",adr,is->insn->address);
4109         return 0;
4110     }
4111     save_misc_val(rule->name,adr,0,(uint32_t)is->insn->address);
4112     return 1;
4113 }
4114 
4115 int sig_match_palette_vars(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4116 {
4117     if(!init_disasm_sig_ref(fw,is,rule)) {
4118         return 0;
4119     }
4120     if(!find_next_sig_call(fw,is,70,"transfer_src_overlay")) {
4121         printf("sig_match_palette_vars: no match transfer_src_overlay\n");
4122         return 0;
4123     }
4124     uint32_t fadr=0;
4125     int i;
4126     // search backwards for call before transfer_src_overlay
4127     for(i=1; i<=6; i++) {
4128         if(!fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i))) {
4129             printf("sig_match_palette_vars: disasm failed\n");
4130             return 0;
4131         }
4132         fadr=get_branch_call_insn_target(fw,fw->is);
4133         if(fadr) {
4134             break;
4135         }
4136    }
4137    if(!fadr) {
4138         printf("sig_match_palette_vars: no match bl 1 0x%"PRIx64"\n",fw->is->insn->address);
4139         return 0;
4140    }
4141     // follow
4142     disasm_iter_init(fw,is,fadr);
4143     // find first func call
4144     if(!insn_match_find_next(fw,is,3,match_bl)) {
4145         printf("sig_match_palette_vars: no match bl 2 0x%"PRIx64"\n",is->insn->address);
4146         return 0;
4147     }
4148     // follow
4149     disasm_iter_init(fw,is,get_branch_call_insn_target(fw,is));
4150 
4151     if(!insn_match_find_next(fw,is,3,match_ldr_pc)) {
4152         printf("sig_match_palette_vars: no match ldr pc 0x%"PRIx64"\n",is->insn->address);
4153         return 0;
4154     }
4155 
4156     uint32_t pal_base=LDR_PC2val(fw,is->insn);
4157     if(!pal_base || !adr_is_var(fw,pal_base)) {
4158         printf("sig_match_palette_vars: bad LDR PC 0x%"PRIx64"\n",is->insn->address);
4159         return 0;
4160     }
4161     // palette_control is at the start of struct, save register
4162     arm_reg ptr_reg = is->insn->detail->arm.operands[0].reg;
4163 
4164     save_misc_val(rule->name,pal_base,0,(uint32_t)is->insn->address);
4165 
4166     int found=0;
4167     // find LDR Rn  [ptr_reg +x]
4168     for(i=0; i<3; i++) {
4169         if(!disasm_iter(fw,is)) {
4170             printf("sig_match_palette_vars: disasm failed\n");
4171             return 0;
4172         }
4173         if (is->insn->id == ARM_INS_LDR && is->insn->detail->arm.operands[1].mem.base == ptr_reg) {
4174             save_misc_val("active_palette_buffer",
4175                         pal_base,
4176                         is->insn->detail->arm.operands[1].mem.disp,
4177                         (uint32_t)is->insn->address);
4178             found=1;
4179             break;
4180         }
4181     }
4182     if(!found) {
4183         printf("sig_match_palette_vars: no match active_palette_buffer 0x%"PRIx64"\n",is->insn->address);
4184         return 0;
4185     }
4186 
4187     if(!find_next_sig_call(fw,is,20,"PTM_RestoreUIProperty_FW")) {
4188         printf("sig_match_palette_vars: no match PTM_RestoreUIProperty_FW\n");
4189         return 0;
4190     }
4191     // find LDR Rn  [ptr_reg +x]
4192     for(i=0; i<6; i++) {
4193         if(!disasm_iter(fw,is)) {
4194             printf("sig_match_palette_vars: disasm failed\n");
4195             return 0;
4196         }
4197         if (is->insn->id == ARM_INS_LDR && is->insn->detail->arm.operands[1].mem.base == ptr_reg) {
4198             save_misc_val("palette_buffer_ptr",
4199                         pal_base,
4200                         is->insn->detail->arm.operands[1].mem.disp,
4201                         (uint32_t)is->insn->address);
4202             return 1;
4203         }
4204     }
4205     printf("sig_match_palette_vars: no match palette_buffer_ptr 0x%"PRIx64"\n",is->insn->address);
4206     return 0;
4207 }
4208 
4209 int sig_match_rom_ptr_get(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4210 {
4211     if(!init_disasm_sig_ref(fw,is,rule)) {
4212         return 0;
4213     }
4214     uint32_t fadr=is->adr;
4215     if(!disasm_iter(fw,is)) {
4216         printf("sig_match_rom_ptr_get: disasm failed\n");
4217         return 0;
4218     }
4219     uint32_t adr=LDR_PC2val(fw,is->insn);
4220     if(!adr) {
4221         printf("sig_match_rom_ptr_get: no match LDR PC 0x%"PRIx64"\n",is->insn->address);
4222         return  0;
4223     }
4224     if(is->insn->detail->arm.operands[0].reg != ARM_REG_R0) {
4225         printf("sig_match_rom_ptr_get: not R0\n");
4226         return 0;
4227     }
4228     if(!disasm_iter(fw,is)) {
4229         printf("sig_match_rom_ptr_get: disasm failed\n");
4230         return 0;
4231     }
4232     // TODO could check for other RET type instructions
4233     if(!insn_match(is->insn,match_bxlr)) {
4234         printf("sig_match_rom_ptr_get: no match BX LR\n");
4235         return 0;
4236     }
4237     save_misc_val(rule->name,adr,0,fadr);
4238     return 1;
4239 }
4240 
4241 // find Nth function call within max_insns ins of string ref, 
4242 // returns address w/thumb bit set according to current state of call instruction
4243 // modifies is and potentially fw->is
4244 uint32_t find_call_near_str(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4245 {
4246     uint32_t str_adr;
4247     if(rule->param & SIG_NEAR_INDIRECT) {
4248         str_adr = find_str_bytes(fw,rule->ref_name); // indirect string could be in data area
4249     } else {
4250         str_adr = find_str_bytes_main_fw(fw,rule->ref_name); // direct string must be near actual code
4251     }
4252     if(!str_adr) {
4253         printf("find_call_near_str: %s failed to find ref %s\n",rule->name,rule->ref_name);
4254         return 0;
4255     }
4256     uint32_t search_adr = str_adr;
4257     // looking for ref to ptr to string, not ref to string
4258     // TODO only looks for first ptr
4259     if(rule->param & SIG_NEAR_INDIRECT) {
4260         // printf("find_call_near_str: %s str 0x%08x\n",rule->name,str_adr);
4261         search_adr=find_u32_adr_range(fw,str_adr,fw->rom_code_search_min_adr,fw->rom_code_search_max_adr);
4262         if(!search_adr) {
4263             printf("find_call_near_str: %s failed to find indirect ref %s\n",rule->name,rule->ref_name);
4264             return 0;
4265         }
4266         // printf("find_call_near_str: %s indirect 0x%08x\n",rule->name,search_adr);
4267     }
4268     const insn_match_t *insn_match;
4269     if(rule->param & SIG_NEAR_JMP_SUB) {
4270         insn_match = match_b_bl_blximm;
4271     } else {
4272         insn_match = match_bl_blximm;
4273     }
4274 
4275     int max_insns=rule->param&SIG_NEAR_OFFSET_MASK;
4276     int n=(rule->param&SIG_NEAR_COUNT_MASK)>>SIG_NEAR_COUNT_SHIFT;
4277     //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");
4278     // TODO should handle multiple instances of string
4279     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
4280     while(fw_search_insn(fw,is,search_disasm_const_ref,str_adr,NULL,search_adr+SEARCH_NEAR_REF_RANGE)) {
4281         // bactrack looking for preceding call
4282         if(rule->param & SIG_NEAR_REV) {
4283             int i;
4284             int n_calls=0;
4285             for(i=1; i<=max_insns; i++) {
4286                 fw_disasm_iter_single(fw,adr_hist_get(&is->ah,i));
4287                 if(insn_match_any(fw->is->insn,insn_match)) {
4288                     n_calls++;
4289                 }
4290                 if(n_calls == n) {
4291                     return iter_state_adr(fw->is);
4292                 }
4293             }
4294         } else {
4295             if(insn_match_find_nth(fw,is,max_insns,n,insn_match)) {
4296                 return iter_state_adr(is);
4297             }
4298         }
4299     }
4300     printf("find_call_near_str: no match %s\n",rule->name);
4301     return 0;
4302 }
4303                                 
4304 // find Nth function call within max_insns ins of string ref
4305 int sig_match_near_str(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4306 {
4307     if (!get_saved_sig_val(rule->name))
4308     {
4309         uint32_t call_adr = find_call_near_str(fw,is,rule);
4310         if(call_adr) {
4311             return save_sig_match_call(fw, rule, call_adr);
4312         }
4313     }
4314     return 0;
4315 }
4316 
4317 
4318 int sig_match_prop_string(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4319 {
4320     uint32_t call_adr = find_call_near_str(fw, is, rule);
4321 
4322     if (call_adr == 0)
4323         return 0;
4324 
4325     // initialize to found address
4326     disasm_iter_init(fw,is,call_adr);
4327     disasm_iter(fw,is);
4328 
4329     uint32_t myreg;
4330 
4331     if (is_sig_call(fw,is,"GetPropertyCase")) {
4332         // looking for r0
4333         myreg = 0;
4334     }
4335     else {
4336         // semaphore version of GetPropertyCase, looking for r1
4337         myreg = 1;
4338     }
4339     
4340     // re-init 'is' to current address minus at least 8 insts
4341     const int hl = 8;
4342     disasm_iter_init(fw,is,call_adr - hl*4);
4343     // history needs to be made
4344     while (is->adr < call_adr) {
4345         if (!disasm_iter(fw,is))
4346             disasm_iter_init(fw,is,(is->adr | is->thumb)+2);
4347     }
4348     uint32_t regs[4];
4349     // get r0 or r1, backtracking up to 8 instructions
4350     if ((get_call_const_args(fw,is,hl,regs)&(1<<myreg))==(1<<myreg)) {
4351         add_prop_hit(rule->name,(int)regs[myreg]);
4352         return 1;
4353     }
4354     return 0;
4355 }
4356 
4357 // check if func is a nullsub or mov r0, x ; ret
4358 // to prevent sig_named* matches from going off the end of dummy funcs
4359 int is_immediate_ret_sub(firmware *fw,iter_state_t *is_init)
4360 {
4361     fw_disasm_iter_single(fw,is_init->adr | is_init->thumb);
4362     const insn_match_t match_mov_r0_imm[]={
4363         {MATCH_INS(MOV,   2),  {MATCH_OP_REG(R0),  MATCH_OP_IMM_ANY}},
4364 #if CS_API_MAJOR < 4
4365         {MATCH_INS(MOVS,  2),  {MATCH_OP_REG(R0),  MATCH_OP_IMM_ANY}},
4366 #endif
4367         {ARM_INS_ENDING}
4368     };
4369     // if it's a MOV, check if next is ret
4370     if(insn_match_any(fw->is->insn,match_mov_r0_imm)) {
4371         fw_disasm_iter(fw);
4372     }
4373     if(isRETx(fw->is->insn)) {
4374         return 1;
4375     }
4376     return 0;
4377 }
4378 
4379 // match last function called by already matched sig, 
4380 // either the last bl/blximmg before pop {... pc}
4381 // or b after pop {... lr}
4382 // param defines min and max number of insns
4383 // doesn't work on functions that don't push/pop since can't tell if unconditional branch is last
4384 // TODO should probably be split into a general "find last call of current func"
4385 #define SIG_NAMED_LAST_MAX_MASK     0x00000FFF
4386 #define SIG_NAMED_LAST_MIN_MASK     0x00FFF000
4387 #define SIG_NAMED_LAST_MIN_SHIFT    12
4388 #define SIG_NAMED_LAST_RANGE(min,max)   ((SIG_NAMED_LAST_MIN_MASK&((min)<<SIG_NAMED_LAST_MIN_SHIFT)) \
4389                                          | (SIG_NAMED_LAST_MAX_MASK&(max)))
4390 
4391 int sig_match_named_last(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4392 {
4393     uint32_t ref_adr = get_saved_sig_val(rule->ref_name);
4394     int min = (rule->param&SIG_NAMED_LAST_MIN_MASK)>>SIG_NAMED_LAST_MIN_SHIFT;
4395     int max = (rule->param&SIG_NAMED_LAST_MAX_MASK);
4396     if(!ref_adr) {
4397         printf("sig_match_named_last: %s missing %s\n",rule->name,rule->ref_name);
4398         return 0;
4399     }
4400     disasm_iter_init(fw,is,ref_adr);
4401     if(is_immediate_ret_sub(fw,is)) {
4402         printf("sig_match_named_last: immediate return %s\n",rule->name);
4403         return 0;
4404     }
4405     uint32_t fadr = find_last_call_from_func(fw,is,min,max);
4406     if(fadr) {
4407         return save_sig_with_j(fw,rule->name,fadr);
4408     }
4409     return 0;
4410 }
4411 
4412 // default - use the named firmware function
4413 #define SIG_NAMED_ASIS          0x00000000
4414 // use the target of the first B, BX, BL, BLX etc
4415 #define SIG_NAMED_JMP_SUB       0x00000001
4416 // use the target of the first BL, BLX
4417 #define SIG_NAMED_SUB           0x00000002
4418 // match address of Nth instruction in named sub
4419 #define SIG_NAMED_INSN          0x00000003
4420 #define SIG_NAMED_TYPE_MASK     0x0000000F
4421 
4422 #define SIG_NAMED_CLEARTHUMB    0x00000010
4423 #define SIG_NAMED_FLAG_MASK     0x000000F0
4424 
4425 #define SIG_NAMED_NTH_MASK      0x00000F00
4426 #define SIG_NAMED_NTH_SHIFT     8
4427 
4428 // number of instructions to search for each Nth
4429 // default 5
4430 #define SIG_NAMED_NTH_RANGE_MASK  0x0003F000
4431 #define SIG_NAMED_NTH_RANGE_SHIFT 12
4432 
4433 //#define SIG_NAMED_NTH(n,type)   ((SIG_NAMED_NTH_MASK&((n)<<SIG_NAMED_NTH_SHIFT)) | ((SIG_NAMED_##type)&SIG_NAME_TYPE_MASK))
4434 #define SIG_NAMED_NTH(n,type)   ((SIG_NAMED_NTH_MASK&((n)<<SIG_NAMED_NTH_SHIFT)) | (SIG_NAMED_##type))
4435 
4436 #define SIG_NAMED_NTH_RANGE(n)   ((SIG_NAMED_NTH_RANGE_MASK&((n)<<SIG_NAMED_NTH_RANGE_SHIFT)))
4437 
4438 void sig_match_named_save_sig(firmware *fw,const char *name, uint32_t adr, uint32_t flags)
4439 {
4440     if(flags & SIG_NAMED_CLEARTHUMB) {
4441         adr = ADR_CLEAR_THUMB(adr);
4442     }
4443     save_sig(fw,name,adr);
4444 }
4445 // match already identified function found by name
4446 // if offset is 1, match the first called function with 20 insn instead (e.g. to avoid eventproc arg handling)
4447 // initial direct jumps (j_foo) assumed to have been handled
4448 int sig_match_named(firmware *fw, iter_state_t *is, sig_rule_t *rule)
4449 {
4450     uint32_t ref_adr = get_saved_sig_val(rule->ref_name);
4451     if(!ref_adr) {
4452         printf("sig_match_named: missing %s\n",rule->ref_name);
4453         return 0;
4454     }
4455     uint32_t sig_type = rule->param & SIG_NAMED_TYPE_MASK;
4456     uint32_t sig_flags = rule->param & SIG_NAMED_FLAG_MASK;
4457     uint32_t sig_nth = (rule->param & SIG_NAMED_NTH_MASK)>>SIG_NAMED_NTH_SHIFT;
4458     uint32_t sig_nth_range = (rule->param & SIG_NAMED_NTH_RANGE_MASK)>>SIG_NAMED_NTH_RANGE_SHIFT;
4459     if(!sig_nth) {
4460         sig_nth=1;
4461     }
4462     if(!sig_nth_range) {
4463         sig_nth_range=5;
4464     }
4465     // no offset, just save match as is
4466     // TODO might want to validate anyway
4467     if(sig_type == SIG_NAMED_ASIS) {
4468         sig_match_named_save_sig(fw,rule->name,ref_adr,sig_flags); 
4469         return 1;
4470     }
4471     const insn_match_t *insn_match;
4472     if(sig_type == SIG_NAMED_JMP_SUB) {
4473         insn_match = match_b_bl_blximm;
4474     } else if(sig_type == SIG_NAMED_SUB) {
4475         insn_match = match_bl_blximm;
4476     } else if(sig_type == SIG_NAMED_INSN) {
4477         insn_match = NULL;
4478     } else {
4479         printf("sig_match_named: %s invalid type %d\n",rule->ref_name,sig_type);
4480         return 0;
4481     }
4482 
4483     disasm_iter_init(fw,is,ref_adr);
4484     // TODO for eventprocs, may just want to use the original
4485     if(is_immediate_ret_sub(fw,is)) {
4486         printf("sig_match_named: immediate return %s\n",rule->name);
4487         return 0;
4488     }
4489     if(sig_type == SIG_NAMED_INSN) {
4490         int i;
4491         // iter starts on the address given to init
4492         for(i=0;i<=sig_nth;i++) {
4493             if(!disasm_iter(fw,is)) {
4494                 printf("sig_match_named: disasm failed %s 0x%08x\n",rule->name,(uint32_t)is->insn->address);
4495                 return 0;
4496             }
4497         }
4498         sig_match_named_save_sig(fw,rule->name,iter_state_adr(is),sig_flags);
4499         return 1;
4500     }
4501 
4502     // initial 15 is hard coded
4503     if(insn_match_find_nth(fw,is,15 + sig_nth_range*sig_nth,sig_nth,insn_match)) {
4504         uint32_t adr = B_BL_BLXimm_target(fw,is->insn);
4505         if(adr) {
4506             // BLX, set thumb bit 
4507             if(is->insn->id == ARM_INS_BLX) {
4508                 // curently not thumb, set in target
4509                 if(!is->thumb) {
4510                     adr=ADR_SET_THUMB(adr);
4511                 }
4512             } else {
4513                 // preserve current state
4514                 adr |= is->thumb;
4515             }
4516             disasm_iter_set(fw,is,adr);
4517             if(disasm_iter(fw,is)) {
4518                 // TODO only checks one level
4519                 uint32_t j_adr=get_direct_jump_target(fw,is);
4520                 if(j_adr) {
4521                     char *buf=malloc(strlen(rule->name)+3);
4522                     // add j_ for cross referencing
4523                     sprintf(buf,"j_%s",rule->name);
4524                     add_func_name(fw,buf,adr,NULL); // add the previous address as j_...
4525                     adr=j_adr;
4526                 }
4527             } else {
4528                 printf("sig_match_named: disasm failed in j_ check at %s 0x%08x\n",rule->name,adr);
4529             }
4530             sig_match_named_save_sig(fw,rule->name,adr,sig_flags); 
4531             return 1;
4532         } else {
4533             printf("sig_match_named: %s invalid branch target 0x%08x\n",rule->ref_name,adr);
4534         }
4535     } else {
4536         printf("sig_match_named: %s branch not found 0x%08x\n",rule->ref_name,ref_adr);
4537     }
4538     return 0;
4539 }
4540 
4541 #define SIG_DRY_MIN(min_rel) (min_rel),0
4542 #define SIG_DRY_MAX(max_rel) 0,(max_rel)
4543 #define SIG_DRY_RANGE(min_rel,max_rel) (min_rel),(max_rel)
4544 // bootstrap sigs:
4545 // Used to find the minimum needed to for find_generic_funcs to get generic task and eventproc matches 
4546 // order is important
4547 sig_rule_t sig_rules_initial[]={
4548 // function         CHDK name                   ref name/string         func param          dry rel
4549 // NOTE _FW is in the CHDK column, because that's how it is in sig_names
4550 {sig_match_str_r0_call, "ExportToEventProcedure_FW","ExportToEventProcedure"},
4551 {sig_match_reg_evp,     "RegisterEventProcedure",},
4552 {sig_match_reg_evp_table, "RegisterEventProcTable","DispDev_EnableEventProc"},
4553 {sig_match_reg_evp_alt2, "RegisterEventProcedure_alt2","EngApp.Delete"},
4554 {sig_match_unreg_evp_table,"UnRegisterEventProcTable","MechaUnRegisterEventProcedure"},
4555 {sig_match_evp_table_veneer,"RegisterEventProcTable_alt","RegisterEventProcTable"},
4556 {sig_match_evp_table_veneer,"UnRegisterEventProcTable_alt","UnRegisterEventProcTable"},
4557 {sig_match_str_r0_call,"CreateTaskStrictly",    "LowConsole",},
4558 {sig_match_str_r0_call,"CreateTaskStrictly_alt","HdmiCecTask",          0,                  SIG_DRY_MIN(59)},
4559 {sig_match_str_r0_call,"CreateTask",            "EvShel",},
4560 {sig_match_str_r0_call,"CreateTask_alt",        "PhySw",                0,                  SIG_DRY_MIN(58)},
4561 {sig_match_named,   "CreateTask_low",           "CreateTask",           (SIG_NAMED_NTH(2,SUB)|SIG_NAMED_NTH_RANGE(10)), SIG_DRY_MAX(52)},
4562 {sig_match_named,   "CreateTask_low",           "CreateTask",           (SIG_NAMED_NTH(3,SUB)|SIG_NAMED_NTH_RANGE(10)), SIG_DRY_MIN(54)},
4563 {sig_match_near_str,   "dry_memcpy",            "EP Slot%d",            SIG_NEAR_BEFORE(4,1)},
4564 {sig_match_add_ptp_handler,"add_ptp_handler",   "PTPtoFAPI_EventProcTask_Try",},
4565 {NULL},
4566 };
4567 
4568 // main sigs:
4569 // Run after find_generic_funcs. Order is important
4570 sig_rule_t sig_rules_main[]={
4571 // function         CHDK name                   ref name/string         func param          dry rel
4572 {sig_match_named,   "SetParameterData",         "PTM_BackupUIProperty_FW", 0, SIG_DRY_MIN(58)},
4573 {sig_match_named,   "ExitTask",                 "ExitTask_FW",},
4574 {sig_match_named,   "EngDrvRead",               "EngDrvRead_FW",        SIG_NAMED_JMP_SUB},
4575 {sig_match_named,   "CalcLog10",                "CalcLog10_FW",         SIG_NAMED_JMP_SUB},
4576 {sig_match_named,   "CalcSqrt",                 "CalcSqrt_FW",          SIG_NAMED_JMP_SUB},
4577 {sig_match_named,   "Close",                    "Close_FW",},
4578 {sig_match_named,   "close",                    "Close",                SIG_NAMED_SUB,      SIG_DRY_MAX(57)},
4579 {sig_match_named,   "DoAELock",                 "SS.DoAELock_FW",       SIG_NAMED_JMP_SUB},
4580 {sig_match_named,   "DoAFLock",                 "SS.DoAFLock_FW",       SIG_NAMED_JMP_SUB},
4581 {sig_match_named,   "Fclose_Fut",               "Fclose_Fut_FW",},
4582 {sig_match_named,   "Fopen_Fut",                "Fopen_Fut_FW",},
4583 {sig_match_named,   "Fread_Fut",                "Fread_Fut_FW",},
4584 {sig_match_named,   "Fseek_Fut",                "Fseek_Fut_FW",},
4585 {sig_match_named,   "Fwrite_Fut",               "Fwrite_Fut_FW",},
4586 {sig_match_named,   "GetAdChValue",             "GetAdChValue_FW",},
4587 {sig_match_named,   "GetCurrentAvValue",        "GetCurrentAvValue_FW",},
4588 {sig_match_named,   "GetCurrentShutterSpeed",   "GetCurrentShutterSpeed_FW",},
4589 {sig_match_named,   "GetBatteryTemperature",    "GetBatteryTemperature_FW",},
4590 {sig_match_named,   "GetCCDTemperature",        "GetCCDTemperature_FW",},
4591 {sig_match_named,   "GetFocusLensSubjectDistance","GetFocusLensSubjectDistance_FW",SIG_NAMED_JMP_SUB},
4592 {sig_match_named,   "GetOpticalTemperature",    "GetOpticalTemperature_FW",},
4593 {sig_match_named,   "GetPropertyCase",          "GetPropertyCase_FW",   SIG_NAMED_SUB},
4594 {sig_match_named,   "GetSystemTime",            "GetSystemTime_FW",},
4595 {sig_match_named,   "GetUsableMaxAv",           "GetUsableMaxAv_FW",},
4596 {sig_match_named,   "GetUsableMinAv",           "GetUsableMinAv_FW",},
4597 // a different match would be needed for older, ND only cams maybe based on "AE Result Tv Setting "
4598 {sig_match_named,   "GetUsableAvRange",         "GetUsableMinAv", SIG_NAMED_SUB},
4599 {sig_match_named,   "GetVRAMHPixelsSize",       "GetVRAMHPixelsSize_FW",},
4600 {sig_match_named,   "GetVRAMVPixelsSize",       "GetVRAMVPixelsSize_FW",},
4601 {sig_match_named,   "GetZoomLensCurrentPoint",  "GetZoomLensCurrentPoint_FW",},
4602 {sig_match_named,   "GetZoomLensCurrentPosition","GetZoomLensCurrentPosition_FW",},
4603 {sig_match_named,   "GiveSemaphore",            "GiveSemaphore_FW",},
4604 {sig_match_named,   "IsStrobeChargeCompleted",  "EF.IsChargeFull_FW",},
4605 {sig_match_named,   "Read",                     "Read_FW",},
4606 {sig_match_named,   "LEDDrive",                 "LEDDrive_FW",},
4607 {sig_match_named,   "LockMainPower",            "LockMainPower_FW",},
4608 {sig_match_named,   "MoveFocusLensToDistance",  "MoveFocusLensToDistance_FW",},
4609 {sig_match_named,   "MoveIrisWithAv",           "MoveIrisWithAv_FW",},
4610 {sig_match_named,   "MoveZoomLensWithPoint",    "MoveZoomLensWithPoint_FW",},
4611 {sig_match_named,   "Open",                     "Open_FW",},
4612 {sig_match_named,   "PostLogicalEventForNotPowerType",  "PostLogicalEventForNotPowerType_FW",},
4613 {sig_match_named,   "PostLogicalEventToUI",     "PostLogicalEventToUI_FW",},
4614 {sig_match_named,   "PT_MFOn",                  "SS.MFOn_FW",           SIG_NAMED_JMP_SUB},
4615 {sig_match_named,   "PT_MFOff",                 "SS.MFOff_FW",          SIG_NAMED_JMP_SUB},
4616 {sig_match_named,   "PT_MoveDigitalZoomToWide", "SS.MoveDigitalZoomToWide_FW", SIG_NAMED_JMP_SUB},
4617 {sig_match_named,   "PT_MoveOpticalZoomAt",     "SS.MoveOpticalZoomAt_FW",},
4618 {sig_match_named,   "PutInNdFilter",            "PutInNdFilter_FW",},
4619 {sig_match_named,   "PutOutNdFilter",           "PutOutNdFilter_FW",},
4620 {sig_match_named,   "SetAE_ShutterSpeed",       "SetAE_ShutterSpeed_FW",},
4621 {sig_match_named,   "SetAutoShutdownTime",      "SetAutoShutdownTime_FW",},
4622 {sig_match_named,   "SetCurrentCaptureModeType","SetCurrentCaptureModeType_FW",},
4623 {sig_match_named,   "SetDate",                  "SetDate_FW",},
4624 {sig_match_named,   "SetLogicalEventActive",    "UiEvnt_SetLogicalEventActive_FW",},
4625 {sig_match_named,   "SetScriptMode",            "SetScriptMode_FW",},
4626 {sig_match_named,   "SleepTask",                "SleepTask_FW",},
4627 {sig_match_named,   "SetPropertyCase",          "SetPropertyCase_FW",   SIG_NAMED_SUB},
4628 {sig_match_named,   "TakeSemaphore",            "TakeSemaphore_FW",},
4629 {sig_match_named,   "TurnOnDisplay",            "DispCon_TurnOnDisplay_FW",SIG_NAMED_SUB},
4630 {sig_match_named,   "TurnOffDisplay",           "DispCon_TurnOffDisplay_FW",SIG_NAMED_SUB},
4631 {sig_match_named,   "TurnOnBackLight",          "DispCon_TurnOnBackLight_FW",SIG_NAMED_SUB, SIG_DRY_MAX(57)},
4632 {sig_match_named,   "TurnOffBackLight",         "DispCon_TurnOffBackLight_FW",SIG_NAMED_SUB},
4633 {sig_match_named,   "UIFS_WriteFirmInfoToFile", "UIFS_WriteFirmInfoToFile_FW",},
4634 {sig_match_named,   "UnlockAE",                 "SS.UnlockAE_FW",       SIG_NAMED_JMP_SUB},
4635 {sig_match_named,   "UnlockAF",                 "SS.UnlockAF_FW",       SIG_NAMED_JMP_SUB},
4636 {sig_match_named,   "UnlockMainPower",          "UnlockMainPower_FW",},
4637 {sig_match_named,   "UnRegisterEventProcedure", "UnRegisterEventProcTable", SIG_NAMED_SUB},
4638 //{s