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