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