root/tools/finsig_dryos.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

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

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