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