root/tools/finsig_dryos.c

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

DEFINITIONS

This source file includes following definitions.
  1. bprintf
  2. add_blankline
  3. write_output
  4. usage
  5. error
  6. match_compare
  7. addMatch
  8. fwAddMatch
  9. find_saved_sig
  10. save_sig
  11. get_saved_sig
  12. search_saved_sig
  13. find_min_ver
  14. find_max_ver
  15. match_apex2us
  16. match_apex2us2
  17. find_apex2us
  18. find_mkdir
  19. find_pow
  20. find_rand
  21. get_ptp_file_buf_id
  22. find_get_ptp_file_buf
  23. find_closedir
  24. find_GetTimeFromRTC_and_more
  25. find_arm_cache_funcs
  26. find_arm_cache_funcs2
  27. find_IsWirelessConnect
  28. find_get_fstype
  29. find_Restart
  30. find_add_ptp_handler
  31. find_PT_PlaySound
  32. find_getImageDirName
  33. match_GetImageFolder
  34. find_GetImageFolder
  35. match_GetDrive_ClusterSize
  36. find_GetDrive_ClusterSize
  37. find_GetDrive_TotalClusters
  38. find_srand
  39. find_malloc_strictly
  40. find_DisplayBusyOnScreen
  41. find_UndisplayBusyOnScreen
  42. find_CreateDialogBox
  43. find_DisplayDialogBox
  44. find_add_ui_to_dialog
  45. find_get_string_by_id
  46. find_get_self_task_errno_pointer
  47. find_get_nd_value
  48. find_get_current_nd_value_iris
  49. find_get_current_nd_value
  50. find_get_current_deltasv
  51. find_getcurrentmachinetime
  52. find_sethptimeraftertimeout
  53. find_DoMovieFrameCapture
  54. find_get_ptp_buf_size
  55. find_GetBaseSv
  56. find_Remove
  57. find_dispatch_funcs
  58. find_func
  59. dryos_offset
  60. fw_string_process
  61. fw_string_process_unaligned
  62. fw_process
  63. match_strsig1
  64. match_strsig2a
  65. match_strsig2
  66. match_strsig3a
  67. match_strsig3
  68. match_strsig4a
  69. match_strsig4
  70. match_strsig5a
  71. match_strsig5
  72. match_strsig6
  73. match_strsig7a
  74. match_strsig7
  75. match_strsig8
  76. find_strsig8
  77. find_strsig9
  78. match_strsig11
  79. find_strsig12
  80. match_strsig13a
  81. match_strsig13
  82. match_strsig15a
  83. match_strsig15
  84. match_strsig16
  85. find_strsig17
  86. find_strsig19
  87. match_strsig23a
  88. match_strsig23
  89. match_strsig24
  90. find_strsig
  91. find_str_sig_matches
  92. find_matches
  93. print_results
  94. mode_name
  95. output_modemap
  96. match_modelist
  97. match_FlashParamsTable2
  98. match_FlashParamsTable
  99. find_modemap
  100. match_CAM_UNCACHED_BIT
  101. find_DebugAssert_argcount
  102. find_platform_vals
  103. find_viewport_address
  104. match_vid_get_bitmap_fb
  105. match_get_flash_params_count
  106. match_uiprop_count
  107. match_imager_active
  108. find_lib_vals
  109. print_stubs_min
  110. print_exmem_types
  111. find_exmem_alloc_table
  112. match_levent_table
  113. match_movie_status
  114. match_full_screen_refresh
  115. match_canon_shoot_menu_active
  116. match_playrec_mode
  117. match_some_flag_for_af_scan
  118. match_palette_data
  119. match_palette_buffer_offset
  120. match_palette_data3
  121. match_palette_data2
  122. match_SavePaletteData
  123. match_viewport_address3
  124. match_viewport_address2
  125. match_viewport_address
  126. match_physw_status
  127. match_physw_run
  128. match_canon_menu_active
  129. match_zoom_busy
  130. match_focus_busy
  131. match_bitmap_buffer2
  132. match_bitmap_buffer
  133. match_raw_buffer
  134. match_fileiosem
  135. match_cameracon_state
  136. find_stubs_min
  137. find_ctypes
  138. match_nrflag3
  139. match_nrflag
  140. match_nrflag2
  141. isSTRw
  142. isSTRB
  143. find_leds
  144. find_task_related_info
  145. find_AdditionAgent_RAM
  146. add_prop_hit
  147. match_propsig1a
  148. match_propsig1
  149. find_strsig2
  150. find_prop_matches
  151. find_propset
  152. find_other_vals
  153. print_kval
  154. print_physw_raw_vals
  155. add_kinfo
  156. add_kmval
  157. kinfo_compare
  158. print_kmvals
  159. match_GetSDProtect
  160. find_key_vals
  161. get_eventproc_val
  162. add_func_name
  163. add_func_name2
  164. match_eventproc
  165. match_registerproc2
  166. match_registerproc
  167. match_registerlists
  168. find_eventprocs
  169. findTaskAddress
  170. match_createtask
  171. find_tasks
  172. find_builddate
  173. save_ptp_handler_func
  174. find_ptp_handler_imm
  175. match_ptp_handlers
  176. find_ptp_handlers
  177. write_levent_table_dump
  178. output_firmware_vals
  179. compare_func_names
  180. compare_func_addresses
  181. write_funcs
  182. 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 "stubs_load.h"
   9 #include "firmware_load.h"
  10 #include "ptp_op_names.h"
  11 
  12 //------------------------------------------------------------------------------------------------------------
  13 // #define LIST_IMPORTANT_FUNCTIONS 1   // always list functions with 'LIST_ALWAYS' flag, even when not found
  14 // #define LIST_PHYSW_TABLE 1           // print all physw events to file
  15 // #define PRINT_LEVENT_TABLE 1         // print all levents to file
  16 //------------------------------------------------------------------------------------------------------------
  17 
  18 // Buffer output into header and body sections
  19 
  20 FILE    *out_fp;
  21 char    out_buf[32*1024] = "";
  22 int     out_len = 0;
  23 char    hdr_buf[32*1024] = "";
  24 int     hdr_len = 0;
  25 int     out_hdr = 1;
  26 
  27 void bprintf(char *fmt, ...)
  28 {
  29     va_list argp;
  30     va_start(argp, fmt);
  31 
  32     if (out_hdr)
  33         hdr_len += vsprintf(hdr_buf+hdr_len,fmt,argp);
  34     else
  35         out_len += vsprintf(out_buf+out_len,fmt,argp);
  36 
  37     va_end(argp);
  38 }
  39 
  40 void add_blankline()
  41 {
  42     if (strcmp(hdr_buf+hdr_len-2,"\n\n") != 0)
  43     {
  44         hdr_buf[hdr_len++] = '\n';
  45         hdr_buf[hdr_len] = 0;
  46     }
  47 }
  48 
  49 void write_output()
  50 {
  51     add_blankline();
  52     if (out_fp)
  53     {
  54         fprintf(out_fp,"%s",hdr_buf);
  55         fprintf(out_fp,"%s",out_buf);
  56     }
  57 }
  58 
  59 //------------------------------------------------------------------------------------------------------------
  60 
  61 void usage(char *err)
  62 {
  63     bprintf("finsig <primary> <base> <outputfilename> [alt base] - Error = %s\n",err);
  64     write_output();
  65     fprintf(stderr,"finsig <primary> <base> <outputfilename> [alt base] - Error = %s\n",err);
  66     exit(1);
  67 }
  68 
  69 void error(char *fmt, int n)
  70 {
  71     bprintf(fmt, n);
  72     write_output();
  73     exit(1);
  74 }
  75 
  76 //------------------------------------------------------------------------------------------------------------
  77 
  78 // Signature match handling
  79 
  80 // Structure to store match info
  81 typedef struct {
  82     uint32_t ptr;
  83     uint32_t fail;
  84     uint32_t success;
  85     int sig;
  86 } Match;
  87 
  88 // qsort compare function the Match struture
  89 int match_compare(const Match *p1, const Match *p2)
  90 {
  91     /* NOTE: If a function has *more* matches, it will be prefered, even if it has a lower percent matches */
  92     if (p1->success > p2->success)
  93     {
  94         if ((p2->fail == 0) && (p1->fail > 0))
  95         {
  96             return 1;
  97         }
  98         else
  99         {
 100             return -1;
 101         }
 102     }
 103     else if (p1->success < p2->success)
 104     {
 105         if ((p1->fail == 0) && (p2->fail > 0))
 106         {
 107             return -1;
 108         }
 109         else
 110         {
 111             return 1;
 112         }
 113     }
 114     else
 115     {
 116         if (p1->fail < p2->fail)
 117         {
 118             return -1;
 119         }
 120         else if (p1->fail > p2->fail)
 121         {
 122             return 1;
 123         }
 124     }
 125 
 126     if (p1->sig < p2->sig)
 127     {
 128         return -1;
 129     }
 130     else if (p1->sig > p2->sig)
 131     {
 132         return 1;
 133     }
 134 
 135     /* scores are equal. prefer lower address */
 136 
 137     if (p1->ptr < p2->ptr)
 138     {
 139         return -1;
 140     }
 141     else if (p1->ptr > p2->ptr)
 142     {
 143         return 1;
 144     }
 145 
 146     return 0;
 147 }
 148 
 149 #define MAX_MATCHES (8192)
 150 
 151 Match matches[MAX_MATCHES];
 152 int count;
 153 
 154 // Add a new Match
 155 void addMatch(uint32_t fadr, int s, int f, int sig)
 156 {
 157     matches[count].ptr = fadr;
 158     matches[count].success = s;
 159     matches[count].fail = f;
 160     matches[count].sig = sig;
 161     count++;
 162 }
 163 
 164 // Add a Match, adjust address for stuff in the block copied to RAM
 165 void fwAddMatch(firmware *fw, uint32_t fadr, int s, int f, int sig)
 166 {
 167     if ((fadr >= fw->base_copied) && (fadr < (fw->base_copied + fw->size2*4)))
 168     {
 169         addMatch(fadr - fw->base_copied + fw->base2,s,f,sig);
 170     }
 171     else
 172     {
 173         addMatch(fadr,s,f,sig);
 174     }
 175 }
 176 
 177 //------------------------------------------------------------------------------------------------------------
 178 
 179 // Signature structures generated by gensig2.exe
 180 
 181 typedef struct {
 182     uint32_t offs;
 183     uint32_t value;
 184     uint32_t mask;
 185 } FuncSig;
 186 
 187 typedef struct {
 188     const char *name;
 189     FuncSig *sig;
 190     int ver;
 191 } FuncsList;
 192 
 193 //------------------------------------------------------------------------------------------------------------
 194 
 195 // Master list of functions / addresses to find
 196 
 197 #define DONT_EXPORT     1
 198 #define OPTIONAL        2
 199 #define UNUSED          4
 200 #define BAD_MATCH       8
 201 #define EV_MATCH        16
 202 #define LIST_ALWAYS     32
 203 
 204 typedef struct {
 205     char        *name;
 206     int         flags;
 207     uint32_t    val;
 208 } func_entry;
 209 
 210 int next_func_entry = 0;
 211 
 212 #define MAX_FUNC_ENTRY  5000
 213 
 214 func_entry  func_names[MAX_FUNC_ENTRY] =
 215 {
 216     // Do these first as they are needed to find others
 217     { "ExportToEventProcedure_FW", UNUSED|DONT_EXPORT },
 218     { "CreateJumptable", UNUSED },
 219     { "_uartr_req", UNUSED },
 220     { "StartRecModeMenu", UNUSED },
 221     { "LogCameraEvent", UNUSED|DONT_EXPORT },
 222     { "getImageDirName", UNUSED|DONT_EXPORT },
 223 
 224     { "AllocateMemory", UNUSED|LIST_ALWAYS },
 225     { "AllocateUncacheableMemory" },
 226     { "Close" },
 227     { "CreateBinarySemaphore" },
 228     { "CreateCountingSemaphore", UNUSED|LIST_ALWAYS },
 229     { "CreateTask" },
 230     { "DebugAssert", OPTIONAL|LIST_ALWAYS },
 231     { "DeleteDirectory_Fut" },
 232     { "DeleteFile_Fut" },
 233     { "DeleteSemaphore", UNUSED|LIST_ALWAYS },
 234     { "DoAELock" },
 235     { "DoAFLock" },
 236     { "EnterToCompensationEVF" },
 237     { "ExecuteEventProcedure" },
 238     { "ExitFromCompensationEVF" },
 239     { "ExitTask" },
 240     { "ExpCtrlTool_StartContiAE" },
 241     { "ExpCtrlTool_StopContiAE" },
 242     { "Fclose_Fut" },
 243     { "Feof_Fut" },
 244     { "Fflush_Fut" },
 245     { "Fgets_Fut" },
 246     { "Fopen_Fut" },
 247     { "Fread_Fut" },
 248     { "FreeMemory", UNUSED|LIST_ALWAYS },
 249     { "FreeUncacheableMemory" },
 250     { "Fseek_Fut" },
 251     { "Fwrite_Fut" },
 252     { "GetBatteryTemperature" },
 253     { "GetCCDTemperature" },
 254     { "GetCurrentAvValue" },
 255     { "GetCurrentShutterSpeed" },
 256     { "GetUsableMaxAv", OPTIONAL },
 257     { "GetUsableMinAv", OPTIONAL },
 258     { "GetDrive_ClusterSize" },
 259     { "GetDrive_FreeClusters" },
 260     { "GetDrive_TotalClusters" },
 261     { "GetFocusLensSubjectDistance" },
 262     { "GetFocusLensSubjectDistanceFromLens" },
 263     { "GetImageFolder", OPTIONAL },
 264     { "GetKbdState" },
 265     { "GetMemInfo" },
 266     { "GetOpticalTemperature" },
 267     { "GetParameterData" },
 268     { "GetPropertyCase" },
 269     { "GetSystemTime" },
 270     { "GetVRAMHPixelsSize" },
 271     { "GetVRAMVPixelsSize" },
 272     { "GetZoomLensCurrentPoint" },
 273     { "GetZoomLensCurrentPosition" },
 274     { "GiveSemaphore" },
 275     { "IsStrobeChargeCompleted" },
 276     { "LEDDrive", OPTIONAL },
 277     { "LocalTime" },
 278     { "LockMainPower" },
 279     { "Lseek", UNUSED|LIST_ALWAYS },
 280     { "MakeDirectory_Fut" },
 281     { "MakeSDCardBootable", OPTIONAL },
 282     { "MoveFocusLensToDistance" },
 283     { "MoveIrisWithAv", OPTIONAL },
 284     { "MoveZoomLensWithPoint" },
 285     { "MoveOpticalZoomAt", OPTIONAL },
 286     { "NewTaskShell", UNUSED },
 287     { "Open" },
 288     { "PB2Rec" },
 289     { "PT_MoveDigitalZoomToWide", OPTIONAL },
 290     { "PT_MoveOpticalZoomAt", OPTIONAL },
 291     { "PT_PlaySound" },
 292     { "PostLogicalEventForNotPowerType" },
 293     { "PostLogicalEventToUI" },
 294     { "PutInNdFilter", OPTIONAL },
 295     { "PutOutNdFilter", OPTIONAL },
 296     { "Read" },
 297     { "ReadFastDir" },
 298     { "Rec2PB" },
 299     { "RefreshPhysicalScreen" },
 300     { "Remove", OPTIONAL|UNUSED },
 301     { "RenameFile_Fut" },
 302     { "Restart" },
 303     { "ScreenLock" },
 304     { "ScreenUnlock" },
 305     { "SetAE_ShutterSpeed" },
 306     { "SetAutoShutdownTime" },
 307     { "SetCurrentCaptureModeType" },
 308     { "SetDate" },
 309     { "SetFileAttributes" },
 310     { "SetFileTimeStamp" },
 311     { "SetLogicalEventActive" },
 312     { "SetParameterData" },
 313     { "SetPropertyCase" },
 314     { "SetScriptMode" },
 315     { "SleepTask" },
 316     { "TakeSemaphore" },
 317     { "TurnOffBackLight" },
 318     { "TurnOnBackLight" },
 319     { "TurnOnDisplay" },
 320     { "TurnOffDisplay" },
 321     { "UIFS_WriteFirmInfoToFile" },
 322     { "UnlockAE" },
 323     { "UnlockAF" },
 324     { "UnlockMainPower" },
 325     { "UnsetZoomForMovie", OPTIONAL },
 326     { "UpdateMBROnFlash" },
 327     { "VbattGet" },
 328     { "Write" },
 329     { "WriteSDCard" },
 330 
 331     { "_log" },
 332     { "_log10" },
 333     { "_pow" },
 334     { "_sqrt" },
 335     { "add_ptp_handler" },
 336     { "apex2us" },
 337     { "close" },
 338     { "err_init_task", OPTIONAL },
 339     { "exmem_alloc", OPTIONAL },
 340     { "exmem_free", UNUSED|OPTIONAL },
 341     { "exmem_ualloc" },
 342     { "exmem_ufree" },
 343     { "exmem_assert", UNUSED|OPTIONAL|LIST_ALWAYS }, // helper, r23 or lower
 344     { "free" },
 345     { "get_nd_value", OPTIONAL },
 346     { "get_current_exp", UNUSED | OPTIONAL }, // helper, underlying function of ShowCurrentExp
 347     { "get_current_nd_value", OPTIONAL },
 348     { "get_current_deltasv", },
 349     { "GetUsableAvRange", OPTIONAL|UNUSED },
 350     { "GetBaseSv", OPTIONAL|UNUSED },
 351     { "GetCurrentDriveBaseSvValue", },
 352 
 353     { "kbd_p1_f" },
 354     { "kbd_p1_f_cont" },
 355     { "kbd_p2_f" },
 356     { "kbd_read_keys" },
 357     { "kbd_read_keys_r2" },
 358 
 359     { "kbd_pwr_off", OPTIONAL },
 360     { "kbd_pwr_on", OPTIONAL },
 361     { "lseek" },
 362     { "malloc" },
 363     { "memcmp" },
 364     { "memcpy" },
 365     { "memset" },
 366     { "mkdir" },
 367     { "mktime_ext" },
 368     { "open" },
 369     { "OpenFastDir" },
 370     { "closedir" },
 371     { "get_fstype", OPTIONAL|LIST_ALWAYS },
 372     { "qsort" },
 373     { "rand" },
 374     { "read", UNUSED|OPTIONAL },
 375     { "realloc", OPTIONAL|LIST_ALWAYS },
 376     { "reboot_fw_update" },
 377     { "set_control_event" },
 378     { "srand" },
 379     { "stat" },
 380     { "strcat" },
 381     { "strchr" },
 382     { "strcmp" },
 383     { "strcpy" },
 384     { "strftime" },
 385     { "strlen" },
 386     { "strncmp" },
 387     { "strncpy" },
 388     { "strrchr" },
 389     { "strtol" },
 390     { "strtolx" },
 391 
 392     { "task_CaptSeq" },
 393     { "task_DvlpSeqTask", OPTIONAL },
 394     { "task_ExpDrv" },
 395     { "task_FileWrite", OPTIONAL },
 396     { "task_InitFileModules" },
 397     { "task_MovieRecord" },
 398     { "task_PhySw", OPTIONAL },
 399     { "task_RotaryEncoder", OPTIONAL },
 400     { "task_TouchPanel", OPTIONAL },
 401 
 402     { "hook_CreateTask" },
 403 
 404     { "time" },
 405     { "vsprintf" },
 406     { "write", UNUSED|OPTIONAL },
 407 
 408     { "EngDrvIn", OPTIONAL|UNUSED|LIST_ALWAYS },
 409     { "EngDrvOut", OPTIONAL|UNUSED|LIST_ALWAYS },
 410     { "EngDrvRead" },
 411     { "EngDrvBits", OPTIONAL|UNUSED|LIST_ALWAYS },
 412 
 413     { "PTM_GetCurrentItem" },
 414     { "PTM_SetCurrentItem", UNUSED|LIST_ALWAYS },
 415     { "PTM_NextItem", OPTIONAL|UNUSED|LIST_ALWAYS },
 416     { "PTM_PrevItem", OPTIONAL|UNUSED|LIST_ALWAYS },
 417     { "PTM_SetPropertyEnable", OPTIONAL|UNUSED|LIST_ALWAYS },
 418 
 419     { "DisableISDriveError", OPTIONAL },
 420 
 421     // OS functions, mostly to aid firmware analysis. Order is important!
 422     { "_GetSystemTime", OPTIONAL|UNUSED|LIST_ALWAYS }, // only for locating timer functions
 423     { "SetTimerAfter", OPTIONAL|UNUSED|LIST_ALWAYS },
 424     { "SetTimerWhen", OPTIONAL|UNUSED|LIST_ALWAYS },
 425     { "CancelTimer", OPTIONAL|UNUSED|LIST_ALWAYS },
 426     { "CancelHPTimer" },
 427     { "SetHPTimerAfterTimeout", OPTIONAL|UNUSED|LIST_ALWAYS },
 428     { "SetHPTimerAfterNow" },
 429     { "CreateTaskStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 430     { "CreateTaskStrictly_alt", OPTIONAL|UNUSED|LIST_ALWAYS }, // widely used in r59, identical to CreateTaskStrictly
 431     { "CreateMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 432     { "CreateRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 433     { "GetSemaphoreValue", OPTIONAL|UNUSED|LIST_ALWAYS },
 434     { "TryTakeSemaphore", OPTIONAL|UNUSED|LIST_ALWAYS },
 435     { "CreateMessageQueueStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 436     { "CreateEventFlagStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 437     { "CreateBinarySemaphoreStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 438     { "CreateCountingSemaphoreStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 439     { "CreateRecursiveLockStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 440     { "TakeSemaphoreStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 441     { "ReceiveMessageQueueStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 442     { "PostMessageQueueStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },    // r23+
 443     { "WaitForAnyEventFlagStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 444     { "WaitForAllEventFlagStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 445     { "AcquireRecursiveLockStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 446     { "DeleteMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 447     { "PostMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 448     { "ReceiveMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 449     { "TryReceiveMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 450     { "TryPostMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 451     { "GetNumberOfPostedMessages", OPTIONAL|UNUSED|LIST_ALWAYS },
 452     { "DeleteRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 453     { "AcquireRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 454     { "ReleaseRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 455     { "WaitForAnyEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 456     { "WaitForAllEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 457     { "ClearEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 458     { "SetEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 459     { "GetEventFlagValue", OPTIONAL|UNUSED|LIST_ALWAYS },
 460     { "CreateEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 461     { "DeleteEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 462     { "CheckAnyEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 463     { "CheckAllEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 464     { "RegisterInterruptHandler", OPTIONAL|UNUSED|LIST_ALWAYS },
 465     { "UnregisterInterruptHandler", OPTIONAL|UNUSED|LIST_ALWAYS },
 466     { "GetSRAndDisableInterrupt", OPTIONAL|UNUSED|LIST_ALWAYS }, // disables IRQ, returns a value
 467     { "SetSR", OPTIONAL|UNUSED|LIST_ALWAYS }, // enables IRQ, puts back value returned by GetSR
 468     { "EnableInterrupt", OPTIONAL|UNUSED|LIST_ALWAYS }, // enables IRQ
 469     { "_divmod_signed_int", OPTIONAL|UNUSED|LIST_ALWAYS}, // division for signed integers, remainder is returned in r1
 470     { "_divmod_unsigned_int", OPTIONAL|UNUSED|LIST_ALWAYS}, // division for unsigned integers, remainder is returned in r1
 471     { "_dflt", OPTIONAL|UNUSED|LIST_ALWAYS}, // int -> double
 472     { "_dfltu", OPTIONAL|UNUSED|LIST_ALWAYS}, // uint -> double
 473     { "_dfix", OPTIONAL|UNUSED|LIST_ALWAYS}, // double -> int
 474     { "_dfixu", OPTIONAL|UNUSED|LIST_ALWAYS}, // double -> uint
 475     { "_dmul", OPTIONAL|UNUSED|LIST_ALWAYS}, // double precision float multiplication
 476     { "_ddiv", OPTIONAL|UNUSED|LIST_ALWAYS}, // double precision float division
 477     { "_dadd", OPTIONAL|UNUSED|LIST_ALWAYS}, // addition for doubles
 478     { "_dsub", OPTIONAL|UNUSED|LIST_ALWAYS}, // subtraction for doubles
 479     { "_drsb", OPTIONAL|UNUSED|LIST_ALWAYS}, // reverse subtraction for doubles (?)
 480     { "_dcmp", OPTIONAL|UNUSED|LIST_ALWAYS}, // comparison of 2 doubles, only updates condition flags
 481     { "_dcmp_reverse", OPTIONAL|UNUSED|LIST_ALWAYS}, // like _dcmp, but operands in reverse order, only updates condition flags
 482     { "_safe_sqrt", OPTIONAL|UNUSED|LIST_ALWAYS}, // only calls _sqrt for numbers >= 0
 483     { "_scalbn", OPTIONAL|UNUSED|LIST_ALWAYS}, // double scalbn (double x, long exp), returns x * FLT_RADIX ** exp
 484     { "_fflt", OPTIONAL|UNUSED|LIST_ALWAYS}, // int -> float
 485     { "_ffltu", OPTIONAL|UNUSED|LIST_ALWAYS}, // uint -> float
 486     { "_ffix", OPTIONAL|UNUSED|LIST_ALWAYS}, // float -> int
 487     { "_ffixu", OPTIONAL|UNUSED|LIST_ALWAYS}, // float -> uint
 488     { "_fmul", OPTIONAL|UNUSED|LIST_ALWAYS}, // single precision float multiplication
 489     { "_fdiv", OPTIONAL|UNUSED|LIST_ALWAYS}, // single precision float division
 490     { "_f2d", OPTIONAL|UNUSED|LIST_ALWAYS}, // float -> double
 491     { "DisplayBusyOnScreen", OPTIONAL|UNUSED|LIST_ALWAYS}, // displays full screen "busy" message
 492     { "UndisplayBusyOnScreen", OPTIONAL|UNUSED|LIST_ALWAYS},
 493     { "CreateDialogBox", OPTIONAL|UNUSED|LIST_ALWAYS},
 494     { "DisplayDialogBox", OPTIONAL|UNUSED|LIST_ALWAYS},
 495     { "add_ui_to_dialog", OPTIONAL|UNUSED|LIST_ALWAYS}, // name made up, assigns resources to a dialog
 496     { "get_string_by_id", OPTIONAL|UNUSED|LIST_ALWAYS}, // name made up, retrieves a localised or unlocalised string by its ID
 497     { "malloc_strictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // name made up
 498     { "GetCurrentMachineTime", OPTIONAL|UNUSED|LIST_ALWAYS }, // reads usec counter, name from ixus30
 499     { "HwOcReadICAPCounter", OPTIONAL|UNUSED|LIST_ALWAYS }, // reads usec counter, name from ixus30
 500     { "get_self_task_id", OPTIONAL|UNUSED|LIST_ALWAYS }, // gets ID of own task
 501     { "get_task_properties", OPTIONAL|UNUSED|LIST_ALWAYS }, // gets copy of task's data (different struct, not the real TCB)
 502     { "get_self_task_errno_pointer", OPTIONAL|UNUSED|LIST_ALWAYS }, // gets pointer to own task's errno
 503     { "EnableDispatch", OPTIONAL|UNUSED }, // enables task switching (high level wrapper)
 504     { "DisableDispatch", OPTIONAL|UNUSED }, // disables task switching (high level wrapper)
 505     { "EnableDispatch_low", OPTIONAL|UNUSED }, // enables task switching
 506     { "DisableDispatch_low", OPTIONAL|UNUSED }, // disables task switching
 507     { "GetValidSystemCalender", OPTIONAL|UNUSED }, // name from ixus30
 508     { "SetValidSystemCalender", OPTIONAL|UNUSED }, // name from ixus30
 509     { "GetTimeFromRTC", OPTIONAL|UNUSED },
 510     { "IsInvalidTime", OPTIONAL|UNUSED }, // name from ixus30
 511     { "PauseTimeOfSystem", OPTIONAL|UNUSED }, // name from ixus30
 512     { "ResumeTimeOfSystem", OPTIONAL|UNUSED }, // name from ixus30
 513 
 514     { "cache_flush_and_enable", OPTIONAL|UNUSED }, // older dryos
 515     { "cache_clean_flush_and_disable", OPTIONAL|UNUSED }, // older dryos
 516     { "cache_flush_range", OPTIONAL|UNUSED }, // older dryos
 517     { "cache_clean_flush_range", OPTIONAL|UNUSED }, // older dryos
 518     { "cache_clean_range", OPTIONAL|UNUSED }, // older dryos
 519 
 520     { "icache_flush_and_enable", OPTIONAL|UNUSED }, // newer dryos
 521     { "icache_disable_and_flush", OPTIONAL|UNUSED }, // newer dryos
 522     { "dcache_flush_and_enable", OPTIONAL|UNUSED }, // newer dryos
 523     { "dcache_clean_flush_and_disable", OPTIONAL|UNUSED }, // newer dryos
 524     { "dcache_flush_range", OPTIONAL|UNUSED }, // newer dryos
 525     { "dcache_clean_range", OPTIONAL|UNUSED }, // newer dryos
 526     { "dcache_clean_flush_range", OPTIONAL|UNUSED }, // newer dryos
 527     { "icache_flush_range", OPTIONAL|UNUSED }, // newer dryos
 528 
 529     // Other stuff needed for finding misc variables - don't export to stubs_entry.S
 530     { "GetSDProtect", UNUSED },
 531     { "DispCon_ShowBitmapColorBar", UNUSED },
 532     { "ResetZoomLens", OPTIONAL|UNUSED },
 533     { "ResetFocusLens", OPTIONAL|UNUSED },
 534     { "NR_GetDarkSubType", OPTIONAL|UNUSED },
 535     { "NR_SetDarkSubType", OPTIONAL|UNUSED },
 536     { "SavePaletteData", OPTIONAL|UNUSED },
 537     { "GUISrv_StartGUISystem", OPTIONAL|UNUSED|LIST_ALWAYS },
 538     { "get_resource_pointer", OPTIONAL|UNUSED|LIST_ALWAYS }, // name made up, gets a pointer to a certain resource (font, dialog, icon)
 539     { "CalcLog10", OPTIONAL|UNUSED|LIST_ALWAYS }, // helper
 540     { "ImagerActivate", OPTIONAL|UNUSED }, // helper
 541     { "DoMovieFrameCapture", OPTIONAL|UNUSED },
 542     { "SetImageMode", OPTIONAL|UNUSED },
 543     { "MenuIn", OPTIONAL|UNUSED },
 544     { "MenuOut", OPTIONAL|UNUSED },
 545 
 546     { "MFOn", OPTIONAL },
 547     { "MFOff", OPTIONAL },
 548     { "PT_MFOn", OPTIONAL },
 549     { "PT_MFOff", OPTIONAL },
 550     { "SS_MFOn", OPTIONAL },
 551     { "SS_MFOff", OPTIONAL },
 552 
 553     { "GetAdChValue", OPTIONAL },
 554     { "EnableHDMIPower", OPTIONAL },
 555     { "DisableHDMIPower", OPTIONAL },
 556 
 557     { "get_ptp_buf_size", OPTIONAL },
 558     { "get_ptp_file_buf", OPTIONAL },
 559 
 560     { "SetVideoOutType", OPTIONAL },
 561     { "GetVideoOutType", OPTIONAL },
 562 
 563     { "cameracon_set_state", UNUSED }, // made up name, helper for cameracon_state variable
 564     { "cameracon_get_state", OPTIONAL|UNUSED }, // for information only, match doesn't work on early dry
 565 
 566     { "IsWirelessConnect", OPTIONAL },
 567 
 568     { 0, 0, 0 }
 569 };
 570 
 571 // Return the array index of a named function in the array above
 572 int find_saved_sig(const char *name)
 573 {
 574     int i;
 575     for (i=0; func_names[i].name != 0; i++)
 576     {
 577         if (strcmp(name,func_names[i].name) == 0)
 578         {
 579             return i;
 580         }
 581     }
 582     return -1;
 583 }
 584 
 585 // Save the address value found for a function in the above array
 586 void save_sig(const char *name, uint32_t val)
 587 {
 588     int i = find_saved_sig(name);
 589     if (i >= 0)
 590     {
 591         func_names[i].val = val;
 592     }
 593 }
 594 
 595 // Get the saved address value for a named function
 596 // If the address value is 0 then assume the function search has not occurred yet, so go search for it.
 597 int get_saved_sig(firmware *fw, const char *name)
 598 {
 599     int i = find_saved_sig(name);
 600     if (i >= 0)
 601     {
 602         if (func_names[i].val == 0)
 603         {
 604             // See if the function is in the 'func_list' array below
 605             int find_func(const char* name);
 606             int k1 = find_func(name);
 607             if (k1 >= 0)
 608             {
 609                 // if found do full search
 610                 void find_matches(firmware*,const char*);
 611                 find_matches(fw, name);
 612                 count = 0;
 613             }
 614             else
 615             {
 616                 // not found, only do string matching search
 617                 void find_str_sig_matches(firmware*,const char*);
 618                 find_str_sig_matches(fw, name);
 619                 count = 0;
 620             }
 621         }
 622         if (func_names[i].val == 0)
 623         {
 624             // If not found return invalid index
 625             i = -1;
 626         }
 627     }
 628     return i;
 629 }
 630 
 631 // Search for something relative to the location stored for a previously matched function
 632 // Matching is done via the 'func' function, searching continues until 'func' returns non-zero
 633 // Starts searching at 'ofst' from the saved address for a max of 'len' instructions
 634 // Returns the 'func' value or 0 if no match found
 635 int search_saved_sig(firmware *fw, char *sig, int (*func)(firmware*, int, int), int v, int ofst, int len)
 636 {
 637     int k = get_saved_sig(fw, sig);
 638     if (k >= 0)
 639     {
 640         int idx = adr2idx(fw, func_names[k].val);
 641         for (k=idx+ofst; k<idx+ofst+len; k++)
 642         {
 643             int rv = func(fw, k, v);
 644             if (rv)
 645                 return rv;
 646         }
 647     }
 648     return 0;
 649 }
 650 
 651 //------------------------------------------------------------------------------------------------------------
 652 
 653 // Signature min / max DryOS versions
 654 
 655 typedef struct {
 656     char        *name;
 657     uint32_t    val;
 658 } sig_stuff;
 659 
 660 sig_stuff min_ver[] = {
 661     { "ScreenLock", 39 },
 662     { "ScreenUnlock", 39 },
 663     { "MakeSDCardBootable", 47 },
 664     { "hook_CreateTask", 51 },
 665     { "CreateTaskStrictly_alt", 59 },
 666 
 667     { 0, 0 }
 668 };
 669 
 670 sig_stuff max_ver[] = {
 671     { "UpdateMBROnFlash", 45 },
 672     { "kbd_pwr_on", 43 },
 673     { "kbd_pwr_off", 43 },
 674 
 675     { 0, 0 }
 676 };
 677 
 678 int find_min_ver(const char *name)
 679 {
 680     int i;
 681     for (i=0; min_ver[i].name != 0; i++)
 682     {
 683         if (strcmp(name,min_ver[i].name) == 0)
 684         {
 685             return min_ver[i].val;
 686         }
 687     }
 688     return 0;
 689 }
 690 
 691 int find_max_ver(const char *name)
 692 {
 693     int i;
 694     for (i=0; max_ver[i].name != 0; i++)
 695     {
 696         if (strcmp(name,max_ver[i].name) == 0)
 697         {
 698             return max_ver[i].val;
 699         }
 700     }
 701     return 99999;
 702 }
 703 
 704 //------------------------------------------------------------------------------------------------------------
 705 
 706 // New string / signature matching structure
 707 
 708 // Structure for matching
 709 
 710 typedef struct {
 711     int     type;               // 1 = func*, string, 2 = string, ... string*, func*, 3 = ADR Rx, func, ADR Ry, string, BL, ... string, etc
 712     char    *name;              // function name
 713     char    *ev_name;           // event / other name to match in the firmware
 714     int     offset;             // offset for following branches, or other tests
 715     // DryOS version specific offsets
 716     int     dryos20_offset;     // ***** UPDATE for new DryOS version *****
 717     int     dryos23_offset;
 718     int     dryos31_offset;
 719     int     dryos39_offset;
 720     int     dryos43_offset;
 721     int     dryos45_offset;
 722     int     dryos47_offset;
 723     int     dryos49_offset;
 724     int     dryos50_offset;
 725     int     dryos51_offset;
 726     int     dryos52_offset;
 727     int     dryos54_offset;
 728     int     dryos55_offset;
 729     int     dryos57_offset;
 730     int     dryos58_offset;
 731     int     dryos59_offset;
 732 } string_sig;
 733 
 734 // used to early out for wifi related functions, valid after tasks found
 735 int cam_has_wifi;
 736 
 737 // Load old signature matching data generated by gensig_dryos
 738 #include "signatures_dryos.h"
 739 
 740 //------------------------------------------------------------------------------------------------------------
 741 
 742 // Data for matching 'apex2us' function
 743 uint32_t apex2us_test[] = { 0x3D09000, 0x3BBA304, 0x3A728D2, 0x3931EF4, 0x37F8303, 0x36C52A2, 0x3598B85, 0x3472B6A, 0 };
 744 uint32_t apex2us_test2[] = { 0x3d090000, 0x3bba3040, 0x3a728d1f, 0x3931ef45, 0x37f8302c, 0x36c52a26, 0x3598b852, 0x3472b699, 0 }; // r52+?
 745 
 746 // Special case for apex2us
 747 int match_apex2us(firmware *fw, int k, uint32_t v1, __attribute__ ((unused))uint32_t v2)
 748 {
 749     if (isLDR_PC(fw,k) && (LDR2val(fw,k) == v1) && ((fwRd(fw,k) == 1) || (fwRd(fw,k) == 2)))
 750     {
 751         k = find_inst_rev(fw, isSTMFD_LR, k, 200);
 752         if (k != -1)
 753         {
 754             if (fwval(fw,k-2) == 0xE3700D09)    // CMN R0, #0x240
 755                 k -= 2;
 756             uint32_t fadr = idx2adr(fw,k);
 757             fwAddMatch(fw,fadr,32,0,121);
 758             return 1;
 759         }
 760     }
 761     return 0;
 762 }
 763 int match_apex2us2(firmware *fw, int k, uint32_t v1, __attribute__ ((unused))uint32_t v2) // r52+?
 764 {
 765     if (isLDR_PC(fw,k) && (LDR2val(fw,k) == v1) && ((fwRd(fw,k) == 1) || (fwRd(fw,k) == 2)))
 766     {
 767         k = find_inst_rev(fw, isSTMFD_LR, k, 200);
 768         if (k != -1)
 769         {
 770             if (fwval(fw,k+1) != 0xe3700d0f)    // CMN R0, #0x3c0
 771                 return 0;
 772             uint32_t fadr = idx2adr(fw,k);
 773             fwAddMatch(fw,fadr,32,0,121);
 774             return 1;
 775         }
 776     }
 777     return 0;
 778 }
 779 int find_apex2us(firmware *fw, __attribute__ ((unused))string_sig *sig, int j)
 780 {
 781     int i;
 782     int fnd = 1;
 783     for (i=0; apex2us_test[i] != 0; i++)
 784     {
 785         if (fwval(fw,j+i) != apex2us_test[i])
 786         {
 787             fnd = 0;
 788             break;
 789         }
 790     }
 791     if (fnd)
 792     {
 793         return search_fw(fw, match_apex2us, idx2adr(fw,j), 0, 1);
 794     }
 795 
 796     for (i=0; apex2us_test2[i] != 0; i++)
 797     {
 798         if (fwval(fw,j+i) != apex2us_test2[i])
 799         {
 800             return 0;
 801         }
 802     }
 803     return search_fw(fw, match_apex2us2, idx2adr(fw,j), 0, 1);
 804 }
 805 
 806 // Special case for mkdir
 807 int find_mkdir(firmware *fw, __attribute__ ((unused))string_sig *sig, int k)
 808 {
 809     if (fwval(fw,k) == 0x12CEA600)
 810     {
 811         int kk;
 812         if (fw->dryos_ver > 58)
 813         {
 814             kk = k-26;
 815         }
 816         else
 817         {
 818             kk = k-20;
 819         }
 820         k = find_inst_rev(fw, isSTMFD_LR, kk, 200);
 821         if (k != -1)
 822         {
 823             if ((((fwval(fw,k+12) & 0xFFF0FFFF) == 0xE350002F) && ((fwval(fw,k+15) & 0xFFF0FFFF) == 0xE3500021) && ((fwval(fw,k+19) & 0xFFF0FFFF) == 0xE3500020)) ||
 824                 (((fwval(fw,k+11) & 0xFFF0FFFF) == 0xE350002F) && ((fwval(fw,k+14) & 0xFFF0FFFF) == 0xE3500021) && ((fwval(fw,k+18) & 0xFFF0FFFF) == 0xE3500020)))
 825             {
 826                 uint32_t fadr = 0;
 827                 if (isBL(fw,k+47))
 828                 {
 829                     fadr = followBranch(fw, idx2adr(fw,k+47), 0x01000001);
 830                 }
 831                 else if (isBL(fw,k+48))
 832                 {
 833                     fadr = followBranch(fw, idx2adr(fw,k+48), 0x01000001);
 834                 }
 835                 if (fadr != 0)
 836                 {
 837                     fwAddMatch(fw,fadr,32,0,121);
 838                     return 1;
 839                 }
 840             }
 841         }
 842     }
 843     return 0;
 844 }
 845 
 846 // Special case for _pow
 847 int find_pow(firmware *fw, __attribute__ ((unused))string_sig *sig, int j)
 848 {
 849     // Find values passed to _pow
 850     if ((fwval(fw,j) == 0x00000000) && (fwval(fw,j+1) == 0x40000000) && (fwval(fw,j+2) == 0x00000000) && (fwval(fw,j+3) == 0x408F4000))
 851     {
 852         uint32_t adr1 = idx2adr(fw,j);        // address of 1st value
 853         uint32_t adr2 = idx2adr(fw,j+2);    // address of 2nd value
 854         int j1;
 855 
 856         for (j1 = j-5; j1>0; j1--)
 857         {
 858             if (isADR_PC_cond(fw,j1) &&                 // ADR ?
 859                 (fwval(fw,j1+1) == 0xE8900003) &&       // LDMIA R0,{R0,R1}
 860                 isBL(fw,j1+2) &&                        // BL
 861                 isADR_PC_cond(fw,j1+4))                 // ADR ?
 862             {
 863                 if ((ADR2adr(fw,j1) == adr1) && (ADR2adr(fw,j1+4) == adr2))
 864                 {
 865                     uint32_t fadr = followBranch(fw,idx2adr(fw,j1+2),0x01000001);
 866                     fwAddMatch(fw,fadr,32,0,121);
 867                     return 1;
 868                 }
 869             }
 870             else
 871             if (isADR_PC_cond(fw,j1) &&                 // ADR ?
 872                 (fwval(fw,j1+2) == 0xE8900003) &&       // LDMIA R0,{R0,R1}
 873                 isBL(fw,j1+3) &&                        // BL
 874                 isADR_PC_cond(fw,j1+4))                 // ADR ?
 875             {
 876                 if ((ADR2adr(fw,j1) == adr1) && (ADR2adr(fw,j1+4) == adr2))
 877                 {
 878                     uint32_t fadr = followBranch(fw,idx2adr(fw,j1+3),0x01000001);
 879                     fwAddMatch(fw,fadr,32,0,121);
 880                     return 1;
 881                 }
 882             }
 883         }
 884     }
 885 
 886     return 0;
 887 }
 888 
 889 // Special case for rand
 890 int find_rand(firmware *fw, __attribute__ ((unused))string_sig *sig, int j)
 891 {
 892     if (fwval(fw,j) == 0x41C64E6D)
 893     {
 894         int j1;
 895 
 896         for (j1 = j-1; j1>j-30; j1--)
 897         {
 898             if (isLDR_PC_cond(fw,j1) &&         // LDR Rx, =0x41C64E6D
 899                 (LDR2val(fw,j1) == 0x41C64E6D)) // LDMIA R0,{R0,R1}
 900             {
 901                 int k = find_inst_rev(fw, isBX_LR,j1-1,15);
 902                 if (k >= 0)
 903                 {
 904                     uint32_t fadr = idx2adr(fw, k+1);
 905                     fwAddMatch(fw,fadr,32,0,121);
 906                     return 1;
 907                 }
 908             }
 909         }
 910     }
 911 
 912     return 0;
 913 }
 914 // helper used for get_ptp_file_buf and get_ptp_buf_size
 915 int get_ptp_file_buf_id(firmware *fw) {
 916     // ID of the file buffer appears to be 5 for r43-r52
 917     if(fw->dryos_ver >= 43 && fw->dryos_ver <= 52) {
 918         return 5;
 919     } else {
 920         return 4;
 921     }
 922 }
 923 
 924 // Special case for get_ptp_file_buf
 925 int find_get_ptp_file_buf(firmware *fw, __attribute__ ((unused))string_sig *sig, int j)
 926 {
 927     /*
 928      * looking for
 929      * MOV r0,#ptp_file_buf_id
 930      * bl get_ptp_buf_size
 931      * bic r1, r0, #1
 932      * MOV r0,#ptp_file_buf_id
 933      * bl sub...
 934     */
 935     if(!(isMOV_immed(fw,j)
 936         && (fwRn(fw,j) == 0)
 937         && isBL(fw,j+1)
 938         && ((fwval(fw,j+2) & 0xFFF00000) == 0xe3C00000) // BIC
 939         && (ALUop2(fw,j+2) == 1)
 940         && isMOV_immed(fw,j+3)
 941         && (fwRn(fw,j+3) == 0)
 942         && isBL(fw,j+4))) {
 943         return 0;
 944     }
 945     uint32_t file_buf_id = get_ptp_file_buf_id(fw);
 946     if(ALUop2(fw,j) != file_buf_id || ALUop2(fw,j+3) != file_buf_id) {
 947         return 0;
 948     }
 949     uint32_t f1 = followBranch(fw,idx2adr(fw,j+1),0x01000001);
 950     int i = get_saved_sig(fw,"get_ptp_buf_size");
 951     // if sig not found, end search completely
 952     if(i < 0) {
 953         // fprintf(stderr,"find_get_ptp_file_buf func missing @0x%08x\n",idx2adr(fw,j));
 954         return 1;
 955     }
 956     if(f1 != func_names[i].val) {
 957         // fprintf(stderr,"find_get_ptp_file_buf func mismatch @0x%08x\n",idx2adr(fw,j));
 958         return 0;
 959     }
 960 
 961     // search backwards for push
 962     int k = find_inst_rev(fw, isSTMFD_LR, j-1, 8);
 963     if(k < 0) {
 964         // fprintf(stderr,"find_get_ptp_file_buf failed to find push @0x%08x\n",idx2adr(fw,j));
 965         return 0;
 966     }
 967     // functions could have a MOV, LDR etc before the push, but not seen for this function
 968     uint32_t fadr = idx2adr(fw, k);
 969     fwAddMatch(fw,fadr,32,0,121);
 970     // fprintf(stderr,"find_get_ptp_file_buf match @0x%08x\n",fadr);
 971 
 972     return 1;
 973 }
 974 
 975 // Special case for 'closedir'
 976 int find_closedir(firmware *fw)
 977 {
 978     int j = get_saved_sig(fw,"OpenFastDir");
 979     if (j >= 0)
 980     {
 981         int k = find_inst(fw, isSTMFD_LR, adr2idx(fw,func_names[j].val)+1, 100);
 982         if (isB(fw,k-1) && isBL(fw,k-2))
 983         {
 984             uint32_t fadr = followBranch(fw, idx2adr(fw, k-2), 0x01000001);
 985             fwAddMatch(fw,fadr,32,0,121);
 986             return 1;
 987         }
 988     }
 989 
 990     return 0;
 991 }
 992 
 993 int find_GetTimeFromRTC_and_more(firmware *fw, int i)
 994 {
 995     int j = fw->main_offs;
 996     int k = -1;
 997     while (j < fw->size)
 998     {
 999         if (isLDR(fw, j) && LDR2val(fw, j) == 0x7FE8177F)
1000         {
1001             if (i == 2)
1002             {
1003                 k = find_inst(fw, isBL, j+1, 6);
1004                 if (k > j)
1005                 {
1006                     k = adr2idx(fw, followBranch(fw, idx2adr(fw, k), 0x01000001));
1007                     uint32_t fadr = idx2adr(fw, k);
1008                     fwAddMatch(fw,fadr,32,0,122); // SetValidSystemCalender
1009                     return 1;
1010                 }
1011             }
1012             k = find_Nth_inst(fw, isBL, j+1, 6, 2);
1013             break;
1014         }
1015         j++;
1016     }
1017     if (k > j)
1018     {
1019         k = adr2idx(fw, followBranch(fw, idx2adr(fw, k), 0x01000001));
1020         j = find_inst(fw, isBLEQ, k+1, 30);
1021         if (j != -1) // newer cam
1022         {
1023             if (i == 0)
1024             {
1025                 j = adr2idx(fw, followBranch(fw, idx2adr(fw, j), 0xe1000001));
1026                 uint32_t fadr = idx2adr(fw, j);
1027                 fwAddMatch(fw,fadr,32,0,122); // GetTimeFromRTC
1028                 return 1;
1029             }
1030             k = find_Nth_inst_rev(fw, isBL, j-1, 14, 2);
1031             j = adr2idx(fw, followBranch(fw, idx2adr(fw, k), 0x01000001));
1032             if (!isSTMFD_LR(fw,j))
1033             {
1034                 uint32_t fadr = idx2adr(fw, j);
1035                 fwAddMatch(fw,fadr,32,0,122); // GetValidSystemCalender
1036                 return 1;
1037             }
1038             return 0;
1039         }
1040         k = find_Nth_inst(fw, isBL, k+1, 20, 2);
1041         if (k == -1)
1042         {
1043             return 0;
1044         }
1045         j = adr2idx(fw, followBranch2(fw, idx2adr(fw, k), 0x01000001)); // followBranch2 to support s110
1046         if (isSTMFD_LR(fw,j))
1047         {
1048             k = find_inst(fw, isBL, k+1, 8);
1049             if (k == -1)
1050             {
1051                 return 0;
1052             }
1053             j = adr2idx(fw, followBranch(fw, idx2adr(fw, k), 0x01000001));
1054         }
1055         if (isSTMFD_LR(fw,j))
1056         {
1057             return 0;
1058         }
1059         if (i == 1) // GetValidSystemCalender (ixus30/40, sic)
1060         {
1061             uint32_t fadr = idx2adr(fw, j);
1062             fwAddMatch(fw,fadr,32,0,122);
1063             return 1;
1064         }
1065         k = find_inst(fw, isBL, k+1, 8);
1066         if (k == -1)
1067         {
1068             return 0;
1069         }
1070         j = adr2idx(fw, followBranch(fw, idx2adr(fw, k), 0x01000001));
1071         if (i == 0 && isSTMFD_LR(fw,j)) // GetTimeFromRTC
1072         {
1073             uint32_t fadr = idx2adr(fw, j);
1074             fwAddMatch(fw,fadr,32,0,122);
1075             return 1;
1076         }
1077     }
1078 
1079     return 0;
1080 }
1081 
1082 int find_arm_cache_funcs(firmware *fw, int ii)
1083 {
1084     static int cfe=0, ccfd=0, cfr=0, ccfr=0, ccr=0;
1085     static int beenhere = 0;
1086     int i, j=0;
1087     if (!beenhere)
1088     {
1089         beenhere++;
1090         if (ii != 2)
1091         {
1092             j = get_saved_sig(fw,"cache_flush_range");
1093         }
1094         if (j >= 0 && cfr == 0)
1095         {
1096             cfr = adr2idx(fw,func_names[j].val);
1097             i = cfr - 1;
1098             while (i > cfr - 0x100)
1099             {
1100                 if (fwval(fw,i) == 0xe3500000) // cmp r0, #0
1101                 {
1102                     if (ccfd == 0)
1103                     {
1104                         ccfd = i;
1105                     }
1106                     else if (cfe == 0)
1107                     {
1108                         cfe = i;
1109                         break;
1110                     }
1111                 }
1112                 i--;
1113             }
1114             i = cfr + 1;
1115             while (i < cfr + 0x140)
1116             {
1117                 if (fwval(fw,i) == 0xe3500000) // cmp r0, #0
1118                 {
1119                     if (ccfr == 0)
1120                     {
1121                         ccfr = i;
1122                     }
1123                     else if (ccr == 0)
1124                     {
1125                         ccr = i;
1126                         break;
1127                     }
1128                 }
1129                 i++;
1130             }
1131         }
1132         else if (ccr == 0)
1133         {
1134             if (ii != 4)
1135             {
1136                 j = get_saved_sig(fw,"cache_clean_range");
1137             }
1138             if (j >= 0)
1139             {
1140                 ccr = adr2idx(fw,func_names[j].val);
1141                 i = ccr - 1;
1142                 while (i > ccr - 0x300)
1143                 {
1144                     if (fwval(fw,i) == 0xe3500000) // cmp r0, #0
1145                     {
1146                         if (ccfr == 0)
1147                         {
1148                             ccfr = i;
1149                         }
1150                         else if (cfr == 0)
1151                         {
1152                             cfr = i;
1153                         }
1154                         else if (ccfd == 0)
1155                         {
1156                             ccfd = i;
1157                         }
1158                         else if (cfe == 0)
1159                         {
1160                             cfe = i;
1161                             break;
1162                         }
1163                     }
1164                     i--;
1165                 }
1166             }
1167         }
1168     }
1169     if (cfe&&ccfd&&cfr&&ccfr&&ccr)
1170     {
1171         i = 0;
1172         switch (ii)
1173         {
1174             case 0: i = cfe; break;
1175             case 1: i = ccfd; break;
1176             case 2: i = cfr; break;
1177             case 3: i = ccfr; break;
1178             case 4: i = ccr; break;
1179         }
1180         uint32_t fadr = idx2adr(fw, i);
1181         fwAddMatch(fw,fadr,32,0,122);
1182         return 1;
1183     }
1184 
1185     return 0;
1186 }
1187 
1188 int find_arm_cache_funcs2(firmware *fw, int ii)
1189 {
1190     static int ife=0, idf=0, dfe=0, dcfd=0, dfr=0, dcr=0, dcfr=0, ifr=0;
1191     static int beenhere = 0;
1192     int i, j=0;
1193     if (!beenhere)
1194     {
1195         beenhere++;
1196         j = get_saved_sig(fw,"dcache_flush_range");
1197         if (j >= 0 && dfr == 0)
1198         {
1199             dfr = adr2idx(fw,func_names[j].val);
1200             i = dfr - 1;
1201             while (i > dfr - 0x100)
1202             {
1203                 if (fwval(fw,i) == 0xe10f3000) // mrs r3, cpsr
1204                 {
1205                     if (dcfd == 0)
1206                     {
1207                         dcfd = i;
1208                     }
1209                     else if (dfe == 0)
1210                     {
1211                         dfe = i;
1212                     }
1213                     else if (idf == 0)
1214                     {
1215                         idf = i;
1216                     }
1217                     else if (ife == 0)
1218                     {
1219                         ife = i;
1220                         break;
1221                     }
1222                 }
1223                 i--;
1224             }
1225             i = dfr + 1;
1226             while (i < dfr + 0x140)
1227             {
1228                 if (fwval(fw,i) == 0xe3510a02) // cmp r1, #0x2000
1229                 {
1230                     if (dcr == 0)
1231                     {
1232                         dcr = i;
1233                     }
1234                     else if (dcfr == 0)
1235                     {
1236                         dcfr = i;
1237                     }
1238                     else if (ifr == 0)
1239                     {
1240                         ifr = i;
1241                         break;
1242                     }
1243                 }
1244                 i++;
1245             }
1246         }
1247     }
1248     if (ife&&idf&&dfe&&dcfd&&dfr&&dcr&&dcfr&&ifr)
1249     {
1250         i = 0;
1251         switch (ii)
1252         {
1253             case 0: i = ife; break;
1254             case 1: i = idf; break;
1255             case 2: i = dfe; break;
1256             case 3: i = dcfd; break;
1257             case 4: i = dcr; break;
1258             case 5: i = dcfr; break;
1259             case 6: i = ifr; break;
1260         }
1261         uint32_t fadr = idx2adr(fw, i);
1262         fwAddMatch(fw,fadr,32,0,122);
1263         return 1;
1264     }
1265 
1266     return 0;
1267 }
1268 
1269 int find_IsWirelessConnect(firmware *fw, __attribute__ ((unused))int ii)
1270 {
1271     // matches might pick up the wrong function if wifi not present
1272     if(!cam_has_wifi) {
1273         return 0;
1274     }
1275     if (fw->dryos_ver < 53) {
1276         int j = find_str_ref(fw,"WiFiDisconnect");
1277         if(j < 0) {
1278             return 0;
1279         }
1280         int k = find_Nth_inst_rev(fw, isBL, j-1, 5, 1);
1281         if(k < 0) {
1282             return 0;
1283         }
1284         uint32_t fadr = followBranch(fw, idx2adr(fw, k), 0x01000001);
1285         fwAddMatch(fw,fadr,32,0,122);
1286         return 1;
1287     } else {
1288         int j = find_str_ref(fw,"USBDisconnect");
1289         if(j < 0) {
1290             return 0;
1291         }
1292         int k = find_Nth_inst_rev(fw, isBL, j-1, 5, 1);
1293         if(k < 0) {
1294             return 0;
1295         }
1296         uint32_t fadr = followBranch(fw, idx2adr(fw, k), 0x01000001);
1297         fwAddMatch(fw,fadr,32,0,122);
1298         return 1;
1299     }
1300     return 0;
1301 }
1302 
1303 // Special case for 'get_fstype'
1304 int find_get_fstype(firmware *fw)
1305 {
1306     int j = get_saved_sig(fw,"OpenFastDir");
1307     if (j >= 0)
1308     {
1309         int k = find_Nth_inst(fw, isBL, adr2idx(fw,func_names[j].val)+1, 6, 2);
1310         if (k > 0)
1311         {
1312             // sanity check 1
1313             if ( (fwval(fw, k+1) & 0xffff0fff) != 0xe1b00000 ) // movs rx, r0
1314                 return 0;
1315             // sanity check 2
1316             uint32_t cmpinst = ((fwval(fw, k+1) & 0x0000f000)<<4) + 0xe3500004; // cmp rx, #4
1317             int l;
1318             int m = 0;
1319             for (l=0; l<32; l++)
1320             {
1321                 if ( fwval(fw, k+1+l) == cmpinst )
1322                     m++;
1323             }
1324             if (m != 2)
1325                 return 0;
1326             // confirmed
1327             uint32_t fadr = followBranch(fw, idx2adr(fw, k), 0x01000001);
1328             fwAddMatch(fw,fadr,32,0,122);
1329             return 1;
1330         }
1331     }
1332 
1333     return 0;
1334 }
1335 
1336 // Special case for 'Restart'
1337 int find_Restart(firmware *fw)
1338 {
1339     int j = get_saved_sig(fw,"reboot_fw_update");
1340     if (j >= 0)
1341     {
1342         int k = get_saved_sig(fw,"StopWDT_FW");
1343         if (k >= 0)
1344         {
1345             j = adr2idx(fw, func_names[j].val);
1346             int i;
1347             for (i=j+1; i<j+100; i++)
1348             {
1349                 if (isBL(fw,i) && isBL(fw,i+2))
1350                 {
1351                     // find call to StopWDT_FW
1352                     uint32_t fadr = followBranch(fw, idx2adr(fw, i), 0x01000001);
1353                     if (func_names[k].val == fadr)
1354                     {
1355                         fadr = followBranch(fw, idx2adr(fw, i+2), 0x01000001);
1356                         fwAddMatch(fw,fadr,32,0,122);
1357                         return 1;
1358                     }
1359                 }
1360             }
1361         }
1362     }
1363 
1364     return 0;
1365 }
1366 
1367 // Special case for 'add_ptp_handler'
1368 int find_add_ptp_handler(firmware *fw, __attribute__ ((unused))string_sig *sig, int k)
1369 {
1370     uint32_t vals[] = { 0x9801, 0x9802, 0x9803, 0x9804, 0x9805, 0 };
1371     uint32_t fadr = 0;
1372 
1373     int i = 0;
1374     while ((vals[i] != 0) && isLDR_PC(fw,k) && (fwRd(fw,k) == 0) && (LDR2val(fw,k) == vals[i]))
1375     {
1376         k = find_inst(fw, isBL, k+1, 5);
1377         if (k == -1) return 0;
1378         if (fadr == 0)
1379             fadr = followBranch(fw, idx2adr(fw,k), 0x01000001);
1380         k = find_inst(fw, isLDR_PC, k+1, 5);
1381         i++;
1382         if (k == -1 && vals[i] != 0) return 0;
1383     }
1384 
1385     if (fadr != 0)
1386     {
1387         fwAddMatch(fw,fadr,32,0,121);
1388         return 1;
1389     }
1390 
1391     return 0;
1392 }
1393 
1394 // Special case for 'PT_PlaySound'
1395 int find_PT_PlaySound(firmware *fw)
1396 {
1397     int j, k;
1398     int k1 = get_saved_sig(fw,"LogCameraEvent");
1399 
1400     if (k1 >= 0)
1401     {
1402         j = find_str_ref(fw,"BufAccBeep");
1403         if (j >= 0)
1404         {
1405             k = find_inst(fw, isBL, j+1, 4);
1406             if (k >= 0)
1407             {
1408                 uint32_t fadr = followBranch(fw, idx2adr(fw,k), 0x01000001);
1409                 if (func_names[k1].val == fadr)
1410                 {
1411                     k = find_inst(fw, isB, k+1, 10);
1412                     fadr = followBranch(fw, idx2adr(fw, k), 1);
1413                     fwAddMatch(fw,fadr,32,0,122);
1414                     return 1;
1415                 }
1416             }
1417         }
1418     }
1419 
1420     return 0;
1421 }
1422 
1423 // Special case for 'getImageDirName'
1424 int find_getImageDirName(firmware *fw)
1425 {
1426     int k = find_str_ref(fw,"%3d_%02d%02d");
1427     if (k >= 0)
1428     {
1429         k = find_inst_rev(fw, isLDMFD_PC, k-1, 16);
1430         if (k >= 0)
1431         {
1432             uint32_t fadr = idx2adr(fw,k+1);
1433             fwAddMatch(fw,fadr,32,0,122);
1434             return 1;
1435         }
1436     }
1437     else
1438     {
1439         k = find_str_ref(fw,"___%02d");
1440         if (k >= 0)
1441         {
1442             k = find_inst_rev(fw, isLDMFD_PC, k-1, 18);
1443             if (k >= 0)
1444             {
1445                 if (isMOV(fw,k+1) && isMOV(fw,k+2)) // sanity check
1446                 {
1447                     uint32_t fadr = idx2adr(fw,k+1);
1448                     fwAddMatch(fw,fadr,32,0,122);
1449                     return 1;
1450                 }
1451             }
1452         }
1453     }
1454 
1455     return 0;
1456 }
1457 
1458 // Special case for 'GetImageFolder'
1459 uint32_t strGIF = 0;
1460 int match_GetImageFolder(firmware *fw, int k, uint32_t a_getImageDirName, uint32_t a_TakeSemaphore)
1461 {
1462     int k1, fnd;
1463 
1464     if (isBL(fw,k))
1465     {
1466         uint32_t fadr = followBranch2(fw,idx2adr(fw,k),0x01000001);
1467         if (fadr == a_getImageDirName)
1468         {
1469             int s = find_inst_rev(fw, isSTMFD_LR, k-1, 80);
1470             int e = find_inst(fw, isLDMFD_PC, k+1, 80);
1471             if ((s >= 0) && (e >= 0))
1472             {
1473                 fnd = 0;
1474                 for (k1=s+1; k1<k-1; k1++)
1475                 {
1476                     if (isBL(fw,k1))
1477                     {
1478                         fadr = followBranch2(fw,idx2adr(fw,k1),0x01000001);
1479                         if (fadr == a_TakeSemaphore)
1480                         {
1481                             fnd++;
1482                             break;
1483                         }
1484                     }
1485                 }
1486                 if (fnd != 0)
1487                 {
1488                     for (k1=k+1; k1<e-1; k1++)
1489                     {
1490                         if ((isLDR_PC(fw,k1) || isADR_PC(fw,k1)) && (idx2adr(fw,k1) == strGIF))
1491                         {
1492                             fnd--;
1493                             break;
1494                         }
1495                     }
1496                 }
1497                 if (fnd != 0)
1498                 {
1499                     fwAddMatch(fw,idx2adr(fw,s),32,0,122);
1500                     return 1;
1501                 }
1502             }
1503         }
1504     }
1505     return 0;
1506 }
1507 int find_GetImageFolder(firmware *fw)
1508 {
1509     int j = find_str_ref(fw,"GetCameraObjectTmpPath ERROR[ID:%lx] [TRY:%lx]\n");
1510     if (j < 0)
1511         j = find_str_ref(fw,"_GetCameraObjectTmpPath ERROR[ID:%lx] [TRY:%lx]\n");
1512     if (j >= 0)
1513     {
1514         strGIF = idx2adr(fw,j);
1515         int j = get_saved_sig(fw,"TakeSemaphore");
1516         int k = get_saved_sig(fw,"getImageDirName");
1517         if ((k >= 0) && (j >= 0))
1518         {
1519             return search_fw(fw, match_GetImageFolder, func_names[k].val, func_names[j].val, 1);
1520         }
1521     }
1522 
1523     return 0;
1524 }
1525 
1526 // Special case for 'GetDrive_ClusterSize'
1527 int match_GetDrive_ClusterSize(firmware *fw, int k, uint32_t v1, __attribute__ ((unused))uint32_t v2)
1528 {
1529     if (isBL_cond(fw,k))
1530     {
1531         uint32_t fadr = followBranch2(fw,idx2adr(fw,k),0xF1000001);
1532         if (fadr == v1)
1533         {
1534             int fnd = 0;
1535             if (isLDR_cond(fw,k-1) && idx_valid(fw,adr2idx(fw,LDR2val(fw,k-1))) && (strcmp(adr2ptr(fw,LDR2val(fw,k-1)),"Mounter.c") == 0))
1536             {
1537                 fnd = 1;
1538             }
1539             else if (isLDR_cond(fw,k-2) && idx_valid(fw,adr2idx(fw,LDR2val(fw,k-2))) && (strcmp(adr2ptr(fw,LDR2val(fw,k-2)),"Mounter.c") == 0))
1540             {
1541                 fnd = 1;
1542             }
1543             else if (isLDR_cond(fw,k-3) && idx_valid(fw,adr2idx(fw,LDR2val(fw,k-3))) && (strcmp(adr2ptr(fw,LDR2val(fw,k-3)),"Mounter.c") == 0))
1544             {
1545                 fnd = 1;
1546             }
1547             else if (isADR_PC_cond(fw,k-1) && (strcmp(adr2ptr(fw,ADR2adr(fw,k-1)),"Mounter.c") == 0))
1548             {
1549                 fnd = 1;
1550             }
1551             else if (isADR_PC_cond(fw,k-2) && (strcmp(adr2ptr(fw,ADR2adr(fw,k-2)),"Mounter.c") == 0))
1552             {
1553                 fnd = 1;
1554             }
1555             if ((fnd == 1) &&
1556                 isLDR_PC(fw,k+1) &&
1557                 ((fwval(fw,k+2) & 0xFFF00FF0) == 0xE0800200) && ((fwval(fw,k+3) & 0xFFF00FF0) == 0xE0800100) &&
1558                 (fwval(fw,k+4) == 0xE5901004) && (fwval(fw,k+5) == 0xE5900008) && (fwval(fw,k+6) == 0xE0000091) &&
1559                 isLDMFD_PC(fw,k+7))
1560             {
1561                 k = find_inst_rev(fw,isSTMFD_LR,k-1,8);
1562                 if (k >= 0)
1563                 {
1564                     if (fwval(fw,k-1) == 0xE3500001)    // CMP R0, #1
1565                         k--;
1566                     fwAddMatch(fw,idx2adr(fw,k),32,0,122);
1567                     return 1;
1568                 }
1569             }
1570         }
1571     }
1572 
1573     return 0;
1574 }
1575 int find_GetDrive_ClusterSize(firmware *fw)
1576 {
1577     int k = get_saved_sig(fw,"DebugAssert");
1578     if (k >= 0)
1579     {
1580         return search_fw(fw, match_GetDrive_ClusterSize, func_names[k].val, 0, 16);
1581     }
1582 
1583     return 0;
1584 }
1585 
1586 int find_GetDrive_TotalClusters(firmware *fw)
1587 {
1588     extern uint32_t find_str_bytes(firmware *fw, char *str);
1589     // restrict usage (we rely on a function preceding a string)
1590     if (fw->dryos_ver < 52)
1591         return 0;
1592     uint32_t j = find_str_bytes(fw,"DriveLetterManager.c");
1593     if (j > 0)
1594     {
1595         int k = adr2idx(fw,j);
1596         k = find_inst_rev(fw,isLDMFD_PC,k-1,2);
1597         if ((k > 0) && ( (fwval(fw,k-1)&0xfffff0f0)==0xe0810090 )) // umull r0, r1, rx, ry
1598         {
1599             if (isBL(fw,k-2))
1600             {
1601                 k = idxFollowBranch(fw,k-2,0x01000001);
1602                 fwAddMatch(fw,idx2adr(fw,k),32,0,122);
1603                 return 1;
1604             }
1605         }
1606     }
1607 
1608     return 0;
1609 }
1610 
1611 // Special case for srand
1612 int find_srand(firmware *fw)
1613 {
1614     int k = get_saved_sig(fw,"rand");
1615     if (k >= 0)
1616     {
1617         k = adr2idx(fw, func_names[k].val) - 3;
1618         if (isLDR_PC(fw,k) && isSTR(fw,k+1) && isBX_LR(fw,k+2))
1619             fwAddMatch(fw,idx2adr(fw,k),32,0,122);
1620     }
1621 
1622     return 0;
1623 }
1624 
1625 int find_malloc_strictly(firmware *fw)
1626 {
1627 
1628     int s1 = find_str(fw,"Size: %ld");
1629     int s2 = find_str(fw,"Memory.c");
1630     int f1 = get_saved_sig(fw,"malloc");
1631     if ((s1 < 0)||(s2 < 0)||(f1 < 0))
1632         return 0;
1633     if (s1 < s2-16) // the two strings should be close
1634         s1 = find_Nth_str(fw,"Size: %ld",2); // this string has multiple instances, try the next one
1635     f1 = adr2idx(fw, func_names[f1].val);
1636 
1637     int r1 = find_nxt_str_ref(fw, s1, 0);
1638     int r2 = find_nxt_str_ref(fw, s2, 0);
1639     int l1 = 0;
1640     while((r1>0) && (r2>0) && (l1<2))
1641     {
1642         if (r2 == r1 + 3)
1643         {
1644             int m1 = find_inst_rev(fw,isBL,r1,6);
1645             if (m1 > 0)
1646             {
1647                 int m2 = idxFollowBranch(fw,m1,0x01000001);
1648                 if (m2 == f1)
1649                 {
1650                     m1 = find_inst_rev(fw,isSTMFD_LR,m1,3);
1651                     if (m1 > 0)
1652                     {
1653                         fwAddMatch(fw,idx2adr(fw,m1),32,0,122);
1654                         return 1;
1655                     }
1656                 }
1657             }
1658         }
1659         r1 = find_nxt_str_ref(fw, s1, r1+1);
1660         r2 = find_nxt_str_ref(fw, s2, r2+1);
1661         l1++;
1662     }
1663     return 0;
1664 }
1665 
1666 static int idx_createdialogbox=-1, idx_displaydialogbox=-1, idx_adduitodialog=-1, idx_getstring=-1;
1667 
1668 int find_DisplayBusyOnScreen(firmware *fw)
1669 {
1670 
1671     int s1 = find_str(fw,"ErrorMessageController.c");
1672     int s2 = find_str(fw,"StrMan.c");
1673     if (s1 < 0)
1674         s1 = find_str(fw,"MessageController.c");
1675     int j = find_str_ref(fw,"_PBBusyScrn");
1676     if (j < 0)
1677         j = find_str_ref(fw,"_PlayBusyScreen");
1678 
1679     if ((j>=0)&&(s1>=0)&&(s2>=0))
1680     {
1681         int m1 = find_Nth_inst(fw,isBL,j+1,12,fw->dryos_ver<54?4:fw->dryos_ver==59?2:3);
1682         int m2, k;
1683 
1684         if (fw->dryos_ver == 58)
1685         {
1686             // 1st B after str ref branches to DisplayBusyOnScreen
1687             m1 = find_inst(fw,isB,j+1,12);
1688             if (m1 > 0)
1689             {
1690                 m2 = idxFollowBranch(fw,m1,0x00000001);
1691                 k = find_nxt_str_ref(fw, s1, m2);
1692             }
1693             else
1694             {
1695                 return 0;
1696             }
1697         }
1698         else if (fw->dryos_ver == 57)
1699         {
1700             // these functions are called indirectly in this part of fw on r57
1701             int found = 0;
1702             for (k=-1; k>-3; k--)
1703             {
1704                 if ((fwval(fw,m1+k) & 0xFE1FF000) == 0xE41F0000) // ldr r0, =func
1705                 {
1706                     uint32_t u1 = LDR2val(fw, m1+k);
1707                     if ( u1 > fw->base )
1708                     {
1709                         if (isSTMFD_LR(fw, adr2idx(fw, u1)))
1710                         {
1711                             found = 1;
1712                             m2 = adr2idx(fw, u1);
1713                             k = find_nxt_str_ref(fw, s1, m2);
1714                             break;
1715                         }
1716                     }
1717                 }
1718             }
1719             if (!found)
1720             {
1721                 return 0;
1722             }
1723         }
1724         else
1725         {
1726             m2 = idxFollowBranch(fw,m1,0x01000001);
1727             k = find_nxt_str_ref(fw, s1, m2);
1728             if ((k <= 0)||(k-m2 >= 22))
1729             {
1730                 // not found, try the next BL
1731                 m1 = find_inst(fw,isBL,m1+1,4);
1732                 m2 = idxFollowBranch(fw,m1,0x01000001);
1733                 k = find_nxt_str_ref(fw, s1, m2);
1734             }
1735         }
1736 
1737 
1738         if ((k > 0)&&(k-m2 < 22))
1739         {
1740             // the string is referenced near enough
1741             idx_createdialogbox = find_inst_rev(fw, isBL, k-1, 4);
1742             // DisplayBusyOnScreen is found
1743             fwAddMatch(fw,idx2adr(fw,m2),32,0,122);
1744             // find additional stuff
1745             idx_adduitodialog = find_inst(fw, isBL, k+1, 7);
1746             int m3;
1747             for (m3=k; m3<k+128; m3++)
1748             {
1749                 // mov r0, #imm or ldr r0, [pc,... between two BLs
1750                 if (isBL(fw,m3)&&isBL(fw,m3+2)&&
1751                     (((fwval(fw,m3+1)&0xfffff000)==0xe3a00000)||((fwval(fw,m3+1)&0xff7ff000)==0xe51f0000)))
1752                 {
1753                     // further check
1754                     int m30 = m3+2;
1755                     int m4 = idxFollowBranch(fw,m30,0x01000001);
1756                     if (m4 > 0)
1757                     {
1758                         // search for ref. to assert string
1759                         int m5 = find_inst(fw, isLDMFD_PC, m4+1, 64);
1760                         int m6 = find_nxt_str_ref(fw, s2, m4);
1761                         if ((m6 > 0)&&(m6 < m5))
1762                         {
1763                             idx_getstring = m30;
1764                             break;
1765                         }
1766                         // no string, search for reference to 0x00000020 (string consisting of a single space char)
1767                         m5 = find_inst(fw, isADR_PC, m4+1, 10);
1768                         if (m5>0)
1769                         {
1770                             uint32_t u1 = ADR2adr(fw, m5);
1771                             if (fwval(fw, adr2idx(fw, u1)) == 0x00000020)
1772                             {
1773                                 idx_getstring = m30;
1774                                 break;
1775                             }
1776                         }
1777                     }
1778                 }
1779             }
1780             if (fw->dryos_ver < 54)
1781             {
1782                 m3 = find_inst(fw, isLDMFD_PC, k+30, 64);
1783                 if (m3>0)
1784                 {
1785                     m3 = find_Nth_inst_rev(fw, isBL, m3-1, 8, 2);
1786                     if (m3>0)
1787                     {
1788                         idx_displaydialogbox = m3;
1789                     }
1790                 }
1791             }
1792             else
1793             {
1794                 m3 = find_inst(fw, isLDMFD, k+30, 20);
1795                 if (m3>0)
1796                 {
1797                     m3 = find_inst_rev(fw, isBL, m3-1, 4);
1798                     if (m3>0)
1799                     {
1800                         idx_displaydialogbox = m3;
1801                     }
1802                 }
1803             }
1804             return 1;
1805         }
1806     }
1807 
1808     return 0;
1809 }
1810 
1811 int find_UndisplayBusyOnScreen(firmware *fw)
1812 {
1813     if (get_saved_sig(fw,"DisplayBusyOnScreen") < 0) return 0;
1814     int j;
1815     if (fw->dryos_ver > 57)
1816     {
1817         j = find_str_ref(fw,"_PBBusyScrnToCtrlSrvTask");
1818     }
1819     else
1820     {
1821         j = find_str_ref(fw,"_PBBusyScrn");
1822     }
1823     if (j < 0)
1824         j = find_str_ref(fw,"_PlayBusyScreen");
1825 
1826     if (fw->dryos_ver < 57)
1827     {
1828         if (idx_createdialogbox > 0)
1829         {
1830             int m;
1831             for (m=0; m<2; m++)
1832             {
1833                 int n = find_Nth_inst(fw, isSTMFD_LR, idx_createdialogbox + 30, 140, m+1);
1834                 if (n>0)
1835                 {
1836                     uint32_t a1 = idx2adr(fw,n);
1837                     if (j > 0)
1838                     {
1839                         int k;
1840                         for (k=j; k<j+24; k++)
1841                         {
1842                             if (isBL_cond(fw,k)&&(idx2adr(fw,idxFollowBranch(fw,k,0xe1000001))==a1)) // BLEQ
1843                             {
1844                                 fwAddMatch(fw,a1,32,0,122);
1845                                 return 1;
1846                             }
1847                         }
1848                     }
1849                 }
1850             }
1851         }
1852     }
1853     else
1854     {
1855         int m1 = find_Nth_inst(fw,isBLEQ,j+1,20,1);
1856         if (m1 > 0)
1857         {
1858             // these functions are called indirectly in this part of fw on r57+
1859             int k;
1860             for (k=-1; k>-3; k--)
1861             {
1862                 if ((fwval(fw,m1+k) & 0xFE1FF000) == 0x041F0000) // ldreq r0, =func
1863                 {
1864                     uint32_t u1 = LDR2val(fw, m1+k);
1865                     if ( u1 > fw->base )
1866                     {
1867                         if (isSTMFD_LR(fw, adr2idx(fw, u1)))
1868                         {
1869                             fwAddMatch(fw,u1,32,0,122);
1870                             return 1;
1871                         }
1872                     }
1873                 }
1874             }
1875         }
1876     }
1877     return 0;
1878 }
1879 // TODO: redundant functions follow
1880 int find_CreateDialogBox(firmware *fw)
1881 {
1882     if (get_saved_sig(fw,"DisplayBusyOnScreen") < 0) return 0;
1883     if (idx_createdialogbox > 0)
1884     {
1885         int n = idxFollowBranch(fw,idx_createdialogbox,0x01000001);
1886         if (n>0)
1887         {
1888             fwAddMatch(fw,idx2adr(fw,n),32,0,122);
1889             return 1;
1890         }
1891     }
1892     return 0;
1893 }
1894 int find_DisplayDialogBox(firmware *fw)
1895 {
1896     if (get_saved_sig(fw,"DisplayBusyOnScreen") < 0) return 0;
1897     if (idx_displaydialogbox > 0)
1898     {
1899         int n = idxFollowBranch(fw,idx_displaydialogbox,0x01000001);
1900         if (n>0)
1901         {
1902             fwAddMatch(fw,idx2adr(fw,n),32,0,122);
1903             return 1;
1904         }
1905     }
1906     return 0;
1907 }
1908 int find_add_ui_to_dialog(firmware *fw)
1909 {
1910     if (get_saved_sig(fw,"DisplayBusyOnScreen") < 0) return 0;
1911     if (idx_adduitodialog > 0)
1912     {
1913         int n = idxFollowBranch(fw,idx_adduitodialog,0x01000001);
1914         if (n>0)
1915         {
1916             fwAddMatch(fw,idx2adr(fw,n),32,0,122);
1917             return 1;
1918         }
1919     }
1920     return 0;
1921 }
1922 int find_get_string_by_id(firmware *fw)
1923 {
1924     if (get_saved_sig(fw,"DisplayBusyOnScreen") < 0) return 0;
1925     if (idx_getstring > 0)
1926     {
1927         int n = idxFollowBranch(fw,idx_getstring,0x01000001);
1928         if (n>0)
1929         {
1930             fwAddMatch(fw,idx2adr(fw,n),32,0,122);
1931             return 1;
1932         }
1933     }
1934     return 0;
1935 }
1936 
1937 int find_get_self_task_errno_pointer(firmware *fw)
1938 {
1939     int f1 = get_saved_sig(fw,"malloc");
1940     int f2 = get_saved_sig(fw,"close");
1941     if ((f1<0) && (f2<0))
1942         return 0;
1943     f1 = adr2idx(fw, func_names[f1].val);
1944     f1 = find_inst(fw, isLDMFD_PC, f1, 24);
1945     if (f1>0)
1946     {
1947         f1 = find_inst_rev(fw, isBL, f1, 6);
1948         if (f1>0)
1949         {
1950             if (fwval(fw,f1+2) == 0xe5801000) // str r1, [r0]
1951             {
1952                 f1 = idxFollowBranch(fw,f1,0x01000001);
1953                 fwAddMatch(fw,idx2adr(fw,f1),32,0,122);
1954                 return 1;
1955             }
1956         }
1957     }
1958     // older cams don't set errno on malloc failure
1959     f1 = adr2idx(fw, func_names[f2].val);
1960     f1 = find_Nth_inst(fw, isBL, f1, 8, 2); // second BL
1961     if (f1>0)
1962     {
1963         if (fwval(fw,f1+2) == 0xe5801000) // str r1, [r0]
1964         {
1965             f1 = idxFollowBranch(fw,f1,0x01000001);
1966             fwAddMatch(fw,idx2adr(fw,f1),32,0,122);
1967             return 1;
1968         }
1969     }
1970     return 0;
1971 }
1972 
1973 int find_get_nd_value(firmware *fw)
1974 {
1975 
1976     int f1 = get_saved_sig(fw,"PutInNdFilter_FW");
1977     int f2 = get_saved_sig(fw,"ClearEventFlag");
1978     int f3 = find_saved_sig("get_nd_value");
1979     if ((f3 >= 0) && (func_names[f3].val != 0)) // return if func already found
1980         return 0;
1981     if ((f1 < 0) || (f2 < 0))
1982         return 0;
1983     f1 = adr2idx(fw, func_names[f1].val);
1984     f2 = adr2idx(fw, func_names[f2].val);
1985     int k1 = find_Nth_inst(fw,isBL,f1,10,2);
1986     int k2 = find_inst(fw,isBL,f1,6);
1987     if ((k1 == -1) || (k2 == -1))
1988         return 0;
1989     // note for the following line: same address can have different index on cams with multiple fw regions
1990     // followBranch2 is for veneer support (s110)
1991     if ( followBranch2(fw,idx2adr(fw,k2),0x01000001) != idx2adr(fw,f2) ) // ClearEventFlag?
1992         return 0;
1993     k1 = idxFollowBranch(fw,k1,0x01000001); // PutInNdFilter_low
1994     k2 = find_inst(fw,isBL,k1,6);
1995     if (k2 == -1)
1996         return 0;
1997     // check for signs of other functions (GetUsableAvRange, etc)
1998     int k3;
1999     int k4 = 0;
2000     for (k3=k2-1;k3>k2-3;k3--)
2001     {
2002         uint32_t v1 = fwval(fw, k3);
2003         k4 += (v1 == 0xe28d0004)?1:(v1 == 0xe1a0100d)?4: // add r0,sp,#4 ; mov r1,sp - GetUsableAvRange
2004               ((v1 & 0xffffff00) == 0xe3a00000)?0x10:0; // mov r0, #small_imm - sx400
2005     }
2006     if (k4 == 0) // probably get_nd_value
2007     {
2008         k2 = idxFollowBranch(fw,k2,0x01000001);
2009         fwAddMatch(fw,idx2adr(fw,k2),32,0,122);
2010         return 1;
2011     }
2012 
2013     return 0;
2014 }
2015 
2016 // for cams with both ND and iris
2017 int find_get_current_nd_value_iris(firmware *fw)
2018 {
2019     // match is only for cams with both, task is mostly a good indicator
2020     if(get_saved_sig(fw,"task_Nd") < 0 || get_saved_sig(fw,"task_IrisEvent") < 0) {
2021         return 0;
2022     }
2023     int f1 = get_saved_sig(fw,"get_current_exp");
2024     if(f1 < 0)
2025         return 0;
2026 
2027     f1 = adr2idx(fw, func_names[f1].val);
2028     int blcnt, i;
2029     // expect
2030     // bleq DebugAssert
2031     // followed by 5 bl with other instruction between
2032     // looking for 5th
2033     for(i=0, blcnt=0; i<16 && blcnt < 7; i++) {
2034         if(!blcnt) {
2035             if(isBL_cond(fw,f1+i)) {
2036                 blcnt++;
2037             } else if(isBL(fw,f1+i)) {
2038                 return 0;
2039             }
2040             continue;
2041         }
2042         if(!isBL(fw,f1+i)) {
2043             continue;
2044         }
2045         blcnt++;
2046         if(blcnt == 6) {
2047             int f2 = idxFollowBranch(fw,f1+i,0x01000001);
2048             // non-ND cameras have a call to return 0
2049             if(isMOV(fw,f2) && (fwRd(fw,f2) == 0) && (fwOp2(fw,f2) == 0)) // MOV R0, 0
2050                 return 0;
2051             // veneer (might be better to require veneer)
2052             if(isB(fw,f2)) {
2053                 f2 = idxFollowBranch(fw,f2,0x00000001);
2054             }
2055             fwAddMatch(fw,idx2adr(fw,f2),32,0,122);
2056             return 1;
2057         }
2058     }
2059     return 0;
2060 }
2061 
2062 int find_get_current_nd_value(firmware *fw)
2063 {
2064 
2065     // string only present on ND-only cameres
2066     if(find_str(fw, "IrisSpecification.c") < 0) {
2067         return find_get_current_nd_value_iris(fw);
2068     }
2069 
2070     int f1 = get_saved_sig(fw,"GetCurrentAvValue");
2071     if(f1 < 0)
2072         return 0;
2073 
2074     f1 = adr2idx(fw, func_names[f1].val);
2075     // expect
2076     // adreq r0, "IrisController.c"
2077     // bleq DebugAssert
2078     // bl j_get_current_nd_value
2079     int sadr = find_str(fw, "IrisController.c");
2080     int j = find_nxt_str_ref(fw, sadr, f1);
2081     if (j < 0)
2082         return 0;
2083 
2084     if(isBL_cond(fw,j+1) && isBL(fw,j+2)) {
2085         f1 = idxFollowBranch(fw,j+2,0x01000001);
2086         // veneer
2087         if(isB(fw,f1)) {
2088             f1 = idxFollowBranch(fw,f1,0x00000001);
2089         }
2090         fwAddMatch(fw,idx2adr(fw,f1),32,0,122);
2091         return 1;
2092     }
2093 
2094     return 0;
2095 }
2096 
2097 // get live view "DeltaSV" value
2098 int find_get_current_deltasv(firmware *fw)
2099 {
2100     int f1 = get_saved_sig(fw,"get_current_exp");
2101     if(f1 < 0)
2102         return 0;
2103 
2104     f1 = adr2idx(fw, func_names[f1].val);
2105     int blcnt, i;
2106     // expect
2107     // bleq DebugAssert
2108     // followed by at least 3 bl with other instructions between
2109     // looking for 3rd
2110     for(i=0, blcnt=0; i<16 && blcnt < 4; i++) {
2111         if(!blcnt) {
2112             if(isBL_cond(fw,f1+i)) {
2113                 blcnt++;
2114             } else if(isBL(fw,f1+i)) {
2115                 return 0;
2116             }
2117             continue;
2118         }
2119         if(!isBL(fw,f1+i)) {
2120             continue;
2121         }
2122         blcnt++;
2123         if(blcnt == 4) {
2124             int f2 = idxFollowBranch(fw,f1+i,0x01000001);
2125             // veneer?
2126             if(isB(fw,f2)) {
2127                 f2 = idxFollowBranch(fw,f2,0x00000001);
2128             }
2129             fwAddMatch(fw,idx2adr(fw,f2),32,0,122);
2130             return 1;
2131         }
2132     }
2133     return 0;
2134 }
2135 
2136 
2137 int find_getcurrentmachinetime(firmware *fw)
2138 {
2139     int f1 = get_saved_sig(fw,"SetHPTimerAfterTimeout");
2140     if (f1 < 0)
2141         return 0;
2142     f1 = adr2idx(fw, func_names[f1].val);
2143     f1 = find_inst(fw, isBL, f1, 16);
2144     if (f1>0)
2145     {
2146         f1 = idxFollowBranch(fw,f1,0x01000001);
2147         fwAddMatch(fw,idx2adr(fw,f1),32,0,122);
2148         return 1;
2149     }
2150     return 0;
2151 }
2152 
2153 // for cases where method 15 fails (sx170)
2154 int find_sethptimeraftertimeout(firmware *fw)
2155 {
2156     int sadr = find_str(fw, "FrameRateGenerator.c");
2157     int j = find_nxt_str_ref(fw, sadr, -1);
2158     if (j < 0)
2159         return 0;
2160     int f1, f2, n;
2161     for (n=0; n<2; n++)
2162     {
2163         f1 = find_inst_rev(fw, isBL, j-1, 7);
2164         f2 = find_Nth_inst_rev(fw, isBL, j-1, 128, 2);
2165         // check whether previous BL is too close
2166         if ((f1 < 1) || (f1-f2<8))
2167         {
2168             j = find_nxt_str_ref(fw, sadr, j+1);
2169             if (j < 0)
2170                 return 0;
2171         }
2172         else
2173         {
2174             f1 = idxFollowBranch(fw,f1,0x01000001);
2175             fwAddMatch(fw,idx2adr(fw,f1),32,0,122);
2176             return 1;
2177         }
2178     }
2179     return 0;
2180 }
2181 
2182 uint32_t frsp_buf = 0;
2183 uint32_t frsp_buf_at = 0;
2184 int frsp_param = -1;
2185 int frsp_argcnt = 0;
2186 int find_DoMovieFrameCapture(firmware *fw)
2187 {
2188     void add_func_name(char*, uint32_t, char*);
2189     // we need the uncached bit
2190     int match_CAM_UNCACHED_BIT(firmware*, int, int);
2191     search_saved_sig(fw, "FreeUncacheableMemory", match_CAM_UNCACHED_BIT, 0, 0, 8);
2192 
2193     int j = get_saved_sig(fw,"SetImageMode");
2194     if (j < 0)
2195         return 0;
2196     j = adr2idx(fw, func_names[j].val);
2197     int k = 0;
2198     int k1 = 0;
2199     int l = j + 20;
2200     while (j < l)
2201     {
2202         j = find_inst(fw, isBL, j+1, 20);
2203         if (j == -1)
2204             break;
2205         int j1 = idxFollowBranch(fw,j,0x01000001);
2206         if (j != j1)
2207         {
2208             int j2;
2209             for (j2=j1; j2<j1+6; j2++)
2210             {
2211                 if ((fwval(fw,j2) & 0xFF000000) == 0x1A000000) // bne
2212                 {
2213                     int j3 = idxFollowBranch(fw,j2,0xF1000001);
2214                     if (j3-j2>0 && j3-j2<5)
2215                     {
2216                         if (isBL(fw,j3))
2217                         {
2218                             // buffer adr is embedded in routine, evaluate later
2219                             k = idxFollowBranch(fw,j3,0x01000001);
2220                             fwAddMatch(fw,idx2adr(fw,k),32,0,122);
2221                             // add_func_name("DoMovieFrameCapture_helper1", idx2adr(fw,k), ""); // for visual verification
2222                             k1 = 1;
2223                             break;
2224                         }
2225                         else
2226                         {
2227                             // buffer and param are func args, evaluate here
2228                             int m = 0;
2229                             while (m < 4)
2230                             {
2231                                 if ((fwval(fw,j3+m) & 0xFE1F0000) == 0xE41F0000) // ldr rx,
2232                                 {
2233                                     frsp_argcnt = fwRd(fw,j3+m) + 1; // this should be loaded in the right register directly
2234                                     frsp_buf = LDR2val(fw,j3+m);
2235                                     frsp_buf_at = idx2adr(fw,j3+m);
2236                                     if (!((frsp_buf > fw->uncached_adr) &&
2237                                           (fw->uncached_adr+fw->maxram))) // has to be uncached ram
2238                                         frsp_buf = 0;
2239                                 }
2240                                 if ((fwval(fw,j3+m) & 0xFFF00000) == 0xE3A00000) // mov rx,
2241                                 {
2242                                     uint32_t u1 = ALUop2a(fw,j3+m);
2243                                     if (u1>fw->uncached_adr && u1<(fw->uncached_adr+fw->maxram))
2244                                     {
2245                                         frsp_buf = u1;
2246                                         frsp_buf_at = idx2adr(fw,j3+m);
2247                                         frsp_argcnt = fwRd(fw,j3+m) + 1; // this should be loaded in the right register directly
2248                                     }
2249                                     else
2250                                     {
2251                                         frsp_param = u1;
2252                                     }
2253                                 }
2254                                 if (isBL(fw,j3+m))
2255                                 {
2256                                     k = idxFollowBranch(fw,j3+m,0x01000001);
2257                                     fwAddMatch(fw,idx2adr(fw,k),32,0,122);
2258                                     // add_func_name("DoMovieFrameCapture_helper2", idx2adr(fw,j1), ""); // for visual verification
2259                                     break;
2260                                 }
2261                                 m++;
2262                             }
2263                             if (k)
2264                                 break;
2265                         }
2266                     }
2267                 }
2268             }
2269             if (k)
2270                 break;
2271         }
2272     }
2273     if (k && k1)
2274     {
2275         k1 = k+1;
2276         while (k1>0 && k1<k+20)
2277         {
2278             if (isLDR_PC(fw,k1))
2279             {
2280                 uint32_t v = LDR2val(fw,k1);
2281                 if (v>fw->uncached_adr && v<fw->uncached_adr+fw->maxram && (v&3)==0)
2282                 {
2283                     frsp_buf = v;
2284                     frsp_param = 0;
2285                     frsp_buf_at = idx2adr(fw,k1);
2286                     break;
2287                 }
2288             }
2289             k1++;
2290         }
2291     }
2292     if (k)
2293         return 1;
2294     return 0;
2295 }
2296 
2297 int find_get_ptp_buf_size(firmware *fw)
2298 {
2299     int j = get_saved_sig(fw,"handle_PTP_OC_SendObject"); // same handler as CANON_SendObjectByPath
2300     if(j < 0) {
2301         // fprintf(stderr,"find_get_ptp_buf_size missing handle_PTP_OC_SendObject\n");
2302         return 0;
2303     }
2304     int k=adr2idx(fw,func_names[j].val);
2305     int k_max=k+80;
2306     uint32_t adr=0;
2307     uint32_t file_buf_id=get_ptp_file_buf_id(fw);
2308 
2309     for(; k < k_max;k++) {
2310         // look for
2311         // mov r0,#file_buf_id
2312         // bl ...
2313         if(isMOV_immed(fw,k) && fwRn(fw,k) == 0 && ALUop2(fw,k) == file_buf_id && isBL(fw, k+1)) {
2314             adr = followBranch(fw,idx2adr(fw,k+1),0x01000001);
2315             // fprintf(stderr,"find_get_ptp_buf_size match 1 0x%08x @0x%08x\n",adr,idx2adr(fw,k+1));
2316             break;
2317         }
2318     }
2319     if(!adr) {
2320         // fprintf(stderr,"find_get_ptp_buf_size no match\n");
2321         return 0;
2322     }
2323     // look for same seq again, within 6 ins
2324     k_max = k+6;
2325     for(; k < k_max;k++) {
2326         if(isMOV_immed(fw,k) && fwRn(fw,k) == 0 && ALUop2(fw,k) == file_buf_id && isBL(fw, k+1)) {
2327             uint32_t adr2 = followBranch(fw,idx2adr(fw,k+1),0x01000001);
2328             // is it the same address?
2329             if(adr2 == adr) {
2330                 // fprintf(stderr,"find_get_ptp_buf_size match 2 @0x%08x\n",idx2adr(fw,k+1));
2331                 fwAddMatch(fw,adr,32,0,122);
2332                 return 0;
2333             }
2334             // fprintf(stderr,"find_get_ptp_buf_size match 2 mismatch 0x%08x != 0x%08x @0x%08x\n",adr,adr2,idx2adr(fw,k+1));
2335         }
2336     }
2337     return 0;
2338 }
2339 
2340 int find_GetBaseSv(firmware *fw)
2341 {
2342     int j = get_saved_sig(fw,"SetPropertyCase");
2343     if (j < 0)
2344         return 0;
2345     j = adr2idx(fw, func_names[j].val);
2346 
2347     int sadr = find_str(fw, "Sensitive.c");
2348     if (sadr < fw->lowest_idx)
2349         return 0;
2350     int s1 = find_nxt_str_ref(fw, sadr, -1/*fw->lowest_idx*/);
2351     int hist[3] = {0, 0, 0};
2352     while (s1 >= 0)
2353     {
2354         hist[2] = hist[1];
2355         hist[1] = hist[0];
2356         hist[0] = s1;
2357         if (hist[0] && hist[1] && hist[2])
2358         {
2359             if ((hist[0]-hist[1]<6) && (hist[1]-hist[2]<7))
2360             {
2361                 int n;
2362                 for (n=s1+1; n<s1+26; n++)
2363                 {
2364                     if ( isBL(fw, n) )
2365                     {
2366                         int k;
2367                         k = idxFollowBranch(fw,n,0x01000001);
2368                         if ( idx2adr(fw, k) == idx2adr(fw, j) )
2369                         {
2370                             // SetPropertyCase call found
2371                             k = find_inst(fw, isBL, s1+2, 6);
2372                             if (k != -1)
2373                             {
2374                                 // first BL following BLEQ DebugAssert
2375                                 int l = idxFollowBranch(fw,k,0x01000001);
2376                                 if ( isB(fw, l) )
2377                                 {
2378                                     // in most cases there's a veneer (exception: sx1)
2379                                     void add_func_name(char*, uint32_t, char*);
2380                                     k = idxFollowBranch(fw,l,0x01000001);
2381                                     if ( isB(fw, k) )
2382                                     {
2383                                         int m = idxFollowBranch(fw,k,0x01000001);
2384                                         add_func_name("j_j_GetBaseSv", idx2adr(fw,l), "");
2385                                         add_func_name("j_GetBaseSv", idx2adr(fw,k), "");
2386                                         fwAddMatch(fw,idx2adr(fw,m),32,0,122);
2387                                     }
2388                                     else
2389                                     {
2390                                         add_func_name("j_GetBaseSv", idx2adr(fw,l), "");
2391                                         fwAddMatch(fw,idx2adr(fw,k),32,0,122);
2392                                     }
2393                                 }
2394                                 else
2395                                 {
2396                                     fwAddMatch(fw,idx2adr(fw,l),32,0,122);
2397                                 }
2398                                 return 1;
2399                             }
2400                         }
2401                     }
2402                 }
2403             }
2404         }
2405         s1 = find_nxt_str_ref(fw, sadr, s1+1);
2406     }
2407 
2408     return 0;
2409 }
2410 
2411 int find_Remove(firmware *fw)
2412 {
2413     int f1 = get_saved_sig(fw,"Close");
2414     if(f1 < 0)
2415         return 0;
2416 
2417     f1 = adr2idx(fw, func_names[f1].val);
2418     int f2, blcnt, i;
2419     f2 = find_str_ref(fw,"File Write Fail.");
2420     if(f2 == -1)
2421         return 0;
2422     // looking for 1st bl after Close
2423     for(i=1, blcnt=0; i<8 && blcnt < 2; i++) {
2424         if(!isBL(fw,f2+i)) {
2425             continue;
2426         }
2427         // is it Close?
2428         if(idxFollowBranch(fw,f2+i,0x01000001)==f1) {
2429             blcnt++;
2430             continue;
2431         }
2432         else if(idxFollowBranch(fw,idxFollowBranch(fw,f2+i,0x01000001),0x01000001)==f1) {
2433             blcnt++;
2434             continue;
2435         }
2436         if (blcnt == 1) {
2437             f2 = idxFollowBranch(fw,f2+i,0x01000001);
2438             fwAddMatch(fw,idx2adr(fw,f2),32,0,122);
2439             return 1;
2440         }
2441     }
2442     return 0;
2443 }
2444 
2445 int find_dispatch_funcs(firmware *fw, int param)
2446 {
2447     int f1;
2448     if (param==0) {
2449         f1= get_saved_sig(fw,"EnableDispatch_low");
2450     }
2451     else if (param==1) {
2452         f1= get_saved_sig(fw,"DisableDispatch_low");
2453     }
2454     else {
2455         return 0;
2456     }
2457     if(f1 < 0)
2458         return 0;
2459 
2460     f1 = adr2idx(fw, func_names[f1].val);
2461     int r0, r1, cnt;
2462     r0 = find_str(fw,"Booting"); // for sx230 (extra task on a few models)
2463     if (r0 == -1) {
2464         r0 = find_str(fw,"Startup"); // locating taskcreate_Startup
2465         r1 = find_str(fw,"Startup.c");
2466         if (r0 == r1) { // for s5is
2467             r0 = find_Nth_str(fw,"Startup",2);
2468         }
2469     }
2470     r0 = find_nxt_str_ref(fw,r0,r0-1024);
2471     if(r0 < 0)
2472         return 0;
2473     r0 = adr2idx(fw,idx2adr(fw,r0)); // needed on cams with code copied to RAM
2474     cnt = 0;
2475     while (r0!=-1 && cnt<5) {
2476         r0 = find_inst_rev(fw,isBL,r0-1,10);
2477         int b1 = idxFollowBranch(fw,r0,0x01000001);
2478         b1 = adr2idx(fw,idx2adr(fw,b1)); // needed on cams with code copied to RAM
2479         if (isLDR_PC(fw,b1)) { // for s110
2480             b1 = idxFollowBranch(fw,b1,0x01000001);
2481         }
2482         if (param==0) { // EnableDispatch
2483             r1 = find_nxt_str_ref_alt(fw, "KerSys.c", b1, 24);
2484             int i1 = find_inst(fw,isLDMFD_PC,b1,24);
2485             if (r1!=-1 && i1>r1) {
2486                 int j1 = find_Nth_inst(fw,isBL,b1,24,1);
2487                 if (j1 != -1) {
2488                     if (idx2adr(fw,idxFollowBranch(fw,j1,0x01000001))==idx2adr(fw,f1)) {
2489                         fwAddMatch(fw,idx2adr(fw,b1),32,0,122);
2490                         return 1;
2491                     }
2492                 }
2493             }
2494         }
2495         else if (param==1) { // DisableDispatch
2496             int c = 1;
2497             while (c<3) {
2498                 int b2 = find_Nth_inst(fw,isBL,b1,12,c);
2499                 if (b2 == -1) {
2500                     break;
2501                 }
2502                 b2 = idxFollowBranch(fw,b2,0x01000001);
2503                 b2 = adr2idx(fw,idx2adr(fw,b2)); // needed on cams with code copied to RAM
2504                 r1 = find_nxt_str_ref_alt(fw, "KerSys.c", b2, 24);
2505                 int i1 = find_inst(fw,isLDMFD_PC,b2,24);
2506                 if (r1!=-1 && i1>r1) {
2507                     int j1 = find_Nth_inst(fw,isBL,b2,24,1);
2508                     if (j1 != -1) {
2509                         if (idx2adr(fw,idxFollowBranch(fw,j1,0x01000001))==idx2adr(fw,f1)) {
2510                             fwAddMatch(fw,idx2adr(fw,b2),32,0,122);
2511                             return 1;
2512                         }
2513                     }
2514                 }
2515                 c++;
2516             }
2517         }
2518         cnt++;
2519     }
2520     return 0;
2521 }
2522 
2523 //------------------------------------------------------------------------------------------------------------
2524 
2525 // Data for matching the '_log' function
2526 uint32_t log_test[] = {
2527     0x1526E50E, 0x3FDBCB7B, 0
2528 };
2529 
2530 // Data for matching 'Fut' functions
2531 uint32_t DeleteDirectory_Fut_test[] = { 0x09400017 };
2532 uint32_t MakeDirectory_Fut_test[]   = { 0x09400015 };
2533 uint32_t RenameFile_Fut_test[]      = { 0x09400013 };
2534 
2535 //------------------------------------------------------------------------------------------------------------
2536 
2537 // Signature matching data
2538 string_sig string_sigs[] =
2539 {
2540     // Same as previously found eventproc - do these first
2541     {20, "AllocateMemory", "AllocateMemory_FW", 1 },
2542     {20, "Close", "Close_FW", 1 },
2543     {20, "CreateCountingSemaphore", "CreateCountingSemaphore_FW", 1 },
2544     {20, "CreateTask", "CreateTask_FW", 1 },
2545     {20, "DeleteSemaphore", "DeleteSemaphore_FW", 1 },
2546     {20, "DispCon_ShowBitmapColorBar", "DispCon_ShowBitmapColorBar_FW", 1 },
2547     {20, "ExitTask", "ExitTask_FW", 1 },
2548     {20, "Fclose_Fut", "Fclose_Fut_FW", 1 },
2549     {20, "Fopen_Fut", "Fopen_Fut_FW", 1 },
2550     {20, "Fread_Fut", "Fread_Fut_FW", 1 },
2551     {20, "FreeMemory", "FreeMemory_FW", 1 },
2552     {20, "Fseek_Fut", "Fseek_Fut_FW", 1 },
2553     {20, "Fwrite_Fut", "Fwrite_Fut_FW", 1 },
2554     {20, "GetSDProtect", "GetSDProtect_FW", 1 },
2555     {20, "GetSystemTime", "GetSystemTime_FW", 1 },
2556     {20, "GetCurrentAvValue", "GetCurrentAvValue_FW", 1 },
2557     {20, "GetCurrentShutterSpeed", "GetCurrentShutterSpeed_FW", 1 },
2558     {20, "GetUsableMaxAv", "GetUsableMaxAv_FW", 1 },
2559     {20, "GetUsableMinAv", "GetUsableMinAv_FW", 1 },
2560     {20, "GetOpticalTemperature", "GetOpticalTemperature_FW", 1 },
2561     {20, "GetVRAMHPixelsSize", "GetVRAMHPixelsSize_FW", 1 },
2562     {20, "GetVRAMVPixelsSize", "GetVRAMVPixelsSize_FW", 1 },
2563     {20, "GetZoomLensCurrentPoint", "GetZoomLensCurrentPoint_FW", 1 },
2564     {20, "GiveSemaphore", "GiveSemaphore_FW", 1 },
2565     {20, "GUISrv_StartGUISystem", "GUISrv_StartGUISystem_FW", 1 },
2566     {20, "LEDDrive", "LEDDrive_FW", 1 },
2567     {20, "LockMainPower", "LockMainPower_FW", 1 },
2568     {20, "lseek", "Lseek_FW", 1 },
2569     {20, "Lseek", "Lseek_FW", 1 },
2570     {20, "MoveIrisWithAv", "MoveIrisWithAv_FW", 1 },
2571     {20, "MoveZoomLensWithPoint", "MoveZoomLensWithPoint_FW", 1 },
2572     {20, "memcmp", "memcmp_FW", 1 },
2573     {20, "memcpy", "memcpy_FW", 1 },
2574     {20, "memset", "memset_FW", 1 },
2575     {20, "NewTaskShell", "NewTaskShell_FW", 1 },
2576     {20, "NR_GetDarkSubType", "NR_GetDarkSubType_FW", 1 },
2577     {20, "NR_SetDarkSubType", "NR_SetDarkSubType_FW", 1 },
2578     {20, "Open", "Open_FW", 1 },
2579     {20, "PostLogicalEventForNotPowerType", "PostLogicalEventForNotPowerType_FW", 1 },
2580     {20, "PostLogicalEventToUI", "PostLogicalEventToUI_FW", 1 },
2581     {20, "PT_MoveDigitalZoomToWide", "PT_MoveDigitalZoomToWide_FW", 1 },
2582     {20, "PT_MoveOpticalZoomAt", "PT_MoveOpticalZoomAt_FW", 1 },
2583     {20, "Read", "Read_FW", 1 },
2584     {20, "RefreshPhysicalScreen", "RefreshPhysicalScreen_FW", 1 },
2585     {20, "ResetFocusLens", "ResetFocusLens_FW", 1 },
2586     {20, "ResetZoomLens", "ResetZoomLens_FW", 1 },
2587     {20, "SavePaletteData", "SavePaletteData_FW", 1 },
2588     {20, "SetAutoShutdownTime", "SetAutoShutdownTime_FW", 1 },
2589     {20, "SetCurrentCaptureModeType", "SetCurrentCaptureModeType_FW", 1 },
2590     {20, "SetDate", "SetDate_FW", 1 },
2591     {20, "SetScriptMode", "SetScriptMode_FW", 1 },
2592     {20, "SleepTask", "SleepTask_FW", 1 },
2593     {20, "strcmp", "j_strcmp_FW", 0 },
2594     {20, "strcmp", "strcmp_FW", 0 },
2595     {20, "strcpy", "strcpy_FW", 1 },
2596     {20, "strlen", "strlen_FW", 1 },
2597     {20, "StartRecModeMenu", "StartRecModeMenu_FW", 1 },
2598     {20, "TakeSemaphore", "TakeSemaphore_FW", 1 },
2599     {20, "UIFS_WriteFirmInfoToFile", "UIFS_WriteFirmInfoToFile_FW", 1 },
2600     {20, "UnlockMainPower", "UnlockMainPower_FW", 1 },
2601     {20, "VbattGet", "VbattGet_FW", 1 },
2602     //{20, "write", "Write_FW", 1 },
2603     {20, "Write", "Write_FW", 1 },
2604     {20, "task_CaptSeq", "task_CaptSeqTask", 1 },
2605     {20, "task_ExpDrv", "task_ExpDrvTask", 1 },
2606     {20, "task_FileWrite", "task_FileWriteTask", 1 },
2607     {20, "task_RotaryEncoder", "task_JogDial", 1 },
2608     {20, "task_RotaryEncoder", "task_RotarySw", 1 },
2609     {20, "TurnOnDisplay", "DispCon_TurnOnDisplay_FW", 0 },
2610     {20, "TurnOffDisplay", "DispCon_TurnOffDisplay_FW", 0 },
2611     {20, "DoAELock", "PT_DoAELock_FW", 0x01000002 },
2612     {20, "DoAELock", "SS.DoAELock_FW", 0x01000002 },
2613     {20, "DoAFLock", "PT_DoAFLock_FW", 0x01000002 },
2614     {20, "DoAFLock", "SS.DoAFLock_FW", 0x01000002 },
2615     {20, "UnlockAE", "PT_UnlockAE_FW", 0x01000002 },
2616     {20, "UnlockAE", "SS.UnlockAE_FW", 0x01000002 },
2617     {20, "UnlockAF", "PT_UnlockAF_FW", 0x01000002 },
2618     {20, "UnlockAF", "SS.UnlockAF_FW", 0x01000002 },
2619     {20, "MFOn", "MFOn_FW", 1 },
2620     {20, "MFOff", "MFOff_FW", 1 },
2621     {20, "PT_MFOn", "PT_MFOn_FW", 1 },
2622     {20, "PT_MFOff", "PT_MFOff_FW", 1 },
2623     {20, "SS_MFOn", "SS.MFOn_FW", 1 },
2624     {20, "SS_MFOff", "SS.MFOff_FW", 1 },
2625     {20, "SetLogicalEventActive", "UiEvnt_SetLogicalEventActive_FW", 1 },
2626     {20, "GetAdChValue", "GetAdChValue_FW", 0 },
2627     {20, "CalcLog10", "CalcLog10_FW", 4 },
2628     {20, "HwOcReadICAPCounter", "GetCurrentMachineTime", 1 },
2629     {20, "DisableISDriveError", "DisableISDriveError_FW", 1},
2630     {20, "SetImageMode", "SetImageMode_FW", 0x01000002 },
2631     {20, "GetVideoOutType", "GetVideoOutType_FW", 1},
2632     {20, "GetCurrentDriveBaseSvValue", "GetCurrentDriveBaseSvValue_FW", 0x01000002 },
2633 
2634     { 1, "ExportToEventProcedure_FW", "ExportToEventProcedure", 1 },
2635     { 1, "AllocateMemory", "AllocateMemory", 1 },
2636     { 1, "Close", "Close", 1 },
2637     { 1, "CreateTask", "CreateTask", 1 },
2638     //{ 1, "DoAFLock", "PT_DoAFLock", 0x01000002 },
2639     { 1, "ExitTask", "ExitTask", 1 },
2640     { 1, "exmem_alloc", "ExMem.AllocCacheable", 4 },
2641     { 1, "exmem_free", "ExMem.FreeCacheable", 0x01000003 },
2642     { 1, "exmem_ualloc", "ExMem.AllocUncacheable", 4 },
2643     { 1, "exmem_ufree", "ExMem.FreeUncacheable", 0x01000003 },
2644     { 1, "Fclose_Fut", "Fclose_Fut", 1 },
2645     { 1, "Feof_Fut", "Feof_Fut", 1 },
2646     { 1, "Fflush_Fut", "Fflush_Fut", 1 },
2647     { 1, "Fgets_Fut", "Fgets_Fut", 1 },
2648     { 1, "Fopen_Fut", "Fopen_Fut", 1 },
2649     { 1, "Fread_Fut", "Fread_Fut", 1 },
2650     { 1, "FreeMemory", "FreeMemory", 1 },
2651     { 1, "Fseek_Fut", "Fseek_Fut", 1 },
2652     { 1, "Fwrite_Fut", "Fwrite_Fut", 1 },
2653     { 1, "GetParameterData", "PTM_RestoreUIProperty", 0xF0000004 },
2654     { 1, "GetPropertyCase", "PT_GetPropertyCaseString", 1 },
2655     { 1, "GetPropertyCase", "PT_GetPropertyCaseInt", 0x0100000F },
2656     { 1, "GetPropertyCase", "GetPropertyCase", 0x0100000F },
2657     { 1, "GetSDProtect", "GetSDProtect", 1 },
2658     { 1, "GetSystemTime", "GetSystemTime", 1 },
2659     { 1, "LEDDrive", "LEDDrive", 1 },
2660     { 1, "LockMainPower", "LockMainPower", 1 },
2661     { 1, "Lseek", "Lseek", 1 },
2662     { 1, "lseek", "Lseek", 1 },
2663     { 1, "memcpy", "memcpy", 1 },
2664     { 1, "memcmp", "memcmp", 1 },
2665     { 1, "memset", "memset", 1 },
2666     { 1, "NewTaskShell", "NewTaskShell", 1 },
2667     { 1, "Open", "Open", 1 },
2668     { 1, "PostLogicalEventToUI", "PostLogicalEventToUI", 1 },
2669     { 1, "PostLogicalEventForNotPowerType", "PostLogicalEventForNotPowerType", 1 },
2670     //{ 1, "Read", "Read", 1 },
2671     //{ 1, "read", "Read", 1 },
2672     { 1, "RefreshPhysicalScreen", "RefreshPhysicalScreen", 1 },
2673     { 1, "SetAutoShutdownTime", "SetAutoShutdownTime", 1 },
2674     { 1, "SetCurrentCaptureModeType", "SetCurrentCaptureModeType", 1 },
2675     { 1, "SetLogicalEventActive", "UiEvnt_SetLogicalEventActive", 1 },
2676     { 1, "SetParameterData", "PTM_BackupUIProperty", 1 },
2677     { 1, "SetPropertyCase", "PT_SetPropertyCaseInt", 0x01000003 },
2678     { 1, "SetPropertyCase", "SetPropertyCase", 0x01000004 },
2679     { 1, "SetScriptMode", "SetScriptMode", 1 },
2680     { 1, "SleepTask", "SleepTask", 1 },
2681     { 1, "strcmp", "strcmp", 0 },
2682     { 1, "strcpy", "strcpy", 1 },
2683     { 1, "strlen", "strlen", 1 },
2684     { 1, "strtol", "atol", 3 },
2685     { 1, "TakeSemaphore", "TakeSemaphore", 1 },
2686     { 1, "UIFS_WriteFirmInfoToFile", "UIFS_WriteFirmInfoToFile", 1 },
2687     //{ 1, "UnlockAF", "PT_UnlockAF", 0x01000002 },
2688     { 1, "UnlockMainPower", "UnlockMainPower", 1 },
2689     { 1, "VbattGet", "VbattGet", 1 },
2690     //{ 1, "Write", "Write", 1 },
2691     //{ 1, "write", "Write", 1 },
2692     { 1, "GUISrv_StartGUISystem", "GUISrv_StartGUISystem", 1 },
2693 
2694     { 2, "GetBatteryTemperature", "GetBatteryTemperature", 1 },
2695     { 2, "GetCCDTemperature", "GetCCDTemperature", 1 },
2696     { 2, "GetOpticalTemperature", "GetOpticalTemperature", 1 },
2697     { 2, "GetFocusLensSubjectDistance", "GetCurrentTargetDistance", 1 },
2698     { 2, "GetZoomLensCurrentPoint", "GetZoomLensCurrentPoint", 1 },
2699     { 2, "GetZoomLensCurrentPosition", "GetZoomLensCurrentPosition", 1 },
2700     { 2, "MoveFocusLensToDistance", "MoveFocusLensToDistance", 1 },
2701     { 2, "MoveZoomLensWithPoint", "MoveZoomLensWithPoint", 1 },
2702     { 2, "GetCurrentAvValue", "GetCurrentAvValue", 1 },
2703     { 2, "PT_MoveOpticalZoomAt", "PT_MoveOpticalZoomAt", 1 },
2704     { 2, "PT_MoveOpticalZoomAt", "SS.MoveOpticalZoomAt", 1 },
2705     { 2, "PT_MoveDigitalZoomToWide", "PT_MoveDigitalZoomToWide", 1 },
2706     { 2, "PT_MoveDigitalZoomToWide", "SS.MoveDigitalZoomToWide", 1 },
2707     { 2, "MoveIrisWithAv", "MoveIrisWithAv", 1},
2708     { 2, "PutInNdFilter", "TurnOnNdFilter", 1 },
2709     { 2, "PutOutNdFilter", "TurnOffNdFilter", 1 },
2710     { 2, "PutInNdFilter", "PutInNdFilter", 1 },
2711     { 2, "PutOutNdFilter", "PutOutNdFilter", 1 },
2712     { 2, "IsStrobeChargeCompleted", "EF.IsChargeFull", 1 },
2713     { 2, "GetPropertyCase", "PT_GetPropertyCaseInt", 0x01000012 },
2714     { 2, "SetPropertyCase", "PT_SetPropertyCaseInt", 0x01000008 },
2715     { 2, "SetPropertyCase", "PT_SetPropertyCaseInt", 0x01000009 },
2716     //{ 2, "UnlockAF", "PT_UnlockAF", 0x01000002 },
2717     //{ 2, "UnlockAF", "SS.UnlockAF", 0x01000002 },
2718     //{ 2, "DoAFLock", "PT_DoAFLock", 0x01000002 },
2719     //{ 2, "DoAFLock", "SS.DoAFLock", 0x01000002 },
2720     { 2, "GetSystemTime", "PT_GetSystemTime", 0x01000003 },
2721     { 2, "PT_PlaySound", "PT_PlaySound", 0x01000005 },
2722     { 2, "StartRecModeMenu", "StartRecModeMenu", 1 },
2723     { 2, "GetSDProtect", "GetSDProtect", 1 },
2724     { 2, "DispCon_ShowBitmapColorBar", "DispCon_ShowBitmapColorBar", 1 },
2725     { 2, "SetAE_ShutterSpeed", "SetAE_ShutterSpeed", 1 },
2726     { 2, "ResetZoomLens", "ResetZoomLens", 1 },
2727     { 2, "ResetFocusLens", "ResetFocusLens", 1 },
2728     { 2, "NR_GetDarkSubType", "NR_GetDarkSubType", 1 },
2729     { 2, "NR_GetDarkSubType", "NRTBL.GetDarkSubType", 1 },
2730     { 2, "NR_SetDarkSubType", "NR_SetDarkSubType", 1 },
2731     { 2, "NR_SetDarkSubType", "NRTBL.SetDarkSubType", 1 },
2732     { 2, "SavePaletteData", "SavePaletteData", 1 },
2733     { 2, "GetVRAMHPixelsSize", "GetVRAMHPixelsSize", 1 },
2734     { 2, "GetVRAMVPixelsSize", "GetVRAMVPixelsSize", 1 },
2735     { 2, "EngDrvIn", "EngDrvIn", 2 },
2736     { 2, "EngDrvOut", "EngDrvOut", 0x01000005 },
2737     { 2, "EngDrvRead", "EngDrvRead", 2 },
2738     { 2, "EngDrvBits", "EngDrvBits", 0x01000007 },
2739     { 2, "EngDrvBits", "EngDrvBits", 0x01000005 },
2740     { 2, "exmem_alloc", "ExMem.AllocCacheable", 4 },
2741     { 2, "exmem_free", "ExMem.FreeCacheable", 0x01000003 },
2742     { 2, "exmem_ualloc", "ExMem.AllocUncacheable", 4 },
2743     { 2, "exmem_ufree", "ExMem.FreeUncacheable", 0x01000003 },
2744 
2745     { 2, "PTM_GetCurrentItem", "PTM_GetCurrentItem", 2 }, // s5is
2746     { 2, "PTM_SetCurrentItem", "PTM_SetCurrentItem", 4 }, // s5is
2747     { 2, "PTM_NextItem", "PTM_NextItem", 2 }, // s5is
2748     { 2, "PTM_PrevItem", "PTM_PrevItem", 2 }, // s5is
2749     { 2, "PTM_SetPropertyEnable", "PTM_SetProprietyEnable", 4 }, // s5is
2750 
2751     { 3, "AllocateMemory", "AllocateMemory", 1 },
2752     { 3, "FreeMemory", "FreeMemory", 1 },
2753     { 3, "PostLogicalEventToUI", "PostLogicalEventToUI", 1 },
2754     { 3, "PostLogicalEventForNotPowerType", "PostLogicalEventForNotPowerType", 1 },
2755     { 3, "LockMainPower", "LockMainPower", 1 },
2756     { 3, "UnlockMainPower", "UnlockMainPower", 1 },
2757     { 3, "SetAutoShutdownTime", "SetAutoShutdownTime", 1 },
2758     { 3, "NewTaskShell", "NewTaskShell", 1 },
2759     { 3, "VbattGet", "VbattGet", 1 },
2760     { 3, "LEDDrive", "LEDDrive", 1 },
2761     { 3, "SetPropertyCase", "PT_SetPropertyCaseInt", 0x01000003 },
2762     //{ 3, "UnlockAF", "PT_UnlockAF", 0x01000002 },
2763     //{ 3, "DoAFLock", "PT_DoAFLock", 0x01000002 },
2764     { 3, "UIFS_WriteFirmInfoToFile", "UIFS_WriteFirmInfoToFile", 1 },
2765     { 3, "PT_MoveOpticalZoomAt", "PT_MoveOpticalZoomAt", 1 },
2766     { 3, "PT_MoveDigitalZoomToWide", "PT_MoveDigitalZoomToWide", 1 },
2767     { 3, "PT_PlaySound", "PT_PlaySound", 1 },
2768     { 3, "exmem_alloc", "ExMem.AllocCacheable", 4 },
2769     { 3, "exmem_free", "ExMem.FreeCacheable", 0x01000003 },
2770     { 3, "exmem_ualloc", "ExMem.AllocUncacheable", 4 },
2771     { 3, "exmem_ufree", "ExMem.FreeUncacheable", 0x01000003 },
2772     { 3, "GetSDProtect", "GetSDProtect", 1 },
2773 
2774     { 4, "TurnOnBackLight", "TurnOnBackLight", 1 },
2775     { 4, "TurnOffBackLight", "TurnOffBackLight", 1 },
2776     { 4, "EnterToCompensationEVF", "SSAPI::EnterToCompensationEVF", 1 },
2777     { 4, "EnterToCompensationEVF", "ExpComp On", 1 },
2778     { 4, "EnterToCompensationEVF", "ExpOn", 1 },
2779     { 4, "ExitFromCompensationEVF", "SSAPI::ExitFromCompensationEVF", 1 },
2780     { 4, "ExitFromCompensationEVF", "ExpComp Off", 1 },
2781     { 4, "ExitFromCompensationEVF", "ExpOff", 1 },
2782     { 4, "PB2Rec", "AC:PB2Rec", 1 },
2783     { 4, "PB2Rec", "AC:PB2Rec", 6 },
2784     { 4, "PB2Rec", "AC:PB2Rec", 9 },
2785     { 4, "PB2Rec", "AC:PB2Rec", 11 },
2786     { 4, "Rec2PB", "AC:Rec2PB", 1 },
2787     { 4, "Rec2PB", "AC:Rec2PB", 2 },
2788     { 4, "RefreshPhysicalScreen", "ScreenUnLock", 1 },
2789     { 4, "RefreshPhysicalScreen", "ScreenUnLock", 7 },
2790     { 4, "RefreshPhysicalScreen", "ScreenUnLock", 15 },
2791     { 4, "RefreshPhysicalScreen", "Reduce ScreenUnLock", 5 },
2792     { 4, "RefreshPhysicalScreen", "Window:IneffectiveLockPhysicalScreen", 8 },
2793     { 4, "UnsetZoomForMovie", "ZoomCon_UnsetZoomForMovie", 1 },
2794     { 4, "ExpCtrlTool_StopContiAE", "StopContiAE", 9 },
2795     { 4, "ExpCtrlTool_StopContiAE", "StopContiAE", 10 },
2796     { 4, "ExpCtrlTool_StopContiAE", "StopContiAE", 11 },
2797     { 4, "ExpCtrlTool_StartContiAE", "StartContiAE", 9 },
2798     { 4, "ExpCtrlTool_StartContiAE", "StartContiAE", 10 },
2799     { 4, "ExpCtrlTool_StartContiAE", "StartContiAE", 11 },
2800     { 4, "ExecuteEventProcedure", "Can not Execute ", 14 },
2801 
2802     { 5, "UIFS_WriteFirmInfoToFile", "UIFS_WriteFirmInfoToFile", 1 },
2803     { 5, "CreateTask", "CreateTask", 1 },
2804     { 5, "hook_CreateTask", "CreateTask", 1 },
2805     { 5, "ExitTask", "ExitTask", 1 },
2806     { 5, "SleepTask", "SleepTask", 1 },
2807     { 5, "DeleteSemaphore", "DeleteSemaphore", 1 },
2808     { 5, "CreateCountingSemaphore", "CreateCountingSemaphore", 1 },
2809     //                                                                   R20   R23   R31   R39   R43   R45   R47   R49   R50   R51   R52   R54   R55   R57   R58   R59
2810     { 5, "UpdateMBROnFlash", "MakeBootDisk", 0x01000003,                  11,   11,   11,   11,   11,   11,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2811     { 5, "MakeSDCardBootable", "MakeBootDisk", 0x01000003,                 1,    1,    1,    1,    1,    1,    8,    8,    8,    8,    8,    9,    9,    9,    9,    9 },
2812 
2813     { 5, "PTM_GetCurrentItem", "PTM_GetCurrentItem", 1 },
2814     { 5, "PTM_SetCurrentItem", "PTM_SetCurrentItem", 1 },
2815     { 5, "PTM_NextItem", "PTM_NextItem", 1 },
2816     { 5, "PTM_PrevItem", "PTM_PrevItem", 1 },
2817     { 5, "PTM_SetPropertyEnable", "PTM_SetProprietyEnable", 1 },
2818 
2819     //{ 6, "Restart", "Bye", 0 },
2820     { 6, "reboot_fw_update", "FirmUpgrade.c", 0 },
2821 
2822     { 7, "CreateTaskStrictly", "PhySw", 0x01000001 },
2823     { 7, "CreateTaskStrictly_alt", "FsIoNotifyTask", 0x01000001 },
2824     { 7, "RegisterInterruptHandler", "WdtInt", 0x01000001 },
2825     { 7, "LogCameraEvent", "BufAccBeep", 0x01000001 },
2826     { 7, "LogCameraEvent", "MyCamFunc_PlaySound_MYCAM_COVER_OPEN", 0x01000001 },
2827     { 7, "DebugAssert", "Console.c", 0x01000001 },
2828     { 7, "exmem_assert", "Type < MAX_NUM_OF_EXMEMORY_TYPE", 0x01000001 },
2829 
2830     { 8, "WriteSDCard", "Mounter.c", 0 },
2831 
2832     // Ensure ordering in func_names is correct for dependencies here
2833     //                                                                   R20   R23   R31   R39   R43   R45   R47   R49   R50   R51   R52   R54   R55   R57   R58   R59
2834     { 9, "kbd_p1_f", "task_PhySw", 0,                                      5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5 },
2835     { 9, "kbd_p2_f", "task_PhySw", 0,                                      7,    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,    7 },
2836     { 9, "kbd_read_keys", "kbd_p1_f", 0,                                   2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2 },
2837     { 9, "kbd_p1_f_cont", "kbd_p1_f", -1,                                  3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3 },
2838     { 9, "kbd_read_keys_r2", "kbd_read_keys", 0,                          11,   11,   11,   11,   11,   11,   11,   11,   11,   11,   11,   11,   11,   11,   11,   11 },
2839     { 9, "GetKbdState", "kbd_read_keys", 0,                                8,    8,    8,    8,    8,    8,    8,    8,    8,    8,    8,    8,    8,    8,    8,    8 },
2840     { 9, "GetKbdState", "kbd_read_keys", 0,                                9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9 },
2841     { 9, "strtolx", "strtol", 0,                                           1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2842     { 9, "mkdir", "MakeDirectory_Fut", 0x01000001,                        17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17 },
2843     { 9, "mkdir", "MakeDirectory_Fut", 0x01000002,                        17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17 },
2844     { 9, "time", "MakeDirectory_Fut", 0,                                  12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12 },
2845     { 9, "stat", "_uartr_req", 0,                                          0,    0,    0,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4 },
2846     { 9, "PostMessageQueue", "PostMessageQueueStrictly", 0,                3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3 },
2847     { 9, "WaitForAnyEventFlag", "WaitForAnyEventFlagStrictly", 0,          3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3 },
2848     { 9, "WaitForAllEventFlag", "WaitForAllEventFlagStrictly", 0,          3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3 },
2849     { 9, "CreateMessageQueue", "CreateMessageQueueStrictly", 0,            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2850     { 9, "CreateRecursiveLock", "CreateRecursiveLockStrictly", 0,          1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2851     { 9, "CreateEventFlag", "CreateEventFlagStrictly", 0,                  1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2852     { 9, "_GetSystemTime", "GetSystemTime", 0,                             2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2 },
2853     { 9, "close", "Close", 0,                                              2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2 },
2854     { 9, "open", "Open", 0,                                                3,    3,    3,    3,   16,   16,   35,   35,   35,   35,   35,   35,   35,   35,   35,   35 },
2855     { 9, "open", "Open", 0,                                                3,    3,    3,   13,   16,   16,   35,   35,   35,   35,   35,   35,   35,   35,   35,   35 },
2856     { 9, "_divmod_signed_int", "PT_mod_FW", 0,                             4,    7,    7,    7,    7,    7,    6,    6,    6,    6,    6,    6,    6,    6,    6,    6 },
2857     { 9, "_divmod_signed_int", "PT_mod_FW", 0,                             0,    4,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0 },
2858     { 9, "_divmod_signed_int", "mod_FW", 0,                                0,    0,    0,    0,    0,    0,    0,    0,    0,    4,    4,    4,    4,    4,    4,    4 },
2859     { 9, "_divmod_unsigned_int", "SetTimerAfter", 0,                      23,   23,   23,   23,   23,   23,   23,   23,   23,   23,   23,    0,    0,    0,    0,    0 },
2860     { 9, "_divmod_unsigned_int", "DispCon_ShowWhiteChart_FW", 0,           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   15,   15,   15,   15,   13,   13 },
2861     { 9, "_divmod_unsigned_int", "DispCon_ShowWhiteChart_FW", 0,           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    8,    8,    8,    0,    0,    0 },
2862     { 9, "_dflt", "CalcLog10", 0,                                          9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9 },
2863     { 9, "_dfltu", "CalcLog10", 0,                                         4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4 },
2864     { 9, "_dmul", "CalcLog10", 0,                                         12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12 },
2865     { 9, "_dfix", "CalcLog10", 0,                                         14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14 },
2866     { 9, "_dadd", "_pow", 0,                                              26,   26,   26,   26,   26,   26,   29,   29,   29,   29,   29,   29,   29,   29,   29,   29 },
2867     { 9, "_dadd", "_pow", 0,                                               1,    1,    1,    1,    1,    1,   24,   24,    1,    1,    1,    1,    1,    1,    1,    1 }, // s100, sx230 (100c only...)
2868     { 9, "_scalbn", "_log", 0,                                            19,   19,   19,   19,   19,   19,   18,   18,   18,   18,   18,   18,   18,   18,   18,   18 },
2869     { 9, "_scalbn", "_log", 0,                                             1,    1,    1,    1,    1,    1,   14,   14,    1,    1,    1,    1,    1,    1,    1,    1 }, // s100, sx230 (100c only...)
2870     { 9, "_safe_sqrt", "CalcSqrt_FW", 0,                                   0,    0,   -3,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6 },
2871     { 9, "_ddiv", "ConvertApexStdToApex_FW", 0,                            0,    0,    0,   21,   21,   21,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0 },
2872     { 9, "_fflt", "ConvertApexStdToApex_FW", 0,                           -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7 },
2873     { 9, "_ffix", "ConvertApexStdToApex_FW", 0,                           -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4 },
2874     { 9, "_fmul", "ConvertApexStdToApex_FW", 0,                           -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5 },
2875     { 9, "_fdiv", "ConvertApexToApexStd_FW", 0,                           -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3 },
2876     { 9, "GetSRAndDisableInterrupt", "_GetSystemTime", 0,                  9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9 },
2877     { 9, "SetSR", "_GetSystemTime", 0,                                    12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12 },
2878     { 9, "MoveOpticalZoomAt", "PT_MoveOpticalZoomAt_FW", 0,                1,    2,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3 },
2879     { 9, "MoveOpticalZoomAt", "PT_MoveOpticalZoomAt_FW", 0,                1,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3 },
2880     { 9, "MoveOpticalZoomAt", "SS.MoveOpticalZoomAt_FW", 0,                0,    0,    0,    0,    0,    0,    0,    0,    0,    3,    5,    5,    5,    5,    5,    5 },
2881     { 9, "SetVideoOutType", "SetVideoOutType_FW", 0,                       1,    1,    1,    1,    1,    1,    1,    1,    1,    2,    2,    2,    2,    2,    2,    2 },
2882     { 9, "cache_flush_range", "AllocateUncacheableMemory", 0,              0,    0,   12,   12,   12,   12,   12,   12,   12,   12,   12,    0,    0,    0,    0,    0 },
2883     { 9, "cache_clean_range", "AllocateUncacheableMemory", 0,              9,    9,    9,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0 },
2884     { 9, "dcache_flush_range", "AllocateUncacheableMemory", 0,             0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   11,   11,   11,   11,   11,   11 },
2885 
2886     //                                                                   R20   R23   R31   R39   R43   R45   R47   R49   R50   R51   R52   R54   R55   R57   R58   R59
2887 //    { 11, "DebugAssert", "\nAssert: File %s Line %d\n", 0,                 5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    1,    6 },
2888     { 11, "err_init_task", "\n-- %s() error in init_task() --", 0,         2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2 },
2889     { 11, "set_control_event", "Button:0x%08X:%s", 0x01000001,            14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14 },
2890     { 11, "set_control_event", "Button:0x%08X:%s", 0xf1000001,            15,   15,   15,   15,   15,   15,   15,   15,   15,   15,   15,   15,   15,   15,   15,   15 },
2891     { 11, "set_control_event", "Button:0x%08X:%s", 0x01000001,            19,   19,   19,   19,   19,   19,   19,   19,   19,   19,   19,   19,   19,   19,   19,   19 },
2892     { 11, "set_control_event", "Button:0x%08X:%s", 0x01000001,            20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20,   20 },
2893     { 11, "_log", (char*)log_test, 0x01000001,                             1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2894     { 11, "_uartr_req", "A/uartr.req", 0,                                  3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3 },
2895     { 11, "MenuIn", "MenuIn", 0,                                           1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2896     { 11, "MenuOut", "MenuOut", 0,                                         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2897     { 11, "MenuIn", "SSAPI::MenuIn", 0,                                    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2898     { 11, "MenuOut", "SSAPI::MenuOut", 0,                                  1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2899 
2900     //                                                                   R20   R23   R31   R39   R43   R45   R47   R49   R50   R51   R52   R54   R55   R57   R58   R59
2901     { 12, "DeleteFile_Fut", "DeleteFile_Fut", 1,                        0x38, 0x38, 0x4C, 0x4C, 0x4C, 0x54, 0x54, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2902     { 12, "AllocateUncacheableMemory", "AllocateUncacheableMemory", 1,  0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x34, 0x34, 0x34, 0x4C, 0x4C, 0x4C, 0x4C, 0x54, 0x54, 0x54, 0x54 },
2903     { 12, "FreeUncacheableMemory", "FreeUncacheableMemory", 1,          0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x38, 0x38, 0x50, 0x50, 0x50, 0x50, 0x58, 0x58, 0x58, 0x58 },
2904     { 12, "free", "free", 1,                                            0x28, 0x28, 0x28, 0x28, 0x28, 0x30, 0x30, 0x30, 0x48, 0x48, 0x48, 0x48, 0x50, 0x50, 0x50, 0x50 },
2905     { 12, "malloc", "malloc", 0x01000003,                               0x24, 0x24, 0x24, 0x24, 0x24, 0x2C, 0x2C, 0x2C, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x4c, 0x4c, 0x4c }, // uses 'malloc_strictly'
2906     { 12, "TakeSemaphore", "TakeSemaphore", 1,                          0x14, 0x14, 0x14, 0x14, 0x14, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C },
2907     { 12, "GiveSemaphore", "GiveSemaphore", 1,                          0x18, 0x18, 0x18, 0x18, 0x18, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 },
2908     { 12, "_log10", "_log10", 0x01000006,                              0x278,0x280,0x280,0x284,0x294,0x2FC,0x2FC,0x31C,0x354,0x35C,0x35C,0x35C,0x388,0x38c,0x390,0x394 }, // uses 'CalcLog10'
2909     { 12, "_log10", "_log10", 0x01000006,                              0x000,0x278,0x27C,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x38c,0x000,0x000,0x000 },
2910     { 12, "_log10", "_log10", 0x01000006,                              0x000,0x000,0x2C4,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000 },
2911     { 12, "ClearEventFlag", "ClearEventFlag", 1,                        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 },
2912     { 12, "SetEventFlag", "SetEventFlag", 1,                            0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 },
2913     { 12, "WaitForAnyEventFlag", "WaitForAnyEventFlag", 1,              0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
2914     { 12, "WaitForAllEventFlag", "WaitForAllEventFlag", 1,              0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
2915 
2916     { 13, "strftime", "Sunday", 1 },
2917 
2918     { 15, "LocalTime", "%04d:%02d:%02d %02d:%02d:%02d", 0x01000001 },
2919     { 15, "GetMemInfo", "Malloc Information\n", 0x01000001 },
2920     { 15, "GetMemInfo", "Malloc Information (%s type)\n", 0x01000001 },
2921     { 15, "vsprintf", "\nCPrintf Size Over!!", 0x01000001 },
2922     { 15, "ReadFastDir", "ReadFast_ERROR\n", 0x01000001 },
2923     { 15, "OpenFastDir", "OpenFastDir_ERROR\n", 0x01000001 },
2924     { 15, "realloc", "fatal error - scanner input buffer overflow", 0x01000001 },
2925     { 15, "CreateBinarySemaphore", "SdPower.c", 0x01000001 },
2926     { 15, "get_resource_pointer", "Not found icon resource.\r\n", 0x01000001 },
2927     { 15, "get_self_task_id", "ASSERT!! %s Line %d\n", 0x01000001 },
2928     { 15, "get_current_exp", "Exp  Av %d, Tv %d, Gain %d\r", 0x01000001 },
2929     { 15, "EnableDispatch_low", "\n%s Task was Suspended.\n", 0x01000001 },
2930     //{ 15, "DoMovieFrameCapture", "DoMovieFrameCapture executed.",  0x01000001 },
2931     //                                                                           R20     R23     R31     R39     R43     R45     R47     R49     R50     R51     R52     R54     R55     R57     R58     R59
2932     { 15, "SetHPTimerAfterTimeout", "FrameRateGenerator.c", 0x01000001,          0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0001, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007 },
2933     { 15, "get_task_properties", "Task ID: %d\n", 0x01000001,                    0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003 }, // string not unique!
2934 
2935     { 16, "DeleteDirectory_Fut", (char*)DeleteDirectory_Fut_test, 0x01000001 },
2936     { 16, "MakeDirectory_Fut", (char*)MakeDirectory_Fut_test, 0x01000001 },
2937     { 16, "RenameFile_Fut", (char*)RenameFile_Fut_test, 0x01000001 },
2938 
2939     { 17, "ScreenLock", "StartRecModeMenu", 0 },
2940     { 17, "ScreenUnlock", "StartRecModeMenu", 0 },
2941 
2942     // Ensure ordering in func_names is correct for dependencies here
2943     //                                                                           R20     R23     R31     R39     R43     R45     R47     R49     R50     R51     R52     R54     R55     R57     R58     R59
2944     { 19, "GetSemaphoreValue", "GiveSemaphore", 0,                               0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014 },
2945     { 19, "GetSemaphoreValue", "GiveSemaphore", 0,                               0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x000f, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2946     { 19, "CreateMessageQueueStrictly", "CreateTaskStrictly", 0,                 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d },
2947     { 19, "CreateMessageQueueStrictly", "CreateTaskStrictly", 0,                 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e },
2948     { 19, "CreateEventFlagStrictly", "CreateMessageQueueStrictly", 0,            0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009 },
2949     { 19, "CreateEventFlagStrictly", "CreateMessageQueueStrictly", 0,            0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a },
2950     { 19, "CreateBinarySemaphoreStrictly", "CreateEventFlagStrictly", 0,         0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009 },
2951     { 19, "CreateBinarySemaphoreStrictly", "CreateEventFlagStrictly", 0,         0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a },
2952     { 19, "CreateCountingSemaphoreStrictly", "CreateBinarySemaphoreStrictly", 0, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009 },
2953     { 19, "CreateCountingSemaphoreStrictly", "CreateBinarySemaphoreStrictly", 0, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a },
2954     { 19, "CreateRecursiveLockStrictly", "CreateCountingSemaphoreStrictly", 0,   0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009 },
2955     { 19, "CreateRecursiveLockStrictly", "CreateCountingSemaphoreStrictly", 0,   0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a },
2956     { 19, "TakeSemaphoreStrictly", "CreateRecursiveLockStrictly", 0,             0x0001, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0xf000, 0xf000 }, // name made up
2957     { 19, "TakeSemaphoreStrictly", "CreateRecursiveLockStrictly", 0,             0x0001, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x000a, 0x000a, 0x000a, 0x000a, 0x0014, 0x0014 }, // name made up
2958     { 19, "ReceiveMessageQueueStrictly", "TakeSemaphoreStrictly", 0,             0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b }, // name made up
2959     { 19, "PostMessageQueueStrictly", "ReceiveMessageQueueStrictly", 0,          0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b }, // name made up
2960     { 19, "WaitForAnyEventFlagStrictly", "PostMessageQueueStrictly", 0,          0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b }, // name made up
2961     { 19, "WaitForAllEventFlagStrictly", "WaitForAnyEventFlagStrictly", 0,       0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x0510 }, // name made up
2962     { 19, "AcquireRecursiveLockStrictly", "WaitForAllEventFlagStrictly", 0,      0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b }, // name made up
2963 
2964     { 19, "PostMessageQueue", "TryReceiveMessageQueue", 0,                       0x091f, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 },
2965     { 19, "DeleteMessageQueue", "CreateMessageQueue", 0,                         0x1021, 0x1021, 0x1021, 0x1021, 0x1021, 0x1021, 0x1021, 0x1021, 0x1021, 0x1021, 0x1021, 0x002c, 0x002c, 0x002c, 0x002c, 0x002c },
2966     { 19, "DeleteMessageQueue", "CreateMessageQueue", 0,                         0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x0027, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2967     { 19, "ReceiveMessageQueue", "DeleteMessageQueue", 0,                        0x1024, 0x1024, 0x1024, 0x1024, 0x1024, 0x1024, 0x1024, 0x1024, 0x1024, 0x1024, 0x1024, 0x1029, 0x1029, 0x1029, 0x1028, 0x1028 },
2968     { 19, "ReceiveMessageQueue", "DeleteMessageQueue", 0,                        0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x1025, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2969     { 19, "TryReceiveMessageQueue", "ReceiveMessageQueue", 0,                    0x002b, 0x002b, 0x1032, 0x1032, 0x1032, 0x1032, 0x1032, 0x1032, 0x1032, 0x1032, 0x1032, 0x073d, 0x073d, 0x073d, 0x073d, 0x073d },
2970     { 19, "TryReceiveMessageQueue", "ReceiveMessageQueue", 0,                    0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x183e, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2971     { 19, "TryPostMessageQueue", "PostMessageQueue", 0,                          0x0027, 0x0027, 0x102e, 0x102e, 0x102e, 0x102e, 0x102e, 0x102e, 0x102e, 0x102e, 0x102e, 0x0031, 0x0031, 0x0031, 0x0031, 0x0031 },
2972     { 19, "TryPostMessageQueue", "PostMessageQueue", 0,                          0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x1031, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2973     { 19, "GetNumberOfPostedMessages", "TryPostMessageQueue", 0,                 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015 },
2974     { 19, "DeleteRecursiveLock", "CreateRecursiveLock", 0,                       0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016 },
2975     { 19, "DeleteRecursiveLock", "CreateRecursiveLock", 0,                       0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x0016, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2976     { 19, "AcquireRecursiveLock", "DeleteRecursiveLock", 0,                      0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a },
2977     { 19, "AcquireRecursiveLock", "DeleteRecursiveLock", 0,                      0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x0015, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2978     { 19, "ReleaseRecursiveLock", "AcquireRecursiveLock", 0,                     0x0041, 0x0041, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x085a, 0x085a, 0x085a, 0x0658, 0x095b },
2979     { 19, "ReleaseRecursiveLock", "AcquireRecursiveLock", 0,                     0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x004d, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2980     { 19, "GetEventFlagValue", "ClearEventFlag", 0,                              0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013 },
2981     { 19, "DeleteEventFlag", "CreateEventFlag", 0,                               0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018 },
2982     { 19, "DeleteEventFlag", "CreateEventFlag", 0,                               0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x0018, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2983     { 19, "CheckAnyEventFlag", "DeleteEventFlag", 0,                             0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a },
2984     { 19, "CheckAnyEventFlag", "DeleteEventFlag", 0,                             0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x0015, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2985     { 19, "CheckAllEventFlag", "CheckAnyEventFlag", 0,                           0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0017, 0x0017, 0x0017, 0x0017, 0x0017 },
2986     { 19, "TryTakeSemaphore", "DeleteSemaphore", 0,                              0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d },
2987     { 19, "TryTakeSemaphore", "DeleteSemaphore", 0,                              0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x0018, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2988     { 19, "SetTimerAfter", "_GetSystemTime", 0,                                  0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x0054, 0x0054, 0x005d },
2989     { 19, "SetTimerWhen", "SetTimerAfter", 0,                                    0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x001b, 0x001b, 0x001b, 0x001b, 0x001b },
2990     { 19, "SetTimerWhen", "SetTimerAfter", 0,                                    0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x001b, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2991     { 19, "CancelTimer", "SetTimerWhen", 0,                                      0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019 },
2992     { 19, "CancelHPTimer", "SetHPTimerAfterTimeout", 0,                          0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022 },
2993     { 19, "SetHPTimerAfterNow", "SetHPTimerAfterTimeout", 0,                    -0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020 },
2994     //{ 19, "UnregisterInterruptHandler", "RegisterInterruptHandler", 0,         0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013 }, // unreliable on r52+
2995     //{ 19, "GetSRAndDisableInterrupt", "UnregisterInterruptHandler", 0,         0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x004c, 0x004c, 0x004c, 0x004c, 0x004c }, // unreliable on r52+
2996     //{ 19, "SetSR", "UnregisterInterruptHandler", 0,                            0x1007, 0x1007, 0x1007, 0x1007, 0x1007, 0x1007, 0x1007, 0x1007, 0x1007, 0x1007, 0x1007, 0x104d, 0x104d, 0x104d, 0x104d, 0x104d }, // unreliable on r52+
2997     { 19, "EnableInterrupt", "UnregisterInterruptHandler", 0,                    0x170f, 0x170f, 0x170f, 0x170f, 0x170f, 0x170f, 0x170f, 0x170f, 0x170f, 0x170f, 0x170f, 0x1755, 0x1755, 0x1755, 0x1755, 0x1755 },
2998     { 19, "EnableInterrupt", "SetSR", 0,                                         0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x1708, 0x1708, 0x1708, 0x1708, 0x1708, 0x1708 },
2999     //                                                                           R20     R23     R31     R39     R43     R45     R47     R49     R50     R51     R52     R54     R55     R57     R58     R59
3000     { 19, "GetDrive_TotalClusters", "GetDrive_ClusterSize", 0,                   0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x000d, 0x000c, 0x000c, 0x000c, 0x000c, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 },
3001     { 19, "GetDrive_FreeClusters", "GetDrive_TotalClusters", 0,                  0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x000b, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b },
3002     { 19, "GetDrive_FreeClusters", "GetDrive_TotalClusters", 0,                  0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x000b, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 }, // alt r52 (sx510)
3003 
3004     { 19, "time", "GetTimeOfSystem_FW", 0,                                       0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,-0x002c,-0x002d,-0x0c2d,-0x0c2d,-0x0c2d,-0x0e2d },
3005     { 19, "time", "GetTimeOfSystem_FW", 0,                                       0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,-0x002d, 0x0001, 0x0001,-0x0b2d, 0x0001, 0x0001 }, // alt r52 (sx510), r57 (ixus275)
3006     { 19, "IsInvalidTime", "GetValidSystemCalender", 0,                          0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008 },
3007     { 19, "PauseTimeOfSystem", "GetValidSystemCalender", 0,                      0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e },
3008     { 19, "ResumeTimeOfSystem", "GetValidSystemCalender", 0,                     0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012 },
3009 
3010     { 19, "CalcLog10", "CalcLog10_FW", 0,                                       -0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f },
3011     { 19, "_dfixu", "_dfix", 0,                                                  0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c },
3012     { 19, "_dsub", "_sqrt", 0,                                                   0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d },
3013     { 19, "_drsb", "_sqrt", 0,                                                  -0x1114,-0x1114,-0x1114,-0x1114,-0x1114,-0x1114,-0x1106,-0x1106,-0x1106,-0x1106,-0x1106,-0x1106,-0x1106,-0x1106,-0x1106,-0x1106 },
3014     { 19, "_dcmp_reverse", "_dmul", 0,                                           0xf000, 0xf000, 0x33fc, 0x33fc, 0x33fc, 0x33fc, 0x43e2, 0x43e2, 0x43e2, 0x43e2, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 }, // has to come first
3015     { 19, "_dcmp_reverse", "_dmul", 0,                                           0x2e80, 0x2e80, 0x3580, 0x3580, 0x3580, 0x3580, 0x3474, 0x3474, 0x3474, 0x3474, 0x3474, 0x3474, 0x3474, 0x3474, 0x3474, 0x3474 },
3016     { 19, "_dcmp", "_dfltu", 0,                                                  0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003 },
3017     { 19, "_safe_sqrt", "_dadd", 0,                                              0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,-0x1d13,-0x1d13,-0x1d13,-0x1d13,-0x1d13,-0x1d13,-0x1d13,-0x1d13,-0x1d13,-0x1d13 },
3018     { 19, "_safe_sqrt", "_log", 0,                                              -0x132f,-0x132f,-0x1695,-0x132f,-0x132f,-0x132f, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
3019     { 19, "_safe_sqrt", "_log", 0,                                               0xf000, 0xf000,-0x132f,-0x1695, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
3020     { 19, "_ddiv", "_dadd", 0,                                                   0x10aa, 0x10aa, 0x10aa, 0x10aa, 0x10aa, 0x10c3, 0x10b6, 0x10b6, 0x10b6, 0x10b6, 0x10b6, 0x10b6, 0x10b6, 0x10b6, 0x10b6, 0x10b6 },
3021     { 19, "_ffixu", "_ffix", 0,                                                  0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d },
3022     { 19, "_ffltu", "_fflt", 0,                                                  0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d },
3023     { 19, "_f2d", "_fdiv", 0,                                                    0xf000,-0x301f,-0x301f,-0x301f,-0x301f,-0x301f,-0x3061,-0x3061,-0x3061,-0x3061,-0x3061,-0x3061,-0x3061,-0x3061,-0x3061,-0x3061 },
3024     { 19, "_f2d", "_fdiv", 0,                                                   -0x306b,-0x306b,-0x306b,-0x306b,-0x306b,-0x306b, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
3025 
3026     { 21, "add_ptp_handler", (char*)find_add_ptp_handler, 0 },
3027     { 21, "apex2us", (char*)find_apex2us, 0 },
3028     { 21, "mkdir", (char*)find_mkdir, 0 },
3029     { 21, "_pow", (char*)find_pow, 0 },
3030     { 21, "rand", (char*)find_rand, 0 },
3031     { 21, "get_ptp_file_buf", (char*)find_get_ptp_file_buf, 0 },
3032 
3033     { 22, "closedir", (char*)find_closedir, 0 },
3034     { 22, "PT_PlaySound", (char*)find_PT_PlaySound, 0 },
3035     { 22, "getImageDirName", (char*)find_getImageDirName, 0 },
3036     { 22, "GetImageFolder", (char*)find_GetImageFolder, 0 },
3037     { 22, "GetDrive_ClusterSize", (char*)find_GetDrive_ClusterSize, 0 },
3038     { 22, "GetDrive_TotalClusters", (char*)find_GetDrive_TotalClusters, 0 },
3039     { 22, "srand", (char*)find_srand, 0 },
3040     { 22, "Restart", (char*)find_Restart, 0 },
3041     { 22, "DisplayBusyOnScreen", (char*)find_DisplayBusyOnScreen, 0 },
3042     { 22, "UndisplayBusyOnScreen", (char*)find_UndisplayBusyOnScreen, 0 },
3043     { 22, "CreateDialogBox", (char*)find_CreateDialogBox, 0 },
3044     { 22, "DisplayDialogBox", (char*)find_DisplayDialogBox, 0 },
3045     { 22, "add_ui_to_dialog", (char*)find_add_ui_to_dialog, 0 },
3046     { 22, "get_string_by_id", (char*)find_get_string_by_id, 0 },
3047     { 22, "get_fstype", (char*)find_get_fstype, 0 },
3048     { 22, "malloc_strictly", (char*)find_malloc_strictly, 0 },
3049     { 22, "SetHPTimerAfterTimeout", (char*)find_sethptimeraftertimeout, 0},
3050     { 22, "GetCurrentMachineTime", (char*)find_getcurrentmachinetime, 0},
3051     { 22, "get_self_task_errno_pointer", (char*)find_get_self_task_errno_pointer, 0},
3052     { 22, "get_nd_value", (char*)find_get_nd_value, 0},
3053     { 22, "get_current_nd_value", (char*)find_get_current_nd_value, 0},
3054     { 22, "get_current_deltasv", (char*)find_get_current_deltasv, 0},
3055     { 22, "GetBaseSv", (char*)find_GetBaseSv, 0},
3056     { 22, "DoMovieFrameCapture", (char*)find_DoMovieFrameCapture, 0},
3057     { 22, "get_ptp_buf_size", (char*)find_get_ptp_buf_size, 0},
3058     { 22, "Remove", (char*)find_Remove, 0},
3059     { 22, "EnableDispatch", (char*)find_dispatch_funcs, 0},
3060     { 22, "DisableDispatch", (char*)find_dispatch_funcs, 1},
3061     { 22, "GetTimeFromRTC", (char*)find_GetTimeFromRTC_and_more, 0},
3062     { 22, "GetValidSystemCalender", (char*)find_GetTimeFromRTC_and_more, 1},
3063     { 22, "SetValidSystemCalender", (char*)find_GetTimeFromRTC_and_more, 2},
3064     { 22, "cache_flush_and_enable", (char*)find_arm_cache_funcs, 0},
3065     { 22, "cache_clean_flush_and_disable", (char*)find_arm_cache_funcs, 1},
3066     { 22, "cache_flush_range", (char*)find_arm_cache_funcs, 2},
3067     { 22, "cache_clean_flush_range", (char*)find_arm_cache_funcs, 3},
3068     { 22, "cache_clean_range", (char*)find_arm_cache_funcs, 4},
3069     { 22, "icache_flush_and_enable", (char*)find_arm_cache_funcs2, 0},
3070     { 22, "icache_disable_and_flush", (char*)find_arm_cache_funcs2, 1},
3071     { 22, "dcache_flush_and_enable", (char*)find_arm_cache_funcs2, 2},
3072     { 22, "dcache_clean_flush_and_disable", (char*)find_arm_cache_funcs2, 3},
3073     { 22, "dcache_clean_range", (char*)find_arm_cache_funcs2, 4},
3074     { 22, "dcache_clean_flush_range", (char*)find_arm_cache_funcs2, 5},
3075     { 22, "icache_flush_range", (char*)find_arm_cache_funcs2, 6},
3076     { 22, "IsWirelessConnect", (char*)find_IsWirelessConnect, 0},
3077 
3078     //                                                                           R20     R23     R31     R39     R43     R45     R47     R49     R50     R51     R52     R54     R55     R57     R58     R59
3079     { 23, "UnregisterInterruptHandler", "HeadInterrupt1", 76,                    1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1 },
3080     { 23, "get_string_by_id", "NoError", 16,                                    99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     -2 },
3081     { 23, "EnableHDMIPower", "HDMIConnectCnt", 9,                               99,     99,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,},
3082     { 23, "DisableHDMIPower", "HDMIConnectCnt", 9,                              99,     99,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,},
3083     { 23, "get_nd_value", "IrisSpecification.c", 25,                            -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,},
3084     { 23, "GetUsableAvRange", "[AE]Prog Line Error!\n", 20,                      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,},
3085     { 23, "ImagerActivate", "Fail ImagerActivate(ErrorCode:%x)\r", 7,           -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,}, // two functions satisfy this, either will work for us
3086     { 23, "DisableDispatch_low", "data abort", 7,                                0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,},
3087     { 23, "GetCurrentDriveBaseSvValue", "KeepPreviousExposureWithProgress", 5,   2,      2,      2,      2,      2,      2,      2,     99,     99,     99,     99,     99,     99,     99,     99,     99,},
3088     { 23, "cameracon_set_state", "AC:PB2Rec", 5,                                 1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1 },
3089     { 23, "cameracon_get_state", "ex:PB", 5,                                    99,     99,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
3090     { 23, "cameracon_get_state", "exchange:PB", 5,                              99,     99,     -1,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99 }, // a1000 uses this string
3091 
3092     //                                                                           R20     R23     R31     R39     R43     R45     R47     R49     R50     R51     R52     R54     R55     R57     R58     R59
3093     { 24, "get_string_by_id", "StringID[%d] is not installed!!\n", 64,           0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x0000, 0x0000, 0x0000, 0xf000 },
3094 
3095     { 25, "", "", 0 },
3096 
3097     { 0, 0, 0, 0 }
3098 };
3099 
3100 // Find the named function in the 'func_list' array above, return index of entry
3101 int find_func(const char* name)
3102 {
3103     int i;
3104     for (i=0; func_list[i].name != 0; i++)
3105     {
3106         if (strcmp(name, func_list[i].name) == 0)
3107         {
3108             return i;
3109         }
3110     }
3111     return -1;  // Not found
3112 }
3113 
3114 // Get DryOS version specific offset
3115 int dryos_offset(firmware *fw, string_sig *sig)
3116 {
3117     switch (fw->dryos_ver)
3118     {
3119     case 20:    return sig->dryos20_offset;
3120     case 23:    return sig->dryos23_offset;
3121     case 31:    return sig->dryos31_offset;
3122     case 39:    return sig->dryos39_offset;
3123     case 43:    return sig->dryos43_offset;
3124     case 45:    return sig->dryos45_offset;
3125     case 47:    return sig->dryos47_offset;
3126     case 49:    return sig->dryos49_offset;
3127     case 50:    return sig->dryos50_offset;
3128     case 51:    return sig->dryos51_offset;
3129     case 52:    return sig->dryos52_offset;
3130     case 54:    return sig->dryos54_offset;
3131     case 55:    return sig->dryos55_offset;
3132     case 57:    return sig->dryos57_offset;
3133     case 58:    return sig->dryos58_offset;
3134     case 59:    return sig->dryos59_offset;
3135     }
3136     return 0;
3137 }
3138 
3139 //------------------------------------------------------------------------------------------------------------
3140 
3141 // Loop through firmware looking for instances of a sig string
3142 // For each one found call the check_match function to see if it matches the sig
3143 // Return 1 if match found, else return 0
3144 int fw_string_process(firmware *fw, string_sig *sig, int (*check_match)(firmware *fw, string_sig *sig, int j), int inc_eos)
3145 {
3146     int nlen = strlen(sig->ev_name);
3147     uint32_t nm0 = *((uint32_t*)sig->ev_name);
3148     uint32_t *p;
3149     int j;
3150     BufRange *br;
3151 
3152     for (br = fw->br; br != 0; br = br->next)
3153     {
3154         for (p = br->p, j = br->off; j < br->off+br->len-nlen/4; p++, j++)
3155         {
3156             if ((nm0 == *p) && (memcmp(p+1,sig->ev_name+4,nlen-4+inc_eos) == 0))
3157             {
3158                 if (check_match(fw,sig,j))
3159                     return 1;
3160             }
3161         }
3162     }
3163 
3164     return 0;
3165 }
3166 
3167 // As above; but scan the firmware byte-by-byte rather than by words
3168 // Slower; but required when strings are not stores on 32 bit boundaries
3169 int fw_string_process_unaligned(firmware *fw, string_sig *sig, int (*check_match)(firmware *fw, string_sig *sig, int j))
3170 {
3171     int nlen = strlen(sig->ev_name);
3172     char *p;
3173     int j;
3174     BufRange *br;
3175 
3176     for (br = fw->br; br != 0; br = br->next)
3177     {
3178         for (p = (char*)br->p, j = 0; j < br->len*4-nlen; p++, j++)
3179         {
3180             if (strcmp(p,sig->ev_name) == 0)
3181             {
3182                 if (check_match(fw,sig,j+br->off*4))
3183                     return 1;
3184             }
3185         }
3186     }
3187 
3188     return 0;
3189 }
3190 
3191 // Loop through the firmware from the start, calling 'check_match' for each location
3192 // If 'check_match' returns non-zero, exit returning 1.
3193 // Otherwise returns 0 - no match found.
3194 int fw_process(firmware *fw, string_sig *sig, int (*check_match)(firmware *fw, string_sig *sig, int j))
3195 {
3196     uint32_t *p;
3197     int j;
3198     BufRange *br;
3199 
3200     for (br = fw->br; br != 0; br = br->next)
3201     {
3202         for (p = br->p, j = br->off; j < br->off+br->len; p++, j++)
3203         {
3204             if (check_match(fw,sig,j))
3205                 return 1;
3206         }
3207     }
3208 
3209     return 0;
3210 }
3211 
3212 //------------------------------------------------------------------------------------------------------------
3213 
3214 // New string / signature matching functions
3215 
3216 // Sig pattern:
3217 //      Function pointer    -   DCD func
3218 //      String              -   DCB "func"
3219 // Note: 'func' may not be the target address, the sig->offset value allows selection of another function
3220 //       called at a fixed number of instructions from the 'func' address found
3221 int match_strsig1(firmware *fw, string_sig *sig, int j)
3222 {
3223     uint32_t fadr = fwval(fw,j-1);      // function address
3224     if (idx_valid(fw,adr2idx(fw,fadr))) // is function address valid
3225     {
3226         // If function address is a B, and we are following branches, then follow the first B
3227         if (sig->offset > 1) fadr = followBranch(fw, fadr, 1);
3228         // Follow any subsequent branch at the given offset
3229         fadr = followBranch2(fw, fadr, sig->offset);
3230         fwAddMatch(fw,fadr,32,0,101);
3231         return 1;
3232     }
3233     return 0;
3234 }
3235 
3236 // Sig pattern:
3237 //      String pointer      -       DCD str
3238 //      Function pointer    -       DCD func
3239 //                ...
3240 //      String              -   str DCB "func"
3241 // Note: 'func' may not be the target address, the offset value allows selection of another function
3242 //       called at a fixed number of instructions from the 'func' address found
3243 int match_strsig2a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
3244 {
3245     if (fwval(fw,k) == sadr)                // pointer to string?
3246     {
3247         uint32_t fadr = fwval(fw,k+1);      // function address
3248         if (idx_valid(fw,adr2idx(fw,fadr))) // is function address valid
3249         {
3250             uint32_t bfadr = followBranch2(fw, fadr, offset);
3251             if ((offset <= 1) || (bfadr != fadr))
3252             {
3253                 fwAddMatch(fw,bfadr,32,0,102);
3254                 return 1;
3255             }
3256         }
3257     }
3258     return 0;
3259 }
3260 int match_strsig2(firmware *fw, string_sig *sig, int j)
3261 {
3262     // Note - 'j' is byte offset in firmware not instruction index (called from fw_string_process_unaligned)
3263     return search_fw(fw, match_strsig2a, fw->base + j, sig->offset, 2);
3264 }
3265 
3266 // Sig pattern:
3267 //      Load Func Address   -   ADR Rx, func
3268 //      Load String Address -   ADR Rx, "func"
3269 //      Branch              -   BL
3270 //              ...
3271 //      String              -   DCB "func"
3272 // or
3273 //      Load Func Address   -   ADR Rx, func
3274 //                              B   loc
3275 //              ...
3276 //                          loc:
3277 //      Load String Address -   ADR    Rx, "func"
3278 //      Branch              -   BL
3279 //              ...
3280 //      String              -   DCB "func"
3281 // 'sadr' = address of "func" string
3282 // Note: 'func' may not be the target address, the offset value allows selection of another function
3283 //       called at a fixed number of instructions from the 'func' address found
3284 int match_strsig3a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
3285 {
3286     if (isADR_PC(fw,k+1) &&    // ADR ?
3287         isBorBL(fw,k+2))       // B or BL ?
3288     {
3289         uint32_t padr = ADR2adr(fw,k+1);    // get address pointed to by 2nd ADR instructioin
3290         if (padr == sadr)                   // does it match target string
3291         {
3292             int j2 = k;
3293             int found = 0;
3294             if (isADR_PC(fw,k))             // ADR ?
3295                 found = 1;
3296             else
3297             {
3298                 // May be DCD block between 1st and 2nd ADR
3299                 for (j2 = k-2; j2 >= 0 && j2 >= k-4096; j2--)
3300                 {
3301                     if (isADR_PC(fw,j2) &&  // ADR ?
3302                         isB(fw,j2+1))       // B
3303                     {
3304                         uint32_t fa = idx2adr(fw,j2+1);
3305                         fa = followBranch(fw,fa,1);
3306                         if (adr2idx(fw,fa) == k+1)
3307                         {
3308                             found = 1;
3309                             break;
3310                         }
3311                     }
3312                 }
3313             }
3314             if (found)
3315             {
3316                 uint32_t fadr = ADR2adr(fw,j2);
3317                 if (offset > 1) fadr = followBranch(fw, fadr, 1);
3318                 fadr = followBranch2(fw, fadr, offset);
3319                 fwAddMatch(fw,fadr,32,0,103);
3320                 return 1;
3321             }
3322         }
3323     }
3324     return 0;
3325 }
3326 int match_strsig3(firmware *fw, string_sig *sig, int j)
3327 {
3328     return search_fw(fw, match_strsig3a, idx2adr(fw,j), sig->offset, 3);
3329 }
3330 
3331 // Sig pattern:
3332 //      Save Regs           -   STMFD
3333 //                ... (offset)
3334 //      Load String Address -   ADR Rx, "func"
3335 //                ...
3336 //      String              -   DCB "func"
3337 int match_strsig4a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
3338 {
3339     if (isSTMFD(fw,k) &&        // STMFD
3340         isADR_PC(fw,k+offset))  // ADR ?
3341     {
3342         uint32_t padr = ADR2adr(fw,k+offset);
3343         if (padr == sadr)
3344         {
3345             uint32_t fadr = idx2adr(fw,k);
3346             fwAddMatch(fw,fadr,32,0,104);
3347             return 1;
3348         }
3349     }
3350     return 0;
3351 }
3352 int match_strsig4(firmware *fw, string_sig *sig, int j)
3353 {
3354     return search_fw(fw, match_strsig4a, idx2adr(fw,j), sig->offset, sig->offset+1);
3355 }
3356 
3357 // Sig pattern:
3358 //      Load Func Address   -   LDR Rx, =func
3359 //      Load String Address -   xDR Rx, "func"  (LDR or ADR)
3360 //      Branch              -   BL
3361 //              ...
3362 //      String              -   DCB "func"
3363 // or
3364 //      Load Func Address   -   LDR Rx, =func
3365 //                              B   loc
3366 //              ...
3367 //                          loc:
3368 //      Load String Address -   xDR Rx, "func"  (LDR or ADR)
3369 //      Branch              -   BL
3370 //              ...
3371 //      String              -   DCB "func"
3372 static int dryos_ofst;
3373 int match_strsig5a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
3374 {
3375     if ((isADR_PC(fw,k+1) || isLDR_PC(fw,k+1)) &&   // LDR or ADR ?
3376         isBorBL(fw,k+2))                            // B or BL ?
3377     {
3378         uint32_t padr;
3379         if (isLDR_PC(fw,k+1))                       // LDR ?
3380             padr = LDR2val(fw,k+1);
3381         else
3382             padr = ADR2adr(fw,k+1);
3383         if (padr == sadr)
3384         {
3385             int j2 = k;
3386             int found = 0;
3387             if (isLDR_PC(fw,k))                     // LDR ?
3388                 found = 1;
3389             else
3390             {
3391                 for (j2 = k-2; j2 >= 0 && j2 >= k-4096; j2--)
3392                 {
3393                     if (isLDR_PC(fw,j2) &&  // LDR ?
3394                         isB(fw,j2+1))       // B
3395                     {
3396                         if (idxFollowBranch(fw,j2+1,1) == k+1)
3397                         {
3398                             found = 1;
3399                             break;
3400                         }
3401                     }
3402                 }
3403             }
3404             if (found)
3405             {
3406                 uint32_t fadr = LDR2val(fw,j2);
3407                 if (offset > 1) fadr = followBranch(fw, fadr, 1);
3408                 fadr = followBranch2(fw, fadr, offset);
3409                 if (dryos_ofst != 0)
3410                 {
3411                     uint32_t fadr2 = followBranch(fw, fadr, dryos_ofst);
3412                     if (fadr == fadr2) return 0;
3413                     fadr = fadr2;
3414                 }
3415                 fwAddMatch(fw,fadr,32,0,105);
3416                 return 1;
3417             }
3418         }
3419     }
3420     return 0;
3421 }
3422 int match_strsig5(firmware *fw, string_sig *sig, int j)
3423 {
3424     dryos_ofst = dryos_offset(fw,sig);
3425     return search_fw(fw, match_strsig5a, idx2adr(fw,j), sig->offset, 3);
3426 }
3427 
3428 // Sig pattern:
3429 //    Function immediately preceeding string
3430 int match_strsig6(firmware *fw, __attribute__ ((unused))string_sig *sig, int j)
3431 {
3432     int j1 = find_inst_rev(fw, isSTMFD_LR, j-1, j-1);
3433     if (j1 > 0)
3434     {
3435         uint32_t fadr = idx2adr(fw,j1);
3436         fwAddMatch(fw,fadr,32,0,106);
3437         return 1;
3438     }
3439 
3440     return 0;
3441 }
3442 
3443 // Sig pattern:
3444 //      Str ref -   xDRnn Rx, =str_ptr
3445 //            ...
3446 //                  BL  func
3447 //            ...
3448 //      String      DCB "str"
3449 int match_strsig7a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
3450 {
3451     if (isADR_PC_cond(fw,k) || isLDR_PC_cond(fw,k)) // LDR or ADR ?
3452     {
3453         uint32_t padr;
3454         if (isLDR_PC_cond(fw,k)) // LDR ?
3455             padr = LDR2val(fw,k);
3456         else
3457             padr = ADR2adr(fw,k);
3458         if (padr == sadr)
3459         {
3460             int j2 = find_inst(fw, isBL, k+1, 10);
3461             if (j2 > 0)
3462             {
3463                 uint32_t fa = idx2adr(fw,j2);
3464                 fa = followBranch2(fw,fa,offset);
3465                 fwAddMatch(fw,fa,32,0,107);
3466                 return 1;
3467             }
3468         }
3469     }
3470     return 0;
3471 }
3472 int match_strsig7(firmware *fw, string_sig *sig, int j)
3473 {
3474     return search_fw(fw, match_strsig7a, idx2adr(fw,j), sig->offset, 2);
3475 }
3476 
3477 // Sig pattern:
3478 //      Special case for WriteSDCard
3479 int ofst;
3480 int match_strsig8(firmware *fw, __attribute__ ((unused))string_sig *sig, int j)
3481 {
3482     int j1;
3483     uint32_t u1;
3484     for (j1=j-2; j1<j+8; j1++)
3485     {
3486         uint32_t fadr = idx2adr(fw,j1);
3487         u1 = fwval(fw,j1);
3488         if ((u1 >= fw->base) || ((u1 >= fw->base2) && (u1 < fw->base2 + fw->size2*4)))  // pointer ??
3489         {
3490             int j2;
3491             for (j2=j1-1; j2>=j1-1000 && j2>=0; j2--)
3492             {
3493                 if (isLDR_PC(fw,j2) && (LDR2adr(fw,j2) == fadr))    // LDR ?
3494                 {
3495                     if ((isSTR(fw,j2+1) && (fwOp2(fw,j2+1) == ofst)) ||    // STR ?
3496                         (isSTR(fw,j2+2) && (fwOp2(fw,j2+2) == ofst)))      // STR ?
3497                     {
3498                         fadr = fwval(fw,j1);
3499                         if (idx_valid(fw,adr2idx(fw,fadr)))
3500                         {
3501                             fwAddMatch(fw,fadr,32,0,108);
3502                             return 1;
3503                         }
3504                     }
3505                 }
3506             }
3507         }
3508     }
3509 
3510     return 0;
3511 }
3512 int find_strsig8(firmware *fw, string_sig *sig)
3513 {
3514     uint32_t fadr = 0;
3515     int srch = 20;
3516 
3517     // Find "UpdateMBROnFlash" code
3518     int j = get_saved_sig(fw,"UpdateMBROnFlash");
3519     if (j >= 0)
3520     {
3521         fadr = func_names[j].val;
3522     }
3523     else
3524     {
3525         j = get_saved_sig(fw,"MakeSDCardBootable");
3526         if (j >= 0)
3527         {
3528             fadr = func_names[j].val;
3529             srch = 32;
3530         }
3531     }
3532 
3533     if (fadr == 0) return 0;
3534 
3535     int idx = adr2idx(fw, fadr);
3536     ofst = -1;
3537 
3538     for (j=idx+srch; j<idx+srch+12; j++)
3539     {
3540         if (isLDR(fw,j) && isLDR(fw,j+1) && isLDR(fw,j+2))
3541         {
3542             ofst = fwOp2(fw,j) + fwOp2(fw,j+1) + fwOp2(fw,j+2);
3543             break;
3544         }
3545     }
3546 
3547     if (ofst == -1) return 0;
3548 
3549     return fw_string_process(fw, sig, match_strsig8, 1);
3550 }
3551 
3552 // Sig pattern:
3553 //      Func is B/BL @ offset from previous found func
3554 //          prev_func
3555 //              ... (offset)
3556 //              BL    func
3557 int find_strsig9(firmware *fw, string_sig *sig)
3558 {
3559     int j = get_saved_sig(fw,sig->ev_name);
3560     if (j >= 0)
3561     {
3562         if (func_names[j].val != 0)
3563         {
3564             int ofst = dryos_offset(fw, sig);
3565             uint32_t fadr = followBranch(fw, func_names[j].val+ofst*4, 0xF1000001);
3566             if ((sig->offset == -1) || (fadr != func_names[j].val+ofst*4))
3567             {
3568                 uint32_t fadr2 = fadr;
3569                 if (sig->offset != -1) fadr2 = followBranch2(fw, fadr2, sig->offset);
3570                 if ((sig->offset <= 0) || (fadr2 != fadr))
3571                 {
3572                     fwAddMatch(fw,fadr2,32,0,109);
3573                     return 1;
3574                 }
3575             }
3576         }
3577     }
3578 
3579     return 0;
3580 }
3581 
3582 // Sig pattern:
3583 //      Func            -   func
3584 //            .... (offset)
3585 //      Ref to string   -       ADR Rx, str
3586 //            ....
3587 //      String          -       DCB "str"
3588 int match_strsig11(firmware *fw, string_sig *sig, int j)
3589 {
3590     int ofst = dryos_offset(fw, sig);
3591 
3592     uint32_t sadr = idx2adr(fw,j);        // string address
3593     int j1;
3594     for (j1 = j-1; j1 >= 0; j1--)
3595     {
3596         if (isADR_PC_cond(fw,j1))   // ADR ?
3597         {
3598             uint32_t padr = ADR2adr(fw,j1);
3599             if (padr == sadr)
3600             {
3601                 uint32_t fadr = idx2adr(fw,j1-ofst);
3602                 uint32_t bfadr = followBranch(fw,fadr,sig->offset);
3603                 // special case for 'set_control_event'
3604                 int found = 0;
3605                 if (strcmp(sig->name,"set_control_event") == 0)
3606                 {
3607                     int j2 = j1 - ofst;
3608                     if (isBL_cond(fw,j2) &&                                             // BLxx
3609                         isLDR_SP(fw,j2+1) && (fwRd(fw,j2+1) == 0) &&                    // LDR R0,[SP,x]
3610                         isBL(fw,j2+2) &&                                                // BL
3611                         isMOV(fw,j2+3) && (fwRd(fw,j2+3) == 4) && (fwRn(fw,j2+3) == 0)) // LDR R4, R0
3612                     {
3613                         found = 1;
3614                     }
3615                 }
3616                 else
3617                     found = 1;
3618                 if (found && ((sig->offset == 0) || (bfadr != fadr)))
3619                 {
3620                     fwAddMatch(fw,bfadr,32,0,111);
3621                     return 1;
3622                 }
3623             }
3624         }
3625     }
3626 
3627     return 0;
3628 }
3629 
3630 // Sig pattern:
3631 //      Func is referenced in 'CreateJumptable'
3632 //          LDR R1, =func
3633 //          STR R1, [R0,nnn]
3634 //      nnn - dryos version dependant offset
3635 int find_strsig12(firmware *fw, string_sig *sig)
3636 {
3637     int j = get_saved_sig(fw,"CreateJumptable");
3638 
3639     int ofst = dryos_offset(fw, sig);
3640 
3641     if (ofst == 0) return 0;
3642 
3643     if (j >= 0)
3644     {
3645         if (func_names[j].val != 0)
3646         {
3647             int idx = adr2idx(fw, func_names[j].val);
3648             for(; !isBX_LR(fw,idx); idx++)  // BX LR
3649             {
3650                 if (((fwval(fw,idx+1) & 0xFFFFF000) == 0xE5801000) && // STR R1,[R0,nnn]
3651                     (fwOp2(fw,idx+1) == ofst))
3652                 {
3653                     uint32_t fadr = LDR2val(fw,idx);
3654                     uint32_t bfadr = followBranch2(fw,fadr,sig->offset);
3655                     if ((sig->offset <= 1) || ((bfadr != fadr) && ((fw->buf[adr2idx(fw,fadr)] & 0xFFFF0000) == 0xE92D0000)))
3656                     {
3657                         fwAddMatch(fw,bfadr,32,0,112);
3658                         return 1;
3659                     }
3660                 }
3661                 else if (isB(fw,idx))    // B
3662                 {
3663                     idx = adr2idx(fw,followBranch(fw,idx2adr(fw,idx),1)) - 1;
3664                 }
3665             }
3666         }
3667     }
3668 
3669     return 0;
3670 }
3671 
3672 // Sig pattern:
3673 //      Func    -   func
3674 //          ... (offset)
3675 //      Str ref -       LDR Rx, =str_ptr
3676 //          ...
3677 //      Str ptr -       DCD str_ptr
3678 //          ...
3679 //      Str ptr -   str_ptr
3680 //                      DCD str
3681 //          ...
3682 //      String          DCB "str"
3683 int match_strsig13a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
3684 {
3685     if (fwval(fw,k) == sadr)    // string ptr
3686     {
3687         uint32_t padr = idx2adr(fw,k);      // string ptr address
3688         int j2;
3689         for (j2 = k-1; j2 >= 0; j2--)
3690         {
3691             if (fwval(fw,j2) == padr)       // string ptr address
3692             {
3693                 uint32_t ppadr = idx2adr(fw,j2);        // string ptr ptr address
3694                 int j3;
3695                 for (j3 = j2-1; j3 >= 0; j3--)
3696                 {
3697                     if (isLDR_PC(fw,j3) && (LDR2adr(fw,j3) == ppadr))
3698                     {
3699                         uint32_t fadr = idx2adr(fw,j3-offset);
3700                         fwAddMatch(fw,fadr,32,0,113);
3701                         return 1;
3702                     }
3703                 }
3704             }
3705         }
3706     }
3707     return 0;
3708 }
3709 int match_strsig13(firmware *fw, string_sig *sig, int j)
3710 {
3711     // Note - 'j' is offset in firmware not instruction index (called from fw_string_process_unaligned)
3712     return search_fw(fw, match_strsig13a, fw->base + j, sig->offset, 1);
3713 }
3714 
3715 // Sig pattern:
3716 //                  BL  func
3717 //            ...
3718 //      Str ref -   xDR Rx, =str_ptr
3719 //            ...
3720 //      String      DCB "str"
3721 // dryos_ofst: search range limit for the previous bl instruction
3722 int match_strsig15a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
3723 {
3724     if (isADR_PC_cond(fw,k) || isLDR_PC_cond(fw,k))   // LDR or ADR ?
3725     {
3726         uint32_t padr;
3727         if (isLDR_PC_cond(fw,k)) // LDR ?
3728             padr = LDR2val(fw,k);
3729         else
3730             padr = ADR2adr(fw,k);
3731         if (padr == sadr)
3732         {
3733             int j2 = find_inst_rev(fw, isBL, k-1, dryos_ofst);
3734             if (j2 != -1)
3735             {
3736                 // cams with code copied to RAM: use RAM address
3737                 j2 = idxcorr(fw, j2);
3738                 uint32_t fa = idx2adr(fw,j2);
3739                 fa = followBranch2(fw,fa,offset);
3740                 fwAddMatch(fw,fa,32,0,115);
3741                 return 1;
3742             }
3743         }
3744     }
3745     return 0;
3746 }
3747 int match_strsig15(firmware *fw, string_sig *sig, int j)
3748 {
3749     dryos_ofst = dryos_offset(fw,sig);
3750     if (dryos_ofst == 0) dryos_ofst = 50;
3751     return search_fw(fw, match_strsig15a, idx2adr(fw,j), sig->offset, 1);
3752 }
3753 
3754 // Sig pattern:
3755 //      Function immediately preceeding usage of hex value
3756 int match_strsig16(firmware *fw, string_sig *sig, int j)
3757 {
3758     uint32_t nm0 = *((uint32_t*)sig->ev_name);
3759 
3760     if (isADR_PC_cond(fw,j) || isLDR_PC_cond(fw,j))   // LDR or ADR ?
3761     {
3762         uint32_t padr;
3763         if (isLDR_PC_cond(fw,j)) // LDR ?
3764             padr = LDR2val(fw,j);
3765         else
3766             padr = ADR2adr(fw,j);
3767         if (padr == nm0)
3768         {
3769             int j2 = find_inst_rev(fw, isSTMFD_LR, j-1, 50);
3770             if (j2 > 0)
3771             {
3772                 uint32_t fa = idx2adr(fw,j2);
3773                 fwAddMatch(fw,fa,32,0,116);
3774                 return 1;
3775             }
3776         }
3777     }
3778 
3779     return 0;
3780 }
3781 
3782 // Sig pattern:
3783 //      Special case for ScreenLock & ScreenUnlock
3784 int find_strsig17(firmware *fw, string_sig *sig)
3785 {
3786     int j = get_saved_sig(fw,"StartRecModeMenu");
3787 
3788     if (j >= 0)
3789     {
3790         if (func_names[j].val != 0)
3791         {
3792             int idx = adr2idx(fw, func_names[j].val);
3793             int k = 0;
3794             if (fw->dryos_ver < 58)
3795             {
3796                 if (isLDR_PC(fw,idx-3) && isMOV_immed(fw,idx-2) && isB(fw,idx-1))
3797                 {
3798                     k = adr2idx(fw,LDR2val(fw,idx-3));
3799                 }
3800                 else if (isMOV_immed(fw,idx-3) && isADR_PC(fw,idx-2) && isB(fw,idx-1))
3801                 {
3802                     k = adr2idx(fw,ADR2adr(fw,idx-2));
3803                 }
3804             }
3805             else
3806             {
3807                 int l = find_inst_rev(fw, isBL, idx-1, 4);
3808                 if (l > 0)
3809                 {
3810                     if (isLDR_PC(fw,l-2) && isMOV_immed(fw,l-1))
3811                     {
3812                         k = adr2idx(fw,LDR2val(fw,l-2));
3813                     }
3814                 }
3815             }
3816             if (k != 0)
3817             {
3818                 uint32_t fadr = 0;
3819                 if (strcmp(sig->name,"ScreenLock") == 0)
3820                     fadr = followBranch(fw,idx2adr(fw,k+1),0x01000001);
3821                 else
3822                 {
3823                     k = find_inst(fw, isLDMFD, k+1, 60);
3824                     if (fw->dryos_ver < 58)
3825                     {
3826                         fadr = followBranch(fw,idx2adr(fw,k-1),0x01000001);
3827                     }
3828                     else
3829                     {
3830                         k = find_inst_rev(fw, isBL, k-1, 4);
3831                         if (k > 0)
3832                         {
3833                             fadr = followBranch(fw,idx2adr(fw,k),0x01000001);
3834                         }
3835                     }
3836                 }
3837                 if (fadr > 0)
3838                 {
3839                     fwAddMatch(fw,fadr,32,0,117);
3840                     return 1;
3841                 }
3842             }
3843         }
3844     }
3845 
3846     return 0;
3847 }
3848 
3849 // Sig pattern:
3850 //      Func is offset from previously found func
3851 //          prev_func
3852 //              ... (offset, less than 0xff)
3853 //          func
3854 // dryos_offset to be encoded as: 0xQRPP
3855 // PP) offset, 0x00...0xff, in words
3856 // Q) 'previous instruction flag': 0 for LDMFD, 1 for B, 2 for conditional B, 3 for mov pc,lr, 4 for bx lr
3857 // R) 'additional gap size': 0x0 ... 0xf, to skip an additional gap, in words
3858 // offset is negative if dryos_offset is negative
3859 int find_strsig19(firmware *fw, string_sig *sig)
3860 {
3861     int j = get_saved_sig(fw,sig->ev_name);
3862     if (j >= 0)
3863     {
3864         if (func_names[j].val != 0) // address, not idx
3865         {
3866             int ofst = dryos_offset(fw, sig);
3867             int neg = 1;
3868             if (ofst<0)
3869             {
3870                 neg=-1;
3871                 ofst=-ofst;
3872             }
3873             int addoffs = (ofst & 0xf00)>>8;
3874             uint32_t fadr = func_names[j].val+neg*(ofst&0xff)*4;
3875             int k = 0;
3876             switch ((ofst&0xf000)>>12)
3877             {
3878                 case 0: k = isLDMFD_PC(fw, adr2idx(fw, fadr)-1-addoffs); break;
3879                 case 1: k = isB(fw, adr2idx(fw, fadr)-1-addoffs); break;
3880                 case 2: k = ((fwval(fw, adr2idx(fw, fadr)-1-addoffs) & 0x0f000000) == 0x0a000000); break; // B cond.
3881                 case 3: k = (fwval(fw, adr2idx(fw, fadr)-1-addoffs) == 0xE1A0F00E); break; // mov pc, lr
3882                 case 4: k = (fwval(fw, adr2idx(fw, fadr)-1-addoffs) == 0xE12FFF1E); break; // bx lr
3883                 default: return 0;
3884             }
3885             if (k)
3886             {
3887                 fwAddMatch(fw,fadr,32,0,119);
3888                 return 1;
3889             }
3890         }
3891     }
3892 
3893     return 0;
3894 }
3895 
3896 // Sig pattern:
3897 //      Str ref -   xDRnn Rx, =str_ptr
3898 //            ...
3899 //                  BL  func
3900 //            ...
3901 //      String      DCB "str"
3902 // offset: interpreted as max search distance
3903 // dryos_ofst: 0 for 1st B/BL after str ref, 1 for 2nd, etc.; -1 for 1st preceding, etc...; disable with 99
3904 // based on method 7
3905 int match_strsig23a(firmware *fw, int k, uint32_t sadr, uint32_t maxdist)
3906 {
3907     if (isADR_PC_cond(fw,k) || isLDR_PC_cond(fw,k)) // LDR or ADR ?
3908     {
3909         uint32_t padr;
3910         if (isLDR_PC_cond(fw,k)) // LDR ?
3911             padr = LDR2val(fw,k);
3912         else
3913             padr = ADR2adr(fw,k);
3914         if (padr == sadr)
3915         {
3916             int j2;
3917             if (dryos_ofst < 0)
3918             {
3919                 j2 = find_Nth_inst_rev(fw, isBorBL, k, maxdist, -dryos_ofst);
3920             }
3921             else
3922             {
3923                 j2 = find_Nth_inst(fw, isBorBL, k+1, maxdist, dryos_ofst+1);
3924             }
3925             if (j2 > 0)
3926             {
3927                 uint32_t fa = idx2adr(fw,j2);
3928                 fa = followBranch2(fw,fa,0x01000001);
3929                 fwAddMatch(fw,fa,32,0,123);
3930                 return 1;
3931             }
3932         }
3933     }
3934     return 0;
3935 }
3936 int match_strsig23(firmware *fw, string_sig *sig, int j)
3937 {
3938     dryos_ofst = dryos_offset(fw,sig);
3939 
3940     if (dryos_ofst == 99)
3941         return 0;
3942 
3943     return search_fw(fw, match_strsig23a, idx2adr(fw,j), sig->offset, 2);
3944 }
3945 
3946 // Sig pattern:
3947 //      Func            -   func
3948 //            .... [offset]
3949 //      Nth instruction backwards from string ref
3950 //      Ref to string   -       LDR Rx, pstr
3951 //            ....
3952 //      Ptr to string   -       DCD pstr
3953 // dryos_offset to be encoded as: 0xQNPP
3954 // P) additional offset
3955 // Q) instruction to locate: 0 for STMFD_LR, 0xf to disable
3956 // N) search the instruction this many times - 1 (i.e. 0 = first instruction backwards)
3957 // prev instruction search range is limited by sig->offset
3958 // the reference to the string has to occur within 256 words (fixed range)
3959 // based on method 104 of finsig_vxworks
3960 int match_strsig24(firmware *fw, string_sig *sig, int j)
3961 {
3962 
3963     int ofst = dryos_offset(fw, sig);
3964     int prinst = (ofst&0xf000)>>12;
3965     int ninst = ((ofst&0xf00)>>8)+1;
3966     ofst &= 0xff;
3967     void *instid;
3968     switch (prinst) {
3969         case 0:
3970             instid = (void*)isSTMFD_LR;
3971             break;
3972         default:
3973             return 0;
3974     }
3975 
3976     uint32_t sadr = idx2adr(fw,j);        // string address
3977     int j1;
3978     for (j1 = j; j1 >= MAX(j-256,0); j1--)
3979     {
3980         if (isLDR(fw,j1))   // LDR ?
3981         {
3982             uint32_t pval = LDR2val(fw,j1);
3983             if (pval == sadr)
3984             {
3985                 int j2 = find_Nth_inst_rev(fw,instid,j1-1,sig->offset,ninst);
3986                 if (j2>0)
3987                 {
3988                     fwAddMatch(fw,idx2adr(fw,j2-ofst),32,0,124);
3989                     return 1;
3990                 }
3991             }
3992         }
3993         else if (isADR_PC(fw,j1))   // ADR ?
3994         {
3995             uint32_t pval = ADR2adr(fw,j1);
3996             if (pval == sadr)
3997             {
3998                 int j2 = find_Nth_inst_rev(fw,instid,j1-1,sig->offset,ninst);
3999                 if (j2>0)
4000                 {
4001                     fwAddMatch(fw,idx2adr(fw,j2-ofst),32,0,124);
4002                     return 1;
4003                 }
4004             }
4005         }
4006     }
4007 
4008     return 0;
4009 }
4010 
4011 // Call processing function based on type
4012 int find_strsig(firmware *fw, string_sig *sig)
4013 {
4014     switch (sig->type)
4015     {
4016     case 1:     return fw_string_process(fw, sig, match_strsig1, 1);
4017     case 2:     return fw_string_process_unaligned(fw, sig, match_strsig2);
4018     case 3:     return fw_string_process(fw, sig, match_strsig3, 1);
4019     case 4:     return fw_string_process(fw, sig, match_strsig4, 1);
4020     case 5:     return fw_string_process(fw, sig, match_strsig5, 1);
4021     case 6:     return fw_string_process(fw, sig, match_strsig6, 1);
4022     case 7:     return fw_string_process(fw, sig, match_strsig7, 1);
4023     case 8:     return find_strsig8(fw, sig);
4024     case 9:     return find_strsig9(fw, sig);
4025     case 11:    return fw_string_process(fw, sig, match_strsig11, 0);
4026     case 12:    return find_strsig12(fw, sig);
4027     case 13:    return fw_string_process_unaligned(fw, sig, match_strsig13);
4028     case 15:    return fw_string_process(fw, sig, match_strsig15, 1);
4029     case 16:    return fw_process(fw, sig, match_strsig16);
4030     case 17:    return find_strsig17(fw, sig);
4031     case 19:    return find_strsig19(fw, sig);
4032     case 20:
4033         {
4034             int j = find_saved_sig(sig->ev_name);
4035             if (j >= 0)
4036             {
4037                 uint32_t fadr = followBranch2(fw,func_names[j].val,sig->offset);
4038                 fwAddMatch(fw,fadr,32,0,120);
4039                 return 1;
4040             }
4041             return 0;
4042         }
4043     case 21:    return fw_process(fw, sig, (int (*)(firmware*, string_sig*, int))(sig->ev_name));
4044     case 22:    return ((int (*)(firmware*,int))(sig->ev_name))(fw,sig->offset);
4045     case 23:    return fw_string_process(fw, sig, match_strsig23, 1);
4046     case 24:    return fw_string_process(fw, sig, match_strsig24, 0);
4047     }
4048 
4049     return 0;
4050 }
4051 
4052 //------------------------------------------------------------------------------------------------------------
4053 
4054 // Matching functions
4055 
4056 // Search using new style matching only
4057 void find_str_sig_matches(firmware *fw, const char *curr_name)
4058 {
4059     int i;
4060 
4061     int found_ev = 0;
4062 
4063     count = 0;
4064 
4065     for (i = 0; string_sigs[i].ev_name != 0 && !found_ev; i++)
4066     {
4067         if (strcmp(curr_name, string_sigs[i].name) == 0)
4068         {
4069             if (find_strsig(fw, &string_sigs[i]))
4070             {
4071                 found_ev = 1;
4072                 break;
4073             }
4074         }
4075     }
4076 
4077     if (count > 1)
4078     {
4079         qsort(matches, count, sizeof(Match), (void*)match_compare);
4080     }
4081 
4082     if (count > 0)
4083     {
4084         save_sig(curr_name, matches->ptr);
4085     }
4086 }
4087 
4088 // Search using new style matching first
4089 // If not found used old style matching
4090 void find_matches(firmware *fw, const char *curr_name)
4091 {
4092     FuncSig *sig, *s;
4093     BufRange *n;
4094     uint32_t *p;
4095     int i, j;
4096     int fail, success;
4097 
4098     int found_ev = 0;
4099 
4100     count = 0;
4101 
4102     // Already found (eventproc)?
4103     i = find_saved_sig(curr_name);
4104     if (i >= 0)
4105     {
4106         if ((func_names[i].val != 0) && (func_names[i].flags & EV_MATCH) != 0)
4107         {
4108             fwAddMatch(fw,func_names[i].val,32,0,120);
4109             found_ev = 1;
4110         }
4111     }
4112 
4113 
4114     // Try and match using 'string' based signature matching first
4115     for (i = 0; string_sigs[i].ev_name != 0 && !found_ev; i++)
4116     {
4117         if (strcmp(curr_name, string_sigs[i].name) == 0)
4118         {
4119             if (find_strsig(fw, &string_sigs[i]))
4120             {
4121                 found_ev = 1;
4122                 break;
4123             }
4124         }
4125     }
4126 
4127     // If not found see if the name is in the old style instruction compare match table
4128     // Set start value for j in next section if found
4129     if (!found_ev)
4130     {
4131         found_ev = 1;
4132         for (j=0; func_list[j].name; j++)
4133         {
4134             if (strcmp(curr_name,func_list[j].name) == 0)
4135             {
4136                 found_ev = 0;
4137                 break;
4138             }
4139         }
4140     }
4141 
4142     // Not found so far, try instruction comparison matching
4143     while (!found_ev)
4144     {
4145         sig = func_list[j].sig;
4146 
4147         for (n = fw->br; n != 0; n = n->next)
4148         {
4149             for (p = n->p, i = 0; i < n->len; p++, i++)
4150             {
4151                 fail = 0;
4152                 success = 0;
4153                 for (s = sig; s->offs != 0xFFFFFFFF; s++)
4154                 {
4155                     if ((p[s->offs] & s->mask) != s->value)
4156                         fail++;
4157                     else
4158                         success++;
4159                 }
4160                 // If sig starts with STMFD and first instruction does not match ignore it
4161                 if (((p[sig->offs] & sig->mask) != sig->value) && (sig->offs == 0) && (sig->value == 0xe92d0000)) success = 0;
4162                 if (success > fail)
4163                 {
4164                     if (s->mask == 0xFFFFFFFE)
4165                     {
4166                         int end_branch = 0;
4167                         int idx = 0;
4168                         uint32_t *p1 = 0;
4169                         if ((fw->buf[n->off+i+s->value] & 0x0F000000) == 0x0A000000)   // B
4170                         {
4171                             idx = adr2idx(fw, followBranch2(fw, idx2adr(fw,n->off+i+s->value), 0xF0000001));
4172                             if ((idx >= 0) && (idx < fw->size))
4173                             {
4174                                 end_branch = 1;
4175                                 p1 = &fw->buf[idx];
4176                             }
4177                         }
4178                         int fail2 = 0;
4179                         int success2 = 0;
4180                         //fprintf(stderr,"\t%s %d %08x %08x %d %d\n",curr_name,idx,idx2adr(fw,idx),idx2adr(fw,i+n->off),success,fail);
4181                         s++;
4182                         for (; s->offs != 0xFFFFFFFF; s++)
4183                         {
4184                             if (!end_branch || (p1[s->offs] & s->mask) != s->value){
4185                                 fail2++;
4186                             } else {
4187                                 success2++;
4188                             }
4189                         }
4190                         if (fail2 == 0)
4191                         {
4192                             success = success + fail + success2;
4193                             fail = 0;
4194                         }
4195                         else
4196                         {
4197                             success = success + success2;
4198                             fail = fail + fail2;
4199                         }
4200                         //fprintf(stderr,"\t%s %d %08x %08x %d %d\n",curr_name,idx,idx2adr(fw,idx),idx2adr(fw,i+n->off),success,fail);
4201                     }
4202                 }
4203                 if (success > fail)
4204                 {
4205                     // Special case for drive space functions, see if there is a refernce to "Mounter.c" in the function
4206                     // Increase match % if so, increase fail count if not
4207                     if ((strcmp(curr_name, "GetDrive_ClusterSize") == 0) ||
4208                         (strcmp(curr_name, "GetDrive_FreeClusters") == 0) ||
4209                         (strcmp(curr_name, "GetDrive_TotalClusters") == 0))
4210                     {
4211                         int fnd = 0;
4212                         for (s = sig; s->offs != 0xFFFFFFFF; s++)
4213                         {
4214                             if (isLDR_PC_cond(fw,n->off+i+s->offs))
4215                             {
4216                                 int m = adr2idx(fw,LDR2val(fw,n->off+i+s->offs));
4217                                 if ((m >= 0) && (m < fw->size) && (strcmp((char*)(&fw->buf[m]),"Mounter.c") == 0))
4218                                 {
4219                                     fnd = 1;
4220                                 }
4221                             }
4222                             else if (isADR_PC_cond(fw,n->off+i+s->offs))
4223                             {
4224                                 int m = adr2idx(fw,ADR2adr(fw,n->off+i+s->offs));
4225                                 if ((m >= 0) && (m < fw->size) && (strcmp((char*)(&fw->buf[m]),"Mounter.c") == 0))
4226                                 {
4227                                     fnd = 1;
4228                                 }
4229                             }
4230                         }
4231                         if (fnd)
4232                             success++;
4233                         else
4234                             fail++;
4235                     }
4236                     fwAddMatch(fw,idx2adr(fw,i+n->off),success,fail,func_list[j].ver);
4237                     if (count >= MAX_MATCHES)
4238                     {
4239                         bprintf("// WARNING: too many matches for %s!\n", func_list[j].name);
4240                         break;
4241                     }
4242                 }
4243             }
4244         }
4245 
4246         // same name, so we have another version of the same function
4247         if ((func_list[j+1].name == NULL) || (strcmp(curr_name, func_list[j+1].name) != 0))
4248         {
4249             found_ev = 1;
4250             break;
4251         }
4252         j++;
4253     }
4254 
4255     if (count > 1)
4256     {
4257         qsort(matches, count, sizeof(Match), (void*)match_compare);
4258     }
4259 
4260     if (count > 0)
4261     {
4262         save_sig(curr_name, matches->ptr);
4263     }
4264 }
4265 
4266 // Output match results for function
4267 void print_results(firmware *fw, const char *curr_name, int k)
4268 {
4269     int i;
4270     int err = 0;
4271     char line[500] = "";
4272 
4273     if (func_names[k].flags & DONT_EXPORT) return;
4274 
4275     // find best match and report results
4276     osig* ostub2 = find_sig(fw->sv->stubs,curr_name);
4277 
4278     if ((count == 0)
4279         || (matches->fail > 0)
4280         || (ostub2 && (matches->ptr != ostub2->val))
4281        )
4282     {
4283         if (!ostub2 || (ostub2->type != TYPE_IGNORE))
4284             err = 1;
4285         func_names[k].flags |= BAD_MATCH;
4286     }
4287     else
4288     {
4289         if (func_names[k].flags & UNUSED) return;
4290     }
4291 
4292     // write to header (if error) or body buffer (no error)
4293     out_hdr = err;
4294 
4295     char *macro = "NHSTUB";
4296     if (strncmp(curr_name,"task_",5) == 0 ||
4297         strncmp(curr_name,"hook_",5) == 0) macro = "   DEF";
4298 
4299     if (count == 0)
4300     {
4301         if (func_names[k].flags & OPTIONAL) return;
4302         char fmt[51] = "";
4303         sprintf(fmt, "// ERROR: %%s is not found. %%%ds//--- --- ", (int)(34-strlen(curr_name)));
4304         sprintf(line+strlen(line), fmt, curr_name, "");
4305     }
4306     else
4307     {
4308         if (ostub2 || (func_names[k].flags & UNUSED))
4309             sprintf(line+strlen(line),"//%s(%-37s,0x%08x) //%3d ", macro, curr_name, matches->ptr, matches->sig);
4310         else
4311             sprintf(line+strlen(line),"%s(%-39s,0x%08x) //%3d ", macro, curr_name, matches->ptr, matches->sig);
4312 
4313         if (matches->fail > 0)
4314             sprintf(line+strlen(line),"%2d%% ", matches->success*100/(matches->success+matches->fail));
4315         else
4316             sprintf(line+strlen(line),"    ");
4317     }
4318 
4319     if (ostub2)
4320     {
4321         if (ostub2->type == TYPE_IGNORE)
4322             sprintf(line+strlen(line),"       Overridden");
4323         else if ((count > 0) && (matches->ptr == ostub2->val))
4324             sprintf(line+strlen(line),"       == 0x%08x    ",ostub2->val);
4325         else
4326             sprintf(line+strlen(line),"   *** != 0x%08x    ",ostub2->val);
4327     }
4328     else
4329         sprintf(line+strlen(line),"                        ");
4330 
4331     for (i=strlen(line)-1; i>=0 && line[i]==' '; i--) line[i] = 0;
4332     bprintf("%s\n",line);
4333 
4334     for (i=1;i<count && matches[i].fail==matches[0].fail;i++)
4335     {
4336         if (matches[i].ptr != matches->ptr)
4337         {
4338             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);
4339         }
4340     }
4341 }
4342 
4343 //------------------------------------------------------------------------------------------------------------
4344 
4345 typedef struct
4346 {
4347     uint16_t mode;
4348     char *nm;
4349 } ModeMapName;
4350 
4351 ModeMapName mmnames[] = {
4352     { 32768,"MODE_AUTO" },
4353     { 32769,"MODE_M" },
4354     { 32770,"MODE_AV" },
4355     { 32771,"MODE_TV" },
4356     { 32772,"MODE_P" },
4357 
4358     { 65535,"" }
4359 };
4360 
4361 char* mode_name(uint16_t v)
4362 {
4363     int i;
4364     for (i=0; mmnames[i].mode != 65535; i++)
4365     {
4366         if (mmnames[i].mode == v)
4367             return mmnames[i].nm;
4368     }
4369 
4370     return "";
4371 }
4372 
4373 void output_modemap(firmware *fw, int k)
4374 {
4375     int cnt = 0;
4376 
4377     if (isLDR_PC(fw,k))
4378     {
4379         k = adr2idx(fw,LDR2val(fw,k));
4380         bprintf("%08x\n",idx2adr(fw,k));
4381         uint16_t *p = (uint16_t*)(&fw->buf[k]);
4382         k = 0;
4383         while ((*p != 0xFFFF) && (k < 50))
4384         {
4385             if (((fw->dryos_ver < 47) && ((*p < 8000) || (*p > 8999))) || ((fw->dryos_ver >= 47) && ((*p < 4000) || (*p > 4999))))
4386             {
4387                 osig *m = find_sig_val(fw->sv->modemap, *p);
4388                 if (!m)
4389                 {
4390                     char *s = mode_name(*p);
4391                     bprintf("// Mode %5d in firmware but not in current modemap",*p);
4392                     if (strcmp(s,"") != 0)
4393                         bprintf(" (%s)",s);
4394                     bprintf("\n");
4395                     cnt++;
4396                 }
4397                 else
4398                 {
4399                     m->pct = 100;
4400                 }
4401             }
4402             p++;
4403             k++;
4404         }
4405     }
4406     osig *m = fw->sv->modemap;
4407     while (m)
4408     {
4409         if (m->pct != 100)    // not matched above?
4410         {
4411             bprintf("// Current modemap entry not found in firmware - %-24s %5d\n",m->nm,m->val);
4412             cnt++;
4413         }
4414         m = m->nxt;
4415     }
4416     if (cnt == 0)
4417     {
4418         bprintf("// No problems found with modemap table.\n");
4419     }
4420 }
4421 
4422 int match_modelist(firmware *fw, int k, uint32_t fadr, __attribute__ ((unused))uint32_t v2)
4423 {
4424     if (isBX_LR(fw,k) && (fw->buf[k+4] == fadr))
4425     {
4426         fadr = fwval(fw,k+1);
4427         int k1;
4428         for (k1=k-1; k1>k-20; k1--)
4429         {
4430             if (isLDR_PC(fw,k1) && (LDR2val(fw,k1) == fadr))
4431             {
4432                 bprintf("// Firmware modemap table found @%08x -> ",idx2adr(fw,k1));
4433                 output_modemap(fw,k1);
4434                 return 1;
4435             }
4436         }
4437     }
4438 
4439     return 0;
4440 }
4441 
4442 static uint32_t FlashParamsTable_address = 0;
4443 
4444 int match_FlashParamsTable2(firmware *fw, int k, uint32_t v1, __attribute__ ((unused))uint32_t v2)
4445 {
4446     if (fw->buf[k] == v1)
4447     {
4448         FlashParamsTable_address = idx2adr(fw,k);
4449         return 1;
4450     }
4451     return 0;
4452 }
4453 
4454 int match_FlashParamsTable(firmware *fw, int k, __attribute__ ((unused))uint32_t v1, __attribute__ ((unused))uint32_t v2)
4455 {
4456     if ((fw->buf[k] > fw->base) && (fw->buf[k+1] == 0x00010000) && (fw->buf[k+2] == 0xFFFF0002))
4457     {
4458         if (search_fw(fw, match_FlashParamsTable2, idx2adr(fw,k), 0, 1))
4459             return 1;
4460     }
4461     return 0;
4462 }
4463 
4464 void find_modemap(firmware *fw)
4465 {
4466     out_hdr = 1;
4467 
4468     // Find 'FlashParamsTable'
4469     search_fw(fw, match_FlashParamsTable, 0, 0, 1);
4470     // Find 'modelist'
4471     if (FlashParamsTable_address != 0)
4472     {
4473         add_blankline();
4474         bprintf("// Check of modemap from 'platform/CAMERA/shooting.c':\n");
4475         search_fw(fw, match_modelist, FlashParamsTable_address, 0, 5);
4476     }
4477 }
4478 
4479 //------------------------------------------------------------------------------------------------------------
4480 
4481 int match_CAM_UNCACHED_BIT(firmware *fw, int k, __attribute__ ((unused))int v)
4482 {
4483     if ((fw->buf[k] & 0x0FFFF000) == 0x03C00000)    // BIC
4484     {
4485         fw->uncached_adr = ALUop2(fw,k);
4486         fw->uncached_adr_idx = k;
4487     }
4488 
4489     return 0;
4490 }
4491 
4492 int find_DebugAssert_argcount(firmware *fw)
4493 {
4494     int s1 = find_str_ref(fw, "CameraLog.c");
4495     if (s1 < 0)
4496         return 0;
4497     int k = isADR_PC_cond(fw, s1);
4498     if (!k)
4499         return 0;
4500     k = fwRd(fw, s1);
4501     if (k > 0)
4502         bprintf("//#define CAM_3ARG_DebugAssert 1\n");
4503     return 1;
4504 }
4505 
4506 // Search for things that go in 'platform_camera.h'
4507 void find_platform_vals(firmware *fw)
4508 {
4509     int k,k1;
4510 
4511     out_hdr = 1;
4512     add_blankline();
4513 
4514     bprintf("// Values below go in 'platform_camera.h':\n");
4515     bprintf("//#define CAM_DRYOS         1\n");
4516     if (fw->dryos_ver >= 39)
4517         bprintf("//#define CAM_DRYOS_2_3_R39 1 // Defined for cameras with DryOS version R39 or higher\n");
4518     if (fw->dryos_ver >= 47)
4519         bprintf("//#define CAM_DRYOS_2_3_R47 1 // Defined for cameras with DryOS version R47 or higher\n");
4520     if (fw->dryos_ver >= 59)
4521         bprintf("//#define CAM_DRYOS_2_3_R59 1 // Defined for cameras with DryOS version R59 or higher\n");
4522 
4523     // Find 'RAW' image size
4524     uint32_t raw_width = 0;
4525     uint32_t raw_height = 0;
4526     uint32_t kw=0, kh=0;
4527 
4528     k = find_str_ref(fw, "\r[%ld] AdjDrvType[%02ld] -> DrvType[%02");
4529     if (k >= 0)
4530     {
4531         // Width
4532         for (k1 = k-1; k1 >= k-20; k1--)
4533         {
4534             if ((fw->buf[k1] & 0x0FFF0FFF) == 0x058D0034)           // STRxx Rn, [SP,#0x34]
4535             {
4536                 if ((fw->buf[k1-1] & 0x0FFF0000) == 0x03A00000)     // MOVxx Rn, #YYY
4537                 {
4538                     raw_width = ALUop2(fw, k1-1);
4539                     kw = k1-1;
4540                 }
4541                 else if ((fw->buf[k1-2] & 0x0FFF0000) == 0x03A00000)// MOVxx Rn, #YYY
4542                 {
4543                     raw_width = ALUop2(fw, k1-2);
4544                     kw = k1-2;
4545                 }
4546                 else if (isLDR_PC_cond(fw,k1-1))
4547                 {
4548                     raw_width = LDR2val(fw,k1-1);
4549                     kw = k1-1;
4550                 }
4551                 else if (isLDR_PC_cond(fw,k1-2))
4552                 {
4553                     raw_width = LDR2val(fw,k1-2);
4554                     kw = k1-2;
4555                 }
4556             }
4557         }
4558         // Height
4559         for (k1 = k-1; k1 >= k-20; k1--)
4560         {
4561             if ((fw->buf[k1] & 0x0FFF0FFF) == 0x058D0030)           // STRxx Rn, [SP,#0x30]
4562             {
4563                 if ((fw->buf[k1-1] & 0x0FFF0000) == 0x03A00000)     // MOVxx Rn, #YYY
4564                 {
4565                     raw_height = ALUop2(fw, k1-1);
4566                     kh = k1-1;
4567                 }
4568                 else if ((fw->buf[k1-2] & 0x0FFF0000) == 0x03A00000)// MOVxx Rn, #YYY
4569                 {
4570                     raw_height = ALUop2(fw, k1-2);
4571                     kh = k1-2;
4572                 }
4573                 else if (isLDR_PC_cond(fw,k1-1))
4574                 {
4575                     raw_height = LDR2val(fw,k1-1);
4576                     kh = k1-1;
4577                 }
4578                 else if (isLDR_PC_cond(fw,k1-2))
4579                 {
4580                     raw_height = LDR2val(fw,k1-2);
4581                     kh = k1-2;
4582                 }
4583                 if ((fw->buf[k1-1] & 0x0FFF0000) == 0x02400000)     // SUBxx Rn, #YYY
4584                 {
4585                     raw_height = raw_width - ALUop2(fw, k1-1);
4586                     kh = k1-1;
4587                 }
4588             }
4589         }
4590     }
4591 
4592     if ((raw_width == 0) && (raw_height == 0))
4593     {
4594         k = find_str_ref(fw, " CrwAddress %lx, CrwSize H %ld V %ld\r");
4595         if (k >= 0)
4596         {
4597             // Width
4598             for (k1=k-1; k1>=k-5; k1--)
4599             {
4600                 if ((fw->buf[k1] & 0xFFFFF000) == 0xE3A02000)       // MOV R2, #nnn
4601                 {
4602                     raw_width = ALUop2(fw,k1);
4603                     kw = k1;
4604                 }
4605                 else
4606                 if (isLDR_PC(fw,k1) && ((fw->buf[k1]& 0x0000F000) == 0x00002000))   // LDR R2, =nnn
4607                 {
4608                     raw_width = LDR2val(fw,k1);
4609                     kw = k1;
4610                 }
4611             }
4612             // Height
4613             for (k1=k-1; k1>=k-5; k1--)
4614             {
4615                 if ((fw->buf[k1] & 0xFFFFF000) == 0xE3A03000)       // MOV R3, #nnn
4616                 {
4617                     raw_height = ALUop2(fw,k1);
4618                     kh = k1;
4619                 }
4620                 else
4621                 if (isLDR_PC(fw,k1) && ((fw->buf[k1]& 0x0000F000) == 0x00003000))   // LDR R3, =nnn
4622                 {
4623                     raw_height = LDR2val(fw,k1);
4624                     kh = k1;
4625                 }
4626                 else
4627                 if ((fw->buf[k1] & 0xFFFFF000) == 0xE2423000)       // SUB R3, R2, #nnn
4628                 {
4629                     raw_height = raw_width - ALUop2(fw,k1);
4630                     kh = k1;
4631                 }
4632             }
4633         }
4634     }
4635 
4636     if (raw_width != 0)
4637     {
4638         bprintf("//#define CAM_RAW_ROWPIX    %d // Found @0x%08x\n",raw_width,idx2adr(fw,kw));
4639     }
4640     else
4641     {
4642         bprintf("//#define CAM_RAW_ROWPIX    *** Not Found ***\n");
4643     }
4644     if (raw_height != 0)
4645     {
4646         bprintf("//#define CAM_RAW_ROWS      %d // Found @0x%08x\n",raw_height,idx2adr(fw,kh));
4647     }
4648     else
4649     {
4650         bprintf("//#define CAM_RAW_ROWS      *** Not Found ***\n");
4651     }
4652 
4653     // Find 'CAM_UNCACHED_BIT'
4654     if (fw->uncached_adr_idx != 0)
4655     {
4656         bprintf("//#undef  CAM_UNCACHED_BIT\n");
4657         bprintf("//#define CAM_UNCACHED_BIT  0x%08x // Found @0x%08x\n",fw->uncached_adr,idx2adr(fw,fw->uncached_adr_idx));
4658     }
4659 
4660     // Look for CAM_DATE_FOLDER_NAMING value
4661     k = get_saved_sig(fw,"GetImageFolder");
4662     if (k >= 0)
4663     {
4664         uint32_t fadr = func_names[k].val;
4665         int s = adr2idx(fw,fadr);
4666         int e = find_inst(fw, isLDMFD_PC, s+1, 160);
4667         for (k1=s+1; k1<s+16; k1++)
4668         {
4669             if (isMOV(fw,k1) && (fwRnMOV(fw,k1) == 2))
4670             {
4671                 int r1 = fwRd(fw,k1);
4672                 int k2;
4673                 for (k2=e-32; k2<e; k2++)
4674                 {
4675                     int b = 0;
4676                     if (isMOV(fw,k2) && isBL(fw,k2+1) && (fwRnMOV(fw,k2) == r1))
4677                         b = 1;
4678                     else if (isMOV(fw,k2) && isBL(fw,k2+7) && (fwRnMOV(fw,k2) == r1))
4679                         b = 7;
4680                     if (b != 0)
4681                     {
4682                         int r2 = fwRd(fw,k2);
4683                         fadr = followBranch2(fw,idx2adr(fw,k2+b),0x01000001);
4684                         k = adr2idx(fw,fadr);
4685                         int k3;
4686                         for (k3=k; k3<k+8; k3++)
4687                         {
4688                             if (isCMP(fw,k3) && (fwRn(fw,k3) == r2))
4689                             {
4690                                 int val = ALUop2(fw,k3);
4691                                 bprintf("//#define CAM_DATE_FOLDER_NAMING 0x%03x // Found @0x%08x (pass as 3rd param to GetImageFolder)\n",val,idx2adr(fw,k3));
4692                             }
4693                         }
4694                     }
4695                 }
4696             }
4697         }
4698     }
4699 
4700     // Find 'PARAM_CAMERA_NAME'
4701     if (FlashParamsTable_address != 0)
4702     {
4703         k1 = adr2idx(fw,FlashParamsTable_address);
4704         for (k=k1; k<k1+20; k++)
4705         {
4706             uint32_t fadr = fwval(fw,k);
4707             int k2 = adr2idx(fw,fadr);
4708             if (idx_valid(fw,k2))
4709             {
4710                 uint32_t sadr = fwval(fw,k2);
4711                 k2 = adr2idx(fw,sadr);
4712                 if (idx_valid(fw,k2))
4713                 {
4714                     char *s = adr2ptr(fw,sadr);
4715                     if (((fw->cam != 0) && (strcmp(s,fw->cam) == 0)) || (strcmp(s,"Unknown") == 0))
4716                     {
4717                         bprintf("//#define PARAM_CAMERA_NAME %d // Found @0x%08x\n",k-k1,fadr);
4718                         break;
4719                     }
4720                 }
4721             }
4722         }
4723     }
4724 
4725     find_DebugAssert_argcount(fw);
4726 
4727     if (cam_has_wifi) {
4728         bprintf("//#define CAM_HAS_WIFI 1 // Firmware has wifi support (only define if camera has hardware)\n");
4729     }
4730 
4731     k = get_saved_sig(fw,"task_FileWrite");
4732     if (k >= 0)
4733     {
4734         uint32_t fadr = func_names[k].val;
4735         k1 = adr2idx(fw, fadr);
4736         for (k=1; k<32; k++)
4737         {
4738             if ((fwval(fw, k1+k) & 0x0fffff00) == 0x008ff100) // add[cond] pc, pc, rx, lsl#2
4739             {
4740                 for (k++;isB(fw,k1+k) && idxFollowBranch(fw,k1+k,1) != idxFollowBranch(fw,k1+k-1,1);k++);
4741                 int c = 1;
4742                 for (;isB(fw,k1+k) && idxFollowBranch(fw,k1+k,1) == idxFollowBranch(fw,k1+k-1,1);k++,c++);
4743                 bprintf("\n// Below goes in 'filewrite.c' or 'platform_camera.h':\n");
4744                 bprintf("//#define MAX_CHUNKS_FOR_FWT %d // Found @0x%08x\n",c,idx2adr(fw,k+k1));
4745                 break;
4746             }
4747         }
4748     }
4749 }
4750 
4751 //------------------------------------------------------------------------------------------------------------
4752 
4753 uint32_t find_viewport_address(firmware *fw, int *kout)
4754 {
4755     int k, k1;
4756 
4757     // find viewwport address for 'vid_get_viewport_fb'
4758     k = find_str_ref(fw, "VRAM Address  : %p\r");
4759     if (k >= 0)
4760     {
4761         for (k1=k-1; k1>k-8; k1--)
4762         {
4763             if (isLDR(fw,k1) && isLDR(fw,k1+1))
4764             {
4765                 uint32_t v1 = LDR2val(fw,k1);
4766                 uint32_t v2 = LDR2val(fw,k1+1);
4767                 if (v2 > v1) v1 = v2;
4768                 *kout = k1;
4769                 return v1;
4770             }
4771         }
4772     }
4773 
4774     *kout = -1;
4775     return 0;
4776 }
4777 
4778 int match_vid_get_bitmap_fb(firmware *fw, int k, __attribute__ ((unused))int v)
4779 {
4780     if (isBL(fw,k-1) && // BL
4781         isLDR_PC(fw,k))
4782     {
4783         uint32_t v1 = LDR2val(fw,k);
4784         bprintf("//void *vid_get_bitmap_fb()        { return (void*)0x%08x; }             // Found @0x%08x\n",v1,idx2adr(fw,k));
4785         return 1;
4786     }
4787     else
4788     if (isBL(fw,k-1) && // BL
4789         (isLDR_PC(fw,k+1)))
4790     {
4791         uint32_t v1 = LDR2val(fw,k+1);
4792         bprintf("//void *vid_get_bitmap_fb()        { return (void*)0x%08x; }             // Found @0x%08x\n",v1,idx2adr(fw,k));
4793         return 1;
4794     }
4795 
4796     return 0;
4797 }
4798 
4799 int match_get_flash_params_count(firmware *fw, int k, __attribute__ ((unused))int v)
4800 {
4801     if ((fw->buf[k] & 0xFFF00FFF) == 0xE3C00901)    // BIC Rn, Rn, #0x4000
4802     {
4803         uint32_t r = fw->buf[k] & 0x000F0000;       // Register
4804         if (((fw->buf[k+1] & 0xFFF00000) == 0xE3500000) && ((fw->buf[k+1] & 0x000F0000) == r))  // CMP, Rn #val
4805         {
4806             bprintf("//int get_flash_params_count(void) { return 0x%02x; }                          // Found @0x%08x\n",fw->buf[k+1]&0xFFF,idx2adr(fw,k+1));
4807             return 1;
4808         }
4809     }
4810 
4811     return 0;
4812 }
4813 
4814 // based on match_get_flash_params_count
4815 int match_uiprop_count(firmware *fw, int k, __attribute__ ((unused))int v)
4816 {
4817     if ((fw->buf[k] & 0xFFF00FFF) == 0xe3c00902)    // BIC Rn, Rn, #0x8000
4818     {
4819         uint32_t r = fw->buf[k] & 0x000F0000;       // Register
4820         if (((fw->buf[k+1] & 0xFFF00000) == 0xE3500000) && ((fw->buf[k+1] & 0x000F0000) == r))  // CMP, Rn #val
4821         {
4822             char *name = "uiprop_count";
4823             uint32_t fadr = fw->buf[k+1]&0xFFF;
4824             osig *o = find_sig(fw->sv->stubs_min,name);
4825             if (o)
4826             {
4827                 bprintf("//DEF_CONST(%-34s,0x%08x) // Found @0x%08x",name,fadr,idx2adr(fw,k+1));
4828                 if (fadr != o->val)
4829                 {
4830                     bprintf(", ** != ** stubs_min = 0x%08x (%s)",o->val,o->sval);
4831                 }
4832                 else
4833                 {
4834                     bprintf(",          stubs_min = 0x%08x (%s)",o->val,o->sval);
4835                 }
4836             }
4837             else
4838             {
4839                 bprintf("DEF_CONST(%-34s,0x%08x) // Found @0x%08x",name,fadr,idx2adr(fw,k+1));
4840             }
4841             bprintf("\n");
4842             return 1;
4843         }
4844     }
4845 
4846     return 0;
4847 }
4848 
4849 int match_imager_active(firmware *fw, int k, __attribute__ ((unused))int v)
4850 {
4851     int gotit = 0;
4852     int reg = -1;
4853     int o = 0;
4854     uint32_t adr,where;
4855     if (isLDMFD_PC(fw,k))
4856     {
4857         int k1 = find_inst_rev(fw, isBL, k-1, 10);
4858         if (k1 == -1)
4859             return 0;
4860         uint32_t a;
4861         int k2 = k1 - 8;
4862         for (k1=k1-1;k1>=k2;k1--)
4863         {
4864             if (isLDR(fw,k1) || isADR(fw,k1))
4865             {
4866                 if (isADR(fw,k1))
4867                 {
4868                     a = ADR2adr(fw, k1);
4869                 }
4870                 else
4871                 {
4872                     a = LDR2val(fw, k1);
4873                 }
4874                 if ((a>fw->base) && ((a&3) == 0))
4875                 {
4876                     int k3 = adr2idx(fw, a);
4877                     if (isSTMFD_LR(fw,k3))
4878                     {
4879                         k3 = find_inst(fw, isBLX, k3+1, 6);
4880                         if (k3 != -1)
4881                         {
4882                             int k4;
4883                             for(k4=5; k4>0; k4--)
4884                             {
4885                                 if (isSTR_cond(fw,k3+k4))
4886                                 {
4887                                     reg = fwRn(fw,k3+k4);
4888                                     o = fwval(fw,k3+k4) & 0xff; // offset, should be around 4
4889                                     where = idx2adr(fw,k3+k4);
4890                                 }
4891                                 if (reg>=0 && isLDR_cond(fw,k3+k4) && fwRd(fw,k3+k4)==reg)
4892                                 {
4893                                     adr = LDR2val(fw,k3+k4);
4894                                     if (adr < fw->memisostart)
4895                                     {
4896                                         gotit = 1;
4897                                         break;
4898                                     }
4899                                 }
4900                             }
4901                             if (gotit)
4902                                 break;
4903                         }
4904                     }
4905                 }
4906             }
4907         }
4908     }
4909     if (gotit)
4910     {
4911         bprintf("DEF(%-40s,0x%08x) // Found @0x%08x (0x%x + %i)\n","imager_active",adr+o,where,adr,o);
4912         return 1;
4913     }
4914     return 0;
4915 }
4916 
4917 // Search for things that go in 'lib.c'
4918 void find_lib_vals(firmware *fw)
4919 {
4920     int k,k1;
4921 
4922     out_hdr = 1;
4923     add_blankline();
4924 
4925     bprintf("// Values below go in 'lib.c':\n");
4926 
4927     // Find 'vid_get_bitmap_fb'
4928     search_saved_sig(fw, "DispCon_ShowBitmapColorBar", match_vid_get_bitmap_fb, 0, 1, 30);
4929 
4930     // find 'vid_get_viewport_fb'
4931     uint32_t v = find_viewport_address(fw,&k);
4932     if (k >= 0)
4933     {
4934         bprintf("//void *vid_get_viewport_fb()      { return (void*)0x%08x; }             // Found @0x%08x\n",v,idx2adr(fw,k));
4935     }
4936 
4937     // find 'vid_get_viewport_fb_d'
4938     static int fbd[3][3] =
4939     {
4940         { -2, -3,  1 },
4941         {  1,  3,  4 },
4942         { -1, -2,  1 },
4943     };
4944     int sadr = find_str(fw, "ImagePlayer.c");
4945     k = find_nxt_str_ref(fw, sadr, -1);
4946     int found = 0;
4947     while ((k >= 0) && !found)
4948     {
4949         int f;
4950         for (f=0; f<3 && !found; f++)
4951         {
4952             if (isLDR(fw,k+fbd[f][0]) && isLDR(fw,k+fbd[f][1]) && isLDR(fw,k+fbd[f][2]))
4953             {
4954                 uint32_t reg = fw->buf[k+fbd[f][2]] & 0x000F0000;    // Index register used
4955                 int ka = 0;
4956                 if (((fw->buf[k+fbd[f][0]] & 0x0000F000) << 4) == reg)      { ka = k+fbd[f][0]; }
4957                 else if (((fw->buf[k+fbd[f][1]] & 0x0000F000) << 4) == reg) { ka = k+fbd[f][1]; }
4958                 if (ka > 0)
4959                 {
4960                     uint32_t adr = LDR2val(fw,ka);
4961                     for (k1=k+2; k1<k+20; k1++)
4962                     {
4963                         if (isSTR(fw,k1) && ((fw->buf[k1] & 0x000F0000) == reg))
4964                         {
4965                             uint32_t ofst = fw->buf[k1] & 0x00000FFF;
4966                             bprintf("DEF(%-40s,0x%08x) // Found 0x%04x (@0x%08x) + 0x%02x (@0x%08x)\n","viewport_fb_d",adr+ofst,adr,idx2adr(fw,ka),ofst,idx2adr(fw,k1));
4967                             bprintf("//void *vid_get_viewport_fb_d()    { return (void*)(*(int*)(0x%04x+0x%02x)); } // Found @0x%08x & 0x%08x\n",adr,ofst,idx2adr(fw,ka),idx2adr(fw,k1));
4968                             found = 1;
4969                             break;
4970                         }
4971                     }
4972                 }
4973             }
4974         }
4975         k = find_nxt_str_ref(fw, sadr, k);
4976     }
4977 
4978     // find 'camera_jpeg_count_str'
4979     k = find_str_ref(fw, "9999");
4980     if (k >= 0)
4981     {
4982         if (isLDR(fw,k-1) && isBL(fw,k+1))
4983         {
4984             uint32_t v1 = LDR2val(fw,k-1);
4985             bprintf("DEF(%-40s,0x%08x) // Found @0x%08x\n","jpeg_count_str",v1,idx2adr(fw,k-1));
4986             bprintf("//char *camera_jpeg_count_str()    { return (char*)0x%08x; }             // Found @0x%08x\n",v1,idx2adr(fw,k-1));
4987         }
4988     }
4989 
4990 //    // find 'hook_raw_size'
4991 //    k = find_str_ref(fw, "CRAW BUFF SIZE  %p");
4992 //    if (k >= 0)
4993 //    {
4994 //        if (isLDR(fw,k-1))
4995 //        {
4996 //            uint32_t craw_bufsize = LDR2val(fw,k-1);
4997 //            bprintf("//long hook_raw_size()             { return 0x%08x; }                    // Found @0x%08x\n",craw_bufsize,idx2adr(fw,k-1));
4998 //        }
4999 //    }
5000 
5001     // Find value for 'get_flash_params_count'
5002     search_saved_sig(fw, "GetParameterData", match_get_flash_params_count, 0, 0, 30);
5003 }
5004 
5005 //------------------------------------------------------------------------------------------------------------
5006 
5007 void print_stubs_min(firmware *fw, const char *name, uint32_t fadr, uint32_t atadr)
5008 {
5009     osig *o = find_sig(fw->sv->stubs_min,name);
5010     if (o)
5011     {
5012         bprintf("//DEF(%-40s,0x%08x) // Found @0x%08x",name,fadr,atadr);
5013         if (fadr != o->val)
5014         {
5015             bprintf(", ** != ** stubs_min = 0x%08x (%s)",o->val,o->sval);
5016         }
5017         else
5018         {
5019             bprintf(",          stubs_min = 0x%08x (%s)",o->val,o->sval);
5020         }
5021     }
5022     else
5023     {
5024         bprintf("DEF(%-40s,0x%08x) // Found @0x%08x",name,fadr,atadr);
5025     }
5026     bprintf("\n");
5027 }
5028 
5029 uint32_t exm_typ_tbl=0, exm_typ_cnt=0;
5030 int print_exmem_types(firmware *fw)
5031 {
5032     if (exm_typ_tbl==0 || exm_typ_cnt==0)
5033         return 1;
5034     bprintf("// EXMEM types:\n");
5035     int ii = adr2idx(fw, exm_typ_tbl);
5036     uint32_t n;
5037     for (n=0; n<exm_typ_cnt; n++)
5038     {
5039         bprintf("// %s %i\n",adr2ptr(fw, fwval(fw,ii+n)),n);
5040     }
5041     bprintf("\n");
5042     return 0;
5043 }
5044 
5045 int find_exmem_alloc_table(firmware *fw)
5046 {
5047     int i = get_saved_sig(fw,"ExMem.View_FW"); // s5 and earlier don't have this
5048     if (i < 0)
5049     {
5050         i = get_saved_sig(fw,"exmem_assert"); // s5
5051     }
5052     if (i < 0)
5053     {
5054         return 0;
5055     }
5056     i = adr2idx(fw, func_names[i].val);
5057     uint32_t u, us;
5058     uint32_t exm_typ_tbl_orig = 0;
5059     int n;
5060     us = 0;
5061     for (n=1; n<16; n++)
5062     {
5063         if ( ((fwval(fw,i+n)&0xffff0000)==0xe59f0000) ) // ldr rx, [pc, #imm]
5064         {
5065             u = LDR2val(fw, i+n);
5066             if (u>fw->data_start && u<fw->data_start+fw->data_len*4 && (fwRd(fw,i+n)>3))
5067             {
5068                 exm_typ_tbl_orig = u;
5069                 u = u - fw->data_start + fw->data_init_start;
5070                 break;
5071             }
5072             else if (us==0 && u>fw->base && u<fw->base+fw->size*4-4 && (u&3)==0)
5073             {
5074                 us = u;
5075             }
5076         }
5077         u = 0;
5078     }
5079     if (!u && us)
5080     {
5081         u = us;
5082         exm_typ_tbl_orig = u;
5083     }
5084     if (u)
5085     {
5086         exm_typ_tbl = u;
5087         int ii = adr2idx(fw, exm_typ_tbl);
5088         char* extyp;
5089         for (n=0; n<32; n++)
5090         {
5091             if ( (fwval(fw,ii+n)!=0) && isASCIIstring(fw, fwval(fw,ii+n)) )
5092             {
5093                 extyp = adr2ptr(fw, fwval(fw,ii+n));
5094                 if ( strncmp(extyp,"EXMEM",5)==0 )
5095                 {
5096                     exm_typ_cnt++;
5097                 }
5098             }
5099             else
5100             {
5101                 break;
5102             }
5103         }
5104     }
5105 
5106     for (n=1; n<42; n++)
5107     {
5108         if ( ((fwval(fw,i+n)&0xffff0000)==0xe59f0000) ) // ldr rx, [pc, #imm]
5109         {
5110             u = LDR2val(fw, i+n);
5111             if (u>fw->data_start+fw->data_len*4 && u<fw->memisostart && (fwRd(fw,i+n)>3))
5112             {
5113                 break;
5114             }
5115         }
5116         u = 0;
5117     }
5118     if (u)
5119     {
5120         print_stubs_min(fw,"exmem_alloc_table",u,idx2adr(fw,i+n));
5121     }
5122     if (exm_typ_tbl)
5123     {
5124         print_stubs_min(fw,"exmem_types_table",exm_typ_tbl,exm_typ_tbl_orig);
5125     }
5126     if (exm_typ_cnt)
5127     {
5128         bprintf("DEF_CONST(%-34s,0x%08x)\n","exmem_type_count",exm_typ_cnt);
5129     }
5130     return 0;
5131 }
5132 
5133 int match_levent_table(firmware *fw, int k, __attribute__ ((unused))uint32_t v1, __attribute__ ((unused))uint32_t v2)
5134 {
5135     if ((fw->buf[k] > fw->base) && (fw->buf[k+1] == 0x00000800) && (fw->buf[k+2] == 0x00000002))
5136     {
5137         print_stubs_min(fw,"levent_table",idx2adr(fw,k),idx2adr(fw,k));
5138 #ifdef PRINT_LEVENT_TABLE
5139         uint32_t levent_tbl = idx2adr(fw,k);
5140         void write_levent_table_dump(firmware*, uint32_t);
5141         write_levent_table_dump(fw, levent_tbl);
5142 #endif
5143     }
5144     return 0;
5145 }
5146 
5147 int match_movie_status(firmware *fw, int k, __attribute__ ((unused))uint32_t v1, __attribute__ ((unused))uint32_t v2)
5148 {
5149     if (isLDR_PC(fw, k) &&                              // LDR R0, =base
5150         ((fw->buf[k+1] & 0xFE0F0000) == 0xE20F0000) &&  // ADR R1, =sub
5151         isSTR(fw, k+2) &&                               // STR R1, [R0,N]
5152         (fw->buf[k+3] == 0xE3A01003) &&                 // MOV R1, 3
5153         isSTR(fw, k+4) &&                               // STR R1, [R0,ofst]
5154         (LDR2val(fw,k) < fw->base))
5155     {
5156         uint32_t base = LDR2val(fw,k);
5157         uint32_t ofst = fw->buf[k+4] & 0x00000FFF;
5158         print_stubs_min(fw,"movie_status",base+ofst,idx2adr(fw,k));
5159         return 1;
5160     }
5161     else
5162     if (isLDR_PC(fw, k) &&                              // LDR R1, =sub
5163         isLDR_PC(fw, k+1) &&                            // LDR R0, =base
5164         isSTR(fw, k+2) &&                               // STR R1, [R0,N]
5165         (fw->buf[k+3] == 0xE3A01003) &&                 // MOV R1, 3
5166         isSTR(fw, k+4) &&                               // STR R1, [R0,ofst]
5167         (LDR2val(fw,k+1) < fw->base))
5168     {
5169         uint32_t base = LDR2val(fw,k+1);
5170         uint32_t ofst = fw->buf[k+4] & 0x00000FFF;
5171         print_stubs_min(fw,"movie_status",base+ofst,idx2adr(fw,k));
5172         return 1;
5173     }
5174     else
5175     if (isLDR_PC(fw, k) &&                                      // LDR Rx, =base
5176         isLDR(fw, k+1) && (fwRd(fw,k) == fwRn(fw,k+1)) &&       // LDR R0, [Rx, ...]
5177         isCMP(fw, k+2) && (fwRd(fw,k+2) == fwRd(fw,k+1)) &&     // CMP R0, #...
5178         (fwval(fw,k+3) == 0x03A00005) &&
5179         isSTR_cond(fw, k+4) && (fwRn(fw,k+4) == fwRd(fw,k)) &&  // STRxx R0, [Rx,ofst]
5180         (LDR2val(fw,k) < fw->base))
5181     {
5182         uint32_t base = LDR2val(fw,k);
5183         uint32_t ofst = fwOp2(fw,k+4);
5184         print_stubs_min(fw,"movie_status",base+ofst,idx2adr(fw,k));
5185         return 1;
5186     }
5187     return 0;
5188 }
5189 
5190 int match_full_screen_refresh(firmware *fw, int k, __attribute__ ((unused))uint32_t v1, __attribute__ ((unused))uint32_t v2)
5191 {
5192     if (((fw->buf[k] & 0xFF1FF000) == 0xE51F0000) &&    // LDR R0, =base
5193         (fw->buf[k+1] == 0xE5D01000) &&                 // LDRB R1, [R0]
5194         (fw->buf[k+2] == 0xE3811002) &&                 // ORR R1, R1, #2
5195         (fw->buf[k+3] == 0xE5C01000) &&                 // STRB R1, [R0]
5196         isBX_LR(fw,k+4))                                // BX LR
5197     {
5198         uint32_t base = LDR2val(fw,k);
5199         print_stubs_min(fw,"full_screen_refresh",base,idx2adr(fw,k));
5200     }
5201     return 0;
5202 }
5203 
5204 int match_canon_shoot_menu_active(firmware *fw, int k, __attribute__ ((unused))uint32_t v1, __attribute__ ((unused))uint32_t v2)
5205 {
5206     if (((fw->buf[k]   & 0xFF1FF000) == 0xE51F1000) &&  // LDR R1, =base
5207         ((fw->buf[k+1] & 0xFFFFF000) == 0xE5D10000) &&  // LDRB R0, [R1, #n]
5208         (fw->buf[k+2] == 0xE2800001) &&                 // ADD R0, R0, #1
5209         ((fw->buf[k+3] & 0xFFFFF000) == 0xE5C10000) &&  // STRB R0, [R1, #n]
5210         (isB(fw,k+4)))                                  // B
5211     {
5212         uint32_t base = LDR2val(fw,k);
5213         uint32_t ofst = fw->