root/tools/finsig_thumb2.c

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

DEFINITIONS

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

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

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