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

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