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