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_get_fstype
  25. find_Restart
  26. find_add_ptp_handler
  27. find_PT_PlaySound
  28. find_getImageDirName
  29. match_GetImageFolder
  30. find_GetImageFolder
  31. match_GetDrive_ClusterSize
  32. find_GetDrive_ClusterSize
  33. find_GetDrive_TotalClusters
  34. find_srand
  35. find_malloc_strictly
  36. find_DisplayBusyOnScreen
  37. find_UndisplayBusyOnScreen
  38. find_CreateDialogBox
  39. find_DisplayDialogBox
  40. find_add_ui_to_dialog
  41. find_get_string_by_id
  42. find_get_self_task_errno_pointer
  43. find_get_nd_value
  44. find_get_current_nd_value_iris
  45. find_get_current_nd_value
  46. find_getcurrentmachinetime
  47. find_sethptimeraftertimeout
  48. find_DoMovieFrameCapture
  49. find_get_ptp_buf_size
  50. find_GetBaseSv
  51. find_Remove
  52. find_func
  53. dryos_offset
  54. fw_string_process
  55. fw_string_process_unaligned
  56. fw_process
  57. match_strsig1
  58. match_strsig2a
  59. match_strsig2
  60. match_strsig3a
  61. match_strsig3
  62. match_strsig4a
  63. match_strsig4
  64. match_strsig5a
  65. match_strsig5
  66. match_strsig6
  67. match_strsig7a
  68. match_strsig7
  69. match_strsig8
  70. find_strsig8
  71. find_strsig9
  72. match_strsig11
  73. find_strsig12
  74. match_strsig13a
  75. match_strsig13
  76. match_strsig15a
  77. match_strsig15
  78. match_strsig16
  79. find_strsig17
  80. find_strsig19
  81. match_strsig23a
  82. match_strsig23
  83. match_strsig24
  84. find_strsig
  85. find_str_sig_matches
  86. find_matches
  87. print_results
  88. mode_name
  89. output_modemap
  90. match_modelist
  91. match_FlashParamsTable2
  92. match_FlashParamsTable
  93. find_modemap
  94. match_CAM_UNCACHED_BIT
  95. find_DebugAssert_argcount
  96. find_platform_vals
  97. find_viewport_address
  98. match_vid_get_bitmap_fb
  99. match_get_flash_params_count
  100. match_uiprop_count
  101. match_imager_active
  102. find_lib_vals
  103. print_stubs_min
  104. print_exmem_types
  105. find_exmem_alloc_table
  106. match_levent_table
  107. match_movie_status
  108. match_full_screen_refresh
  109. match_canon_shoot_menu_active
  110. match_playrec_mode
  111. match_some_flag_for_af_scan
  112. match_palette_data
  113. match_palette_buffer_offset
  114. match_palette_data3
  115. match_palette_data2
  116. match_SavePaletteData
  117. match_viewport_address3
  118. match_viewport_address2
  119. match_viewport_address
  120. match_physw_status
  121. match_physw_run
  122. match_canon_menu_active
  123. match_zoom_busy
  124. match_focus_busy
  125. match_bitmap_buffer2
  126. match_bitmap_buffer
  127. match_raw_buffer
  128. match_fileiosem
  129. find_stubs_min
  130. find_ctypes
  131. match_nrflag3
  132. match_nrflag
  133. match_nrflag2
  134. isSTRw
  135. isSTRB
  136. find_leds
  137. find_task_related_info
  138. find_AdditionAgent_RAM
  139. add_prop_hit
  140. match_propsig1a
  141. match_propsig1
  142. find_strsig2
  143. find_prop_matches
  144. find_propset
  145. find_other_vals
  146. print_kval
  147. print_physw_raw_vals
  148. add_kinfo
  149. add_kmval
  150. kinfo_compare
  151. print_kmvals
  152. match_GetSDProtect
  153. find_key_vals
  154. get_eventproc_val
  155. add_func_name
  156. add_func_name2
  157. match_eventproc
  158. match_registerproc2
  159. match_registerproc
  160. match_registerlists
  161. find_eventprocs
  162. findTaskAddress
  163. match_createtask
  164. find_tasks
  165. find_builddate
  166. save_ptp_handler_func
  167. find_ptp_handler_imm
  168. match_ptp_handlers
  169. find_ptp_handlers
  170. write_levent_table_dump
  171. output_firmware_vals
  172. compare_func_names
  173. compare_func_addresses
  174. write_funcs
  175. main

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